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 9bc602db7669e8b66fb23266a35506ef75c806ff..6513050c52d7f1be52d5745053118c90ea2a41fe 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 |
@@ -5,18 +5,86 @@ |
package org.chromium.webapk.shell_apk; |
import android.app.Service; |
+import android.content.Context; |
import android.content.Intent; |
import android.os.IBinder; |
+import android.util.Log; |
-import org.chromium.webapk.lib.runtime_library.WebApkServiceImpl; |
+import org.chromium.webapk.lib.common.WebApkUtils; |
+ |
+import java.io.File; |
+import java.lang.reflect.Constructor; |
/** |
- * Implements services offered by the WebAPK to Chrome. |
+ * Shell class for services provided by WebAPK to Chrome. Extracts code with implementation of |
+ * services from .dex file in Chrome APK. |
*/ |
public class WebApkServiceFactory extends Service { |
+ private static final String TAG = "cr_WebApkServiceFactory"; |
+ |
+ /** |
+ * Name of the class with IBinder API implementation. |
+ */ |
+ private static final String WEBAPK_SERVICE_IMPL_CLASS_NAME = |
+ "org.chromium.webapk.lib.runtime_library.WebApkServiceImpl"; |
+ |
+ /* |
+ * 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 |
+ * lifetime. |
+ */ |
+ private static ClassLoader sClassLoader; |
@Override |
public IBinder onBind(Intent intent) { |
- return new WebApkServiceImpl(this, R.drawable.app_icon); |
+ ClassLoader webApkClassLoader = getClassLoaderInstance(this); |
+ if (webApkClassLoader == null) { |
+ Log.w(TAG, "Unable to create ClassLoader."); |
+ return null; |
+ } |
+ |
+ try { |
+ Class<?> webApkServiceImplClass = |
+ webApkClassLoader.loadClass(WEBAPK_SERVICE_IMPL_CLASS_NAME); |
+ Constructor<?> webApkServiceImplConstructor = |
+ webApkServiceImplClass.getConstructor(Context.class, int.class); |
+ return (IBinder) webApkServiceImplConstructor.newInstance( |
+ new Object[] {this, R.drawable.app_icon}); |
+ } catch (Exception e) { |
+ Log.w(TAG, "Unable to create WebApkServiceImpl."); |
+ e.printStackTrace(); |
+ return null; |
+ } |
+ } |
+ |
+ /** |
+ * Gets / creates ClassLaoder for loading {@link WEBAPK_SERVICE_IMPL_CLASS_NAME}. |
+ * @param context WebAPK's context. |
+ * @return The ClassLoader. |
+ */ |
+ private static ClassLoader getClassLoaderInstance(Context context) { |
+ if (sClassLoader == null) { |
+ sClassLoader = createClassLoader(context); |
+ } |
+ return sClassLoader; |
+ } |
+ |
+ /** |
+ * Creates ClassLoader for loading {@link WEBAPK_SERVICE_IMPL_CLASS_NAME}. |
+ * @param context WebAPK's context. |
+ * @return The ClassLoader. |
+ */ |
+ private static ClassLoader createClassLoader(Context context) { |
+ Context remoteContext = WebApkUtils.getHostBrowserContext(context); |
+ if (remoteContext == null) { |
+ Log.w(TAG, "Failed to get remote context."); |
+ return null; |
+ } |
+ |
+ File localDexDir = context.getDir("dex", Context.MODE_PRIVATE); |
+ 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, |
+ remoteDexFile, localDexDir); |
} |
} |