| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.webapk.shell_apk; | 5 package org.chromium.webapk.shell_apk; |
| 6 | 6 |
| 7 import android.app.Service; | |
| 8 import android.content.Context; | 7 import android.content.Context; |
| 9 import android.content.Intent; | |
| 10 import android.content.SharedPreferences; | 8 import android.content.SharedPreferences; |
| 11 import android.content.pm.PackageInfo; | 9 import android.content.pm.PackageInfo; |
| 12 import android.content.pm.PackageManager; | 10 import android.content.pm.PackageManager; |
| 13 import android.os.Bundle; | |
| 14 import android.os.IBinder; | |
| 15 import android.util.Log; | 11 import android.util.Log; |
| 16 | 12 |
| 17 import org.chromium.webapk.lib.common.WebApkUtils; | 13 import org.chromium.webapk.lib.common.WebApkUtils; |
| 18 | 14 |
| 19 import java.io.File; | 15 import java.io.File; |
| 20 import java.lang.reflect.Constructor; | |
| 21 import java.util.Scanner; | 16 import java.util.Scanner; |
| 22 | 17 |
| 23 /** | 18 /** |
| 24 * Shell class for services provided by WebAPK to Chrome. Extracts code with imp
lementation of | 19 * Creates ClassLoader for WebAPK-specific dex file in Chrome APK's assets. |
| 25 * services from .dex file in Chrome APK. | |
| 26 */ | 20 */ |
| 27 public class WebApkServiceFactory extends Service { | 21 public class HostBrowserClassLoader { |
| 28 private static final String TAG = "cr_WebApkServiceFactory"; | 22 private static final String TAG = "cr_HostBrowserClassLoader"; |
| 29 | |
| 30 /** | |
| 31 * Name of the class with IBinder API implementation. | |
| 32 */ | |
| 33 private static final String WEBAPK_SERVICE_IMPL_CLASS_NAME = | |
| 34 "org.chromium.webapk.lib.runtime_library.WebApkServiceImpl"; | |
| 35 | 23 |
| 36 /** | 24 /** |
| 37 * Name of the shared preferences file. | 25 * Name of the shared preferences file. |
| 38 */ | 26 */ |
| 39 private static final String PREF_PACKAGE = "org.chromium.webapk.shell_apk"; | 27 private static final String PREF_PACKAGE = "org.chromium.webapk.lib.runtime_
library"; |
| 40 | 28 |
| 41 /** | 29 /** |
| 42 * Name of the shared preference for Chrome's version code. | 30 * Name of the shared preference for Chrome's version code. |
| 43 */ | 31 */ |
| 44 private static final String REMOTE_VERSION_CODE_PREF = | 32 private static final String REMOTE_VERSION_CODE_PREF = |
| 45 "org.chromium.webapk.shell_apk.version_code"; | 33 "org.chromium.webapk.lib.runtime_library.version_code"; |
| 46 | 34 |
| 47 /** | 35 /** |
| 48 * Name of the shared preference for the version number of the dynamically l
oaded dex. | 36 * Name of the shared preference for the version number of the dynamically l
oaded dex. |
| 49 */ | 37 */ |
| 50 private static final String RUNTIME_DEX_VERSION_PREF = | 38 private static final String RUNTIME_DEX_VERSION_PREF = |
| 51 "org.chromium.webapk.shell_apk.dex_version"; | 39 "org.chromium.webapk.shell_apk.dex_version"; |
| 52 | 40 |
| 53 /** | |
| 54 * Key for passing id of icon to represent WebAPK notifications in status ba
r. | |
| 55 */ | |
| 56 private static final String KEY_SMALL_ICON_ID = "small_icon_id"; | |
| 57 | |
| 58 /** | |
| 59 * Key for passing package name of only process allowed to call the service'
s methods. | |
| 60 */ | |
| 61 private static final String KEY_HOST_BROWSER_PACKAGE = "host_browser_package
"; | |
| 62 | |
| 63 /* | 41 /* |
| 64 * ClassLoader for loading {@link WEBAPK_SERVICE_IMPL_CLASS_NAME}. Static so
that all | 42 * ClassLoader for WebAPK dex. Static so that the same ClassLoader is used f
or app's lifetime. |
| 65 * {@link WebApkServiceFactory} service instatiations use the same ClassLoad
er during the app's | |
| 66 * lifetime. | |
| 67 */ | 43 */ |
| 68 private static ClassLoader sClassLoader; | 44 private static ClassLoader sClassLoader; |
| 69 | 45 |
| 70 @Override | |
| 71 public IBinder onBind(Intent intent) { | |
| 72 ClassLoader webApkClassLoader = getClassLoaderInstance(this); | |
| 73 if (webApkClassLoader == null) { | |
| 74 Log.w(TAG, "Unable to create ClassLoader."); | |
| 75 return null; | |
| 76 } | |
| 77 | |
| 78 try { | |
| 79 Class<?> webApkServiceImplClass = | |
| 80 webApkClassLoader.loadClass(WEBAPK_SERVICE_IMPL_CLASS_NAME); | |
| 81 Constructor<?> webApkServiceImplConstructor = | |
| 82 webApkServiceImplClass.getConstructor(Context.class, Bundle.
class); | |
| 83 String hostPackageName = WebApkUtils.getHostBrowserPackageName(this)
; | |
| 84 Bundle bundle = new Bundle(); | |
| 85 bundle.putInt(KEY_SMALL_ICON_ID, R.drawable.app_icon); | |
| 86 bundle.putString(KEY_HOST_BROWSER_PACKAGE, hostPackageName); | |
| 87 return (IBinder) webApkServiceImplConstructor.newInstance(new Object
[] {this, bundle}); | |
| 88 } catch (Exception e) { | |
| 89 Log.w(TAG, "Unable to create WebApkServiceImpl."); | |
| 90 e.printStackTrace(); | |
| 91 return null; | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 /** | 46 /** |
| 96 * Gets / creates ClassLoader for loading {@link WEBAPK_SERVICE_IMPL_CLASS_N
AME}. | 47 * Gets / creates ClassLoader for WebAPK dex. |
| 97 * @param context WebAPK's context. | 48 * @param context WebAPK's context. |
| 49 * @param canaryClassname Class to load to check that ClassLoader is valid. |
| 98 * @return The ClassLoader. | 50 * @return The ClassLoader. |
| 99 */ | 51 */ |
| 100 private static ClassLoader getClassLoaderInstance(Context context) { | 52 public static ClassLoader getClassLoaderInstance(Context context, String can
aryClassName) { |
| 101 if (sClassLoader == null) { | 53 if (sClassLoader == null) { |
| 102 sClassLoader = createClassLoader(context); | 54 sClassLoader = createClassLoader(context, canaryClassName); |
| 103 } | 55 } |
| 104 return sClassLoader; | 56 return sClassLoader; |
| 105 } | 57 } |
| 106 | 58 |
| 107 /** | 59 /** |
| 108 * Creates ClassLoader for loading {@link WEBAPK_SERVICE_IMPL_CLASS_NAME}. | 60 * Creates ClassLoader for WebAPK dex. |
| 109 * @param context WebAPK's context. | 61 * @param context WebAPK's context. |
| 62 * @param canaryClassName Class to load to check that ClassLoader is valid. |
| 110 * @return The ClassLoader. | 63 * @return The ClassLoader. |
| 111 */ | 64 */ |
| 112 private static ClassLoader createClassLoader(Context context) { | 65 private static ClassLoader createClassLoader(Context context, String canaryC
lassName) { |
| 113 Context remoteContext = WebApkUtils.getHostBrowserContext(context); | 66 Context remoteContext = WebApkUtils.getHostBrowserContext(context); |
| 114 if (remoteContext == null) { | 67 if (remoteContext == null) { |
| 115 Log.w(TAG, "Failed to get remote context."); | 68 Log.w(TAG, "Failed to get remote context."); |
| 116 return null; | 69 return null; |
| 117 } | 70 } |
| 118 | 71 |
| 119 SharedPreferences preferences = context.getSharedPreferences(PREF_PACKAG
E, MODE_PRIVATE); | 72 SharedPreferences preferences = |
| 73 context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE)
; |
| 120 | 74 |
| 121 int runtimeDexVersion = preferences.getInt(RUNTIME_DEX_VERSION_PREF, -1)
; | 75 int runtimeDexVersion = preferences.getInt(RUNTIME_DEX_VERSION_PREF, -1)
; |
| 122 int newRuntimeDexVersion = checkForNewRuntimeDexVersion(preferences, rem
oteContext); | 76 int newRuntimeDexVersion = checkForNewRuntimeDexVersion(preferences, rem
oteContext); |
| 123 if (newRuntimeDexVersion == -1) { | 77 if (newRuntimeDexVersion == -1) { |
| 124 newRuntimeDexVersion = runtimeDexVersion; | 78 newRuntimeDexVersion = runtimeDexVersion; |
| 125 } | 79 } |
| 126 File localDexDir = context.getDir("dex", Context.MODE_PRIVATE); | 80 File localDexDir = context.getDir("dex", Context.MODE_PRIVATE); |
| 127 if (newRuntimeDexVersion != runtimeDexVersion) { | 81 if (newRuntimeDexVersion != runtimeDexVersion) { |
| 128 Log.w(TAG, "Delete cached dex files."); | 82 Log.w(TAG, "Delete cached dex files."); |
| 129 DexLoader.deleteCachedDexes(localDexDir); | 83 DexLoader.deleteCachedDexes(localDexDir); |
| 130 } | 84 } |
| 131 | 85 |
| 132 String dexAssetName = WebApkUtils.getRuntimeDexName(newRuntimeDexVersion
); | 86 String dexAssetName = WebApkUtils.getRuntimeDexName(newRuntimeDexVersion
); |
| 133 File remoteDexFile = | 87 File remoteDexFile = |
| 134 new File(remoteContext.getDir("dex", Context.MODE_PRIVATE), dexA
ssetName); | 88 new File(remoteContext.getDir("dex", Context.MODE_PRIVATE), dexA
ssetName); |
| 135 return DexLoader.load(remoteContext, dexAssetName, WEBAPK_SERVICE_IMPL_C
LASS_NAME, | 89 return DexLoader.load(remoteContext, dexAssetName, canaryClassName, |
| 136 remoteDexFile, localDexDir); | 90 remoteDexFile, localDexDir); |
| 137 } | 91 } |
| 138 | 92 |
| 139 /** | 93 /** |
| 140 * Checks if there is a new "runtime dex" version number. If there is a new
version number, | 94 * Checks if there is a new "runtime dex" version number. If there is a new
version number, |
| 141 * updates SharedPreferences. | 95 * updates SharedPreferences. |
| 142 * @param preferences WebAPK's SharedPreferences. | 96 * @param preferences WebAPK's SharedPreferences. |
| 143 * @param remoteContext | 97 * @param remoteContext |
| 144 * @return The new "runtime dex" version number. -1 if there is no new versi
on number. | 98 * @return The new "runtime dex" version number. -1 if there is no new versi
on number. |
| 145 */ | 99 */ |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 if (scanner != null) { | 142 if (scanner != null) { |
| 189 try { | 143 try { |
| 190 scanner.close(); | 144 scanner.close(); |
| 191 } catch (Exception e) { | 145 } catch (Exception e) { |
| 192 } | 146 } |
| 193 } | 147 } |
| 194 } | 148 } |
| 195 return value; | 149 return value; |
| 196 } | 150 } |
| 197 } | 151 } |
| OLD | NEW |