360 Android 插件开发 DroidPlugin 代码分析 -随笔
备注:本文是个人的随笔,之后如果有时间,会书写比较正式的分析博客
60的插件
DroidPlugin
60的插件
DroidPlugin
引用的工程
DroidPlugin中在资源清单文件中几乎申请了所有的权限
在demo中配置插件的启动
PluginHelper.getInstance().applicationOnCreate(getBaseContext());是核心操作,进行了初始化的一系列的工作
PluginHelper
.
getInstance
().
applicationAttachBaseContext
(
base
); 并没有做什么操作,只是注册了crash之后的log发送之类的信息
分析
PluginHelper
.
getInstance
().
applicationOnCreate
(
getBaseContext
());
public void applicationOnCreate(final Context baseContext) {initPlugin(baseContext);}
1. 安装钩子函数相关
2. 判断是否允许钩子函数的运行
3. 注册插件service的监听
4. 启动插件service
private void initPlugin(Context baseContext) {long b = System.currentTimeMillis();try {try {fixMiUiLbeSecurity();} catch (Throwable e) {Log.e(TAG, "fixMiUiLbeSecurity has error", e);}try {PluginProcessManager.installHook(baseContext);} catch (Throwable e) {Log.e(TAG, "installHook has error", e);}try {if (PluginProcessManager.isPluginProcess(baseContext)) {PluginProcessManager.setHookEnable(true);} else {PluginProcessManager.setHookEnable(false);}} catch (Throwable e) {Log.e(TAG, "setHookEnable has error", e);}try {PluginManager.getInstance().addServiceConnection(PluginHelper.this);PluginManager.getInstance().init(baseContext);} catch (Throwable e) {Log.e(TAG, "installHook has error", e);}} finally {Log.i(TAG, "Init plugin in process cost %s ms", (System.currentTimeMillis() - b));}}
PluginProcessManager
.
installHook
(
baseContext
);
public static void installHook(Context hostContext) throws Throwable {HookFactory.getInstance().installHook(hostContext, null);}
public final void installHook(Context context, ClassLoader classLoader) throws Throwable {installHook(new IClipboardBinderHook(context), classLoader);//for ISearchManagerinstallHook(new ISearchManagerBinderHook(context), classLoader);//for INotificationManagerinstallHook(new INotificationManagerBinderHook(context), classLoader);installHook(new IMountServiceBinder(context), classLoader);installHook(new IAudioServiceBinderHook(context), classLoader);installHook(new IContentServiceBinderHook(context), classLoader);installHook(new IWindowManagerBinderHook(context), classLoader);if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP_MR1) {installHook(new IGraphicsStatsBinderHook(context), classLoader);}if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {installHook(new IMediaRouterServiceBinderHook(context), classLoader);}if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {installHook(new ISessionManagerBinderHook(context), classLoader);}if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {installHook(new IWifiManagerBinderHook(context), classLoader);}if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {installHook(new IInputMethodManagerBinderHook(context), classLoader);}installHook(new IPackageManagerHook(context), classLoader);installHook(new IActivityManagerHook(context), classLoader);//以此为案例,做分析installHook(new PluginCallbackHook(context), classLoader);installHook(new InstrumentationHook(context), classLoader);installHook(new LibCoreHook(context), classLoader);installHook(new SQLiteDatabaseHook(context), classLoader);}
public void installHook(Hook hook, ClassLoader cl) {try {hook.onInstall(cl);synchronized (mHookList) {mHookList.add(hook);}} catch (Throwable throwable) {Log.e(TAG, "installHook %s error", throwable, hook);}}
以IActivityManagerHook为例,在初始化之后,调用了onInstall的方法,先记录到此处
现在查看Hook的体系结构
Hook
--| ProxyHook
--|
IActivityManagerHook
Hook基类,
1. 设置是否可以enable hook
2. 在构造时,需要创建hook的处理类
3. install和uninstall hook
public abstract class Hook {private boolean mEnable = false;protected Context mHostContext;protected BaseHookHandle mHookHandles;public void setEnable(boolean enable, boolean reInstallHook) {this.mEnable = enable;}public final void setEnable(boolean enable) {setEnable(enable, false);}public boolean isEnable() {return mEnable;}protected Hook(Context hostContext) {mHostContext = hostContext;mHookHandles = createHookHandle();}protected abstract BaseHookHandle createHookHandle();protected abstract void onInstall(ClassLoader classLoader) throws Throwable;protected void onUnInstall(ClassLoader classLoader) throws Throwable {}}
下面查看ProxyHook
因为是代理,
1. 提供了一个setOldobj的方法,用户缓存OldObj
2. 实现了Java体系中默认的动态代理方式
3. 如果当前的handle不为空,并且是enabled的情况下,那么交给HookedMethodHandle.doHookInner()方法来处理
public abstract class ProxyHook extends Hook implements InvocationHandler {protected Object mOldObj;public ProxyHook(Context hostContext) {super(hostContext);}public void setOldObj(Object oldObj) {this.mOldObj = oldObj;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (!isEnable()) {return method.invoke(mOldObj, args);}HookedMethodHandler hookedMethodHandler = mHookHandles.getHookedMethodHandler(method);if (hookedMethodHandler != null) {return hookedMethodHandler.doHookInner(mOldObj, method, args);}return method.invoke(mOldObj, args);} catch (InvocationTargetException e) {Throwable cause = e.getTargetException();if (cause != null && MyProxy.isMethodDeclaredThrowable(method, cause)) {throw cause;} else if (cause != null) {RuntimeException runtimeException = !TextUtils.isEmpty(cause.getMessage()) ? new RuntimeException(cause.getMessage()) : new RuntimeException();runtimeException.initCause(cause);throw runtimeException;} else {RuntimeException runtimeException = !TextUtils.isEmpty(e.getMessage()) ? new RuntimeException(e.getMessage()) : new RuntimeException();runtimeException.initCause(e);throw runtimeException;}} catch (Throwable e) {if (MyProxy.isMethodDeclaredThrowable(method, e)) {throw e;} else {RuntimeException runtimeException = !TextUtils.isEmpty(e.getMessage()) ? new RuntimeException(e.getMessage()) : new RuntimeException();runtimeException.initCause(e);throw runtimeException;}}}}
插曲: HookedMethodHandle的内容
核心内容:
doHookInner实现代理的逻辑
{
1. 先执行beforeInvoke方法,如果返回true,那么便拦截掉了这个事件
2. 如果
beforeInvoke返回false,那么继续处理这个事件
3. 调用afterInvoke的方法
}
public class HookedMethodHandler {private static final String TAG = HookedMethodHandler.class.getSimpleName();protected final Context mHostContext;private Object mFakedResult = null;private boolean mUseFakedResult = false;public HookedMethodHandler(Context hostContext) {this.mHostContext = hostContext;}public synchronized Object doHookInner(Object receiver, Method method, Object[] args) throws Throwable {long b = System.currentTimeMillis();try {mUseFakedResult = false;mFakedResult = null;boolean suc = beforeInvoke(receiver, method, args);Object invokeResult = null;if (!suc) {invokeResult = method.invoke(receiver, args);}afterInvoke(receiver, method, args, invokeResult);if (mUseFakedResult) {return mFakedResult;} else {return invokeResult;}} finally {long time = System.currentTimeMillis() - b;if (time > 5) {Log.i(TAG, "doHookInner method(%s.%s) cost %s ms", method.getDeclaringClass().getName(), method.getName(), time);}}}public void setFakedResult(Object fakedResult) {this.mFakedResult = fakedResult;mUseFakedResult = true;}/*** 在某个方法被调用之前执行,如果返回true,则不执行原始的方法,否则执行原始方法*/protected boolean beforeInvoke(Object receiver, Method method, Object[] args) throws Throwable {return false;}protected void afterInvoke(Object receiver, Method method, Object[] args, Object invokeResult) throws Throwable {}public boolean isFakedResult() {return mUseFakedResult;}public Object getFakedResult() {return mFakedResult;}}
插曲结束
继续分析Hook的结构 :
IActivityManagerHook
1. 在createHookHandle()的时候,新创建了一个IActivityManagerHookHandle
2. onInstall为安装此Hook的调用方法
public class IActivityManagerHook extends ProxyHook {private static final String TAG = IActivityManagerHook.class.getSimpleName();public IActivityManagerHook(Context hostContext) {super(hostContext);}@Overridepublic BaseHookHandle createHookHandle() {return new IActivityManagerHookHandle(mHostContext);}@Overridepublic void onInstall(ClassLoader classLoader) throws Throwable {//TODO ------解析来分析-------}}
IActivityManagerHook --> onInstall方法分析
1. 找到系统的IActivityManager
2. 接下来判断此IActivityManager是否是单例,根据是否是单例,做不同的代理的处理
但是这个对于我们想要看的逻辑没有大的影响,我们按照简单的看(个人查看android 2.3的源码时(在线查看地址: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.7_r1/android/app/ActivityManagerNative.java
),发现是单例,我们不按照单例的看,为什么,是因为简单,便于理解!)
@Overridepublic void onInstall(ClassLoader classLoader) throws Throwable {Class cls = ActivityManagerNativeCompat.Class();Object obj = FieldUtils.readStaticField(cls, "gDefault");if (obj == null) {ActivityManagerNativeCompat.getDefault();obj = FieldUtils.readStaticField(cls, "gDefault");}if (IActivityManagerCompat.isIActivityManager(obj)) {setOldObj(obj);Class<?> objClass = mOldObj.getClass();List<Class<?>> interfaces = Utils.getAllInterfaces(objClass);Class[] ifs = interfaces != null && interfaces.size() > 0 ? interfaces.toArray(new Class[interfaces.size()]) : new Class[0];Object proxiedActivityManager = MyProxy.newProxyInstance(objClass.getClassLoader(), ifs, this);FieldUtils.writeStaticField(cls, "gDefault", proxiedActivityManager);Log.i(TAG, "Install ActivityManager Hook 1 old=%s,new=%s", mOldObj, proxiedActivityManager);} else if (SingletonCompat.isSingleton(obj)) {Object obj1 = FieldUtils.readField(obj, "mInstance");if (obj1 == null) {SingletonCompat.get(obj);obj1 = FieldUtils.readField(obj, "mInstance");}setOldObj(obj1);List<Class<?>> interfaces = Utils.getAllInterfaces(mOldObj.getClass());Class[] ifs = interfaces != null && interfaces.size() > 0 ? interfaces.toArray(new Class[interfaces.size()]) : new Class[0];final Object object = MyProxy.newProxyInstance(mOldObj.getClass().getClassLoader(),ifs, IActivityManagerHook.this);Object iam1 = ActivityManagerNativeCompat.getDefault();//这里先写一次,防止后面找不到Singleton类导致的挂钩子失败的问题。FieldUtils.writeField(obj, "mInstance", object);//这里使用方式1,如果成功的话,会导致上面的写操作被覆盖。FieldUtils.writeStaticField(cls, "gDefault", new android.util.Singleton<Object>() {@Overrideprotected Object create() {Log.e(TAG, "Install ActivityManager 3 Hook old=%s,new=%s", mOldObj, object);return object;}});Log.i(TAG, "Install ActivityManager Hook 2 old=%s,new=%s", mOldObj.toString(), object);Object iam2 = ActivityManagerNativeCompat.getDefault();// 方式2if (iam1 == iam2) {//这段代码是废的,没啥用,写这里只是不想改而已。FieldUtils.writeField(obj, "mInstance", object);}} else {throw new AndroidRuntimeException("Can not install IActivityManagerNative hook");}}
这里采用了java的动态代理,用的activityManager是我们经过代理的activityManager
非静态代理的源码:
setOldObj(obj);Class<?> objClass = mOldObj.getClass();List<Class<?>> interfaces = Utils.getAllInterfaces(objClass);Class[] ifs = interfaces != null && interfaces.size() > 0 ? interfaces.toArray(new Class[interfaces.size()]) : new Class[0];Object proxiedActivityManager = MyProxy.newProxyInstance(objClass.getClassLoader(), ifs, this);FieldUtils.writeStaticField(cls, "gDefault", proxiedActivityManager);Log.i(TAG, "Install ActivityManager Hook 1 old=%s,new=%s", mOldObj, proxiedActivityManager);
既然是经过代理的,那么代理部分肯定是部分经过我们处理的,那么这部分逻辑就是关键了,看到代理的回调部分是交给
IActivityManagerHook处理的,其实就是基类ProxyHook来处理的
刚才已经分析,就是invoke的插曲部分
那么现在需要关心的就是HookedMethodHandler的实现逻辑了
但是在
HookedMethodHandler中,我们只是看到了逻辑框架部分,具体的处理逻辑需要在子类中查看,那么对应
IActivityManagerHook的Handler是那个呢?
在
IActivityManagerHook的createHookHandle()的方法中,我们已经看到使用的是
IActivityManagerHookHandle
,那么现在我们需要关系新的就是
IActivityManagerHookHandle中做了怎么样的逻辑处理,但是在这之前,我们先看看
IActivityManagerHookHandle的构造部分
代码看起来很长的样子,其实就是
sHookedMethodHandlers中存放了当前需要关联的函数名字和对应的处理内容
public IActivityManagerHookHandle(Context hostContext) {super(hostContext);}@Overrideprotected void init() {sHookedMethodHandlers.put("startActivity", new startActivity(mHostContext));sHookedMethodHandlers.put("startActivityAsUser", new startActivityAsUser(mHostContext));sHookedMethodHandlers.put("startActivityAsCaller", new startActivityAsCaller(mHostContext));sHookedMethodHandlers.put("startActivityAndWait", new startActivityAndWait(mHostContext));sHookedMethodHandlers.put("startActivityWithConfig", new startActivityWithConfig(mHostContext));sHookedMethodHandlers.put("startActivityIntentSender", new startActivityIntentSender(mHostContext));sHookedMethodHandlers.put("startVoiceActivity", new startVoiceActivity(mHostContext));sHookedMethodHandlers.put("startNextMatchingActivity", new startNextMatchingActivity(mHostContext));sHookedMethodHandlers.put("startActivityFromRecents", new startActivityFromRecents(mHostContext));sHookedMethodHandlers.put("finishActivity", new finishActivity(mHostContext));sHookedMethodHandlers.put("registerReceiver", new registerReceiver(mHostContext));sHookedMethodHandlers.put("broadcastIntent", new broadcastIntent(mHostContext));sHookedMethodHandlers.put("unbroadcastIntent", new unbroadcastIntent(mHostContext));sHookedMethodHandlers.put("getCallingPackage", new getCallingPackage(mHostContext));sHookedMethodHandlers.put("getCallingActivity", new getCallingActivity(mHostContext));sHookedMethodHandlers.put("getAppTasks", new getAppTasks(mHostContext));sHookedMethodHandlers.put("addAppTask", new addAppTask(mHostContext));sHookedMethodHandlers.put("getTasks", new getTasks(mHostContext));sHookedMethodHandlers.put("getServices", new getServices(mHostContext));sHookedMethodHandlers.put("getProcessesInErrorState", new getProcessesInErrorState(mHostContext));sHookedMethodHandlers.put("getContentProvider", new getContentProvider(mHostContext));sHookedMethodHandlers.put("getContentProviderExternal", new getContentProviderExternal(mHostContext));sHookedMethodHandlers.put("removeContentProviderExternal", new removeContentProviderExternal(mHostContext));sHookedMethodHandlers.put("publishContentProviders", new publishContentProviders(mHostContext));sHookedMethodHandlers.put("getRunningServiceControlPanel", new getRunningServiceControlPanel(mHostContext));sHookedMethodHandlers.put("startService", new startService(mHostContext));sHookedMethodHandlers.put("stopService", new stopService(mHostContext));sHookedMethodHandlers.put("stopServiceToken", new stopServiceToken(mHostContext));sHookedMethodHandlers.put("setServiceForeground", new setServiceForeground(mHostContext));sHookedMethodHandlers.put("bindService", new bindService(mHostContext));sHookedMethodHandlers.put("publishService", new publishService(mHostContext));sHookedMethodHandlers.put("unbindFinished", new unbindFinished(mHostContext));sHookedMethodHandlers.put("peekService", new peekService(mHostContext));sHookedMethodHandlers.put("bindBackupAgent", new bindBackupAgent(mHostContext));sHookedMethodHandlers.put("backupAgentCreated", new backupAgentCreated(mHostContext));sHookedMethodHandlers.put("unbindBackupAgent", new unbindBackupAgent(mHostContext));sHookedMethodHandlers.put("killApplicationProcess", new killApplicationProcess(mHostContext));sHookedMethodHandlers.put("startInstrumentation", new startInstrumentation(mHostContext));sHookedMethodHandlers.put("getActivityClassForToken", new getActivityClassForToken(mHostContext));sHookedMethodHandlers.put("getPackageForToken", new getPackageForToken(mHostContext));sHookedMethodHandlers.put("getIntentSender", new getIntentSender(mHostContext));sHookedMethodHandlers.put("clearApplicationUserData", new clearApplicationUserData(mHostContext));sHookedMethodHandlers.put("handleIncomingUser", new handleIncomingUser(mHostContext));sHookedMethodHandlers.put("grantUriPermission", new grantUriPermission(mHostContext));sHookedMethodHandlers.put("getPersistedUriPermissions", new getPersistedUriPermissions(mHostContext));sHookedMethodHandlers.put("killBackgroundProcesses", new killBackgroundProcesses(mHostContext));sHookedMethodHandlers.put("forceStopPackage", new forceStopPackage(mHostContext));sHookedMethodHandlers.put("getRunningAppProcesses", new getRunningAppProcesses(mHostContext));sHookedMethodHandlers.put("getRunningExternalApplications", new getRunningExternalApplications(mHostContext));sHookedMethodHandlers.put("getMyMemoryState", new getMyMemoryState(mHostContext));sHookedMethodHandlers.put("crashApplication", new crashApplication(mHostContext));sHookedMethodHandlers.put("grantUriPermissionFromOwner", new grantUriPermissionFromOwner(mHostContext));sHookedMethodHandlers.put("checkGrantUriPermission", new checkGrantUriPermission(mHostContext));sHookedMethodHandlers.put("startActivities", new startActivities(mHostContext));sHookedMethodHandlers.put("getPackageScreenCompatMode", new getPackageScreenCompatMode(mHostContext));sHookedMethodHandlers.put("setPackageScreenCompatMode", new setPackageScreenCompatMode(mHostContext));sHookedMethodHandlers.put("getPackageAskScreenCompat", new getPackageAskScreenCompat(mHostContext));sHookedMethodHandlers.put("setPackageAskScreenCompat", new setPackageAskScreenCompat(mHostContext));sHookedMethodHandlers.put("navigateUpTo", new navigateUpTo(mHostContext));sHookedMethodHandlers.put("serviceDoneExecuting", new serviceDoneExecuting(mHostContext));}
这样在ProxyHook的invoke的方法中,便可以获取到对应的方法需要处理的
HookedMethodHandler,假如此方法需要处理,那么便调用此方法的doHookInner方法即可
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (!isEnable()) {return method.invoke(mOldObj, args);}HookedMethodHandler hookedMethodHandler = mHookHandles.getHookedMethodHandler(method);if (hookedMethodHandler != null) {return hookedMethodHandler.doHookInner(mOldObj, method, args);}return method.invoke(mOldObj, args);} catch (InvocationTargetException e) {Throwable cause = e.getTargetException();if (cause != null && MyProxy.isMethodDeclaredThrowable(method, cause)) {throw cause;} else if (cause != null) {RuntimeException runtimeException = !TextUtils.isEmpty(cause.getMessage()) ? new RuntimeException(cause.getMessage()) : new RuntimeException();runtimeException.initCause(cause);throw runtimeException;} else {RuntimeException runtimeException = !TextUtils.isEmpty(e.getMessage()) ? new RuntimeException(e.getMessage()) : new RuntimeException();runtimeException.initCause(e);throw runtimeException;}} catch (Throwable e) {if (MyProxy.isMethodDeclaredThrowable(method, e)) {throw e;} else {RuntimeException runtimeException = !TextUtils.isEmpty(e.getMessage()) ? new RuntimeException(e.getMessage()) : new RuntimeException();runtimeException.initCause(e);throw runtimeException;}}}
以startActivity为例,代码如下:
关于HookedMethodHandler的处理逻辑我们已经介绍,下面,只需要关心子类的beforeInvoke方法和
afterInvoke方法即可
发现startActivity类,只是做了beforeInvoke的逻辑,并且没有返回true,因而,还是会调用系统的startActivity方法,但是为什么就可以打开作为插件打开呢?这就是beforeInvoke的逻辑了
private static class startActivity extends HookedMethodHandler {public startActivity(Context hostContext) {super(hostContext);}protected void doReplaceIntentForStartActivityAPIHigh(Object[] args) throws RemoteException {int intentOfArgIndex = findFirstIntentIndexInArgs(args);if (args != null && args.length > 1 && intentOfArgIndex >= 0) {Intent intent = (Intent) args[intentOfArgIndex];//XXX String callingPackage = (String) args[1];ActivityInfo activityInfo = resolveActivity(intent);if (activityInfo != null && isPackagePlugin(activityInfo.packageName)) {ComponentName component = selectProxyActivity(intent);if (component != null) {Intent newIntent = new Intent();try {ClassLoader pluginClassLoader = PluginProcessManager.getPluginClassLoader(component.getPackageName());setIntentClassLoader(newIntent, pluginClassLoader);} catch (IllegalAccessException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}newIntent.setComponent(component);newIntent.putExtra(Env.EXTRA_TARGET_INTENT, intent);String callingPackage = (String) args[1];if (TextUtils.equals(mHostContext.getPackageName(), callingPackage)) {newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);}args[intentOfArgIndex] = newIntent;args[1] = mHostContext.getPackageName();} else {Log.w(TAG, "startActivity,replace selectProxyActivity fail");}}}}private void setIntentClassLoader(Intent intent, ClassLoader classLoader) {try {Bundle mExtras = (Bundle) FieldUtils.readField(intent, "mExtras");if (mExtras != null) {mExtras.setClassLoader(classLoader);} else {Bundle value = new Bundle();value.setClassLoader(classLoader);FieldUtils.writeField(intent, "mExtras", value);}} catch (Exception e) {} finally {intent.setExtrasClassLoader(classLoader);}}protected void doReplaceIntentForStartActivityAPILow(Object[] args) throws RemoteException {int intentOfArgIndex = findFirstIntentIndexInArgs(args);if (args != null && args.length > 1 && intentOfArgIndex >= 0) {Intent intent = (Intent) args[intentOfArgIndex];ActivityInfo activityInfo = resolveActivity(intent);if (activityInfo != null && isPackagePlugin(activityInfo.packageName)) {ComponentName component = selectProxyActivity(intent);if (component != null) {Intent newIntent = new Intent();newIntent.setComponent(component);newIntent.putExtra(Env.EXTRA_TARGET_INTENT, intent);if (TextUtils.equals(mHostContext.getPackageName(), activityInfo.packageName)) {newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);}args[intentOfArgIndex] = newIntent;} else {Log.w(TAG, "startActivity,replace selectProxyActivity fail");}}}}@Overrideprotected boolean beforeInvoke(Object receiver, Method method, Object[] args) throws Throwable {if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {doReplaceIntentForStartActivityAPILow(args);} else {doReplaceIntentForStartActivityAPIHigh(args);}return super.beforeInvoke(receiver, method, args);}}
看到:版本18以前和以后的处理方式是不同的,
我们以版本低的为例
处理的步骤:
1. 找到反射中的intent
2. 根据intent解析为activityInfo
3. 判断是否需要插件来打开,如果不是,不需要处理
4. 如果是,找到对应的代理的acitivity
5. 替换反射中的intent
protected void doReplaceIntentForStartActivityAPILow(Object[] args) throws RemoteException {int intentOfArgIndex = findFirstIntentIndexInArgs(args);if (args != null && args.length > 1 && intentOfArgIndex >= 0) {Intent intent = (Intent) args[intentOfArgIndex];ActivityInfo activityInfo = resolveActivity(intent);if (activityInfo != null && isPackagePlugin(activityInfo.packageName)) {ComponentName component = selectProxyActivity(intent);if (component != null) {Intent newIntent = new Intent();newIntent.setComponent(component);newIntent.putExtra(Env.EXTRA_TARGET_INTENT, intent);if (TextUtils.equals(mHostContext.getPackageName(), activityInfo.packageName)) {newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);}args[intentOfArgIndex] = newIntent;} else {Log.w(TAG, "startActivity,replace selectProxyActivity fail");}}}}

浙公网安备 33010602011771号