1.插件化知识相关
插件化简介(此处省略若干字,,,)
这篇文章主要是自己学习的记录,不实用~~~
- 反射、动态代理
- Android中的几个相关的ClassLoader
- Android中四大组件的相关原理
- ManagerServer
- 资源加载、资源打包
- 等等
2.插件化工作大体流程
- 加载apk
- ClassLoader解析
- 代理反射替换(maybe outdate)
- 使用插件
3.Activity的插件化
接下来跳过加载apk,ClassLoader解析过程,通过Activity插件化的样例讲解如何通过代理和反射替换并使用插件工作;
首先需要说明一点的是,启动一个完全没有在AndroidManifest注册的Activity是不可能的。因为在启动的过程中,存在一个校验的过程,而这个校验则是由PMS来完成的,这个我们无法干预。因此,Activity的插件化方案大多使用占坑的思想。不同的是如何在检验之前替换,在生成对象的时候还原。
由于系统源代码过于繁杂,这里通过 极极极极极极简化版 的样例,简介通过hook实现插件化的思想
代码:
-
模拟Android系统加载Activity:
package com.baiguoqing.test;
import com.baiguoqing.test.activity.ActivityMain;
import com.baiguoqing.test.activity.ActivitySub;
import com.baiguoqing.test.activity.ActivityTest;
import com.baiguoqing.test.app.MyApp;
public class AndroidManifest {
/**
* 模拟配置 application
*/
public static String DEFAULT_LAUNCHER_APPLICATION = MyApp.MyAppClass;
/**
* 模拟配置 launcher activity
*/
public static String DEFAULT_LAUNCHER_ACTIVITY = ActivityMain.ActivityMainClass;
/**
* 模拟配饰 registered activity
*/
public static String[] REGISTERED_ACTIVITY = new String[]{
DEFAULT_LAUNCHER_ACTIVITY,
ActivityTest.ActivityTestClass,
/*实现组件化占位Activity:ActivitySub*/
ActivitySub.ActivitySubClass
};
}
package com.baiguoqing.android;
public interface IBinder {
/**
* 创建 application
*/
Application newApplication(String appName);
/**
* 检查 activity
*/
boolean checkActivity(String className);
/**
* 创建 activity
*/
Activity newActivity(String className);
}
package com.baiguoqing.android;
public interface IActivityManager {
/**
* 开启 application
*/
void startApplication(IBinder binder);
/**
* 开启 launcher activity
*/
void startLauncherActivity(IBinder binder);
/**
* 开启指定activity
*/
void startActivity(IBinder binder, String className);
/**
* 获取操作binder
*/
IBinder getDefault();
/**
* 获取全局application
*/
Application getApplication();
}
package com.baiguoqing.android;
import com.baiguoqing.test.AndroidManifest;
public class Binder implements IBinder {
@Override
public Application newApplication(String appName) {
try {
Class<?> clazz = Class.forName(appName);
return (Application) clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public boolean checkActivity(String className) {
for (String s : AndroidManifest.REGISTERED_ACTIVITY) {
if (s.equals(className)) {
/*do something*/
return true;
}
}
return false;
}
@Override
public Activity newActivity(String className) {
try {
Class<?> clazz = Class.forName(className);
return (Activity) clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
package com.baiguoqing.android;
import com.baiguoqing.test.AndroidManifest;
public class ActivityManager implements IActivityManager {
/**
* 全局 application
*/
private Application mApplication;
@Override
public void startApplication(IBinder binder) {
mApplication = binder.newApplication(AndroidManifest.DEFAULT_LAUNCHER_APPLICATION);
mApplication.onCreate();
}
@Override
public void startLauncherActivity(IBinder binder) {
startActivity(binder, AndroidManifest.DEFAULT_LAUNCHER_ACTIVITY);
}
@Override
public void startActivity(IBinder binder, String className) {
if (binder.checkActivity(className)) {
Activity activity = binder.newActivity(className);
activity.onCreate();
return;
}
throw new RuntimeException("startActivity fail, " + className + " not register");
}
@Override
public Application getApplication() {
return mApplication;
}
@Override
public IBinder getDefault() {
return new Binder();
}
}
package com.baiguoqing.android;
public class Singleton {
private static IActivityManager mManagerInstance = new ActivityManager();
public static IActivityManager getInstance() {
if (mManagerInstance == null) {
synchronized (Singleton.class) {
if (mManagerInstance == null) {
return new ActivityManager();
}
}
}
return mManagerInstance;
}
}
package com.baiguoqing.android;
public class Application {
public Application() {
}
public void onCreate() {
/*maybe do something*/
}
}
package com.baiguoqing.android;
public class Activity {
private IActivityManager mManager = Singleton.getInstance();
public Activity() {
}
public void onCreate() {
/*maybe do something*/
}
public void startActivity(String className) {
mManager.startActivity(mManager.getDefault(), className);
}
public Application getApplication() {
return mManager.getApplication();
}
}
package com.baiguoqing.android;
public class Main {
/**
* 模拟 Thread
*/
public static void main(String[] args) {
new Thread(() -> {
IActivityManager manager = Singleton.getInstance();
manager.startApplication(manager.getDefault());
manager.startLauncherActivity(manager.getDefault());
}).start();
}
}
-
通过hook和proxy实现插件
package com.baiguoqing.test.activity;
import com.baiguoqing.android.Activity;
/**
* 测试开启Activity
*/
public class ActivityTest extends Activity {
public static final String ActivityTestClass = "com.baiguoqing.test.activity.ActivityTest";
private static final String ActivityTestTag = "ActivityTest created";
@Override
public void onCreate() {
super.onCreate();
System.out.println(ActivityTestTag);
}
}
package com.baiguoqing.test.activity;
import com.baiguoqing.android.Activity;
/**
* 插件Activity
*/
public class ActivityTarget extends Activity {
public static final String ActivityTargetClass = "com.baiguoqing.test.activity.ActivityTarget";
private static final String ActivityTargetTag = "ActivityTarget created";
@Override
public void onCreate() {
super.onCreate();
System.out.println(ActivityTargetTag);
}
}
package com.baiguoqing.test.activity;
import com.baiguoqing.android.Activity;
/**
* 占坑Activity
*/
public class ActivitySub extends Activity {
public static final String ActivitySubClass = "com.baiguoqing.test.activity.ActivitySub";
private static final String ActivitySubTag = "ActivitySub created";
@Override
public void onCreate() {
super.onCreate();
System.out.println(ActivitySubTag);
}
}
package com.baiguoqing.test.activity;
import com.baiguoqing.android.Activity;
/**
* 主启动Activity
*/
public class ActivityMain extends Activity {
public static final String ActivityMainClass = "com.baiguoqing.test.activity.ActivityMain";
private static final String ActivityMainTag = "ActivityMain created";
@Override
public void onCreate() {
super.onCreate();
System.out.println(ActivityMainTag);
//开启其他activity
startActivity(ActivityTest.ActivityTestClass);
//开启组件activity
startActivity(ActivityTarget.ActivityTargetClass);
}
}
如上代码启动Thread后,报错:
ActivityMain created
ActivityTest created
Exception in thread "Thread-0" java.lang.RuntimeException: startActivity fail, com.baiguoqing.test.activity.ActivityTarget not register
at com.baiguoqing.android.ActivityManager.startActivity(ActivityManager.java:30)
at com.baiguoqing.android.Activity.startActivity(Activity.java:15)
at com.baiguoqing.test.activity.ActivityMain.onCreate(ActivityMain.java:23)
at com.baiguoqing.android.ActivityManager.startActivity(ActivityManager.java:27)
at com.baiguoqing.android.ActivityManager.startLauncherActivity(ActivityManager.java:20)
at com.baiguoqing.android.Main.lambda$main$0(Main.java:12)
at java.base/java.lang.Thread.run(Thread.java:830)
Process finished with exit code 0
解决方案:占坑思想,钩住关键节点,代理
package com.baiguoqing.test.proxy;
import com.baiguoqing.test.activity.ActivityMain;
import com.baiguoqing.test.activity.ActivitySub;
import com.baiguoqing.test.activity.ActivityTarget;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class BinderProxy implements InvocationHandler {
private Object mObject;
public BinderProxy(Object mObject) {
this.mObject = mObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("checkActivity".equals(method.getName())) {
if (ActivityTarget.ActivityTargetClass.equals(args[0])) {
args[0] = ActivitySub.ActivitySubClass;
return method.invoke(mObject, args);
}
}
try {
return method.invoke(mObject, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.baiguoqing.test.proxy;
import com.baiguoqing.android.IBinder;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ActivityManagerProxy implements InvocationHandler {
private Object mObject;
private IBinder mBinder;
public ActivityManagerProxy(Object object, IBinder binder) {
this.mObject = object;
this.mBinder = binder;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("getDefault".equals(method.getName())) {
return Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{IBinder.class},
new BinderProxy(mBinder));
}
try {
return method.invoke(mObject, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
这里实现了ActivityManager和Binder类的代理,并且拦截了ActivityManager方法getDefault(),并且返回Binder的代理类;在Binder代理类中,调用checkActivity()方法时进行了修改,让其去检测占坑的Activity;
钩子注册
package com.baiguoqing.test.app;
import com.baiguoqing.android.Application;
import com.baiguoqing.android.IActivityManager;
import com.baiguoqing.android.IBinder;
import com.baiguoqing.test.proxy.ActivityManagerProxy;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyApp extends Application {
public static final String MyAppClass = "com.baiguoqing.test.app.MyApp";
private static final String MyAppTag = "My Application created";
@Override
public void onCreate() {
super.onCreate();
System.out.println(MyAppTag);
try {
hookActivityManager();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 钩子,用于跳过Activity检测
*/
private void hookActivityManager() throws Exception {
Field mManagerField = Class.forName("com.baiguoqing.android.Singleton").getDeclaredField("mManagerInstance");
mManagerField.setAccessible(true);
Object object1 = mManagerField.get(null);
Method method = Class.forName("com.baiguoqing.android.ActivityManager").getDeclaredMethod("getDefault");
method.setAccessible(true);
IBinder binder = (IBinder) method.invoke(object1);
IActivityManager managerProxy = (IActivityManager) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{IActivityManager.class},
new ActivityManagerProxy(object1, binder)
);
mManagerField.set(object1, managerProxy);
}
}
My Application created
ActivityMain created
ActivityTest created
ActivityTarget created
Process finished with exit code 0
总的来说,这个小系统能hook的点有很多,这里列举了一个比较简单且清晰的点;
实际做插件开发时,四大组件的实现方式各有不同,但是思想和这个差不多,就是需要对系统原理具备充分的了解和掌握,这样才能找到合适的hook点;
目前插件化的方案还是有很多,这里只是列举了一个最为传统好理解的实现方式;
网友评论