在做插件化初始化
插件化时要明确插件中包含哪些组件,才能在启动组件时加以区分,比如:
public ResolveInfo resolveService(Intent intent, int flags) {
for (LoadedPlugin plugin : this.mPlugins.values()) {
ResolveInfo resolveInfo = plugin.resolveService(intent, flags);
if (null != resolveInfo) {
return resolveInfo;
}
}
return null;
}
校验签名版本号
从下方函数可以看出调用collectCertificates后,签名会被赋值
private static final class PackageParserV24 {
static final PackageParser.Package parsePackage(Context context, File apk, int flags) throws Throwable {
/**
* 解析指定位置的安装包。它自动会检测安装包的模式的是单一APK或者集群APK模式。
* 这样就可以对"集群APK"的安装包进行理性的检查,比如会检查"base APK"和"拆分APK"是否具有相同的包名和版本号。
* 请注意,这里面是不执行签名验证的,所以必须要单独执行collectCertificates(Package,int)这个方法
*/
//Android 安装一个APK的时候首先会解析APK,而解析APK则需要用到一个工具类,这个工具类就是PackageParser
PackageParser parser = new PackageParser();
PackageParser.Package pkg = parser.parsePackage(apk, flags);
//调用PackageParser中collectCertificates方法,传入pkg、flags,
/**
* 从给定包中描述的所有apk收集证书,
* public static void collectCertificates(Package pkg, int parseFlags)
* throws PackageParserException {
* collectCertificatesInternal(pkg, parseFlags);
* final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
* for (int i = 0; i < childCount; i++) {
* Package childPkg = pkg.childPackages.get(i);
* childPkg.mCertificates = pkg.mCertificates;
* childPkg.mSignatures = pkg.mSignatures;
* childPkg.mSigningKeys = pkg.mSigningKeys;
* }
* }
*/
Reflector.with(parser)
.method("collectCertificates", PackageParser.Package.class, int.class)
.call(pkg, flags);
return pkg;
}
}
绑定资源
AssetManager中addAssetPath方法设置的是apk所在的路径。
image.png
AssetManager中:
/**
* Add an additional set of assets to the asset manager. This can be
* either a directory or ZIP file. Not for use by applications. Returns
* the cookie of the added asset, or 0 on failure.
* {@hide}
*/
public final int addAssetPath(String path) {
return addAssetPathInternal(path, false);
}
private native final int addAssetPathNative(String path, boolean appAsLib);
看代码的逻辑,进行资源合并时,要么生成AssetManager,然后调用addAssetPath加入宿主apk的sourceDir,然后再addAssetPath加入自身的路径。
动态广播
通过提取PackageParser中Package信息获取到注册的receivers,然后将静态广播改变为动态广播:
比较以下两种方式:
BroadcastReceiver cc = (BroadcastReceiver) getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance();
BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance());
for (PackageParser.Activity receiver : this.mPackage.receivers) {
receivers.put(receiver.getComponentName(), receiver.info);
//知道BroadcastReceiver类名,由ClassLoader创建实例,并调用宿主的Context的registerReceiver方法完成插件的注册。
//动态注册广播,对于广播只能如此
BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance());
for (PackageParser.ActivityIntentInfo aii : receiver.intents) {
this.mHostContext.registerReceiver(br, aii);
}
}
this.mReceiverInfos = Collections.unmodifiableMap(receivers);
this.mPackageInfo.receivers = receivers.values().toArray(new ActivityInfo[receivers.size()]);
启动插件中service
在service启动过程中和Activity类似的处理,不一样之处在于,分为预置LocalService和RemoteService两类,在manifest文件中通过打桩的方式,先插入
<!-- Local Service running in main process -->
<service android:exported="false" android:name="com.didi.virtualapk.delegate.LocalService" />
<!-- Daemon Service running in child process -->
<service android:exported="false" android:name="com.didi.virtualapk.delegate.RemoteService" android:process=":daemon">
<intent-filter>
<action android:name="${applicationId}.intent.ACTION_DAEMON_SERVICE" />
</intent-filter>
</service>
然后如果通过查找发现时插件中的service组件,则区分LocalService还是RemoteService,然后对Intent进行封装,如本次的行为startService or bindService封装为command指令,target.package 和target.cls可以指定真正要启动的对象,接下来就是在onStartCommand中进行处理了。
由于service在插件中,需要通过插件的classLoader进行加载,并且加载后的service加入记录中rememberService,然后调用onStartCommand方法
在service的启动流程中:ActivityThread会受到创建Service的指令, handleCreateService,如果想要在自己创建Service后,还能继续走后续的流程那么必然是因为又通知了AMS,才能走后续的onBind和onStartCommand之类的函数
private void handleCreateService(ActivityThread.CreateServiceData data) {
this.unscheduleGcIdler();
LoadedApk packageInfo = this.getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
ClassLoader cl = packageInfo.getClassLoader();
service = (Service)cl.loadClass(data.info.name).newInstance();
} catch (Exception var9) {
if (!this.mInstrumentation.onException(service, var9)) {
throw new RuntimeException("Unable to instantiate service " + data.info.name + ": " + var9.toString(), var9);
}
}
try {
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, this.mInstrumentation);
service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault());
service.onCreate();
this.mServices.put(data.token, service);
try {
// 注意此处传递的是0,处理参数,onStartCommand时传递的为1
ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, 0, 0, 0);
} catch (RemoteException var7) {
throw var7.rethrowFromSystemServer();
}
} catch (Exception var8) {
if (!this.mInstrumentation.onException(service, var8)) {
throw new RuntimeException("Unable to create service " + data.info.name + ": " + var8.toString(), var8);
}
}
}
private void handleServiceArgs(ActivityThread.ServiceArgsData data) {
Service s = (Service)this.mServices.get(data.token);
if (s != null) {
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
data.args.prepareToEnterProcess();
}
int res;
if (!data.taskRemoved) {
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = 1000;
}
QueuedWork.waitToFinish();
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, 1, data.startId, res);
} catch (RemoteException var5) {
throw var5.rethrowFromSystemServer();
}
this.ensureJitEnabled();
} catch (Exception var6) {
if (!this.mInstrumentation.onException(s, var6)) {
throw new RuntimeException("Unable to start service " + s + " with " + data.args + ": " + var6.toString(), var6);
}
}
}
}
private void handleBindService(ActivityThread.BindServiceData data) {
Service s = (Service)this.mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, 0, 0, 0);
}
this.ensureJitEnabled();
} catch (RemoteException var4) {
throw var4.rethrowFromSystemServer();
}
} catch (Exception var5) {
if (!this.mInstrumentation.onException(s, var5)) {
throw new RuntimeException("Unable to bind to service " + s + " with " + data.intent + ": " + var5.toString(), var5);
}
}
}
}
switch (command) {
case EXTRA_COMMAND_START_SERVICE: {
ActivityThread mainThread = ActivityThread.currentActivityThread();
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;
}
bindService时,需要传递ServiceConnection,由于是进程内的Binder对象,可以通过PluginUtil
保存获取:
// ActivityManagerProxy
protected Object bindService(Object proxy, Method method, Object[] args) throws Throwable {
Intent target = (Intent) args[2];
ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
if (null == resolveInfo || null == resolveInfo.serviceInfo) {
// is host service
return method.invoke(this.mActivityManager, args);
}
Bundle bundle = new Bundle();
PluginUtil.putBinder(bundle, "sc", (IBinder) args[4]);
startDelegateServiceForTarget(target, resolveInfo.serviceInfo, bundle, RemoteService.EXTRA_COMMAND_BIND_SERVICE);
mPluginManager.getComponentsHandler().remberIServiceConnection((IBinder) args[4], target);
return 1;
}
// Service
public abstract IBinder onBind(Intent var1);
public boolean onUnbind(Intent intent) {
return false;
}
public void onRebind(Intent intent) {
}
// LocalService
case EXTRA_COMMAND_BIND_SERVICE: {
ActivityThread mainThread = ActivityThread.currentActivityThread();
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) {
Log.w(TAG, t);
}
}
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) {
iServiceConnection.connected(component, binder, false);
} else {
Reflector.QuietReflector.with(iServiceConnection).method("connected", ComponentName.class, IBinder.class).call(component, binder);
}
} catch (Exception e) {
Log.w(TAG, e);
}
break;
}
从整体上看,在声明周期这一过程中做了简化。
去除了跨进程的能力,通过静态存储IBinder等进行数据交换。
参考
https://blog.csdn.net/MldXTieJiang/java/article/details/105314237
网友评论