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;
}
}
}
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;
}
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);
}
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;
}
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);
}
Aggregations