Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-20251] Android 6.0: java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2016-02-10T04:15:13.000+0000
Affected Version/sn/a
Fix Version/sRelease 5.2.0
ComponentsAndroid
Labelsmerge-5.2.0, module_android_6.0_Permissions, qe-testadded
ReporterEduardo Gomez
AssigneeHieu Pham
Created2016-01-19T22:53:16.000+0000
Updated2016-02-26T14:29:05.000+0000

Description

Issue Description

While trying to write the attachment content in the file and the directory used is temp_directory. As per the use case we have to save the content passed from the cloud server to the file and file is opened by using the intents. This approach is working fine for the os version upto Android 5.0 (lollipop) but on the Android 6.0 (Marshmallow) it’s failing.

Steps to reproduce

1) Get sample attach to run on Android 5 device 2) Monitor and watch logs. App works fine 3) Get sample attach to run on Android 6 device 4) Monitor and watch logs. App won't load file as expected.

Stack Trace

-- Start application log -----------------------------------------------------
[INFO] :   TiApplication: (main) [0,0] checkpoint, app created.
[INFO] :   TiApplication: (main) [58,58] Titanium 5.1.2 (2015/12/16 19:00 ca822b2)
[INFO] :   DatabaseHelper: No value in database for platform key: 'unique_machine_id' returning supplied default ''
[INFO] :   DatabaseHelper: No value in database for platform key: 'hardware_machine_id' returning supplied default ''
[WARN] :   art: Suspending all threads took: 5.501ms
[INFO] :   art: Background sticky concurrent mark sweep GC freed 512(22KB) AllocSpace objects, 0(0B) LOS objects, 1% free, 2MB/2MB, paused 6.183ms total 22.877ms
[INFO] :   TiApplication: (main) [263,321] Titanium Javascript runtime: v8
[INFO] :   TiRootActivity: (main) [0,0] checkpoint, on root activity create, savedInstanceState: null
[WARN] :   V8Object: (KrollRuntimeThread) [249,249] Runtime disposed, cannot set property 'userAgent'
[DEBUG] :  APSAnalyticsModel: Creating Database appcAnalytics.db
[WARN] :   TiTempFileHelper: (main) [354,603] The external temp directory doesn't exist, skipping cleanup
[DEBUG] :  Module: Loading module: alloy -> Resources/alloy.js
[DEBUG] :  Module: Loading module: alloy/underscore -> Resources/alloy/underscore.js
[DEBUG] :  Module: Loading module: alloy/backbone -> Resources/alloy/backbone.js
[DEBUG] :  Module: Loading module: alloy/constants -> Resources/alloy/constants.js
[DEBUG] :  Module: Loading module: alloy/CFG -> Resources/alloy/CFG.js
[DEBUG] :  Module: Loading module: alloy/controllers/index -> Resources/alloy/controllers/index.js
[DEBUG] :  Module: Loading module: alloy/controllers/BaseController -> Resources/alloy/controllers/BaseController.js
[INFO] :   TiRootActivity: (main) [0,0] checkpoint, on root activity resume. activity = com.example.Docx_pocActivity@b56e552
[DEBUG] :  OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
[DEBUG] :  D/        : HostConnection::get() New Host Connection established 0xec8fdc10, tid 10299
[DEBUG] :  Window: Checkpoint: postWindowCreated()
[DEBUG] :  libEGL: loaded /system/lib/egl/libEGL_emulation.so
[DEBUG] :  libEGL: loaded /system/lib/egl/libGLESv1_CM_emulation.so
[DEBUG] :  libEGL: loaded /system/lib/egl/libGLESv2_emulation.so
[DEBUG] :  D/        : HostConnection::get() New Host Connection established 0xed661cf0, tid 10318
[INFO] :   OpenGLRenderer: Initialized EGL, version 1.4
[WARN] :   EGL_emulation: eglSurfaceAttrib not implemented
[WARN] :   OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xf3d3d160, error=EGL_SUCCESS
[TRACE] :  updating tiapp metadata with Appcelerator Platform...
[TRACE] :  Uploaded tiapp metadata with Appcelerator Platform!
[ERROR] :  TiFileProxy: (KrollRuntimeThread) [11875,11875] IOException encountered
[ERROR] :  TiFileProxy: java.io.FileNotFoundException: /storage/emulated/0/Android/data/com.example/cache/_tmp/sample.doc: open failed: ENOENT (No such file or directory)
[ERROR] :  TiFileProxy: 	at libcore.io.IoBridge.open(IoBridge.java:452)
[ERROR] :  TiFileProxy: 	at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
[ERROR] :  TiFileProxy: 	at org.appcelerator.titanium.io.TiFile.getOutputStream(TiFile.java:273)
[ERROR] :  TiFileProxy: 	at org.appcelerator.titanium.io.TiFile.open(TiFile.java:336)
[ERROR] :  TiFileProxy: 	at org.appcelerator.titanium.io.TiFile.write(TiFile.java:382)
[ERROR] :  TiFileProxy: 	at org.appcelerator.titanium.TiFileProxy.write(TiFileProxy.java:284)
[ERROR] :  TiFileProxy: 	at org.appcelerator.kroll.runtime.v8.V8Object.nativeFireEvent(Native Method)
[ERROR] :  TiFileProxy: 	at org.appcelerator.kroll.runtime.v8.V8Object.fireEvent(V8Object.java:62)
[ERROR] :  TiFileProxy: 	at org.appcelerator.kroll.KrollProxy.doFireEvent(KrollProxy.java:908)
[ERROR] :  TiFileProxy: 	at org.appcelerator.kroll.KrollProxy.handleMessage(KrollProxy.java:1131)
[ERROR] :  TiFileProxy: 	at org.appcelerator.titanium.proxy.TiViewProxy.handleMessage(TiViewProxy.java:352)
[ERROR] :  TiFileProxy: 	at android.os.Handler.dispatchMessage(Handler.java:98)
[ERROR] :  TiFileProxy: 	at android.os.Looper.loop(Looper.java:148)
[ERROR] :  TiFileProxy: 	at org.appcelerator.kroll.KrollRuntime$KrollRuntimeThread.run(KrollRuntime.java:112)
[ERROR] :  TiFileProxy: Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
[ERROR] :  TiFileProxy: 	at libcore.io.Posix.open(Native Method)
[ERROR] :  TiFileProxy: 	at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
[ERROR] :  TiFileProxy: 	at libcore.io.IoBridge.open(IoBridge.java:438)
[ERROR] :  TiFileProxy: 	... 13 more
[ERROR] :  Path/type is empty
[INFO] :   APSAnalyticsService: Analytics Service Started
[INFO] :   APSAnalyticsService: Stopping Analytics Service

Attachments

FileDateSize
TIMOB-20251.zip2016-01-20T22:14:13.000+00009953634

Comments

  1. Chee Kiat Ng 2016-01-28

    This has something to do with file permissions model in Android M. It's something we are looking into now.
  2. Hieu Pham 2016-02-03

    master PR: https://github.com/appcelerator/titanium_mobile/pull/7671 modify code to something like this:
       function openDoc(e) {
       	if (!Ti.Android.hasStoragePermission()) {
           	Ti.Android.requestStoragePermissions(function(e) {
               	openDocument("sample.doc");
           	});
       	} else {
       		openDocument("sample.doc");
       
       	}
       }
       
  3. Ashraf Abu 2016-02-03

    Master PR reviewed and merged.
  4. Fokke Zandbergen 2016-02-03

    We keep all other permissions under related namespaces like Ti.Media.has.... Shouldn't this one live under Ti.Filesystem.. ?
  5. Collin Price 2016-02-03

    I don't think this actually fixes the problem for Case 7777 since I am getting this error in TiResponseCache.java
       java.io.FileNotFoundException: /storage/emulated/0/Android/data/com.meridian.android/cache/_tmp/remote-cache/3254c4bb31a1cc5d21043e49f0704efc1a84213c.hdr: open failed: ENOENT (No such file or directory)
       	at libcore.io.IoBridge.open(IoBridge.java:452)
       	at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
       	at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
       	at java.io.FileWriter.<init>(FileWriter.java:42)
       	at org.appcelerator.titanium.util.TiResponseCache.put(TiResponseCache.java:472)
       	at com.android.okhttp.internal.huc.CacheAdapter.put(CacheAdapter.java:57)
       	at com.android.okhttp.internal.http.HttpEngine.maybeCache(HttpEngine.java:554)
       	at com.android.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:826)
       	at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:443)
       	at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:388)
       	at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:231)
       	at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
       	at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java)
       	at xxxxxx.chchcc.bссссс04410441(Unknown Source)
       	at xxxxxx.chhchc.run(Unknown Source)
       	at xxxxxx.hchchc.bссс0441044104410441(Unknown Source)
       	at xxxxxx.chhhcc.b04410441ссс04410441(Unknown Source)
       	at xxxxxx.jajaja.bЙЙ041904190419ЙЙ(Unknown Source)
       	at xxxxxx.ijjjij.activate(Unknown Source)
       	at ca.interac.flash.activate.ActivateImpl$2.doInBackground(ActivateImpl.java:174)
       	at ca.interac.flash.activate.ActivateImpl$2.doInBackground(ActivateImpl.java:146)
       	at android.os.AsyncTask$2.call(AsyncTask.java:295)
       	at java.util.concurrent.FutureTask.run(FutureTask.java:237)
       	at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
       	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
       	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
       	at java.lang.Thread.run(Thread.java:818)
       Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
       	at libcore.io.Posix.open(Native Method)
       	at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
       	at libcore.io.IoBridge.open(IoBridge.java:438)
       	... 26 more
       
  6. Hieu Pham 2016-02-03

    Colin, the responseCache error is probably due to lack of storage permission on Android 6.0 (Since you have to manually request for these permissions now). Please test the PR and let us know, thanks.
  7. Collin Price 2016-02-03

    Tested PR in Ti SDK 6.0.0.v20160202173231 and fails. Can we please get someone who understands what TiResponseCache is doing on this issue? I am using a third-party library that must be using URLConnection. Since Titanium defines a default ResponseCache (https://github.com/appcelerator/titanium_mobile/blob/master/android/titanium/src/java/org/appcelerator/titanium/TiApplication.java#L440) any library that attempts an HTTP request will automatically be opted in to TiResponseCache without any control. If a developer would just look at the stacktrace I provided they will see that the exception is rooted on line 472 (https://github.com/appcelerator/titanium_mobile/blob/bc85170157d3bebc5de1d61a9fe6e34bce84a8c9/android/titanium/src/java/org/appcelerator/titanium/util/TiResponseCache.java#L472) of TiResponseCache. Since TiResponseCache has not been affected by the PR it does not check if it has permissions before attempting to write the file.
  8. Hieu Pham 2016-02-03

    Colin, TiResponseCache is trying to cache the file, and in order to do that, it needs storage permission. The difference between Android 6.0 (failed version) and Android 5.0 (working - according to this ticket) is you need to manually request the permissions. Did you make changes to your code via my last comment before testing it? i.e make sure you request the permission before launching the HTTP request that would trigger the cache? If the crash persists, it is likely due to a different problem. The test case provided in this ticket does not involve the use of TiResponseCache, and it is fixed with my PR. If you can provide us with a new test project that would reproduce your problem, we'll take a deeper look into it. Thanks,
  9. Collin Price 2016-02-03

    If there isn't file permission then TiResponseCache shouldn't cache the file......................
  10. Collin Price 2016-02-03

    I know the issue is with TiResponseCache because when I forked Titanium and removed TiResponseCache the problem went away. https://github.com/collinprice/titanium_mobile/commit/7a4ed274ce65e6f2ddb3f58e6e59466016339144 An app should not require storage permissions to make an HTTP request. Would you agree?
  11. Ingo Muschenetz 2016-02-03

    [~CollinPrice] The proposed change I am now suggesting is that if we do not have storage permissions, we won't cache the response. That could lead to a slowdown in network response times. Thoughts?
  12. Lokesh Choudhary 2016-02-03

    After looking at the PR, [~fokkezb]'s suggestion to keep it in Ti.Filesystem makes sense as all the media related permissions are in Ti.Media & geolocation in Ti.geolocation. Also, Ti.Android.hasStoragePermission() should be Ti.Android.hasStoragePermissions() (notice the "s" in permissions) to be in parity with other permissions for android 6.0.0.
  13. Collin Price 2016-02-04

    Ingo, having storage permissions is fine. Having no storage permission checks within TiResponseCache is the issue. Let me explain my use case and maybe the issue will become more apparent. I have created a Titanium native module that wraps a third-party library. I am basically just creating the bridge to the third-party library API. This third-party library performs HTTP requests within an Android service so I have no insight into these requests. Since Titanium registers a default ResponseCache, all HTTP requests that use URLConnection within the context of the app pass through the default ResponseCache. This third-party library doesn't care about caching but since it uses URLConnection it automatically uses it when it performs a request. Basically if you want to continue to use TiResponseCache just modify it so that if storage permissions aren't there do not cache. If a developer wants to use the cache they can manually prompt this new requestStoragePermissions API. I as the developer don't care about caching so I shouldn't have to worry about calling requestStoragePermissions. What do you think?
  14. Ashraf Abu 2016-02-05

    In hindsight, I think I'll +1 Fokke's suggestion on the namespace being moved to filesystem.
  15. Ashraf Abu 2016-02-09

    New PR by Hieu (Master branch) https://github.com/appcelerator/titanium_mobile/pull/7689
  16. Ashraf Abu 2016-02-09

    PR merged into master.
  17. Ingo Muschenetz 2016-02-09

    [~hpham] [~msamah], yes, backport.
  18. Hieu Pham 2016-02-09

    Backport PR: https://github.com/appcelerator/titanium_mobile/pull/7692
  19. Ashraf Abu 2016-02-10

    Backport PR Merged.
  20. Ashraf Abu 2016-02-10

    PR for removing unused imports:- 5_2_X: https://github.com/appcelerator/titanium_mobile/pull/7693 Master: https://github.com/appcelerator/titanium_mobile/pull/7694
  21. Srikanth Sombhatla 2016-02-10

    Reviewed and merged.
  22. Lokesh Choudhary 2016-02-10

    Verified the implementation & corrections. hasStoragePermissions() is inside Ti.Filesystem. Files or images in the filesystem can be accessed after permissions are granted. Closing. Environment: Appc Studio : 4.5.0.201602100601 Ti SDK : 5.2.0.v20160210100738 Ti CLI : 5.0.6 Alloy : 1.7.33 MAC Yosemite : 10.10.5 Appc NPM : 4.2.3-2 Appc CLI : 5.2.0-249 Node: 4.2.2 Nexus 6P - Android 6.0.1
  23. Eric Cheung 2016-02-24

    I played around with the 5.2.0 SDK and Nexus 6P... for the most part everything seems to work except for one case with runtime. if I use Ti.Filesystem.tempDirectory as my storage and created the permission checks, this still fails on first try even if you accept the Permission. I also believe the reporter's log show that his app is using the tempDirectory. Steps to recreate: * make sure it is a clean install (not overwriting) * Download file using tempDirectory storage * Use hasStoragePermissions() and requestStoragePermissions() to open the file * Accept the permission on popup. * Accessing the file in temp fails. (file does not exist) * Close the app * Check permission in settings > app permission (storage should be enabled) * Restart the app * Repeat the same step to download and open, accessing the file works in tempDirectory storage. If I switch the tempDirectory to applicationDataDirectory, I do not run into the issue of having to restart the app to open the file.
  24. Fokke Zandbergen 2016-02-26

    [~echeung@leviton.com] Thank you for spotting this. Since this ticket is closed for the released 5.2.0, could you create a new ticket and link to this one? We can then triage and consider for 5.2.1 (cc [~cng])
  25. Eric Cheung 2016-02-26

JSON Source