package com.tws.plugin.core; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import tws.component.log.TwsLog; import android.annotation.TargetApi; import android.app.Activity; import android.app.Application; import android.app.Application.ActivityLifecycleCallbacks; import android.app.Instrumentation; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import com.tws.plugin.content.LoadedPlugin; import com.tws.plugin.content.PluginDescriptor; import com.tws.plugin.core.android.HackActivityThread; import com.tws.plugin.core.android.HackApplication; import com.tws.plugin.core.android.HackSupportV4LocalboarcastManager; import com.tws.plugin.core.compat.CompatForWebViewFactoryApi21; import com.tws.plugin.core.localservice.LocalServiceManager; import com.tws.plugin.manager.PluginActivityMonitor; import com.tws.plugin.manager.PluginManagerHelper; import com.tws.plugin.util.ProcessUtil; import dalvik.system.DexClassLoader; /** * <Pre> * @author yongchen * </Pre> * */ public class PluginLauncher implements Serializable { private static final String TAG = "rick_Print:PluginLauncher"; private static PluginLauncher runtime; private ConcurrentHashMap<String, LoadedPlugin> loadedPluginMap = new ConcurrentHashMap<String, LoadedPlugin>(); private PluginLauncher() { if (!ProcessUtil.isPluginProcess()) { throw new IllegalAccessError("本类仅在插件进程使用"); } } public static PluginLauncher instance() { if (runtime == null) { synchronized (PluginLauncher.class) { if (runtime == null) { runtime = new PluginLauncher(); } } } return runtime; } public LoadedPlugin getRunningPlugin(String packageName) { return loadedPluginMap.get(packageName); } public LoadedPlugin startPlugin(String packageName) { PluginDescriptor pluginDescriptor = PluginManagerHelper.getPluginDescriptorByPluginId(packageName); if (pluginDescriptor != null) { return startPlugin(pluginDescriptor); } return null; } public synchronized LoadedPlugin startPlugin(PluginDescriptor pluginDescriptor) { LoadedPlugin plugin = loadedPluginMap.get(pluginDescriptor.getPackageName()); if (plugin == null) { long beginTime = System.currentTimeMillis(); TwsLog.d(TAG, "正在初始化插: " + pluginDescriptor.getPackageName() + ": Resources, DexClassLoader, Context, Application"); TwsLog.d( TAG, "插件信息 Ver:" + pluginDescriptor.getVersion() + " InstalledPath=" + pluginDescriptor.getInstalledPath()); Resources pluginRes = PluginCreator.createPluginResource( PluginLoader.getApplication().getApplicationInfo().sourceDir, PluginLoader.getApplication() .getResources(), pluginDescriptor); if (pluginRes == null) { TwsLog.e(TAG, "初始化插件失败"); } long ct_Res_end = System.currentTimeMillis(); TwsLog.d(TAG, "初始化插件资源 耗时:" + (ct_Res_end - beginTime)); DexClassLoader pluginClassLoader = PluginCreator.createPluginClassLoader( pluginDescriptor.getInstalledPath(), pluginDescriptor.isStandalone(), pluginDescriptor.getDependencies(), pluginDescriptor.getMuliDexList()); long ct_Dex_end = System.currentTimeMillis(); TwsLog.d(TAG, "初始化插件DexClassLoader 耗时:" + (ct_Dex_end - ct_Res_end)); PluginContextTheme pluginContext = (PluginContextTheme) PluginCreator.createPluginContext(pluginDescriptor, PluginLoader.getApplication().getBaseContext(), pluginRes, pluginClassLoader); // 插件Context默认主题设置为插件application主题 pluginContext.setTheme(pluginDescriptor.getApplicationTheme()); long ct_Theme_end = System.currentTimeMillis(); TwsLog.d(TAG, "初始化插件Theme 耗时:" + (ct_Theme_end - ct_Dex_end)); plugin = new LoadedPlugin(pluginDescriptor.getPackageName(), pluginDescriptor.getInstalledPath(), pluginContext, pluginClassLoader); loadedPluginMap.put(pluginDescriptor.getPackageName(), plugin); if (Thread.currentThread() == Looper.getMainLooper().getThread()) { TwsLog.i(TAG, "当前执行插件初始化的线程是主线程,开始初始化插件Application"); initApplication(pluginContext, pluginClassLoader, pluginRes, pluginDescriptor, plugin); } else { TwsLog.i(TAG, "当前执行插件初始化的线程不是主线程,异步通知主线程初始化插件Application:" + Thread.currentThread().getId() + " name is " + Thread.currentThread().getName()); final LoadedPlugin finalLoadedPlugin = plugin; new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { if (finalLoadedPlugin.pluginApplication == null) { PluginLauncher.instance().initApplication(finalLoadedPlugin.pluginContext, finalLoadedPlugin.pluginClassLoader, finalLoadedPlugin.pluginContext.getResources(), ((PluginContextTheme) finalLoadedPlugin.pluginContext).getPluginDescriptor(), finalLoadedPlugin); } } }); } long ct_end = System.currentTimeMillis(); TwsLog.d(TAG, "startPlugin 耗时:" + (ct_end - beginTime)); } else { // LogUtil.d("IS RUNNING", packageName); } return plugin; } public void initApplication(Context pluginContext, DexClassLoader pluginClassLoader, Resources pluginRes, PluginDescriptor pluginDescriptor, LoadedPlugin plugin) { TwsLog.i(TAG, "开始初始化插件:" + pluginDescriptor.getPackageName() + " " + pluginDescriptor.getApplicationName()); long t13 = System.currentTimeMillis(); Application pluginApplication = callPluginApplicationOnCreate(pluginContext, pluginClassLoader, pluginDescriptor); plugin.pluginApplication = pluginApplication;// 这里之所以不放在LoadedPlugin的构造器里面,是因为contentprovider在安装时loadclass,造成死循环 long t3 = System.currentTimeMillis(); TwsLog.d(TAG, "初始化插件 " + pluginDescriptor.getPackageName() + " " + pluginDescriptor.getApplicationName() + ", 耗时:" + (t3 - t13)); try { HackActivityThread.installPackageInfo(PluginLoader.getApplication(), pluginDescriptor.getPackageName(), pluginDescriptor, pluginClassLoader, pluginRes, pluginApplication); } catch (ClassNotFoundException e) { e.printStackTrace(); } CompatForWebViewFactoryApi21.addWebViewAssets(plugin.pluginApplication.getAssets()); TwsLog.d(TAG, "初始化插件" + pluginDescriptor.getPackageName() + "完成"); } private Application callPluginApplicationOnCreate(Context pluginContext, DexClassLoader classLoader, PluginDescriptor pluginDescriptor) { Application application = null; try { TwsLog.d(TAG, "创建插件Application:" + pluginDescriptor.getApplicationName()); // 为了支持插件中使用multidex ((PluginContextTheme) pluginContext).setCrackPackageManager(true); application = Instrumentation.newApplication(classLoader.loadClass(pluginDescriptor.getApplicationName()), pluginContext); // 为了支持插件中使用multidex ((PluginContextTheme) pluginContext).setCrackPackageManager(false); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } // 安装ContentProvider, 在插件Application对象构造以后,oncreate调用之前 PluginInjector.installContentProviders(PluginLoader.getApplication(), application, pluginDescriptor .getProviderInfos().values()); // 执行onCreate if (application != null) { ((PluginContextTheme) pluginContext).setPluginApplication(application); // 先拿到宿主的crashHandler Thread.UncaughtExceptionHandler old = Thread.getDefaultUncaughtExceptionHandler(); application.onCreate(); // 再还原宿主的crashHandler,这里之所以需要还原CrashHandler, // 是因为如果插件中自己设置了自己的crashHandler(通常是在oncreate中), // 会导致当前进程的主线程的handler被意外修改。 // 如果有多个插件都有设置自己的crashHandler,也会导致混乱 // 所以这里直接屏蔽掉插件的crashHandler // TODO 或许也可以做成消息链进行分发? Thread.setDefaultUncaughtExceptionHandler(old); if (Build.VERSION.SDK_INT >= 14) { // ActivityLifecycleCallbacks // 的回调实际是由Activity内部在自己的声明周期函数内主动调用application的注册的callback触发的 // 由于我们把插件Activity内部的application成员变量替换调用了 // 会导致不会触发宿主中注册的ActivityLifecycleCallbacks // 那么我们在这里给插件的Application对象注册一个callback // bridge。将插件的call发给宿主的call, // 从而使得宿主application中注册的callback能监听到插件Activity的声明周期 application.registerActivityLifecycleCallbacks(new LifecycleCallbackBridge(PluginLoader .getApplication())); } else { // 对于小于14的版本,影响是,StubActivity的绑定关系不能被回收, // 意味着宿主配置的非Stand的StubActivity的个数不能小于插件中对应的类型的个数的总数,否则可能会出现找不到映射的StubActivity } } return application; } public void stopPlugin(String packageName, PluginDescriptor pluginDescriptor) { final LoadedPlugin plugin = getRunningPlugin(packageName); if (plugin == null) { TwsLog.d(TAG, "插件未运行:" + packageName); return; } // 退出LocalService TwsLog.d(TAG, "退出LocalService"); LocalServiceManager.unRegistService(pluginDescriptor); // TODO 还要通知宿主进程退出localService,不过不通知其实本身也不会坏影响。 // 退出Activity TwsLog.d(TAG, "退出Activity"); PluginLoader.getApplication().sendBroadcast( new Intent(plugin.pluginPackageName + PluginActivityMonitor.ACTION_UN_INSTALL_PLUGIN)); // 退出 LocalBroadcastManager TwsLog.d(TAG, "退出LocalBroadcastManager"); Object mInstance = HackSupportV4LocalboarcastManager.getInstance(); if (mInstance != null) { HackSupportV4LocalboarcastManager hackSupportV4LocalboarcastManager = new HackSupportV4LocalboarcastManager( mInstance); HashMap<BroadcastReceiver, ArrayList<IntentFilter>> mReceivers = hackSupportV4LocalboarcastManager .getReceivers(); if (mReceivers != null) { Iterator<BroadcastReceiver> ir = mReceivers.keySet().iterator(); while (ir.hasNext()) { BroadcastReceiver item = ir.next(); if (item.getClass().getClassLoader() == plugin.pluginClassLoader) { hackSupportV4LocalboarcastManager.unregisterReceiver(item); } } } } // 退出Service // bindservie启动的service应该不需要处理,退出activity的时候会unbind Map<IBinder, Service> map = HackActivityThread.get().getServices(); if (map != null) { Collection<Service> list = map.values(); for (Service s : list) { if (s.getClass().getClassLoader() == plugin.pluginClassLoader) { s.stopSelf(); } } } // 退出webview TwsLog.d(TAG, "还原WebView Context"); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { // 退出BroadcastReceiver // 广播一般有个注册方式 // 1、activity、service注册 // 这种方式,在上一步Activitiy、service退出时会自然退出,所以不用处理 // 2、application注册 // 这里需要处理这种方式注册的广播,这种方式注册的广播会被PluginContextTheme对象记录下来 TwsLog.d(TAG, "退出BroadcastReceiver"); ((PluginContextTheme) plugin.pluginApplication.getBaseContext()).unregisterAllReceiver(); } }); // 退出AssetManager // pluginDescriptor.getPluginContext().getResources().getAssets().close(); // 退出ContentProvider // TODO ContentProvider如何退出? // ActivityThread.releaseProvider(IContentProvider provider, boolean // stable) // 退出fragment // 即退出由FragmentManager保存的Fragment // TODO fragment如何退出? loadedPluginMap.remove(packageName); } public boolean isRunning(String packageName) { return loadedPluginMap.get(packageName) != null; } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) static class LifecycleCallbackBridge implements ActivityLifecycleCallbacks { private HackApplication hackPluginApplication; public LifecycleCallbackBridge(Application pluginApplication) { this.hackPluginApplication = new HackApplication(pluginApplication); } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { hackPluginApplication.dispatchActivityCreated(activity, savedInstanceState); } @Override public void onActivityStarted(Activity activity) { hackPluginApplication.dispatchActivityStarted(activity); } @Override public void onActivityResumed(Activity activity) { hackPluginApplication.dispatchActivityResumed(activity); } @Override public void onActivityPaused(Activity activity) { hackPluginApplication.dispatchActivityPaused(activity); } @Override public void onActivityStopped(Activity activity) { hackPluginApplication.dispatchActivityStopped(activity); } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { hackPluginApplication.dispatchActivitySaveInstanceState(activity, outState); } @Override public void onActivityDestroyed(Activity activity) { hackPluginApplication.dispatchActivityDestroyed(activity); } } public void onConfigurationChanged(Configuration newConfig) { for (Map.Entry<String, LoadedPlugin> e : loadedPluginMap.entrySet()) { final LoadedPlugin lp = e.getValue(); if (lp != null && 0 != lp.pluginResource.getConfiguration().diff(newConfig)) { lp.pluginResource.updateConfiguration(newConfig, lp.pluginResource.getDisplayMetrics()); } } } }