You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2015/03/13 15:51:18 UTC

cordova-plugin-file git commit: Add a cache to speed up AssetFilesystem directory listings

Repository: cordova-plugin-file
Updated Branches:
  refs/heads/master eaaaa4803 -> 29804228a


Add a cache to speed up AssetFilesystem directory listings

Adds a gradle step to pre-populate the cache as well, but does not
enable it in this commit.


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/29804228
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/29804228
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/29804228

Branch: refs/heads/master
Commit: 29804228a6b53f7b8f0598e495143ffacecb65b0
Parents: eaaaa48
Author: Andrew Grieve <ag...@chromium.org>
Authored: Thu Mar 12 23:12:30 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Fri Mar 13 10:48:39 2015 -0400

----------------------------------------------------------------------
 src/android/AssetFilesystem.java | 53 ++++++++++++++++++++++++++++++++---
 src/android/FileUtils.java       | 12 ++++----
 src/android/LocalFilesystem.java |  9 ++----
 src/android/build-extras.gradle  | 50 +++++++++++++++++++++++++++++++++
 4 files changed, 109 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/29804228/src/android/AssetFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/AssetFilesystem.java b/src/android/AssetFilesystem.java
index c1c0d6f..525d188 100644
--- a/src/android/AssetFilesystem.java
+++ b/src/android/AssetFilesystem.java
@@ -20,6 +20,7 @@ package org.apache.cordova.file;
 
 import android.content.res.AssetManager;
 import android.net.Uri;
+import android.util.Log;
 
 import org.apache.cordova.CordovaResourceApi;
 import org.json.JSONArray;
@@ -29,11 +30,55 @@ import org.json.JSONObject;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.HashMap;
+import java.util.Map;
 
 public class AssetFilesystem extends Filesystem {
 
     private final AssetManager assetManager;
 
+    // A custom gradle hook creates the cdvasset.manifest file, which speeds up asset listing a tonne.
+    // See: http://stackoverflow.com/questions/16911558/android-assetmanager-list-incredibly-slow
+    private static Object listCacheLock = new Object();
+    private static boolean listCacheFromFile;
+    private static Map<String, String[]> listCache;
+
+    private String[] listAssets(String assetPath) throws IOException {
+        synchronized (listCacheLock) {
+            if (listCache == null) {
+                ObjectInputStream ois = null;
+                try {
+                    ois = new ObjectInputStream(assetManager.open("cdvasset.manifest"));
+                    listCache = (Map<String, String[]>) ois.readObject();
+                    listCacheFromFile = true;
+                } catch (FileNotFoundException e) {
+                    // Asset manifest won't exist if the gradle hook isn't set up correctly.
+                } catch (ClassNotFoundException e) {
+                    e.printStackTrace();
+                } finally {
+                    if (ois != null) {
+                        ois.close();
+                    }
+                }
+                if (listCache == null) {
+                    Log.w("AssetFilesystem", "Asset manifest not found. Recursive copies and directory listing will be slow.");
+                    listCache = new HashMap<String, String[]>();
+                }
+            }
+        }
+        String[] ret = listCache.get(assetPath);
+        if (ret == null) {
+            if (listCacheFromFile) {
+                ret = new String[0];
+            } else {
+                ret = assetManager.list(assetPath);
+                listCache.put(assetPath, ret);
+            }
+        }
+        return ret;
+    }
+
     public AssetFilesystem(AssetManager assetManager, CordovaResourceApi resourceApi) {
         super(Uri.parse("file:///android_asset/"), "assets", resourceApi);
         this.assetManager = assetManager;
@@ -76,15 +121,15 @@ public class AssetFilesystem extends Filesystem {
         return LocalFilesystemURL.parse(b.build());
     }
 
-    private Boolean isDirectory(String assetPath) {
+    private boolean isDirectory(String assetPath) {
         if (assetPath.startsWith("/")) {
             assetPath = assetPath.substring(1);
         }
         try {
-            return assetManager.list(assetPath).length != 0;
+            return listAssets(assetPath).length != 0;
         } catch (IOException e) {
+            return false;
         }
-        return false;
     }
 
     private LocalFilesystemURL URLforFullPath(String fullPath) {
@@ -105,7 +150,7 @@ public class AssetFilesystem extends Filesystem {
 
         String[] files;
         try {
-            files = assetManager.list(pathNoSlashes);
+            files = listAssets(pathNoSlashes);
         } catch (IOException e) {
             throw new FileNotFoundException();
         }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/29804228/src/android/FileUtils.java
----------------------------------------------------------------------
diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java
index 80d281b..ba096ad 100644
--- a/src/android/FileUtils.java
+++ b/src/android/FileUtils.java
@@ -111,7 +111,7 @@ public class FileUtils extends CordovaPlugin {
                 if (fsRoot != null) {
                     File newRoot = new File(fsRoot);
                     if (newRoot.mkdirs() || newRoot.isDirectory()) {
-                        registerFilesystem(new LocalFilesystem(fsName, webView.getContext(), webView.getResourceApi(), Uri.fromFile(newRoot)));
+                        registerFilesystem(new LocalFilesystem(fsName, webView.getContext(), webView.getResourceApi(), newRoot));
                         installedFileSystems.add(fsName);
                     } else {
                        Log.d(LOG_TAG, "Unable to create root dir for filesystem \"" + fsName + "\", skipping");
@@ -184,15 +184,17 @@ public class FileUtils extends CordovaPlugin {
 
     	if (this.configured) {
 			// Create the directories if they don't exist.
-			new File(tempRoot).mkdirs();
-			new File(persistentRoot).mkdirs();
+			File tmpRootFile = new File(tempRoot);
+            File persistentRootFile = new File(persistentRoot);
+            tmpRootFile.mkdirs();
+            persistentRootFile.mkdirs();
 
     		// Register initial filesystems
     		// Note: The temporary and persistent filesystems need to be the first two
     		// registered, so that they will match window.TEMPORARY and window.PERSISTENT,
     		// per spec.
-    		this.registerFilesystem(new LocalFilesystem("temporary", webView.getContext(), webView.getResourceApi(), tempRoot));
-    		this.registerFilesystem(new LocalFilesystem("persistent", webView.getContext(), webView.getResourceApi(), persistentRoot));
+    		this.registerFilesystem(new LocalFilesystem("temporary", webView.getContext(), webView.getResourceApi(), tmpRootFile));
+    		this.registerFilesystem(new LocalFilesystem("persistent", webView.getContext(), webView.getResourceApi(), persistentRootFile));
     		this.registerFilesystem(new ContentFilesystem(webView.getContext(), webView.getResourceApi()));
             this.registerFilesystem(new AssetFilesystem(webView.getContext().getAssets(), webView.getResourceApi()));
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/29804228/src/android/LocalFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystem.java b/src/android/LocalFilesystem.java
index 35a8668..355cccf 100644
--- a/src/android/LocalFilesystem.java
+++ b/src/android/LocalFilesystem.java
@@ -39,13 +39,10 @@ import android.content.Intent;
 public class LocalFilesystem extends Filesystem {
     private final Context context;
 
-    public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, String rootPath) {
-        this(name, context, resourceApi, Uri.fromFile(new File(rootPath)).buildUpon().appendPath("").build());
+    public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, File fsRoot) {
+        super(Uri.fromFile(fsRoot).buildUpon().appendEncodedPath("").build(), name, resourceApi);
+        this.context = context;
     }
-	public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, Uri rootUri) {
-        super(rootUri, name, resourceApi);
-		this.context = context;
-	}
 
     public String filesystemPathForFullPath(String fullPath) {
 	    return new File(rootUri.getPath(), fullPath).toString();

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/29804228/src/android/build-extras.gradle
----------------------------------------------------------------------
diff --git a/src/android/build-extras.gradle b/src/android/build-extras.gradle
new file mode 100644
index 0000000..cf4ad92
--- /dev/null
+++ b/src/android/build-extras.gradle
@@ -0,0 +1,50 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+ext.postBuildExtras = {
+    android.applicationVariants.all { variant ->
+        def variantName = variant.name.capitalize()
+        def processResourcesTask = tasks["process${variantName}Resources"]
+        def inAssetsDir = variant.mergeAssets.rawInputFolders.iterator().next()
+        def outAssetsDir = inAssetsDir
+        def outFile = new File(outAssetsDir, "cdvasset.manifest")
+
+        def newTask = task("cdvCreateAssetManifest$variantName") << {
+            println("Reading from ${inAssetsDir}")
+            println("Writing to ${outFile}")
+
+            def contents = new HashMap()
+            contents[""] = inAssetsDir.list()
+            def tree = fileTree(dir: inAssetsDir)
+            tree.visit { fileDetails ->
+                if (fileDetails.isDirectory()) {
+                    contents[fileDetails.relativePath.toString()] = fileDetails.file.list()
+                }
+            }
+
+            outAssetsDir.mkdirs()
+            outFile.withObjectOutputStream { oos ->
+                oos.writeObject(contents)
+            }
+        }
+        newTask.dependsOn(tasks["prepare${variantName}Dependencies"])
+        newTask.inputs.dir inAssetsDir
+        newTask.outputs.file outFile
+        processResourcesTask.dependsOn(newTask)
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org