Search in sources :

Example 6 with LoadedPlugin

use of com.didi.virtualapk.internal.LoadedPlugin in project AndroidLife by CaMnter.

the class IContentProviderProxy method wrapperUri.

/**
 * 1. 在 IContentProvider 调用任何方法的时候,都去找这个方法中的 Uri 参数
 * -  当 IContentProvider # call(...) 的时候,先抽出 Bundle,再寻找其中的 Uri
 * 2. 校验 url 是否是插件 ContentProvider
 * 3. 是的话,获取 插件 ContentProvider 对应的 ProviderInfo 和 LoadedPlugin
 * -  构造 插桩 ContentProvider 的 Uri
 * -  该协议是复合 Uri 协议,包含了最初的 插件 ContentProvider Uri 信息
 * 4. 根据 复合 Uri 协议,会 call 向 插桩 ContentProvider,在 插桩 ContentProvider
 * -  内,再次分发 插件 ContentProvider Uri
 *
 * 5. 将复合 Uri 协议,替换 1. 中找到的 Uri 参数,IContentProvider # call(...) 的时
 * -  候,先抽出 Bundle,替换其中的 Uri
 */
private void wrapperUri(Method method, Object[] args) {
    Uri uri = null;
    int index = 0;
    if (args != null) {
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof Uri) {
                uri = (Uri) args[i];
                index = i;
                break;
            }
        }
    }
    Bundle bundleInCallMethod = null;
    if (method.getName().equals("call")) {
        bundleInCallMethod = getBundleParameter(args);
        if (bundleInCallMethod != null) {
            String uriString = bundleInCallMethod.getString(KEY_WRAPPER_URI);
            if (uriString != null) {
                uri = Uri.parse(uriString);
            }
        }
    }
    if (uri == null) {
        return;
    }
    PluginManager pluginManager = PluginManager.getInstance(mContext);
    ProviderInfo info = pluginManager.resolveContentProvider(uri.getAuthority(), 0);
    if (info != null) {
        String pkg = info.packageName;
        LoadedPlugin plugin = pluginManager.getLoadedPlugin(pkg);
        String pluginUri = Uri.encode(uri.toString());
        StringBuilder builder = new StringBuilder(PluginContentResolver.getUri(mContext));
        builder.append("/?plugin=" + plugin.getLocation());
        builder.append("&pkg=" + pkg);
        builder.append("&uri=" + pluginUri);
        Uri wrapperUri = Uri.parse(builder.toString());
        if (method.getName().equals("call")) {
            bundleInCallMethod.putString(KEY_WRAPPER_URI, wrapperUri.toString());
        } else {
            args[index] = wrapperUri;
        }
    }
}
Also used : PluginManager(com.didi.virtualapk.PluginManager) LoadedPlugin(com.didi.virtualapk.internal.LoadedPlugin) ProviderInfo(android.content.pm.ProviderInfo) Bundle(android.os.Bundle) Uri(android.net.Uri)

Example 7 with LoadedPlugin

use of com.didi.virtualapk.internal.LoadedPlugin in project AndroidLife by CaMnter.

the class LocalService method onStartCommand.

/**
 * 分发插件 service action
 *
 * 1. 先处理 Service START_STICKY 的情况
 * 2. 插桩 service intent 中抽出 插件 service intent
 * 3. 根据 插件 service intent 获取到对应的 LoadedPlugin
 * 4. 替换 插件 service intent 中的 classloader
 * 5. 分发插件 service action
 * 6. 分发插件 service action 前,都得检查是否要 反射创建 service
 *
 * 关于 start  插件 service: 需要反射调用 Service # attach(...),然后手动调用插件 Service # onCreate(...)
 * 关于 bind   插件 service: 同 start,还需要反射调用插件 Service # onBind(...) 和 service 对应的
 * -           IServiceConnection # connected(...)
 * 关于 stop   插件 service: 手动调用插件 Service # onDestroy()
 * 关于 unbind 插件 service: 手动调用插件 Service # onUnbind(...) 和 Service # onDestroy()
 *
 * start 和 bind,  都得考虑是否要添加 插件 service 缓存
 * stop  和 unbind,都得考虑是否要删除 插件 service 缓存
 *
 * @param intent intent
 * @param flags flags
 * @param startId startId
 * @return int
 */
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (null == intent || !intent.hasExtra(EXTRA_TARGET) || !intent.hasExtra(EXTRA_COMMAND)) {
        return START_STICKY;
    }
    Intent target = intent.getParcelableExtra(EXTRA_TARGET);
    int command = intent.getIntExtra(EXTRA_COMMAND, 0);
    if (null == target || command <= 0) {
        return START_STICKY;
    }
    ComponentName component = target.getComponent();
    LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
    // ClassNotFoundException when unmarshalling in Android 5.1
    target.setExtrasClassLoader(plugin.getClassLoader());
    switch(command) {
        case EXTRA_COMMAND_START_SERVICE:
            {
                ActivityThread mainThread = (ActivityThread) ReflectUtil.getActivityThread(getBaseContext());
                IApplicationThread appThread = mainThread.getApplicationThread();
                Service service;
                if (this.mPluginManager.getComponentsHandler().isServiceAvailable(component)) {
                    service = this.mPluginManager.getComponentsHandler().getService(component);
                } else {
                    try {
                        service = (Service) plugin.getClassLoader().loadClass(component.getClassName()).newInstance();
                        Application app = plugin.getApplication();
                        IBinder token = appThread.asBinder();
                        Method attach = service.getClass().getMethod("attach", Context.class, ActivityThread.class, String.class, IBinder.class, Application.class, Object.class);
                        IActivityManager am = mPluginManager.getActivityManager();
                        attach.invoke(service, plugin.getPluginContext(), mainThread, component.getClassName(), token, app, am);
                        service.onCreate();
                        this.mPluginManager.getComponentsHandler().rememberService(component, service);
                    } catch (Throwable t) {
                        return START_STICKY;
                    }
                }
                service.onStartCommand(target, 0, this.mPluginManager.getComponentsHandler().getServiceCounter(service).getAndIncrement());
                break;
            }
        case EXTRA_COMMAND_BIND_SERVICE:
            {
                ActivityThread mainThread = (ActivityThread) ReflectUtil.getActivityThread(getBaseContext());
                IApplicationThread appThread = mainThread.getApplicationThread();
                Service service = null;
                if (this.mPluginManager.getComponentsHandler().isServiceAvailable(component)) {
                    service = this.mPluginManager.getComponentsHandler().getService(component);
                } else {
                    try {
                        service = (Service) plugin.getClassLoader().loadClass(component.getClassName()).newInstance();
                        Application app = plugin.getApplication();
                        IBinder token = appThread.asBinder();
                        Method attach = service.getClass().getMethod("attach", Context.class, ActivityThread.class, String.class, IBinder.class, Application.class, Object.class);
                        IActivityManager am = mPluginManager.getActivityManager();
                        attach.invoke(service, plugin.getPluginContext(), mainThread, component.getClassName(), token, app, am);
                        service.onCreate();
                        this.mPluginManager.getComponentsHandler().rememberService(component, service);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
                try {
                    IBinder binder = service.onBind(target);
                    IBinder serviceConnection = PluginUtil.getBinder(intent.getExtras(), "sc");
                    IServiceConnection iServiceConnection = IServiceConnection.Stub.asInterface(serviceConnection);
                    if (Build.VERSION.SDK_INT >= 26) {
                        ReflectUtil.invokeNoException(IServiceConnection.class, iServiceConnection, "connected", new Class[] { ComponentName.class, IBinder.class, boolean.class }, new Object[] { component, binder, false });
                    } else {
                        iServiceConnection.connected(component, binder);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            }
        case EXTRA_COMMAND_STOP_SERVICE:
            {
                Service service = this.mPluginManager.getComponentsHandler().forgetService(component);
                if (null != service) {
                    try {
                        service.onDestroy();
                    } catch (Exception e) {
                        Log.e(TAG, "Unable to stop service " + service + ": " + e.toString());
                    }
                } else {
                    Log.i(TAG, component + " not found");
                }
                break;
            }
        case EXTRA_COMMAND_UNBIND_SERVICE:
            {
                Service service = this.mPluginManager.getComponentsHandler().forgetService(component);
                if (null != service) {
                    try {
                        service.onUnbind(target);
                        service.onDestroy();
                    } catch (Exception e) {
                        Log.e(TAG, "Unable to unbind service " + service + ": " + e.toString());
                    }
                } else {
                    Log.i(TAG, component + " not found");
                }
                break;
            }
    }
    return START_STICKY;
}
Also used : Context(android.content.Context) IServiceConnection(android.app.IServiceConnection) Service(android.app.Service) Intent(android.content.Intent) ActivityThread(android.app.ActivityThread) Method(java.lang.reflect.Method) LoadedPlugin(com.didi.virtualapk.internal.LoadedPlugin) IBinder(android.os.IBinder) IApplicationThread(android.app.IApplicationThread) ComponentName(android.content.ComponentName) Application(android.app.Application) IActivityManager(android.app.IActivityManager)

Example 8 with LoadedPlugin

use of com.didi.virtualapk.internal.LoadedPlugin in project AndroidLife by CaMnter.

the class PluginUtil method getTheme.

public static int getTheme(Context context, ComponentName component) {
    LoadedPlugin loadedPlugin = PluginManager.getInstance(context).getLoadedPlugin(component);
    if (null == loadedPlugin) {
        return 0;
    }
    ActivityInfo info = loadedPlugin.getActivityInfo(component);
    if (null == info) {
        return 0;
    }
    if (0 != info.theme) {
        return info.theme;
    }
    ApplicationInfo appInfo = info.applicationInfo;
    if (null != appInfo && appInfo.theme != 0) {
        return appInfo.theme;
    }
    return PluginUtil.selectDefaultTheme(0, Build.VERSION.SDK_INT);
}
Also used : LoadedPlugin(com.didi.virtualapk.internal.LoadedPlugin) ActivityInfo(android.content.pm.ActivityInfo) ApplicationInfo(android.content.pm.ApplicationInfo)

Example 9 with LoadedPlugin

use of com.didi.virtualapk.internal.LoadedPlugin in project AndroidLife by CaMnter.

the class RemoteContentProvider method getContentProvider.

/**
 * 获取插件 ContentProvider
 *
 * 1. 解析复合 Uri 协议,获取其中包含的插件 Uri 协议
 * 2. 获取插件 插件 Uri 协议 中的 Authority
 * 3. 根据 插件 Uri Authority,拿出插件 ContentProvider 缓存
 *
 * 4. 当前面没获取到插件 ContentProvider 缓存的时候,根据 插件 Uri 协议包含的该 ContentProvider 所在
 * -  apk file 的绝对路径,获取到对应的 LoadedPlugin。如果还没有 LoadedPlugin,需要根据 apk file path
 * -  加载出 LoadedPlugin
 *
 * 5. 在保证有 LoadedPlugin 缓存的情况下。去获取该 插件 ContentProvider 对应的 ProviderInfo 信息
 * 6. 给 主线程 发消息,主线程获取对应的 LoadedPlugin 缓存,然后加载出对应的 插件 ContentProvider class
 * -  手动调用 ContentProvider # attachInfo(...)。最后加入到 插件 ContentProvider 集合内
 *
 * @param uri uri
 * @return ContentProvider
 */
private ContentProvider getContentProvider(final Uri uri) {
    final PluginManager pluginManager = PluginManager.getInstance(getContext());
    Uri pluginUri = Uri.parse(uri.getQueryParameter(KEY_URI));
    final String auth = pluginUri.getAuthority();
    ContentProvider cachedProvider = sCachedProviders.get(auth);
    if (cachedProvider != null) {
        return cachedProvider;
    }
    synchronized (sCachedProviders) {
        LoadedPlugin plugin = pluginManager.getLoadedPlugin(uri.getQueryParameter(KEY_PKG));
        if (plugin == null) {
            try {
                pluginManager.loadPlugin(new File(uri.getQueryParameter(KEY_PLUGIN)));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        final ProviderInfo providerInfo = pluginManager.resolveContentProvider(auth, 0);
        if (providerInfo != null) {
            RunUtil.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    try {
                        LoadedPlugin loadedPlugin = pluginManager.getLoadedPlugin(uri.getQueryParameter(KEY_PKG));
                        ContentProvider contentProvider = (ContentProvider) Class.forName(providerInfo.name).newInstance();
                        contentProvider.attachInfo(loadedPlugin.getPluginContext(), providerInfo);
                        sCachedProviders.put(auth, contentProvider);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, true);
            return sCachedProviders.get(auth);
        }
    }
    return null;
}
Also used : PluginManager(com.didi.virtualapk.PluginManager) LoadedPlugin(com.didi.virtualapk.internal.LoadedPlugin) ProviderInfo(android.content.pm.ProviderInfo) ContentProvider(android.content.ContentProvider) Uri(android.net.Uri) File(java.io.File) OperationApplicationException(android.content.OperationApplicationException)

Example 10 with LoadedPlugin

use of com.didi.virtualapk.internal.LoadedPlugin in project AndroidLife by CaMnter.

the class RemoteService method onStartCommand.

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent == null) {
        return super.onStartCommand(intent, flags, startId);
    }
    Intent target = intent.getParcelableExtra(EXTRA_TARGET);
    if (target != null) {
        String pluginLocation = intent.getStringExtra(EXTRA_PLUGIN_LOCATION);
        ComponentName component = target.getComponent();
        LoadedPlugin plugin = PluginManager.getInstance(this).getLoadedPlugin(component);
        if (plugin == null && pluginLocation != null) {
            try {
                PluginManager.getInstance(this).loadPlugin(new File(pluginLocation));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    return super.onStartCommand(intent, flags, startId);
}
Also used : LoadedPlugin(com.didi.virtualapk.internal.LoadedPlugin) Intent(android.content.Intent) ComponentName(android.content.ComponentName) File(java.io.File)

Aggregations

LoadedPlugin (com.didi.virtualapk.internal.LoadedPlugin)15 Intent (android.content.Intent)5 Uri (android.net.Uri)5 ComponentName (android.content.ComponentName)4 Context (android.content.Context)4 ProviderInfo (android.content.pm.ProviderInfo)4 PluginManager (com.didi.virtualapk.PluginManager)4 File (java.io.File)4 ActivityThread (android.app.ActivityThread)2 Application (android.app.Application)2 IActivityManager (android.app.IActivityManager)2 IApplicationThread (android.app.IApplicationThread)2 IServiceConnection (android.app.IServiceConnection)2 Service (android.app.Service)2 ContentProvider (android.content.ContentProvider)2 OperationApplicationException (android.content.OperationApplicationException)2 ActivityInfo (android.content.pm.ActivityInfo)2 ApplicationInfo (android.content.pm.ApplicationInfo)2 Resources (android.content.res.Resources)2 Bundle (android.os.Bundle)2