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 |