美文网首页
virtual apk

virtual apk

作者: 雪国落叶 | 来源:发表于2020-04-12 12:36 被阅读0次

    在做插件化初始化

    插件化时要明确插件中包含哪些组件,才能在启动组件时加以区分,比如:

    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

    相关文章

      网友评论

          本文标题:virtual apk

          本文链接:https://www.haomeiwen.com/subject/ftdvmhtx.html