3.执行dex2oat这里有个难点就是 , 如何才能调用到PackageManagerShellCommand.runCompile
?看下调用逻辑:
// 代码位于PackageManagerService.java 。// IPackageManagerImpl是PackageManagerService的内部类 。@Overridepublic void onShellCommand(FileDescriptor in, FileDescriptor out,FileDescriptor err, String[] args, ShellCallback callback,ResultReceiver resultReceiver) {(new PackageManagerShellCommand(this, mContext, mDomainVerificationManager.getShell())).exec(this, in, out, err, args, callback, resultReceiver);}
IPackageManager.Stub
继承了Binder
, 而这个方法是Binder
中的 , 调用逻辑如下:
// Binder.javaprotected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,int flags) throws RemoteException {if (code == INTERFACE_TRANSACTION) {reply.writeString(getInterfaceDescriptor());return true;} else if (code == DUMP_TRANSACTION) {// 省略部分代码...return true;} else if (code == SHELL_COMMAND_TRANSACTION) {ParcelFileDescriptor in = data.readFileDescriptor();ParcelFileDescriptor out = data.readFileDescriptor();ParcelFileDescriptor err = data.readFileDescriptor();String[] args = data.readStringArray();ShellCallback shellCallback = ShellCallback.CREATOR.createFromParcel(data);ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data);try {if (out != null) {// 重点!!!调用了 shellCommand 方法shellCommand(in != null ? in.getFileDescriptor() : null,out.getFileDescriptor(),err != null ? err.getFileDescriptor() : out.getFileDescriptor(),args, shellCallback, resultReceiver);}} finally {// 省略部分代码...}return true;}return false;}public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,@Nullable FileDescriptor err,@NonNull String[] args, @Nullable ShellCallback callback,@NonNull ResultReceiver resultReceiver) throws RemoteException {// 这里调用的!!!onShellCommand(in, out, err, args, callback, resultReceiver);}
所以这里逻辑清晰了 , 再次整理下逻辑:
- Binder.onTransact收到 SHELL_COMMAND_TRANSACTION 命令会执行 shellCommand方法
- shellCommand方法又调用了onShellCommand方法
- IPackageManager.Stub继承了Binder
- IPackageManagerImpl继承了IPackageManager.Stub并重写了onShellCommand方法
- IPackageManagerImpl的onShellCommand执行了PackageManagerShellCommand相关逻辑
IPackageManager.aidl
, 并向其发送 SHELL_COMMAND_TRANSACTION 命令 。得益于Android Binder机制 , 我们可以在应用进程拿到IPackageManger
的Binder , 并通过它来发送命令 。代码实现如下:
// 执行dex2oatprivate fun performDexOpt() {val args = arrayOf("compile", "-f", "--secondary-dex", "-m",if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) "verify" else "speed-profile",context.packageName)executeShellCommand(args)}// IPackageManager.aidl 发送 SHELL_COMMAND_TRANSACTION 命令private fun executeShellCommand(args: Array<String>) {val lastIdentity = Binder.clearCallingIdentity()var data: Parcel? = nullvar reply: Parcel? = nulltry {data = https://www.huyubaike.com/biancheng/Parcel.obtain()reply = Parcel.obtain()data.writeFileDescriptor(FileDescriptor.`in`)data.writeFileDescriptor(FileDescriptor.out)data.writeFileDescriptor(FileDescriptor.err)data.writeStringArray(args)data.writeStrongBinder(null)resultReceiver.writeToParcel(data, 0)getPMBinder().transact(SHELL_COMMAND_TRANSACTION, data, reply, 0)reply.readException()} catch (t: Throwable) {Log.e(TAG,"executeShellCommand error.", t)} finally {data?.recycle()reply?.recycle()}Binder.restoreCallingIdentity(lastIdentity)}
4.反注册Secondary Apk反注册也是执行PackageManagerShellCommand
相关方法 , 只不过给的参数不一样 。所以大部分逻辑跟第三步是一样的 。代码实现如下:
经验总结扩展阅读
- Azure DevOps Server 入门实践与安装部署
- 快读《ASP.NET Core技术内幕与项目实战》WebApi3.1:WebApi最佳实践
- 重新整理 .net core 实践篇 ———— linux上排查问题 [外篇]
- .NET API 接口数据传输加密最佳实践
- 重新整理 .net core 实践篇 ———— linux 上线篇 [外篇]
- 鹅长微服务发现与治理巨作PolarisMesh实践-上
- Arctic 基于 Hive 的流批一体实践
- 前端监控系列4 | SDK 体积与性能优化实践
- 2 HTML躬行记——WebRTC基础实践
- AI 【第1篇】人工智能语音测试原理和实践---宣传