Uploaded image for project: 'Apache Cordova'
  1. Apache Cordova
  2. CB-9068

FileWriter.write() failure on Lollipop when no ext_sdcard present

    XMLWordPrintableJSON

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Critical
    • Resolution: Fixed
    • Affects Version/s: 5.0.0
    • Fix Version/s: None
    • Environment:

      Android Emulator (4.4.2, 5.0.1 and 5.1.1)
      Xperia Sola (with 4.4.4)
      Xperia Z3 Compact (5.0.2)


      Cordova 5.0.0 / 5.1.1
      cordova-android 4.0.0 / 4.0.2

      Description

      FileWriter write method fails on android lollipop versions when no external sdcard is present.

      Simple test case:

      function fwriteTest(){
      		console.log("START FILE WRITE!!");
      		console.log("CDV dataDirectory: " + cordova.file.dataDirectory);
      
      		window.resolveLocalFileSystemURL(cordova.file.dataDirectory, resolveLocalFSUrlWin, resolveLocalFSUrlErr);
      	}
      
      	function resolveLocalFSUrlErr(err){ console.log("resolve FS ERR: -- " + JSON.stringify(err)); }
      	function resolveLocalFSUrlWin(dirEntry){
      		console.log("resolve FS WIN!!");
      
      		dirEntry.getFile('fileWriter.txt', { create: true, exclusive: false }, getFileWin, getFileErr);
      	}
      
      	function getFileErr(err){ console.log("get file ERR: -- " + JSON.stringify(err)); }
      	function getFileWin(fileEntry){
      		console.log("get file WIN!!");
      
      		fileEntry.createWriter(
      			function(writer){
      				writer.onwrite = function(evt){
      					console.log("Write to file WIN!!");
      					alert("ALL GOOD!!");
      				};
      
      				writer.onerror = function(err){
      					console.log("Write to file FAIL: -- " + JSON.stringify(err));
      				}
      
      				writer.write("sample text goes hereee");
      			},
      			function(err){
      				 console.log("create writer ERR: -- " + JSON.stringify(err)); 
      			}
      		);
      	}
      
             //run test!
            fwriteTest();
      

      AndroidManifest.xml contains the following permission, so it's all good here:

      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

      I have two android devices, different android versions (4.4.4 and 5.0.2) and I have 3 android emulators with android 4.4.2, 5.0.1 and 5.1.1.
      I tested all environments with and without ext_sdcard (for emulators do not enter "Size" for Sd card option) and here are my results:

      Android 4.4.4 with & without extSD (XPERIA Sola)
      ==================================
      
      LEVEL |         TAG      |       TEXT
      =======================================
      I     | chromium         | [INFO:CONSOLE(228)] "START FILE WRITE!!", source: <...>
      --------------------------------
      I     | chromium         | [INFO:CONSOLE(229)] "CDV dataDirectory: file:///data/data/cdv.filewriter.issue/files/", source: <...>
      --------------------------------
      W     | AssetFilesystem  | Asset manifest not found. Recursive copies and directory listing will be slow.
      --------------------------------
      I     | chromium         | [INFO:CONSOLE(236)] "resolve FS WIN!!", source: <...>
      --------------------------------
      I     | chromium         | [INFO:CONSOLE(243)] "get file WIN!!", source: <...>
      --------------------------------
      D     | TEST             | cdvfile://localhost/files/fileWriter.txt: 23
      --------------------------------
      I     | chromium         | [INFO:CONSOLE(248)] "Write to file WIN!!", source: <...>
      
      
      ANDROID 4.4.2 without sdcard / with sdcard (EMULATOR)
      ==========================================
      < same output as XPERIA Sola >
      
      
      ANDROID 5.0.2 without extSD (XPERIA Z3 Compact)
      ===========================
      
      LEVEL |         TAG      |       TEXT
      =======================================
      I     | chromium         | [INFO:CONSOLE(228)] "START FILE WRITE!!", source: <...>
      ---------------------------------------
      I     | chromium         | [INFO:CONSOLE(229)] "CDV dataDirectory: file:///data/data/cdv.filewriter.issue/files/", source: <...>
      ---------------------------------------
      W     | AssetFilesystem  | Asset manifest not found. Recursive copies and directory listing will be slow.
      ---------------------------------------
      I     | chromium         | [INFO:CONSOLE(236)] "resolve FS WIN!!", source: <...>
      ---------------------------------------
      I     | chromium         | [INFO:CONSOLE(243)] "get file WIN!!", source: <...>
      ---------------------------------------
      W     | ContextImpl      | Failed to ensure directory: /storage/sdcard1/Android/media/cdv.filewriter.issue
      ---------------------------------------
      I     | chromium         | [INFO:CONSOLE(253)] "Write to file FAIL: -- {"type":"error","bubbles":false,"cancelBubble":false,"cancelable":false,"lengthComputable":false,"loaded":0,"total":0,"target":{"fileName":"","length":23,"localURL":"cdvfile://localhost/files/fileWriter.txt","position":0,"readyState":2,"result":null,"error":{"code":6},"onwritestart":null,"onprogress":null,"onwriteend":null,"onabort":null}}", source: <...>
      
      
      ANDROID 5.0.2 with extSD
      ========================
      < same output as 4.4.4 >
      
      
      ANDROID 5.0.1 & 5.1.1  without sdcard (EMULATOR)
      =====================================
      < same output as XPERIA Z3 Compact >
      
      ANDROID 5.0.1 & 5.1.1  with sdcard (EMULATOR)
      ==================================
      < same output as XPERIA Sola >
      

      All results are from LogCat console from android-sdk/tools/monitor tool.

      I use Crosswalk 12-stable version as my default webview, but I have tested all this with System-webview too and the problem persists.

      As you can see from printed error on write fail - there is a error 6 code and from what I've read here it's a NO_MODIFICATION_ALLOWED_ERR error.

      You can also replace cordova.file.dataDirectory with any other path (i have tried cacheDirectory and tempDirectory) or with a FileSystem path like LocalFileSystem.PERSISTENT (in this case you'll have to modify the dirEntry.getFile into dirEntry.root.getFile and the resolveLocalFileSystemUrl with requestFileSystem method and its arguments) - issue will persist!

      Am I missing some configurations/permissions or it's really a bug?

      UPDATE #1

      After some more debugging time I found a possible problem.

      • on lollipop each time I try to write something to dataDirectory (or any other path), the system first checks for "/storage/sdcard1/Android/media/app.unique.id" (this is on external sdcard) - if it doesn't exist, then it will be created, otherwise nothing happens here.
      • in case the external sdcard is not present, then the FileWriter.write() will trigger the error event, although the file will be (created and) saved on the specified path!

      So, the issue after all is the error event that's been called and this, for me and probably others that depend on the success event, it changes the app behaviour.

      I have upgraded my Xperia Sola to unofficial lollipop and same thing happens. The Xperia Z3 Compact has the stock version on it (no root, nothing that could interfere with the system).

      Might this be a plugin issue or is lollipop related?

      UPDATE #2

      I don't know if it's related, but here we go!

      storage directory structure:

      • sdcard0 (internal memory)
      • sdcard1 (external sdcard) - empty if no external sdcard present.
      • emulated/0 (internal memory on Z3Compact / Nexus 4; same content as sdcard0 - symlink). From what I've searched this is for multi-user purpose & app backward compatibility.

      From cordova-plugin-file docs:

      Note: If external storage can't be mounted, the cordova.file.external* properties are null.

      With or without external sdcard, all the cordova.external.* paths link to sdcard0 (or emualted/0) and this happens on both kitkat and lollipop. Is it normal? I always thought that the cordova.external.* refers to directories within removable sdcard (sdcard1) and if not present then fallbacks to sdcard0...
      Tested on real devices.

      UPDATE #3

      Tested within Phonegap Developer App - everything works!

        Attachments

          Activity

            People

            • Assignee:
              bowserj Joey Robert Bowser
              Reporter:
              TanaseButcaru Tanase Butcaru
            • Votes:
              1 Vote for this issue
              Watchers:
              6 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: