Chromium Code Reviews| 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 6513050c52d7f1be52d5745053118c90ea2a41fe..89a21e013cab5855fd19e044c3b1383ca3fbb83a 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.IBinder; |
| import android.util.Log; |
| @@ -14,6 +17,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 |
| @@ -28,6 +32,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_FILE_NAME = "WEBAPK_PREFS"; |
|
Xi Han
2016/05/26 21:40:23
I am not sure whether use "WEBAPK_PREFS" or "webap
|
| + |
| + /** |
| + * 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"; |
| + |
| /* |
| * ClassLoader for loading {@link WEBAPK_SERVICE_IMPL_CLASS_NAME}. Static so that all |
| * {@link WebApkServiceFactory} service instatiations use the same ClassLoader during the app's |
| @@ -81,10 +102,82 @@ public class WebApkServiceFactory extends Service { |
| return null; |
| } |
| + SharedPreferences preferences = context.getSharedPreferences(PREF_FILE_NAME, 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, "web_apk_dex_version.txt"); |
|
Xi Han
2016/05/26 21:40:23
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; |
| + } |
| } |