Index: chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkServiceFactory.java |
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkServiceFactory.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkServiceFactory.java |
index d977edbab65e3f1f13d11a26ef47fe2b94dd8f4a..61a43c40ddfba1e91879d261622fc77817cfc16b 100644 |
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkServiceFactory.java |
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkServiceFactory.java |
@@ -7,6 +7,9 @@ package org.chromium.webapk.shell_apk; |
import android.app.Service; |
import android.content.Context; |
import android.content.Intent; |
+import android.content.SharedPreferences; |
+import android.content.pm.PackageInfo; |
+import android.content.pm.PackageManager; |
import android.os.Bundle; |
import android.os.IBinder; |
import android.util.Log; |
@@ -15,6 +18,7 @@ import org.chromium.webapk.lib.common.WebApkUtils; |
import java.io.File; |
import java.lang.reflect.Constructor; |
+import java.util.Scanner; |
/** |
* Shell class for services provided by WebAPK to Chrome. Extracts code with implementation of |
@@ -29,6 +33,23 @@ public class WebApkServiceFactory extends Service { |
private static final String WEBAPK_SERVICE_IMPL_CLASS_NAME = |
"org.chromium.webapk.lib.runtime_library.WebApkServiceImpl"; |
+ /** |
+ * Name of the shared preferences file. |
+ */ |
+ private static final String PREF_PACKAGE = "org.chromium.webapk.shell_apk"; |
+ |
+ /** |
+ * Name of the shared preference for Chrome's version code. |
+ */ |
+ private static final String REMOTE_VERSION_CODE_PREF = |
+ "org.chromium.webapk.shell_apk.version_code"; |
+ |
+ /** |
+ * Name of the shared preference for the version number of the dynamically loaded dex. |
+ */ |
+ private static final String RUNTIME_DEX_VERSION_PREF = |
+ "org.chromium.webapk.shell_apk.dex_version"; |
+ |
private static final String KEY_SMALL_ICON_ID = "small_icon_id"; |
/* |
@@ -62,7 +83,7 @@ public class WebApkServiceFactory extends Service { |
} |
/** |
- * Gets / creates ClassLaoder for loading {@link WEBAPK_SERVICE_IMPL_CLASS_NAME}. |
+ * Gets / creates ClassLoader for loading {@link WEBAPK_SERVICE_IMPL_CLASS_NAME}. |
* @param context WebAPK's context. |
* @return The ClassLoader. |
*/ |
@@ -85,10 +106,82 @@ public class WebApkServiceFactory extends Service { |
return null; |
} |
+ SharedPreferences preferences = context.getSharedPreferences(PREF_PACKAGE, MODE_PRIVATE); |
+ |
+ int runtimeDexVersion = preferences.getInt(RUNTIME_DEX_VERSION_PREF, -1); |
+ int newRuntimeDexVersion = checkForNewRuntimeDexVersion(preferences, remoteContext); |
+ if (newRuntimeDexVersion == -1) { |
+ newRuntimeDexVersion = runtimeDexVersion; |
+ } |
File localDexDir = context.getDir("dex", Context.MODE_PRIVATE); |
+ if (newRuntimeDexVersion != runtimeDexVersion) { |
+ Log.w(TAG, "Delete cached dex files."); |
+ DexLoader.deleteCachedDexes(localDexDir); |
+ } |
+ |
+ String dexAssetName = WebApkUtils.getRuntimeDexName(newRuntimeDexVersion); |
File remoteDexFile = |
- new File(remoteContext.getDir("dex", Context.MODE_PRIVATE), "web_apk.dex"); |
- return DexLoader.load(remoteContext, "web_apk.dex", WEBAPK_SERVICE_IMPL_CLASS_NAME, |
+ new File(remoteContext.getDir("dex", Context.MODE_PRIVATE), dexAssetName); |
+ return DexLoader.load(remoteContext, dexAssetName, WEBAPK_SERVICE_IMPL_CLASS_NAME, |
remoteDexFile, localDexDir); |
} |
+ |
+ /** |
+ * Checks if there is a new "runtime dex" version number. If there is a new version number, |
+ * updates SharedPreferences. |
+ * @param preferences WebAPK's SharedPreferences. |
+ * @param remoteContext |
+ * @return The new "runtime dex" version number. -1 if there is no new version number. |
+ */ |
+ private static int checkForNewRuntimeDexVersion( |
+ SharedPreferences preferences, Context remoteContext) { |
+ // The "runtime dex" version only changes when {@link remoteContext}'s APK version code |
+ // changes. Checking the APK's version code is less expensive than reading from the APK's |
+ // assets. |
+ PackageInfo remotePackageInfo = null; |
+ try { |
+ remotePackageInfo = remoteContext.getPackageManager().getPackageInfo( |
+ remoteContext.getPackageName(), 0); |
+ } catch (PackageManager.NameNotFoundException e) { |
+ Log.e(TAG, "Failed to get remote package info."); |
+ return -1; |
+ } |
+ |
+ int cachedRemoteVersionCode = preferences.getInt(REMOTE_VERSION_CODE_PREF, -1); |
+ if (cachedRemoteVersionCode == remotePackageInfo.versionCode) { |
+ return -1; |
+ } |
+ |
+ int runtimeDexVersion = readAssetContentsToInt(remoteContext, "webapk_dex_version.txt"); |
+ SharedPreferences.Editor editor = preferences.edit(); |
+ editor.putInt(REMOTE_VERSION_CODE_PREF, remotePackageInfo.versionCode); |
+ editor.putInt(RUNTIME_DEX_VERSION_PREF, runtimeDexVersion); |
+ editor.apply(); |
+ return runtimeDexVersion; |
+ } |
+ |
+ /** |
+ * Returns the first integer in an asset file's contents. |
+ * @param context |
+ * @param assetName The name of the asset. |
+ * @return The first integer. |
+ */ |
+ private static int readAssetContentsToInt(Context context, String assetName) { |
+ Scanner scanner = null; |
+ int value = -1; |
+ try { |
+ scanner = new Scanner(context.getAssets().open(assetName)); |
+ value = scanner.nextInt(); |
+ scanner.close(); |
+ } catch (Exception e) { |
+ } finally { |
+ if (scanner != null) { |
+ try { |
+ scanner.close(); |
+ } catch (Exception e) { |
+ } |
+ } |
+ } |
+ return value; |
+ } |
} |