本篇作为总集篇 将对本系列全文进行总结,以下是本系列的速览规划:
您可在如下仓库找到本系列文章的单篇内容:
VirtualAppQuickReview: https://github.com/ErodedElk/VirtualAppQuickReview
或在我的个人博客也将会以单篇的形式发布本系列文稿:
ef7K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6@1L8$3E0S2L8h3g2A6L8X3g2Q4x3X3g2@1L8%4m8Q4x3V1j5`.
如果您在阅读过程中有任何疑问,或发现文稿中存在任何纰漏,欢迎通过邮件或其他方式与我联系,笔者相信技术正是要在相互的交流中才能够进一步向前的。您可通过 tokameine@gmail.com 与我联系。
从很早以前就一直很好奇 VirtualApp 的相关技术,但是一直抽不出时间。正巧最近想试着自己照猫画虎开发一个类似的容器化应用,并做一些定制化的需求,因此抽空把整个项目过了一遍,也正好帮我整理一遍过去一直对整个 Android 系统较为模糊的认知。
以下是本系列的速览规划:
VA 框架对应用的操作涉及三个层面:
考虑到现有开源的 VirtualApp 只支持老版本 Android,因此选择原理相同的 blackbox 进行参考 仓库地址:b6bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6y4L8$3&6K6N6r3g2J5i4K6u0V1c8@1#2Q4x3V1k6K6j5h3&6V1j5X3!0^5
项目代码分为两个模块:
本系列文章会主要关心其中的 VirtualApp 框架实现部分。
为了解 VA 是如何启动 Activity 的,我们需要先知道 Android 是如何启动 Activity 的。在 Android 系统启动以后,系统已经启动了 Zygote,ServiceManager,SystemServer 等系统进程。
ServiceManager
进程中完成了 Binder
初始化;SystemServer
进程中 ActivityManagerService,WindowManagerService
,PackageManagerService
等系统服务在 ServiceManager
中已经注册;最后启动了 Launcher
桌面应用。
Launcher
作为用户的交互界面,在用户点击 APP 图标的时候提供了打开应用的能力。不同的手机厂商可能会根据 Launcher
做一些定制,比如 miui
就是如此,但最终的原理是一致的。
应用安装的时候,通过 PackageManagerService
解析 apk 的 AndroidManifest.xml
文件,提取出这个 apk 的信息写入到 packages.xml
文件中,这些信息包括:权限、应用包名、icon、apk 的安装位置、版本、userID 等等。packages.xml 文件位于系统目录下/data/system/packages.xml。
当用户点击桌面上的应用图标后,Launcher 会通过 service_manager 向 AMS 服务发出请求,查询对应的 APP 信息,然后由 Zygote 创建目标 APP 进程。
先梳理一下大致的流程:
具体到代码实现中,分为几个步骤,首先启动步骤从 Launcher 开始:
Launcher.startActivitySafel
-> Launcher.startActivity
Activity.startActivity
Activity.startActivityForResult
- Instrumentation.execStartActivity
- ActivityTaskManager.getService().startActivity
ActivityManagerNative.getDefault()
会返回一个 ActivityManagerProxy
作为 Launcher 中使用 ActivityTaskManager
的代理,该代理的 startActivity 会发送 START_ACTIVITY_TRANSACTION
来通知 ActivityTaskManager
完成上述过程后,进程从 Launcher
切换到 system_server
中的 ActivityManagerService
,也就是 AMS。
startActivity
- startActivityAsUser
ActivityStackSupervisor.startActivityMayWait
- resolveActivity
PackageManagerService.resolveIntent()
- queryIntentActivities()
获取到调用者的进程信息,通过 Intent.FLAG_ACTIVITY_FORWARD_RESULT
判断是否需要进行 startActivityForResult
处理。检查调用者是否有权限来调用指定的 Activity
Activity 有多种启动模式,对 launchMode 的处理,创建 Task 等操作。启动 Activity 所在进程,已存在则直接 onResume()
,不存在则创建 Activity 并处理是否触发 onNewIntent()
。
ActivityStackSupervisor.startActivityUncheckedLocked
- startActivityLocked
ActivityStack.resumeTopActivityInnerLocked
ActivityStackSupervisor.startSpecificActivity
我们考虑后者的情况,程序将会往下调用 startProcessAsync
创建新进程:
startProcessAsync 会通过消息的方式让 ATMS 服务在处理该消息时创建对应的进程,调用目标为 ActivityManagerInternal::startProcess
而 ActivityManagerInternal::startProcess
调用ActivityManagerService::startProcessLocked
调用 ProcessList::startProcessLocked
调用 ProcessList::startProcess
如果目标进程是 top app,设置 flag 保证启动的最高优先级,并最终在 startProcess 中创建对应的目标进程,也就是 APP 的进程。
在进程创建成功后,将当前进程切换到新进程,并将 ActivityThread
类加载到新进程,调用 ActivityThread.main
Looper 会持续从消息队列中获取消息,然后处理指定的任务。其中,attach 函数调用时会发送 ATTACH_APPLICATION_TRANSACTION
通知 system_server 中的服务。
此时,应用的 ActivityThread
和 ApplicationThread
已经被创建,并创建了消息循环机制。当调用 ActivityThread.attach
时,内部会调用 ActivityManagerProxy.attachApplication
,通过 Binder 来调用 AMS 中的 attachApplication
函数,此时会把 ApplicationThread
传递过去。
attachApplication
- attachApplicationLocked
主要有两个关键函数需要关注:
我们先关注 thread.bindApplication
,thread 就是刚刚由新进程传过来的。
函数先调用 bindApplication
向进程发送 H.BIND_APPLICATION
命令,进程收到该命令后,通过 handleBindApplication
处理:
handleBindApplication
初始化 context
,然后初始化 Instrumentation
对象,创建 Application
对象,并调用该对象的 onCreate
初始化流程调用链为 makeApplication
- newApplication
:
然后是 makeApplicationInner
的细节
对于新创建的这个进程而言,当 callApplicationOnCreate
完成调用以后,这个进程的上下文,以及 Application
对象和 Instrumentation
对象都完成的创建和初始化。而在进程这波完成上述的初始化过程中,AMS 那边也没闲着,在发送完相应的命令以后, ActivityManagerService#attachApplicationLocked
继续往下调用 ActivityTaskManagerService.LocalService#attachApplication
可以注意到,最终这个函数将往下执行 ActivityTaskSupervisor#realStartActivityLocked
完成最后的步骤。而如果此前不需要创建新进程,那么刚打开 APP 的时候就会从这个地方开始恢复进程的状态 了。
函数首先创建 Activity 事务,设置对应的 callback ,以及对应的生命周期 ActivityLifecycleItem
,最终开始调度事务 lientLifecycleManager#scheduleTransaction
。
可以看到,最终由 AMS 向进程发出 H.EXECUTE_TRANSACTION
命令,这个命令同样会被进程那边接受并处理:
这个函数最终会往下调用 ClientTransactionHandler#handleLaunchActivity
,最为抽象类的方法,实际调用 ActivityThread#handleLaunchActivity
:
handleLaunchActivity
最终回调目标 Activity
的 onConfigurationChanged
,初始化 WindowManagerService
,调用 ActivityThread.performLaunchActivity
。
callActivityOnCreate
中会回调 Activity.performCreate
,其中调用 Activity
的 onCreate
、Activity.setContentView
、ActivityThread.performResumeActivity
,performResumeActivity
最终会回调 onResume
。
总之,到这里之后,新应用的进程算是创建完成了。
弯弯绕绕一大圈,有不少的同名函数,在整理这些资料的时候也是被绕晕了好几次了,希望最终写出来的流程没有太混乱吧。如果有哪里写的不对,还请师傅们多多指教。
8c2K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8X3S2Y4P5e0b7I4x3#2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3V1k6V1k6i4c8S2K9h3I4K6i4K6u0r3x3e0l9H3x3o6M7I4y4U0j5%4 96dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8X3S2Y4P5e0b7I4x3#2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3V1k6V1k6i4c8S2K9h3I4K6i4K6u0r3z5e0f1@1y4U0f1K6x3U0p5`. 0beK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9s2g2S2L8X3I4S2L8W2)9J5k6i4A6Z5K9h3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8U0p5#2x3e0l9I4x3o6f1%4y4H3`.`. 939K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6B7N6h3g2B7K9h3&6Q4x3X3g2U0L8W2)9J5c8Y4m8G2M7%4c8Q4x3V1j5%4x3o6t1^5x3e0t1@1z5e0f1%4x3e0b7I4z5o6V1K6x3e0f1H3 62dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6B7k6h3q4F1j5X3!0&6k6r3g2$3i4K6u0r3b7h3&6V1M7X3!0A6k6q4)9J5k6q4u0W2j5h3c8f1K9r3g2r3N6h3y4C8K9h3&6Y4f1$3!0#2M7X3y4W2b7$3!0V1k6g2)9J5c8X3u0D9L8$3u0Q4x3V1k6E0j5i4y4@1k6i4u0Q4x3V1k6S2M7Y4c8A6j5$3I4W2i4K6u0r3j5h3&6V1M7X3!0A6k6q4)9J5c8X3k6J5j5h3#2W2N6$3!0J5K9#2)9J5c8V1q4F1k6s2u0G2K9h3c8Q4x3X3c8m8j5%4c8A6N6X3W2@1P5g2)9J5y4f1f1#2i4K6t1#2z5e0m8Q4x3U0g2m8c8W2)9J5y4f1f1#2i4K6t1#2z5p5q4Q4x3U0g2m8z5q4)9J5y4f1f1^5i4K6t1#2b7V1k6Q4x3U0f1^5y4#2)9J5y4f1f1%4i4K6t1#2b7e0S2Q4x3U0f1^5b7W2)9J5k6h3#2V1 55aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8X3M7&6z5o6b7I4y4U0l9#2y4o6N6Q4x3V1k6S2M7Y4c8A6j5$3I4W2i4K6u0r3k6r3g2@1j5h3W2D9M7#2)9J5c8U0p5J5x3o6j5%4y4U0f1%4y4l9`.`. 876K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8Y4q4I4i4K6g2X3x3e0b7^5y4K6j5I4x3K6y4Q4x3V1k6S2M7Y4c8A6j5$3I4W2i4K6u0r3k6r3g2@1j5h3W2D9M7#2)9J5c8U0p5@1x3e0x3$3x3U0l9&6z5l9`.`. VirtualApp拆解之二:Activity启动流程 - 简书
在了解了正常环境下 app 的 activity 是如何被启动的以后,接下來我们希望能够了解一下 VirtualApp 中是如何启动目标 app 的。不过整个流程涉及到了对部分 Service 的 Hook,但这些内容却不是本节我们重点关心的内容,因此会有相应的介绍,但或许并不全面。
当用户点击了视图上目标应用的图标后,触发点击事件并向下调用,在 blackbox 中将来到 launchApk
函数:
mClientConfiguration.isEnableLauncherActivity
是恒真的,因此最终会调用 LauncherActivity.launch
,在该函数中,blackbox
初始化了一个 Intent
,然后调用原生的 startActivity
函数来进入 LauncherActivity
,在进入时,会调用该对象的 onCreate
函数:
函数首先获取之前那个 splash ,然后从中读取出需要启动的目标应用的包名和用户 ID,并通过包名来读取包的相关信息,最后调用 BActivityManager.startActivity
来在 Blackbox 中启动应用。
getService
函数会返回对应的 Service ,在这个函数中将会返回 BActivityManagerService
,这里涉及到了一个我们尚且没有关注过的问题,VirtualApp 是如何伪造各种系统 Service 的?
在应用的 Manifest
里声明了这么一段:
在启动 Blackbox 的时候,handleBindApplication
中会主动调用对应 ContentProvider
下的 onCreate
函数:
我们重点关注的是 mServices
这个成员,在注意到它将 BActivityManagerService
放入了数组,并调用对应的 systemReady
:
最终会为每个包注册一个 BroadcastReceiver
:
而这个 SystemCallProvider
本身也作为一个 IBinder,将它管理的这些 Service 暴露给其他应用使用:
ServiceManager.getService
可以能够根据参数来返回对应的 Service:
如果 ServiceManager
没初始化的话就先创建并初始化,将所有的 Service 都放入 mCaches
,并在需要的时候返回该对象。最终其他需要使用这些服务的应用就都能够通过 Binder 拿到这些对应的对象了。
对这些获取 Service 的对象来说,他们本该获取到原生的 ActivityManagerService
,却被 BActivityManagerService
替换掉了,对应的去调用那些本该调用的方法时,自然这些方法也就一起被 Hook 掉了。
一般来说我们都是通过 getSystemService
来获取对应的服务的:
而在 Blackbox 的 HookManager 中注册了对各种对象的钩子:
我们主要看 IActivityManagerProxy
是如何对 ActivityManager
进行 hook 的:
这里有一个 _set_mInstance
实际上是 blackreflection
的语法糖,它通过反射的方式来修改 gDefault().mInstance
。我们在上一节中提到过启动应用时会通过 ActivityManagerNative.getDefault
来得到 ActivityManagerProxy
,这里会将结果给改成 Proxy
,也就是用 IActivityManagerProxy
来代理原本的返回对象。
比如说 getServices
函数会被 hook 为:
可以注意到,在注入 Service Hook 的时候是有做进程判断的,因为主进程肯定还是需要和 Service 进行正常沟通的,如果全都 Hook 掉的话,主进程也无法正常通信了。所以在满足isBlackProcess
或 isServerProcess
时才会注入那些代理,也就是那些需要启动的内部应用或是服务进程才会注入。
顺带一提,ServerProcess 中包含了这么几个:
接下来我们回到 BActivityManagerService.startActivity
来看看它如何启动应用。
这里向下继续调用 startActivityLocked
,不过这个函数有点长,这里主要关注两个几个关键步骤即可:
首先我们关注 startActivityInNewTaskLocked
,对于那些需要新启动的情况,使用该函数创建对应的任务:
该函数创建了一个 shadow
,它实际上是用来创建一个虚假的 Intent
的,我们往下跟踪 startActivityProcess
:
targetApp
初始化了我们将要启动的目标应用的相关信息:
可以看到主要就是一些 ID 的初始化,不过注意,其中 bpid 指的其实是对 Blackbox 来说的进程 ID ,因为对系统来说只有 Blackbox 这一个进程,但是对 Blackbox 来说却需要管理其中启动的不同应用。
其中还包括了一个 initAppProcessL
用来初始化 app:
这是一个通过 Binder 来调用 initprocess
函数的接口函数,对应调用为:
向下调用 initProcess
函数:
这里将 appConfig
设置到了 BActivityThread
对象里去。
然后再调用 getStartStubActivityIntentInner
,不过参数其实只有刚才的 bpid
,对应参数中的 vpid
:
这个 vpid 参数会用来查找 Blackbox 提前在 Manifest 中占坑的 Activity :
这样的 Activity 总共有 50 个,相当于 Blackbox 最多能支持同时启动 50 个内部应用。
这个操作相当于构造了一个用于启动 ProxyActivity
的 Intent
,最终再将这个对象传给系统 AMS 来启动它:
AMS 收到这个请求后自然是正常启动这个 Activity 了,因为所有行为都合法。但是当 AMS 完成了相关启动后,在前文我们提到过,会给这个新的 Activity 发一个 H.EXECUTE_TRANSACTION
命令,而这个命令会被 handleLaunchActivity
处理,但是这个函数其实在之前是被 Hook 掉了的:
这个 HCallbackProxy 中是这样注入的:
最终是把 mCallback
对象用 HCallbackProxy
给替换掉了,从而把下面的消息处理函数 handleMessage
给换掉了。不过如果不是我们需要处理的消息,会重新调用原本的函数来处理。
最终调用自己实现的 handleLaunchActivity
函数:
看起来似乎有些复杂,这里稍微总结一下。
首先 handleLaunchActivity
这个函数会有多次调用,不只是收到 LAUNCH_ACTIVITY
时,还有 EXECUTE_TRANSACTION
的时候也一样会调用(似乎是兼容版本),因此看着流程里会有多次提前返回,是因为时机还没到。
以及我们知道,一个 APP 在启动时有可能会创建多个 Activity,第一个创建的 Activity
需要额外的调用 bindApplication
去绑定 Application
对象,这个也是我们前文正常流程里提到过的。
函数一样很长,总结一下内容:
在 handleBindApplication
完成后我们回到 handleLaunchActivity
继续往下:
这里有一个 onActivityCreated
:
将 Activity 指定。
最后将 mIntent
和 mInfo
替换成目标应用。
这个函数从这一步结束后会返回一个 false,之前一直没注意到,但实际上当其返回 false 的时候,会回到原函数:
当 handleLaunchActivity
返回 false 后,程序继续往下执行 mOtherCallback.handleMessage
,这个 mOtherCallback
就是原本的那个处理对象,通过它来调用原本的那个 handleLaunchActivity
。
在原先的那个处理函数中:
注意这里的 ActivityClientRecord
被传进了 performLaunchActivity
:
. 由于我们预先已经把相关的资源路径全部替换成目标应用了,这里会创建目标应用的内存实例对象,获取的 classloader 也都是指向目标应用的路径,使用它们创建 Activity
并最终调用 callActivityOnCreate
。以及目标的相关 dex 和动态库也都在这里被加载进内存。
另外,AppInstrumentation
把这个函数做了个 Hook:
mBaseInstrumentation.callActivityOnCreate
会调用原生的 callActivityOnCreate
,这个里面会去调用 Activity
的 OnCreate
。
最后贴一份流程图,来自于 alen17
0b5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8X3N6S2L8Y4W2S2L8K6V1K6z5e0f1@1x3K6b7H3y4g2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3V1k6V1k6i4c8S2K9h3I4K6i4K6u0r3y4K6j5I4y4K6M7K6z5e0t1`. dddK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9s2g2S2L8X3I4S2L8W2)9J5k6i4A6Z5K9h3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8U0p5#2x3e0l9I4x3o6f1%4y4H3`.`. 97cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3M7X3g2$3k6i4u0U0j5#2)9J5c8Y4m8Q4x3V1j5I4y4U0R3I4x3K6b7K6y4g2)9J5k6h3S2@1L8h3H3`. 49cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2B7K9h3q4F1M7$3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8X3j5&6y4h3k6V1y4e0M7#2j5e0f1%4j5H3`.`.
在前文中我们分析了 VirtualApp 如何在容器内启动目标应用,但一个完整的 APP 除了它本身的代码外,它还有可能创建自己的服务。于是我想要试图了解它是否有在这个过程中做些什么。
与 Activity 不同的是,Service 的生命周期是代码手动管理的,光是这样就能省略掉很多复杂的流程。不过同 Activity 一样,想要创建 Service 仍然需要在 Manifest 中提前占好坑位,通过一些 Hook 等方式实现替换。
先贴一张大致的流程图吧,这里直接引用了 gityuan 大佬的博客内容,原文可在参考文章里找到。
嗯,相比 Activity 要简单多了。一言蔽之就是,进程调用 startService
让 AMS 给这个服务创建个新进程,然后再去调用这个服务中的初始化函数。
网上查了一些 VirtualApp
关于 Service 的实现,但当我在 Blackbox 中对照时发现,似乎后者的实现不太一样,这里我只写出我自己的理解。
从 startService
函数开始:
函数本身没做什么事,主要还是向下调用 BActivityManagerService.startService
:
为用户创建 userSpace
,然后再往下调用 ActiveServices.startService
:
先通过 resolveService
来获取到需要启动的 Service 的相关信息,接下来调用 createStubServiceIntent
来伪造 Intent
:
这里会将 Intent
替换成提前在 Manifest
中占坑好的 ProxyService$Pn
,最后调用原生的 startService
去启动这个 ProxyService
:
于是乎流程就回到了正常的启动过程中去,但注意,这样一来,启动的不就是 ProxyService
了吗?
在上面的流程中可以知道,当 AMS 完成创建的相关步骤后会主动给主线程发 CREATE_SERVICE
的消息,而在被 Hook 了的主线程中会调用 handleCreateService
:
如果创建的目标不是 ProxyJobService
或 ProxyService
的话就会往下调用,但这里我们创建的目标就是 ProxyService
,因此这里返回 false 后会调用原生的那个处理函数真正创建这个 Service 。
而在正常的创建流程中,最后会向下调用这个 Service
的 OnCreate
和 onStartCommand
,其中后者这个函数是在服务每次启动时都会调用的,因此通过 Hook 它来实现替换服务:
在下面这个 onStartCommand
里去加载真正的目标服务相关的代码和对象:
重点关注调用的 createService
函数:
可以看到,程序在这里将服务的代码加载进内存并构建为 Service 对象。
最后再调用它本身的 onStartCommand
函数收个尾:
启动服务还有另外一种通过 bindService
实现的方法,不过同前面的方法并没有太大变化。
函数执行过程中主要关注下面这个函数:
startProcessLocked
函数相信已经不陌生了,就是之前 Activity 时用到的那个,然后最后仍然是执行 createStubServiceIntent
来创建一个用来启动 ProxyService
的 Intent
。
然后最后调用的是原生的那个 bindService:
然后在创建的服务完成以后会主动调用 onBind
:
可以看到也是一样在这个时候去加载真正的目标代码并启动该服务的。
这套流程跟网上搜到的很多资料有些不同,笔者查到的很多资料都表示直接调用 scheduleCreateService
去创建对应服务,而不再经过原生的 AMS 。但在阅读 Blackbox 的代码后我们可以发现实际情况并非如此,启动 Service 跟启动 Activity 有很多地方很相似,它们同样需要提前占坑,并以类似伪造 Intent 的方式去启动对应的目标,然后通过 Hook 的方式来替换真正的目标。
c75K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8&6N6h3q4F1i4K6u0W2j5$3!0E0i4K6u0r3x3U0l9I4y4W2)9J5c8U0l9K6i4K6u0r3x3o6k6Q4x3V1k6K6N6r3q4J5N6q4)9J5k6s2y4W2M7Y4k6A6j5$3g2Q4x3V1j5`. f15K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8Y4q4I4i4K6g2X3x3U0j5@1y4U0l9^5y4o6q4Q4x3V1k6S2M7Y4c8A6j5$3I4W2i4K6u0r3k6r3g2@1j5h3W2D9M7#2)9J5c8U0p5I4z5o6b7@1x3e0M7K6z5l9`.`.
Broadcast Receiver 的容器内实现跟 Service 和 Activity 一样,都是需要提前在 Manifest 中声明才能够调用的,因此对于 VirtualApp 这种容器,就需要提供一种能够在容器内实现的操作。
对于写在 Manifest 中注册的 Broadcast Receiver 在应用启动时会静态注册,而这条途径现在不行了,因此我们需要考虑在容器内应用启动时动态注册 它的那些 Broadcast Receiver。
首先我们来看其创建的时机:
VirtualApp 在创建 BActivityManagerService
时会附带着把 BroadcastManager
一起创建:
然后在 BActivityManagerService
调用 systemReady
的时候会触发 BroadcastManager.startup
:
这里在遍历整个 VirtualApp 已经安装过的所有应用,然后对每个包都调用一次 registerPackage
:
首先获取包里所有需要注册的 receivers,然后往下遍历去判断 action 是否为 BlackAction:
这里的 SYSTEM_ACTIONS
包括了这些:
如果属于上述的这些 action,那就需要额外加一层代理把它们替换掉:
最后再调用 registerReceiver
动态注册这些:
最后调用 addReceiver
把这个包的那些 receiver 放入 Hash 表里做个映射就算是注册完成了:
看起来好像一下子就结束了?总结一下流程就是:把容器内的那些包的每个 Receiver 都拿出来,然后把它们的 IntentFilter 用 VitualApp 自己注册一个一样的,这样就能让 VitualApp 来代管这些收到的 Message 了。
那么问题来了,VitualApp 代管了这些 Message 谁来处理呢?注意到当时注册的时候用到了一个 ProxyBroadcastReceiver
对象。
此处用到的 ProxyBroadcastReceiver
重载了 onReceive
:
可以看出,当 VirtualApp 收到 Message 时会往下调用 scheduleBroadcastReceiver
:
功能也很明显,根据传来的 Intent
去找到对应应用的 ProcessRecord
对象,并通过 scheduleReceiver
来向它们传递 Intent
:
这里就很明显了,通过上述的信息来找到目标应用中的处理函数,通过 loadClass
来加载对应的代码,最后调用它的 onReceive
来让真正的处理函数处理这个消息。
代码过程中一直有个 pendingResultData
在通过 sendBroadcast
发送:
主要是提供一个超时兜底,当广播超时时候会通知一个 PendingResult 表示结束,告诉发送方广播结束了。
除了接受部分需要这样适配,由容器内应用发送广播的过程同样也需要做些调整。
首先是通过 sendBroadcast 把真正需要发送的 Intent 包装起来:
将内部应用发送的 Intent
伪造成由 VirtualApp 发送的 proxyIntent
,然后再调用原生的发送函数把这个广播重新播出去。
不过如果这个发出去的广播最终还是由容器内的应用去处理,那之前注册好的那些 Receiver
就会接收到这些消息然后处理了。后续流程就跟前文一致了。
874K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8X3N6S2L8Y4W2S2L8K6V1K6z5e0f1@1x3K6b7H3y4g2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3V1k6V1k6i4c8S2K9h3I4K6i4K6u0r3y4K6j5J5x3U0V1@1z5o6l9`.
四大核心组件之一的 Content Provider 同样需要在容器内单独做实现。我们主要考虑解决两个问题:
很明显,直到 APP 被安装的那一刻,容器都不知道自己未来要实现怎么样的 Provider,因此我们需要考虑一种办法能够动态的安装这些组件。
在之前启动 Activity
时有一个函数 handleBindApplication
用来绑定 Application 对象,而在这个函数中会调用 installProviders
来安装所有的 Providers
:
其遍历了入参里的 ProviderInfo
数组,并调用 installProvider
来安装每个 Provider
:
这里就是直接调用原生的 installProvider
来完成安装了,并不需要有什么额外的操作。而且跟 Service 或 Activity 一样,VirtualApp 给它们提前占好了坑,用在 Blackbox 中是通过 ProxyContentProvider 来实现的:
这种描述其实有点问题,因为这些 ProxyContentProvider 其实并不是为了占坑而实现的,包括安装之类的操作其实都没有做相关的替换之类的操作。
然后在上面的操作完成以后,最后还有一个初始化的操作:
注意到这个地方相当于把那些注册好了的 mProvider 全部包了一层:、
然后对应的 invoke
函数:
相当于最终会得到一个 ContentProviderStub
来充当 ContentProvider
,然后把其中的 invoke 做了点 hook。
而在那些需要使用 ContentProvider
的进程中,具体来说,VirtualApp 对那些需要使用 ContentProvider
的应用做了些手脚。在容器中,如果有哪个进程想要获取另外一个进程的 ContentProvider
,就需要调用 getContentProvider
:
最后这里替换 provider
为 providerBinder
的时候有一层 ContentProviderStub
的包装。不过在调用它的 invoke 函数的时候会使用传入的 providerBinder 进行调用,因此没有问题。
综上所述,VirtualApp 实现了在容器内伪造 Content Provider 的能力。
530K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8&6N6h3q4F1i4K6u0W2j5$3!0E0i4K6u0r3x3U0l9I4y4W2)9J5c8U0l9%4i4K6u0r3x3K6m8Q4x3V1k6U0L8$3&6@1k6h3&6@1i4K6u0V1M7s2u0G2N6X3W2V1k6i4u0Q4x3V1j5`. 11bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8X3N6S2L8Y4W2S2L8K6V1K6z5e0f1@1x3K6b7H3y4g2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3V1k6V1k6i4c8S2K9h3I4K6i4K6u0r3y4K6j5J5y4e0x3#2y4U0t1`. e00K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6B7N6h3g2B7K9h3&6Q4x3X3g2U0L8W2)9J5c8Y4m8G2M7%4c8Q4x3V1j5%4x3o6t1^5x3e0t1@1z5e0f1%4x3e0b7I4z5o6V1K6x3e0f1H3
在过完了四大组件的容器内实现后,最后我们打算着重看看之前只是模糊提了几句的重定向问题,看看容器是如何把相关的资源和路径进行重定向的。
在之前分析 Activity 时有这么一行代码用来支持路径的重定向:
代码注释中可以看到,应用本身的资源其实已经通过 Application 完成重定向了,但是仍有一些通过硬编码路径来访问文件的情况,为了避免这类访问引发崩溃,因此需要把它们重定向到新路径:
总的来说,先初始化了一些重定向规则,包括:
除此之位还有对进程路径的重定向:
相当于把对这些路径的访问全部过滤成后面的那个参数,然后再把它们注入到 Native 层去:
最后激活一下这些规则:
可以看到,容器对三个对象做了重定向,分别是文件系统、ClassLoader 以及 Binder。
我们从文件系统看起:
可以看到主要就是对这些函数做了 Hook,以及 Hook 的方式也很朴素:
先用 GetStaticMethodID 或 GetMethodID 来获取原始函数的位置,然后把它回填到 orig_fun 中,最后调用 RegisterNatives 用新函数注册进去,替换结束。
而新函数基本上都是这样实现的:
先过滤一遍路径,然后调用原函数。过滤流程最终会调用这个函数:
就是遍历一下找到合适的规则然后根据规则做替换,没啥别的内容了。不过这里有一个疑问,看起来程序并没有对 open、stat 之类的 libc 函数做 Hook,那如果后续有硬编码写死去调用 open 的情况是不是就会出错呢?
同样的,除此之外还有很多各种各样的函数被调用时参数中都会附带路径,这些函数不需要一起过滤吗?以及同时过滤这么多函数也很容易被检查发现也是一个问题。或许后续需要完善。
挺朴素的,跟前文的方式是一样的,只是目标改成了 findLoadedClass
函数。
新函数的实现如下:
可以看到其实是在做一些过滤,把一些不希望被发现的 Class 过滤掉。
同上,这次的目标是 getCallingUid 函数:
最终会先调用一遍原生函数,然后再用下面这个函数做处理:
如果是系统 UID 或不是用户应用的话就直接返回原本的值,而如果返回的结果是容器的 Uid ,那就要过滤一下替换成容器内目标应用的 Uid 了:
除此之位,Blackbox 还基于 seccomp 实现了对系统调用的 Hook:
触发上述的过滤条件时,会通过信号来回调:
可以看到,在这类对 openat 的系统调用做了拦截,不过目前还并没有做什么过滤,未来应该会有更好的支持。
算是最后一个笔者好奇的点。笔者之前并没有使用过 Xposed 的经历,因此对相关的内容其实不是很了解。通过网上的一些资料了解到,Xposed 是通过修改 app_process 的方式向进程里注入代码实现的,而这些操作需要它能够对 zygote 实现 Hook,那么对于 VirtualApp 来说要如何支持呢?
入口从创建应用时的 newApplication
开始:
因为之前创建启动 Activity
时已经用 AppInstrumentation
替换掉了 Instrumentation
,而在正常的创建流程中会调用该对象的 newApplication
函数,而 Xposed 的注入就发生在这个时机。这个时候应用对应的进程已经创建好了,后续就是等待绑定的流程了,而应用还尚且没有开始运行,因此算是合适的时机之一。
可以看到代码中在此刻加载了 Xposed,然后再带调用原生的 newApplication
恢复创建流程:
代码中遍历了容器内安装的所有模块,并通过 PineXposed.loadModule
来加载,这似乎是一个框架的内部实现,翻到了作者的原文笔记。里面提到的说是直接套了 SandHook 的 API ,继续往下翻似乎就是 SandVXposed ,不过最后也没咋找到我想看的,于是只好自己翻起其他的资料对照着源码试着啃啃看了。
首先是加载 Xposed 的相关代码:
然后从资源里读取代码然后加载:
然后下面有一个初始化 Xposed 的操作:
起初还以为是要注入 Zygote ,但是没有 root 也不能注入才对,翻了下源代码似乎是这样的:
看起来似乎不是注入 Zygote ,只是对其中的一些方法做了 Hook,既然如此就不需要真的去注入 Zygote 了,只需要在加载应用时把调一下这个方法把它们拦截下来就行了。
完成 Hook 以后再加载对应模块:
这个 sLoadedPackageCallbacks
只是暂存。在对每个模块做完上述操作以后,下面还有一段:
往下跟一下:
这里最后会去调用 XC_LoadPackage
下的方法:
最后这个 handleLoadPackage
方法就会调用到模块里那个重载后的 handleLoadPackage
来实现模块功能的加载了。
不过这里有一点很奇怪的是,为什么需要每个模块都调用一遍 initZygote
呢?岂不是在重复 Hook 那些方法么?看起来似乎每次都把模块信息传进去了,但是好像没有用到这个信息,那又为什么需要每次都调用一遍呢?
没想明白,如果有大佬知道的话还请多多指教。
在最后一部分我们可以看到,如果通过 Seccomp 对 open 等系统调用做拦截的话,应该上层的很多重定向都可以放掉了?毕竟不管上层用了什么函数,底层对文件的访问都是需要系统调用去支持的,从这个层面说,只要在系统调用层面把路径全部做好过滤,是不是上层的重定向可以直接删掉?
不过 Seccomp 这一策略首先支持的版本比较新,老设备肯定是没有的,以及另一方面是,检测 Seccomp 是不是较为简单呢?笔者目前对这些问题尚没有答案,还需要请教各位大佬。
bacK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5$3q4F1P5h3W2W2i4K6u0W2N6r3!0H3i4K6u0r3x3U0l9J5x3q4)9J5c8U0l9@1i4K6u0r3x3U0N6Q4x3V1k6V1P5h3&6S2L8h3W2U0i4K6u0V1K9r3!0G2K9$3W2F1k6#2)9J5k6r3k6J5j5h3#2W2N6$3!0J5K9#2)9J5k6r3!0F1i4K6u0V1j5i4u0@1i4K6u0r3 87aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6h3k6W2L8X3N6^5N6h3g2Q4x3X3g2Y4K9i4c8Z5N6h3u0Q4x3X3g2A6L8#2)9J5c8U0t1H3x3e0W2Q4x3V1j5I4x3g2)9J5c8U0l9I4i4K6u0r3k6$3g2@1i4K6u0V1x3%4u0V1i4K6u0V1P5s2m8Q4x3X3c8E0L8$3c8#2L8r3g2Q4x3X3c8Z5L8$3!0C8k6i4u0K6i4K6u0W2K9s2c8E0L8l9`.`. 739K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5$3q4F1P5h3W2W2i4K6u0W2N6r3!0H3i4K6u0r3x3U0l9J5x3q4)9J5c8U0l9J5i4K6u0r3x3o6y4Q4x3V1k6S2i4K6u0V1L8X3g2%4i4K6u0V1P5s2m8G2M7$3g2V1i4K6u0V1M7%4c8&6L8r3g2Q4x3X3c8X3M7X3q4E0k6i4N6G2M7X3E0Q4x3V1j5`.
层次
主要工作
VA Space
由VA提供了一个内部的空间,用于安装要在其内部运行的APP,这个空间是系统隔离的。
VA Framework
这一层主要给Android Framework和VAPP做代理,这也是VA的核心。VA提供了一套自己的VA Framework,处于Android Framework与VA APP之间 。 1. 对于VAPP,其访问的所有系统Service 均已被 VA Framework
代理,它会修改VAPP的请求参数,将其中与VAPP安装信息相关的全部参数修改为宿主的参数 之后发送给Android Framework(有部分请求会发送给自己的VA Server直接处理而不再发送给Android系统)。这样Android Framework收到VAPP请求后检查参数就会认为没有问题。 2. 待Android系统对该请求处理完成返回结果时,VA Framework同样也会拦截住该返回结果,此时再将原来修改过的参数全部还原为VAPP请求时发送的。 这样VAPP与Android系统的交互也就能跑通了。
VA Native
在这一层主要为了完成2个工作,IO重定向 和VA APP与Android系统交互的请求修改 。 1. IO重定向是因为可能有部分APP会通过写死的绝对路径访问 ,但是如果APP没有安装到系统,这个路径是不存在的,通过IO重定向,则将其转向VA内部安装的路径。 2. 另外有部分jni函数在VA Framework中无法hook的 ,所以需要在native层来做hook。
void
startProcessAsync(ActivityRecord activity,
boolean
knownToBeDead,
boolean
isTop,String hostingType) {
try
{
...
final
Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
isTop, hostingType, activity.intent.getComponent());
mH.sendMessage(m);
}
finally
{
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
void
startProcessAsync(ActivityRecord activity,
boolean
knownToBeDead,
boolean
isTop,String hostingType) {
try
{
...
final
Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
isTop, hostingType, activity.intent.getComponent());
mH.sendMessage(m);
}
finally
{
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
public
static
void
main(String[] args) {
...
Looper.prepareMainLooper();
...
ActivityThread thread =
new
ActivityThread();
thread.attach(
false
, startSeq);
if
(sMainThreadHandler ==
null
) {
sMainThreadHandler = thread.getHandler();
}
if
(
false
) {
Looper.myLooper().setMessageLogging(
new
LogPrinter(Log.DEBUG,
"ActivityThread"
));
}
Looper.loop();
throw
new
RuntimeException(
"Main thread loop unexpectedly exited"
);
}
public
static
void
main(String[] args) {
...
Looper.prepareMainLooper();
...
ActivityThread thread =
new
ActivityThread();
thread.attach(
false
, startSeq);
if
(sMainThreadHandler ==
null
) {
sMainThreadHandler = thread.getHandler();
}
if
(
false
) {
Looper.myLooper().setMessageLogging(
new
LogPrinter(Log.DEBUG,
"ActivityThread"
));
}
Looper.loop();
throw
new
RuntimeException(
"Main thread loop unexpectedly exited"
);
}
private
boolean
attachApplicationLocked(
@NonNull
IApplicationThread thread,
int
pid,
int
callingUid,
long
startSeq) {
synchronized
(mProcLock) {
app.mState.setCurAdj(ProcessList.INVALID_ADJ);
app.mState.setSetAdj(ProcessList.INVALID_ADJ);
app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ);
mOomAdjuster.setAttachingSchedGroupLSP(app);
app.mState.setForcingToImportant(
null
);
updateProcessForegroundLocked(app,
false
,
0
,
false
);
app.mState.setHasShownUi(
false
);
app.mState.setCached(
false
);
app.setDebugging(
false
);
app.setKilledByAm(
false
);
app.setKilled(
false
);
app.setUnlocked(StorageManager.isUserKeyUnlocked(app.userId));
}
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
final
ProviderInfoList providerList = ProviderInfoList.fromList(providers);
if
(app.getIsolatedEntryPoint() !=
null
) {
thread.runIsolatedEntryPoint(
app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
}
else
if
(instr2 !=
null
) {
thread.bindApplication(processName, appInfo,
app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new
Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap,
app.getStartElapsedTime(), app.getStartUptime());
}
else
{
thread.bindApplication(processName, appInfo,
app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList,
null
, profilerInfo,
null
,
null
,
null
, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new
Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap,
app.getStartElapsedTime(), app.getStartUptime());
}
if
(normalMode) {
try
{
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
}
catch
(Exception e) {
}
}
return
true
;
}
private
boolean
attachApplicationLocked(
@NonNull
IApplicationThread thread,
int
pid,
int
callingUid,
long
startSeq) {
synchronized
(mProcLock) {
app.mState.setCurAdj(ProcessList.INVALID_ADJ);
app.mState.setSetAdj(ProcessList.INVALID_ADJ);
app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ);
mOomAdjuster.setAttachingSchedGroupLSP(app);
app.mState.setForcingToImportant(
null
);
updateProcessForegroundLocked(app,
false
,
0
,
false
);
app.mState.setHasShownUi(
false
);
app.mState.setCached(
false
);
app.setDebugging(
false
);
app.setKilledByAm(
false
);
app.setKilled(
false
);
app.setUnlocked(StorageManager.isUserKeyUnlocked(app.userId));
}
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
final
ProviderInfoList providerList = ProviderInfoList.fromList(providers);
if
(app.getIsolatedEntryPoint() !=
null
) {
thread.runIsolatedEntryPoint(
app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
}
else
if
(instr2 !=
null
) {
thread.bindApplication(processName, appInfo,
app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new
Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap,
app.getStartElapsedTime(), app.getStartUptime());
}
else
{
thread.bindApplication(processName, appInfo,
app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList,
null
, profilerInfo,
null
,
null
,
null
, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new
Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap,
app.getStartElapsedTime(), app.getStartUptime());
}
if
(normalMode) {
try
{
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
}
catch
(Exception e) {
}
}
return
true
;
}
private
void
handleBindApplication(AppBindData data) {
final
ContextImpl appContext = ContextImpl.createAppContext(
this
, data.info);
if
(ii !=
null
) {
initInstrumentation(ii, data, appContext);
}
else
{
mInstrumentation =
new
Instrumentation();
mInstrumentation.basicInit(
this
);
}
Application app;
try
{
app = data.info.makeApplicationInner(data.restrictedBackupMode,
null
);
mInstrumentation.onCreate(data.instrumentationArgs);
mInstrumentation.callApplicationOnCreate(app);
}
finally
{
}
}
private
void
handleBindApplication(AppBindData data) {
final
ContextImpl appContext = ContextImpl.createAppContext(
this
, data.info);
if
(ii !=
null
) {
initInstrumentation(ii, data, appContext);
}
else
{
mInstrumentation =
new
Instrumentation();
mInstrumentation.basicInit(
this
);
}
Application app;
try
{
app = data.info.makeApplicationInner(data.restrictedBackupMode,
null
);
mInstrumentation.onCreate(data.instrumentationArgs);
mInstrumentation.callApplicationOnCreate(app);
}
finally
{
}
}
private
void
handleBindApplication(AppBindData data) {
final
ContextImpl appContext = ContextImpl.createAppContext(
this
, data.info);
if
(ii !=
null
) {
initInstrumentation(ii, data, appContext);
}
else
{
mInstrumentation =
new
Instrumentation();
mInstrumentation.basicInit(
this
);
}
Application app;
try
{
app = data.info.makeApplicationInner(data.restrictedBackupMode,
null
);
mInstrumentation.onCreate(data.instrumentationArgs);
mInstrumentation.callApplicationOnCreate(app);
}
finally
{
}
}
public
Application makeApplication(
boolean
forceDefaultAppClass,Instrumentation instrumentation) {
if
(mApplication !=
null
) {
return
mApplication;
}
String appClass = mApplicationInfo.className;
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread,
this
);
app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
appContext.setOuterContext(app);
}
public
Application newApplication(ClassLoader cl, String className, Context context) {
return
newApplication(cl.loadClass(className), context);
}
Instrumentation类:
static
public
Application newApplication(Class<?> clazz, Context context) {
Application app = (Application)clazz.newInstance();
app.attach(context);
return
app;
}
final
void
attach(Context context) {
mBase = base;
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
private
void
handleBindApplication(AppBindData data) {
final
ContextImpl appContext = ContextImpl.createAppContext(
this
, data.info);
if
(ii !=
null
) {
initInstrumentation(ii, data, appContext);
}
else
{
mInstrumentation =
new
Instrumentation();
mInstrumentation.basicInit(
this
);
}
Application app;
try
{
app = data.info.makeApplicationInner(data.restrictedBackupMode,
null
);
mInstrumentation.onCreate(data.instrumentationArgs);
mInstrumentation.callApplicationOnCreate(app);
}
finally
{
}
}
public
Application makeApplication(
boolean
forceDefaultAppClass,Instrumentation instrumentation) {
if
(mApplication !=
null
) {
return
mApplication;
}
String appClass = mApplicationInfo.className;
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread,
this
);
app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
appContext.setOuterContext(app);
}
public
Application newApplication(ClassLoader cl, String className, Context context) {
return
newApplication(cl.loadClass(className), context);
}
Instrumentation类:
static
public
Application newApplication(Class<?> clazz, Context context) {
Application app = (Application)clazz.newInstance();
app.attach(context);
return
app;
}
final
void
attach(Context context) {
mBase = base;
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
public
Application makeApplicationInner(
boolean
forceDefaultAppClass,
Instrumentation instrumentation) {
return
makeApplicationInner(forceDefaultAppClass, instrumentation,
false
);
}
private
Application makeApplicationInner(
boolean
forceDefaultAppClass,
Instrumentation instrumentation,
boolean
allowDuplicateInstances) {
if
(mApplication !=
null
) {
return
mApplication;
}
synchronized
(sApplications) {
final
Application cached = sApplications.get(mPackageName);
if
(cached !=
null
) {
if
(!allowDuplicateInstances) {
mApplication = cached;
return
cached;
}
}
}
Application app =
null
;
final
String myProcessName = Process.myProcessName();
String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(
myProcessName);
try
{
final
java.lang.ClassLoader cl = getClassLoader();
if
(!mPackageName.equals(
"android"
)) {
initializeJavaContextClassLoader();
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread,
this
);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
}
catch
(Exception e) {
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
if
(!allowDuplicateInstances) {
synchronized
(sApplications) {
sApplications.put(mPackageName, app);
}
}
if
(instrumentation !=
null
) {
try
{
instrumentation.callApplicationOnCreate(app);
}
catch
(Exception e) {
}
}
return
app;
}
public
Application makeApplicationInner(
boolean
forceDefaultAppClass,
Instrumentation instrumentation) {
return
makeApplicationInner(forceDefaultAppClass, instrumentation,
false
);
}
private
Application makeApplicationInner(
boolean
forceDefaultAppClass,
Instrumentation instrumentation,
boolean
allowDuplicateInstances) {
if
(mApplication !=
null
) {
return
mApplication;
}
synchronized
(sApplications) {
final
Application cached = sApplications.get(mPackageName);
if
(cached !=
null
) {
if
(!allowDuplicateInstances) {
mApplication = cached;
return
cached;
}
}
}
Application app =
null
;
final
String myProcessName = Process.myProcessName();
String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(
myProcessName);
try
{
final
java.lang.ClassLoader cl = getClassLoader();
if
(!mPackageName.equals(
"android"
)) {
initializeJavaContextClassLoader();
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread,
this
);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
}
catch
(Exception e) {
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
if
(!allowDuplicateInstances) {
synchronized
(sApplications) {
sApplications.put(mPackageName, app);
}
}
if
(instrumentation !=
null
) {
try
{
instrumentation.callApplicationOnCreate(app);
}
catch
(Exception e) {
}
}
return
app;
}
public
boolean
attachApplication(WindowProcessController wpc)
throws
RemoteException {
synchronized
(mGlobalLockWithoutBoost) {
try
{
return
mRootWindowContainer.attachApplication(wpc);
}
finally
{
}
}
}
public
boolean
test(ActivityRecord r) {
if
(r.finishing || !r.showToCurrentUser() || !r.visibleIgnoringKeyguard
|| r.app !=
null
|| mApp.mUid != r.info.applicationInfo.uid
|| !mApp.mName.equals(r.processName)) {
return
false
;
}
try
{
if
(mTaskSupervisor.realStartActivityLocked(r, mApp,
mTop == r && r.getTask().canBeResumed(r)
)) {
mHasActivityStarted =
true
;
}
}
catch
(RemoteException e) {
}
return
false
;
}
public
boolean
attachApplication(WindowProcessController wpc)
throws
RemoteException {
synchronized
(mGlobalLockWithoutBoost) {
try
{
return
mRootWindowContainer.attachApplication(wpc);
}
finally
{
}
}
}
public
boolean
test(ActivityRecord r) {
if
(r.finishing || !r.showToCurrentUser() || !r.visibleIgnoringKeyguard
|| r.app !=
null
|| mApp.mUid != r.info.applicationInfo.uid
|| !mApp.mName.equals(r.processName)) {
return
false
;
}
try
{
if
(mTaskSupervisor.realStartActivityLocked(r, mApp,
mTop == r && r.getTask().canBeResumed(r)
)) {
mHasActivityStarted =
true
;
}
}
catch
(RemoteException e) {
}
return
false
;
}
boolean
realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean
andResume,
boolean
checkConfig)
throws
RemoteException {
final
ClientTransaction clientTransaction = ClientTransaction.obtain(proc.getThread(), r.token);
final
boolean
isTransitionForward = r.isTransitionForward();
final
IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
clientTransaction.addCallback(LaunchActivityItem.obtain(
new
Intent(r.intent),
System.identityHashCode(r), r.info,
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
results, newIntents, r.takeOptions(), isTransitionForward,
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken));
final
ActivityLifecycleItem lifecycleItem;
if
(andResume) {
lifecycleItem = ResumeActivityItem.obtain(isTransitionForward);
}
else
{
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
return
true
;
}
boolean
realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean
andResume,
boolean
checkConfig)
throws
RemoteException {
final
ClientTransaction clientTransaction = ClientTransaction.obtain(proc.getThread(), r.token);
final
boolean
isTransitionForward = r.isTransitionForward();
final
IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
clientTransaction.addCallback(LaunchActivityItem.obtain(
new
Intent(r.intent),
System.identityHashCode(r), r.info,
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
results, newIntents, r.takeOptions(), isTransitionForward,
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken));
final
ActivityLifecycleItem lifecycleItem;
if
(andResume) {
lifecycleItem = ResumeActivityItem.obtain(isTransitionForward);
}
else
{
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
return
true
;
}
void
scheduleTransaction(ClientTransaction transaction)
throws
RemoteException {
final
IApplicationThread client = transaction.getClient();
transaction.schedule();
}
public
void
schedule()
throws
RemoteException {
mClient.scheduleTransaction(
this
);
}
@Override
public
void
scheduleTransaction(ClientTransaction transaction)
throws
RemoteException {
ActivityThread.
this
.scheduleTransaction(transaction);
}
void
scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(
this
);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
void
scheduleTransaction(ClientTransaction transaction)
throws
RemoteException {
final
IApplicationThread client = transaction.getClient();
transaction.schedule();
}
public
void
schedule()
throws
RemoteException {
mClient.scheduleTransaction(
this
);
}
@Override
public
void
scheduleTransaction(ClientTransaction transaction)
throws
RemoteException {
ActivityThread.
this
.scheduleTransaction(transaction);
}
void
scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(
this
);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
class
H
extends
Handler {
public
void
handleMessage(Message msg) {
switch
(msg.what) {
case
EXECUTE_TRANSACTION:
final
ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if
(isSystem()) {
transaction.recycle();
}
break
;
}
}
}
class
H
extends
Handler {
public
void
handleMessage(Message msg) {
switch
(msg.what) {
case
EXECUTE_TRANSACTION:
final
ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if
(isSystem()) {
transaction.recycle();
}
break
;
}
}
}
public
void
execute(ClientTransaction transaction) {
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
}
public
void
execute(ClientTransaction transaction) {
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
}
public
Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
if
(ThreadedRenderer.sRendererEnabled
&& (r.activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) !=
0
) {
HardwareRenderer.preload();
}
WindowManagerGlobal.initialize();
GraphicsEnvironment.hintActivityLaunch();
final
Activity a = performLaunchActivity(r, customIntent);
return
a;
}
public
Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
if
(ThreadedRenderer.sRendererEnabled
&& (r.activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) !=
0
) {
HardwareRenderer.preload();
}
WindowManagerGlobal.initialize();
GraphicsEnvironment.hintActivityLaunch();
final
Activity a = performLaunchActivity(r, customIntent);
return
a;
}
ActivityThread.performLaunchActivity() {
activity = mInstrumentation.newActivity(classLoader,
component.getClassName(), r.intent);
Context appContext = createBaseContextForActivity(r, activity);
activity.attach(context,mInstrumentation,application,...);
mInstrumentation.callActivityOnCreate(activity,...)
}
public
void
callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
ActivityThread.performLaunchActivity() {
activity = mInstrumentation.newActivity(classLoader,
component.getClassName(), r.intent);
Context appContext = createBaseContextForActivity(r, activity);
activity.attach(context,mInstrumentation,application,...);
mInstrumentation.callActivityOnCreate(activity,...)
}
public
void
callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
public
boolean
launchApk(String packageName,
int
userId) {
Intent launchIntentForPackage =
getBPackageManager().getLaunchIntentForPackage(packageName, userId);
if
(launchIntentForPackage ==
null
) {
return
false
;
}
startActivity(launchIntentForPackage, userId);
return
true
;
}
public
void
startActivity(Intent intent,
int
userId) {
if
(mClientConfiguration.isEnableLauncherActivity()) {
LauncherActivity.launch(intent, userId);
}
else
{
getBActivityManager().startActivity(intent, userId);
}
}
public
static
void
launch(Intent intent,
int
userId) {
Intent splash =
new
Intent();
splash.setClass(SandBoxCore.getContext(), LauncherActivity.
class
);
splash.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
splash.putExtra(LauncherActivity.KEY_INTENT, intent);
splash.putExtra(LauncherActivity.KEY_PKG, intent.getPackage());
splash.putExtra(LauncherActivity.KEY_USER_ID, userId);
SandBoxCore.getContext().startActivity(splash);
}
public
boolean
launchApk(String packageName,
int
userId) {
Intent launchIntentForPackage =
getBPackageManager().getLaunchIntentForPackage(packageName, userId);
if
(launchIntentForPackage ==
null
) {
return
false
;
}
startActivity(launchIntentForPackage, userId);
return
true
;
}
public
void
startActivity(Intent intent,
int
userId) {
if
(mClientConfiguration.isEnableLauncherActivity()) {
LauncherActivity.launch(intent, userId);
}
else
{
getBActivityManager().startActivity(intent, userId);
}
}
public
static
void
launch(Intent intent,
int
userId) {
Intent splash =
new
Intent();
splash.setClass(SandBoxCore.getContext(), LauncherActivity.
class
);
splash.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
splash.putExtra(LauncherActivity.KEY_INTENT, intent);
splash.putExtra(LauncherActivity.KEY_PKG, intent.getPackage());
splash.putExtra(LauncherActivity.KEY_USER_ID, userId);
SandBoxCore.getContext().startActivity(splash);
}
@Override
protected
void
onCreate(
@Nullable
Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
Intent intent = getIntent();
if
(intent ==
null
) {
finish();
return
;
}
Intent launchIntent = intent.getParcelableExtra(KEY_INTENT);
String packageName = intent.getStringExtra(KEY_PKG);
int
userId = intent.getIntExtra(KEY_USER_ID,
0
);
PackageInfo packageInfo =
SandBoxCore.getBPackageManager().getPackageInfo(packageName,
0
, userId);
if
(packageInfo ==
null
) {
Slog.e(TAG, packageName +
" not installed!"
);
finish();
return
;
}
Drawable drawable = packageInfo.applicationInfo.loadIcon(SandBoxCore.getPackageManager());
setContentView(R.layout.activity_launcher);
findViewById(R.id.iv_icon).setBackgroundDrawable(drawable);
new
Thread(() -> SandBoxCore.getBActivityManager().startActivity(launchIntent, userId)).start();
}
@Override
protected
void
onCreate(
@Nullable
Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
Intent intent = getIntent();
if
(intent ==
null
) {
finish();
return
;
}
Intent launchIntent = intent.getParcelableExtra(KEY_INTENT);
String packageName = intent.getStringExtra(KEY_PKG);
int
userId = intent.getIntExtra(KEY_USER_ID,
0
);
PackageInfo packageInfo =
SandBoxCore.getBPackageManager().getPackageInfo(packageName,
0
, userId);
if
(packageInfo ==
null
) {
Slog.e(TAG, packageName +
" not installed!"
);
finish();
return
;
}
Drawable drawable = packageInfo.applicationInfo.loadIcon(SandBoxCore.getPackageManager());
setContentView(R.layout.activity_launcher);
findViewById(R.id.iv_icon).setBackgroundDrawable(drawable);
new
Thread(() -> SandBoxCore.getBActivityManager().startActivity(launchIntent, userId)).start();
}
public
void
startActivity(Intent intent,
int
userId) {
try
{
getService().startActivity(intent, userId);
}
catch
(RemoteException e) {
e.printStackTrace();
}
}
public
Service getService() {
if
(mService !=
null
&& mService.asBinder().pingBinder()
&& mService.asBinder().isBinderAlive()) {
return
mService;
}
try
{
mService =
Reflector.on(getTClass().getName() +
"$Stub"
)
.method(
"asInterface"
, IBinder.
class
)
.call(SandBoxCore.get().getService(getServiceName()));
mService
.asBinder()
.linkToDeath(
new
IBinder.DeathRecipient() {
@Override
public
void
binderDied() {
mService.asBinder().unlinkToDeath(
this
,
0
);
mService =
null
;
}
},
0
);
return
getService();
}
catch
(Throwable e) {
e.printStackTrace();
return
null
;
}
}
public
void
startActivity(Intent intent,
int
userId) {
try
{
getService().startActivity(intent, userId);
}
catch
(RemoteException e) {
e.printStackTrace();
}
}
public
Service getService() {
if
(mService !=
null
&& mService.asBinder().pingBinder()
&& mService.asBinder().isBinderAlive()) {
return
mService;
}
try
{
mService =
Reflector.on(getTClass().getName() +
"$Stub"
)
.method(
"asInterface"
, IBinder.
class
)
.call(SandBoxCore.get().getService(getServiceName()));
mService
.asBinder()
.linkToDeath(
new
IBinder.DeathRecipient() {
@Override
public
void
binderDied() {
mService.asBinder().unlinkToDeath(
this
,
0
);
mService =
null
;
}
},
0
);
return
getService();
}
catch
(Throwable e) {
e.printStackTrace();
return
null
;
}
}
<
provider
android:name
=
".core.system.SystemCallProvider"
android:authorities
=
"${applicationId}.blackbox.SystemCallProvider"
android:exported
=
"false"
android:process
=
"@string/black_box_service_name"
/>
<
provider
android:name
=
".core.system.SystemCallProvider"
android:authorities
=
"${applicationId}.blackbox.SystemCallProvider"
android:exported
=
"false"
android:process
=
"@string/black_box_service_name"
/>
@Override
public
boolean
onCreate() {
return
initSystem();
}
private
boolean
initSystem() {
BlackBoxSystem.getSystem().startup();
return
true
;
}
public
void
startup() {
if
(isStartup.getAndSet(
true
))
return
;
BEnvironment.load();
mServices.add(BPackageManagerService.get());
mServices.add(BUserManagerService.get());
mServices.add(BActivityManagerService.get());
mServices.add(BJobManagerService.get());
mServices.add(BStorageManagerService.get());
mServices.add(BPackageInstallerService.get());
mServices.add(BXposedManagerService.get());
mServices.add(BProcessManagerService.get());
mServices.add(BAccountManagerService.get());
mServices.add(BLocationManagerService.get());
mServices.add(BNotificationManagerService.get());
for
(ISystemService service : mServices) {
service.systemReady();
}
List<String> preInstallPackages = AppSystemEnv.getPreInstallPackages();
for
(String preInstallPackage : preInstallPackages) {
try
{
if
(!BPackageManagerService.get().isInstalled(preInstallPackage, BUserHandle.USER_ALL)) {
PackageInfo packageInfo =
SandBoxCore.getPackageManager().getPackageInfo(preInstallPackage,
0
);
BPackageManagerService.get()
.installPackageAsUser(
packageInfo.applicationInfo.sourceDir,
InstallOption.installBySystem(),
BUserHandle.USER_ALL);
}
}
catch
(PackageManager.NameNotFoundException ignored) {
}
}
initJarEnv();
}
@Override
public
boolean
onCreate() {
return
initSystem();
}
private
boolean
initSystem() {
BlackBoxSystem.getSystem().startup();
return
true
;
}
public
void
startup() {
if
(isStartup.getAndSet(
true
))
return
;
BEnvironment.load();
mServices.add(BPackageManagerService.get());
mServices.add(BUserManagerService.get());
mServices.add(BActivityManagerService.get());
mServices.add(BJobManagerService.get());
mServices.add(BStorageManagerService.get());
mServices.add(BPackageInstallerService.get());
mServices.add(BXposedManagerService.get());
mServices.add(BProcessManagerService.get());
mServices.add(BAccountManagerService.get());
mServices.add(BLocationManagerService.get());
mServices.add(BNotificationManagerService.get());
for
(ISystemService service : mServices) {
service.systemReady();
}
List<String> preInstallPackages = AppSystemEnv.getPreInstallPackages();
for
(String preInstallPackage : preInstallPackages) {
try
{
if
(!BPackageManagerService.get().isInstalled(preInstallPackage, BUserHandle.USER_ALL)) {
PackageInfo packageInfo =
SandBoxCore.getPackageManager().getPackageInfo(preInstallPackage,
0
);
BPackageManagerService.get()
.installPackageAsUser(
packageInfo.applicationInfo.sourceDir,
InstallOption.installBySystem(),
BUserHandle.USER_ALL);
}
}
catch
(PackageManager.NameNotFoundException ignored) {
}
}
initJarEnv();
}
public
BActivityManagerService() {
mBroadcastManager = BroadcastManager.startSystem(
this
, mPms);
}
@Override
public
void
systemReady() {
mBroadcastManager.startup();
}
public
void
startup() {
mPms.addPackageMonitor(
this
);
List<BPackageSettings> bPackageSettings = mPms.getBPackageSettings();
for
(BPackageSettings bPackageSetting : bPackageSettings) {
BPackage bPackage = bPackageSetting.pkg;
registerPackage(bPackage);
}
}
public
BActivityManagerService() {
mBroadcastManager = BroadcastManager.startSystem(
this
, mPms);
}
@Override
public
void
systemReady() {
mBroadcastManager.startup();
}
public
void
startup() {
mPms.addPackageMonitor(
this
);
List<BPackageSettings> bPackageSettings = mPms.getBPackageSettings();
for
(BPackageSettings bPackageSetting : bPackageSettings) {
BPackage bPackage = bPackageSetting.pkg;
registerPackage(bPackage);
}
}
private
void
addReceiver(String packageName, BroadcastReceiver receiver) {
List<BroadcastReceiver> broadcastReceivers = mReceivers.get(packageName);
if
(broadcastReceivers ==
null
) {
broadcastReceivers =
new
ArrayList<>();
mReceivers.put(packageName, broadcastReceivers);
}
broadcastReceivers.add(receiver);
}
private
void
addReceiver(String packageName, BroadcastReceiver receiver) {
List<BroadcastReceiver> broadcastReceivers = mReceivers.get(packageName);
if
(broadcastReceivers ==
null
) {
broadcastReceivers =
new
ArrayList<>();
mReceivers.put(packageName, broadcastReceivers);
}
broadcastReceivers.add(receiver);
}
@Nullable
@Override
public
Bundle call(
@NonNull
String method,
@Nullable
String arg,
@Nullable
Bundle extras) {
Slog.d(TAG,
"call: "
+ method +
", "
+ extras);
if
(
"VM"
.equals(method)) {
Bundle bundle =
new
Bundle();
if
(extras !=
null
) {
String name = extras.getString(
"_B_|_server_name_"
);
BundleCompat.putBinder(bundle,
"_B_|_server_"
, ServiceManager.getService(name));
}
return
bundle;
}
return
super
.call(method, arg, extras);
}
@Nullable
@Override
public
Bundle call(
@NonNull
String method,
@Nullable
String arg,
@Nullable
Bundle extras) {
Slog.d(TAG,
"call: "
+ method +
", "
+ extras);
if
(
"VM"
.equals(method)) {
Bundle bundle =
new
Bundle();
if
(extras !=
null
) {
String name = extras.getString(
"_B_|_server_name_"
);
BundleCompat.putBinder(bundle,
"_B_|_server_"
, ServiceManager.getService(name));
}
return
bundle;
}
return
super
.call(method, arg, extras);
}
public
static
IBinder getService(String name) {
return
get().getServiceInternal(name);
}
public
static
ServiceManager get() {
if
(sServiceManager ==
null
) {
synchronized
(ServiceManager.
class
) {
if
(sServiceManager ==
null
) {
sServiceManager =
new
ServiceManager();
}
}
}
return
sServiceManager;
}
private
ServiceManager() {
mCaches.put(ACTIVITY_MANAGER, BActivityManagerService.get());
mCaches.put(JOB_MANAGER, BJobManagerService.get());
mCaches.put(PACKAGE_MANAGER, BPackageManagerService.get());
mCaches.put(STORAGE_MANAGER, BStorageManagerService.get());
mCaches.put(USER_MANAGER, BUserManagerService.get());
mCaches.put(XPOSED_MANAGER, BXposedManagerService.get());
mCaches.put(ACCOUNT_MANAGER, BAccountManagerService.get());
mCaches.put(LOCATION_MANAGER, BLocationManagerService.get());
mCaches.put(NOTIFICATION_MANAGER, BNotificationManagerService.get());
}
public
IBinder getServiceInternal(String name) {
return
mCaches.get(name);
}
public
static
IBinder getService(String name) {
return
get().getServiceInternal(name);
}
public
static
ServiceManager get() {
if
(sServiceManager ==
null
) {
synchronized
(ServiceManager.
class
) {
if
(sServiceManager ==
null
) {
sServiceManager =
new
ServiceManager();
}
}
}
return
sServiceManager;
}
private
ServiceManager() {
mCaches.put(ACTIVITY_MANAGER, BActivityManagerService.get());
mCaches.put(JOB_MANAGER, BJobManagerService.get());
mCaches.put(PACKAGE_MANAGER, BPackageManagerService.get());
mCaches.put(STORAGE_MANAGER, BStorageManagerService.get());
mCaches.put(USER_MANAGER, BUserManagerService.get());
mCaches.put(XPOSED_MANAGER, BXposedManagerService.get());
mCaches.put(ACCOUNT_MANAGER, BAccountManagerService.get());
mCaches.put(LOCATION_MANAGER, BLocationManagerService.get());
mCaches.put(NOTIFICATION_MANAGER, BNotificationManagerService.get());
}
public
IBinder getServiceInternal(String name) {
return
mCaches.get(name);
}
@Override
public
Object getSystemService(String name) {
return
SystemServiceRegistry.getSystemService(
this
, name);
}
@Override
public
Object getSystemService(String name) {
return
SystemServiceRegistry.getSystemService(
this
, name);
}
public
void
init() {
if
(SandBoxCore.get().isBlackProcess() || SandBoxCore.get().isServerProcess()) {
addInjector(
new
IDisplayManagerProxy());
addInjector(
new
OsStub());
addInjector(
new
IActivityManagerProxy());
addInjector(
new
IPackageManagerProxy());
addInjector(
new
ITelephonyManagerProxy());
addInjector(
new
HCallbackProxy());
addInjector(
new
IAppOpsManagerProxy());
addInjector(
new
INotificationManagerProxy());
addInjector(
new
IAlarmManagerProxy());
addInjector(
new
IAppWidgetManagerProxy());
addInjector(
new
ContentServiceStub());
addInjector(
new
IWindowManagerProxy());
addInjector(
new
IUserManagerProxy());
addInjector(
new
RestrictionsManagerStub());
addInjector(
new
IMediaSessionManagerProxy());
addInjector(
new
ILocationManagerProxy());
addInjector(
new
IStorageManagerProxy());
addInjector(
new
ILauncherAppsProxy());
addInjector(
new
IJobServiceProxy());
addInjector(
new
IAccessibilityManagerProxy());
addInjector(
new
ITelephonyRegistryProxy());
addInjector(
new
IDevicePolicyManagerProxy());
addInjector(
new
IAccountManagerProxy());
addInjector(
new
IConnectivityManagerProxy());
addInjector(
new
IClipboardManagerProxy());
addInjector(
new
IPhoneSubInfoProxy());
addInjector(
new
IMediaRouterServiceProxy());
addInjector(
new
IPowerManagerProxy());
addInjector(
new
IContextHubServiceProxy());
addInjector(
new
IVibratorServiceProxy());
addInjector(
new
IPersistentDataBlockServiceProxy());
addInjector(AppInstrumentation.get());
addInjector(
new
IWifiManagerProxy());
addInjector(
new
IWifiScannerProxy());
if
(BuildCompat.isS()) {
addInjector(
new
IActivityClientProxy(
null
));
addInjector(
new
IVpnManagerProxy());
}
if
(BuildCompat.isR()) {
addInjector(
new
IPermissionManagerProxy());
}
if
(BuildCompat.isQ()) {
addInjector(
new
IActivityTaskManagerProxy());
}
if
(BuildCompat.isPie()) {
addInjector(
new
ISystemUpdateProxy());
}
if
(BuildCompat.isOreo()) {
addInjector(
new
IAutofillManagerProxy());
addInjector(
new
IDeviceIdentifiersPolicyProxy());
addInjector(
new
IStorageStatsManagerProxy());
}
if
(BuildCompat.isN_MR1()) {
addInjector(
new
IShortcutManagerProxy());
}
if
(BuildCompat.isN()) {
addInjector(
new
INetworkManagementServiceProxy());
}
if
(BuildCompat.isM()) {
addInjector(
new
IFingerprintManagerProxy());
addInjector(
new
IGraphicsStatsProxy());
}
if
(BuildCompat.isL()) {
addInjector(
new
IJobServiceProxy());
}
}
injectAll();
}
public
void
init() {
if
(SandBoxCore.get().isBlackProcess() || SandBoxCore.get().isServerProcess()) {
addInjector(
new
IDisplayManagerProxy());
addInjector(
new
OsStub());
addInjector(
new
IActivityManagerProxy());
addInjector(
new
IPackageManagerProxy());
addInjector(
new
ITelephonyManagerProxy());
addInjector(
new
HCallbackProxy());
addInjector(
new
IAppOpsManagerProxy());
addInjector(
new
INotificationManagerProxy());
addInjector(
new
IAlarmManagerProxy());
addInjector(
new
IAppWidgetManagerProxy());
addInjector(
new
ContentServiceStub());
addInjector(
new
IWindowManagerProxy());
addInjector(
new
IUserManagerProxy());
addInjector(
new
RestrictionsManagerStub());
addInjector(
new
IMediaSessionManagerProxy());
addInjector(
new
ILocationManagerProxy());
addInjector(
new
IStorageManagerProxy());
addInjector(
new
ILauncherAppsProxy());
addInjector(
new
IJobServiceProxy());
addInjector(
new
IAccessibilityManagerProxy());
addInjector(
new
ITelephonyRegistryProxy());
addInjector(
new
IDevicePolicyManagerProxy());
addInjector(
new
IAccountManagerProxy());
addInjector(
new
IConnectivityManagerProxy());
addInjector(
new
IClipboardManagerProxy());
addInjector(
new
IPhoneSubInfoProxy());
addInjector(
new
IMediaRouterServiceProxy());
addInjector(
new
IPowerManagerProxy());
addInjector(
new
IContextHubServiceProxy());
addInjector(
new
IVibratorServiceProxy());
addInjector(
new
IPersistentDataBlockServiceProxy());
addInjector(AppInstrumentation.get());
addInjector(
new
IWifiManagerProxy());
addInjector(
new
IWifiScannerProxy());
if
(BuildCompat.isS()) {
addInjector(
new
IActivityClientProxy(
null
));
addInjector(
new
IVpnManagerProxy());
}
if
(BuildCompat.isR()) {
addInjector(
new
IPermissionManagerProxy());
}
if
(BuildCompat.isQ()) {
addInjector(
new
IActivityTaskManagerProxy());
}
if
(BuildCompat.isPie()) {
addInjector(
new
ISystemUpdateProxy());
}
if
(BuildCompat.isOreo()) {
addInjector(
new
IAutofillManagerProxy());
addInjector(
new
IDeviceIdentifiersPolicyProxy());
addInjector(
new
IStorageStatsManagerProxy());
}
if
(BuildCompat.isN_MR1()) {
addInjector(
new
IShortcutManagerProxy());
}
if
(BuildCompat.isN()) {
addInjector(
new
INetworkManagementServiceProxy());
}
if
(BuildCompat.isM()) {
addInjector(
new
IFingerprintManagerProxy());
addInjector(
new
IGraphicsStatsProxy());
}
if
(BuildCompat.isL()) {
addInjector(
new
IJobServiceProxy());
}
}
injectAll();
}
@Override
protected
void
inject(Object base, Object proxy) {
Object iActivityManager =
null
;
if
(BuildCompat.isOreo()) {
iActivityManager = BRActivityManagerOreo.get().IActivityManagerSingleton();
}
else
if
(BuildCompat.isL()) {
iActivityManager = BRActivityManagerNative.get().gDefault();
}
BRSingleton.get(iActivityManager)._set_mInstance(proxy);
}
@Override
protected
void
inject(Object base, Object proxy) {
Object iActivityManager =
null
;
if
(BuildCompat.isOreo()) {
iActivityManager = BRActivityManagerOreo.get().IActivityManagerSingleton();
}
else
if
(BuildCompat.isL()) {
iActivityManager = BRActivityManagerNative.get().gDefault();
}
BRSingleton.get(iActivityManager)._set_mInstance(proxy);
}
@ProxyMethod
(
"getServices"
)
public
static
class
GetServices
extends
MethodHook {
@Override
protected
Object hook(Object who, Method method, Object[] args)
throws
Throwable {
RunningServiceInfo runningServices =
BActivityManager.get()
.getRunningServices(BActivityThread.getAppPackageName(), BActivityThread.getUserId());
if
(runningServices ==
null
) {
return
new
ArrayList<>();
}
return
runningServices.mRunningServiceInfoList;
}
}
@ProxyMethod
(
"getServices"
)
public
static
class
GetServices
extends
MethodHook {
@Override
protected
Object hook(Object who, Method method, Object[] args)
throws
Throwable {
RunningServiceInfo runningServices =
BActivityManager.get()
.getRunningServices(BActivityThread.getAppPackageName(), BActivityThread.getUserId());
if
(runningServices ==
null
) {
return
new
ArrayList<>();
}
return
runningServices.mRunningServiceInfoList;
}
}
<
provider
android:name
=
".core.system.SystemCallProvider"
android:authorities
=
"${applicationId}.blackbox.SystemCallProvider"
android:exported
=
"false"
android:process
=
"@string/black_box_service_name"
/>
<
receiver
android:name
=
".proxy.ProxyBroadcastReceiver"
android:enabled
=
"true"
android:exported
=
"true"
android:process
=
"@string/black_box_service_name"
>
<
intent-filter
> <
action
android:name
=
"${applicationId}.stub_receiver"
/>
</
intent-filter
></
receiver
>
<
service
android:name
=
".core.system.DaemonService"
android:exported
=
"false"
android:process
=
"@string/black_box_service_name"
/>
<
service
android:name
=
".core.system.DaemonService$DaemonInnerService"
android:exported
=
"false"
android:process
=
"@string/black_box_service_name"
/>
<
provider
android:name
=
".core.system.SystemCallProvider"
android:authorities
=
"${applicationId}.blackbox.SystemCallProvider"
android:exported
=
"false"
android:process
=
"@string/black_box_service_name"
/>
<
receiver
android:name
=
".proxy.ProxyBroadcastReceiver"
android:enabled
=
"true"
android:exported
=
"true"
android:process
=
"@string/black_box_service_name"
>
<
intent-filter
> <
action
android:name
=
"${applicationId}.stub_receiver"
/>
</
intent-filter
></
receiver
>
<
service
android:name
=
".core.system.DaemonService"
android:exported
=
"false"
android:process
=
"@string/black_box_service_name"
/>
<
service
android:name
=
".core.system.DaemonService$DaemonInnerService"
android:exported
=
"false"
android:process
=
"@string/black_box_service_name"
/>
@Override
public
void
startActivity(Intent intent,
int
userId) {
UserSpace userSpace = getOrCreateSpaceLocked(userId);
synchronized
(userSpace.mStack) {
userSpace.mStack.startActivityLocked(userId, intent,
null
,
null
,
null
, -
1
, -
1
,
null
);
}
}
@Override
public
void
startActivity(Intent intent,
int
userId) {
UserSpace userSpace = getOrCreateSpaceLocked(userId);
synchronized
(userSpace.mStack) {
userSpace.mStack.startActivityLocked(userId, intent,
null
,
null
,
null
, -
1
, -
1
,
null
);
}
}
public
int
startActivityLocked(
int
userId,
Intent intent,
String resolvedType,
IBinder resultTo,
String resultWho,
int
requestCode,
int
flags,
Bundle options) {
synchronized
(mTasks) {
synchronizeTasks();
}
ResolveInfo resolveInfo =
BPackageManagerService.get().resolveActivity(intent, GET_ACTIVITIES, resolvedType, userId);
if
(resolveInfo ==
null
|| resolveInfo.activityInfo ==
null
) {
return
0
;
}
Log.d(TAG,
"startActivityLocked : "
+ resolveInfo.activityInfo);
ActivityInfo activityInfo = resolveInfo.activityInfo;
ActivityRecord sourceRecord = findActivityRecordByToken(userId, resultTo);
if
(sourceRecord ==
null
) {
resultTo =
null
;
}
TaskRecord sourceTask =
null
;
if
(sourceRecord !=
null
) {
sourceTask = sourceRecord.task;
}
String taskAffinity = ComponentUtils.getTaskAffinity(activityInfo);
int
launchModeFlags =
0
;
boolean
singleTop =
containsFlag(intent, Intent.FLAG_ACTIVITY_SINGLE_TOP)
|| activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
boolean
newTask = containsFlag(intent, Intent.FLAG_ACTIVITY_NEW_TASK);
boolean
clearTop = containsFlag(intent, Intent.FLAG_ACTIVITY_CLEAR_TOP);
boolean
clearTask = containsFlag(intent, Intent.FLAG_ACTIVITY_CLEAR_TASK);
TaskRecord taskRecord =
null
;
switch
(activityInfo.launchMode) {
case
ActivityInfo.LAUNCH_SINGLE_TOP:
case
ActivityInfo.LAUNCH_MULTIPLE:
case
ActivityInfo.LAUNCH_SINGLE_TASK:
taskRecord = findTaskRecordByTaskAffinityLocked(userId, taskAffinity);
if
(taskRecord ==
null
&& !newTask) {
taskRecord = sourceTask;
}
break
;
case
ActivityInfo.LAUNCH_SINGLE_INSTANCE:
taskRecord = findTaskRecordByTaskAffinityLocked(userId, taskAffinity);
break
;
}
if
(taskRecord ==
null
|| taskRecord.needNewTask()) {
return
startActivityInNewTaskLocked(userId, intent, activityInfo, resultTo, launchModeFlags);
}
mAms.moveTaskToFront(taskRecord.id,
0
);
boolean
notStartToFront =
false
;
if
(clearTop || singleTop || clearTask) {
notStartToFront =
true
;
}
boolean
startTaskToFront =
!notStartToFront
&& ComponentUtils.intentFilterEquals(taskRecord.rootIntent, intent)
&& taskRecord.rootIntent.getFlags() == intent.getFlags();
if
(startTaskToFront)
return
0
;
ActivityRecord topActivityRecord = taskRecord.getTopActivityRecord();
ActivityRecord targetActivityRecord =
findActivityRecordByComponentName(userId, ComponentUtils.toComponentName(activityInfo));
ActivityRecord newIntentRecord =
null
;
boolean
ignore =
false
;
if
(clearTop) {
if
(targetActivityRecord !=
null
) {
synchronized
(targetActivityRecord.task.activities) {
for
(
int
i = targetActivityRecord.task.activities.size() -
1
; i >=
0
; i--) {
ActivityRecord next = targetActivityRecord.task.activities.get(i);
if
(next != targetActivityRecord) {
next.finished =
true
;
Log.d(TAG,
"makerFinish: "
+ next.component.toString());
}
else
{
if
(singleTop) {
newIntentRecord = targetActivityRecord;
}
else
{
targetActivityRecord.finished =
true
;
}
break
;
}
}
}
}
}
if
(singleTop && !clearTop) {
if
(ComponentUtils.intentFilterEquals(topActivityRecord.intent, intent)) {
newIntentRecord = topActivityRecord;
}
else
{
synchronized
(mLaunchingActivities) {
for
(ActivityRecord launchingActivity : mLaunchingActivities) {
if
(!launchingActivity.finished
&& launchingActivity.component.equals(intent.getComponent())) {
ignore =
true
;
}
}
}
}
}
if
(activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK && !clearTop) {
if
(ComponentUtils.intentFilterEquals(topActivityRecord.intent, intent)) {
newIntentRecord = topActivityRecord;
}
else
{
ActivityRecord record =
findActivityRecordByComponentName(userId, ComponentUtils.toComponentName(activityInfo));
if
(record !=
null
) {
newIntentRecord = record;
synchronized
(taskRecord.activities) {
for
(
int
i = taskRecord.activities.size() -
1
; i >=
0
; i--) {
ActivityRecord next = taskRecord.activities.get(i);
if
(next != record) {
next.finished =
true
;
}
else
{
break
;
}
}
}
}
}
}
if
(activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
newIntentRecord = topActivityRecord;
}
if
(clearTask && newTask) {
for
(ActivityRecord activity : taskRecord.activities) {
activity.finished =
true
;
}
}
finishAllActivity(userId);
if
(newIntentRecord !=
null
) {
deliverNewIntentLocked(newIntentRecord, intent);
return
0
;
}
else
if
(ignore) {
return
0
;
}
if
(resultTo ==
null
) {
ActivityRecord top = taskRecord.getTopActivityRecord();
if
(top !=
null
) {
resultTo = top.token;
}
}
else
if
(sourceTask !=
null
) {
ActivityRecord top = sourceTask.getTopActivityRecord();
if
(top !=
null
) {
resultTo = top.token;
}
}
return
startActivityInSourceTask(
intent,
resolvedType,
resultTo,
resultWho,
requestCode,
flags,
options,
userId,
topActivityRecord,
activityInfo,
launchModeFlags);
}
public
int
startActivityLocked(
int
userId,
Intent intent,
String resolvedType,
IBinder resultTo,
String resultWho,
int
requestCode,
int
flags,
Bundle options) {
synchronized
(mTasks) {
synchronizeTasks();
}
ResolveInfo resolveInfo =
BPackageManagerService.get().resolveActivity(intent, GET_ACTIVITIES, resolvedType, userId);
if
(resolveInfo ==
null
|| resolveInfo.activityInfo ==
null
) {
return
0
;
}
Log.d(TAG,
"startActivityLocked : "
+ resolveInfo.activityInfo);
ActivityInfo activityInfo = resolveInfo.activityInfo;
ActivityRecord sourceRecord = findActivityRecordByToken(userId, resultTo);
if
(sourceRecord ==
null
) {
resultTo =
null
;
}
TaskRecord sourceTask =
null
;
if
(sourceRecord !=
null
) {
sourceTask = sourceRecord.task;
}
String taskAffinity = ComponentUtils.getTaskAffinity(activityInfo);
int
launchModeFlags =
0
;
boolean
singleTop =
containsFlag(intent, Intent.FLAG_ACTIVITY_SINGLE_TOP)
|| activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
boolean
newTask = containsFlag(intent, Intent.FLAG_ACTIVITY_NEW_TASK);
boolean
clearTop = containsFlag(intent, Intent.FLAG_ACTIVITY_CLEAR_TOP);
boolean
clearTask = containsFlag(intent, Intent.FLAG_ACTIVITY_CLEAR_TASK);
TaskRecord taskRecord =
null
;
switch
(activityInfo.launchMode) {
case
ActivityInfo.LAUNCH_SINGLE_TOP:
case
ActivityInfo.LAUNCH_MULTIPLE:
case
ActivityInfo.LAUNCH_SINGLE_TASK:
taskRecord = findTaskRecordByTaskAffinityLocked(userId, taskAffinity);
if
(taskRecord ==
null
&& !newTask) {
taskRecord = sourceTask;
}
break
;
case
ActivityInfo.LAUNCH_SINGLE_INSTANCE:
taskRecord = findTaskRecordByTaskAffinityLocked(userId, taskAffinity);
break
;
}
if
(taskRecord ==
null
|| taskRecord.needNewTask()) {
return
startActivityInNewTaskLocked(userId, intent, activityInfo, resultTo, launchModeFlags);
}
mAms.moveTaskToFront(taskRecord.id,
0
);
boolean
notStartToFront =
false
;
if
(clearTop || singleTop || clearTask) {
notStartToFront =
true
;
}
boolean
startTaskToFront =
!notStartToFront
&& ComponentUtils.intentFilterEquals(taskRecord.rootIntent, intent)
&& taskRecord.rootIntent.getFlags() == intent.getFlags();
if
(startTaskToFront)
return
0
;
ActivityRecord topActivityRecord = taskRecord.getTopActivityRecord();
ActivityRecord targetActivityRecord =
findActivityRecordByComponentName(userId, ComponentUtils.toComponentName(activityInfo));
ActivityRecord newIntentRecord =
null
;
boolean
ignore =
false
;
if
(clearTop) {
if
(targetActivityRecord !=
null
) {
synchronized
(targetActivityRecord.task.activities) {
for
(
int
i = targetActivityRecord.task.activities.size() -
1
; i >=
0
; i--) {
ActivityRecord next = targetActivityRecord.task.activities.get(i);
if
(next != targetActivityRecord) {
next.finished =
true
;
Log.d(TAG,
"makerFinish: "
+ next.component.toString());
}
else
{
if
(singleTop) {
newIntentRecord = targetActivityRecord;
}
else
{
targetActivityRecord.finished =
true
;
}
break
;
}
}
}
}
}
if
(singleTop && !clearTop) {
if
(ComponentUtils.intentFilterEquals(topActivityRecord.intent, intent)) {
newIntentRecord = topActivityRecord;
}
else
{
synchronized
(mLaunchingActivities) {
for
(ActivityRecord launchingActivity : mLaunchingActivities) {
if
(!launchingActivity.finished
&& launchingActivity.component.equals(intent.getComponent())) {
ignore =
true
;
}
}
}
}
}
if
(activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK && !clearTop) {
if
(ComponentUtils.intentFilterEquals(topActivityRecord.intent, intent)) {
newIntentRecord = topActivityRecord;
}
else
{
ActivityRecord record =
findActivityRecordByComponentName(userId, ComponentUtils.toComponentName(activityInfo));
if
(record !=
null
) {
newIntentRecord = record;
synchronized
(taskRecord.activities) {
for
(
int
i = taskRecord.activities.size() -
1
; i >=
0
; i--) {
ActivityRecord next = taskRecord.activities.get(i);
if
(next != record) {
next.finished =
true
;
}
else
{
break
;
}
}
}
}
}
}
if
(activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
newIntentRecord = topActivityRecord;
}
if
(clearTask && newTask) {
for
(ActivityRecord activity : taskRecord.activities) {
activity.finished =
true
;
}
}
finishAllActivity(userId);
if
(newIntentRecord !=
null
) {
deliverNewIntentLocked(newIntentRecord, intent);
return
0
;
}
else
if
(ignore) {
return
0
;
}
if
(resultTo ==
null
) {
ActivityRecord top = taskRecord.getTopActivityRecord();
if
(top !=
null
) {
resultTo = top.token;
}
}
else
if
(sourceTask !=
null
) {
ActivityRecord top = sourceTask.getTopActivityRecord();
if
(top !=
null
) {
resultTo = top.token;
}
}
return
startActivityInSourceTask(
intent,
resolvedType,
resultTo,
resultWho,
requestCode,
flags,
options,
userId,
topActivityRecord,
activityInfo,
launchModeFlags);
}
private
int
startActivityInNewTaskLocked(
int
userId, Intent intent, ActivityInfo activityInfo, IBinder resultTo,
int
launchMode) {
ActivityRecord record = newActivityRecord(intent, activityInfo, resultTo, userId);
Intent shadow = startActivityProcess(userId, intent, activityInfo, record);
shadow.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
shadow.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
shadow.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shadow.addFlags(launchMode);
SandBoxCore.getContext().startActivity(shadow);
return
0
;
}
private
int
startActivityInNewTaskLocked(
int
userId, Intent intent, ActivityInfo activityInfo, IBinder resultTo,
int
launchMode) {
ActivityRecord record = newActivityRecord(intent, activityInfo, resultTo, userId);
Intent shadow = startActivityProcess(userId, intent, activityInfo, record);
shadow.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
shadow.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
shadow.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shadow.addFlags(launchMode);
SandBoxCore.getContext().startActivity(shadow);
return
0
;
}
private
Intent startActivityProcess(
int
userId, Intent intent, ActivityInfo info, ActivityRecord record) {
ProxyActivityRecord stubRecord =
new
ProxyActivityRecord(userId, info, intent, record);
ProcessRecord targetApp =
BProcessManagerService.get()
.startProcessLocked(
info.packageName, info.processName, userId, -
1
, Binder.getCallingPid());
if
(targetApp ==
null
) {
throw
new
RuntimeException(
"Unable to create process, name:"
+ info.name);
}
return
getStartStubActivityIntentInner(intent, targetApp.bpid, userId, stubRecord, info);
}
private
Intent startActivityProcess(
int
userId, Intent intent, ActivityInfo info, ActivityRecord record) {
ProxyActivityRecord stubRecord =
new
ProxyActivityRecord(userId, info, intent, record);
ProcessRecord targetApp =
BProcessManagerService.get()
.startProcessLocked(
info.packageName, info.processName, userId, -
1
, Binder.getCallingPid());
if
(targetApp ==
null
) {
throw
new
RuntimeException(
"Unable to create process, name:"
+ info.name);
}
return
getStartStubActivityIntentInner(intent, targetApp.bpid, userId, stubRecord, info);
}
public
ProcessRecord startProcessLocked(
String packageName, String processName,
int
userId,
int
bpid,
int
callingPid) {
ApplicationInfo info = BPackageManagerService.get().getApplicationInfo(packageName,
0
, userId);
if
(info ==
null
)
return
null
;
ProcessRecord app;
int
buid = BUserHandle.getUid(userId, BPackageManagerService.get().getAppId(packageName));
synchronized
(mProcessLock) {
Map<String, ProcessRecord> bProcess = mProcessMap.get(buid);
if
(bProcess ==
null
) {
bProcess =
new
HashMap<>();
}
if
(bpid == -
1
) {
app = bProcess.get(processName);
if
(app !=
null
) {
if
(app.initLock !=
null
) {
app.initLock.block();
}
if
(app.bActivityThread !=
null
) {
return
app;
}
}
bpid = getUsingBPidL();
Slog.d(TAG,
"init bUid = "
+ buid +
", bPid = "
+ bpid);
}
if
(bpid == -
1
) {
throw
new
RuntimeException(
"No processes available"
);
}
app =
new
ProcessRecord(info, processName);
app.uid = Process.myUid();
app.bpid = bpid;
app.buid = BPackageManagerService.get().getAppId(packageName);
app.callingBUid = getBUidByPidOrPackageName(callingPid, packageName);
app.userId = userId;
bProcess.put(processName, app);
mPidsSelfLocked.add(app);
synchronized
(mProcessMap) {
mProcessMap.put(buid, bProcess);
}
if
(!initAppProcessL(app)) {
bProcess.remove(processName);
mPidsSelfLocked.remove(app);
app =
null
;
}
else
{
app.pid = getPid(SandBoxCore.getContext(), ProxyManifest.getProcessName(app.bpid));
}
}
return
app;
}
public
ProcessRecord startProcessLocked(
String packageName, String processName,
int
userId,
int
bpid,
int
callingPid) {
ApplicationInfo info = BPackageManagerService.get().getApplicationInfo(packageName,
0
, userId);
if
(info ==
null
)
return
null
;
ProcessRecord app;
int
buid = BUserHandle.getUid(userId, BPackageManagerService.get().getAppId(packageName));
synchronized
(mProcessLock) {
Map<String, ProcessRecord> bProcess = mProcessMap.get(buid);
if
(bProcess ==
null
) {
bProcess =
new
HashMap<>();
}
if
(bpid == -
1
) {
app = bProcess.get(processName);
if
(app !=
null
) {
if
(app.initLock !=
null
) {
app.initLock.block();
}
if
(app.bActivityThread !=
null
) {
return
app;
}
}
bpid = getUsingBPidL();
Slog.d(TAG,
"init bUid = "
+ buid +
", bPid = "
+ bpid);
}
if
(bpid == -
1
) {
throw
new
RuntimeException(
"No processes available"
);
}
app =
new
ProcessRecord(info, processName);
app.uid = Process.myUid();
app.bpid = bpid;
app.buid = BPackageManagerService.get().getAppId(packageName);
app.callingBUid = getBUidByPidOrPackageName(callingPid, packageName);
app.userId = userId;
bProcess.put(processName, app);
mPidsSelfLocked.add(app);
synchronized
(mProcessMap) {
mProcessMap.put(buid, bProcess);
}
if
(!initAppProcessL(app)) {
bProcess.remove(processName);
mPidsSelfLocked.remove(app);
app =
null
;
}
else
{
app.pid = getPid(SandBoxCore.getContext(), ProxyManifest.getProcessName(app.bpid));
}
}
return
app;
}
private
boolean
initAppProcessL(ProcessRecord record) {
Log.d(TAG,
"initProcess: "
+ record.processName);
AppConfig appConfig = record.getClientConfig();
Bundle bundle =
new
Bundle();
bundle.putParcelable(AppConfig.KEY, appConfig);
Bundle init =
ProviderCall.callSafely(
record.getProviderAuthority(),
"_Black_|_init_process_"
,
null
, bundle);
IBinder appThread = BundleCompat.getBinder(init,
"_Black_|_client_"
);
if
(appThread ==
null
|| !appThread.isBinderAlive()) {
return
false
;
}
attachClientL(record, appThread);
createProc(record);
return
true
;
}
private
boolean
initAppProcessL(ProcessRecord record) {
Log.d(TAG,
"initProcess: "
+ record.processName);
AppConfig appConfig = record.getClientConfig();
Bundle bundle =
new
Bundle();
bundle.putParcelable(AppConfig.KEY, appConfig);
Bundle init =
ProviderCall.callSafely(
record.getProviderAuthority(),
"_Black_|_init_process_"
,
null
, bundle);
IBinder appThread = BundleCompat.getBinder(init,
"_Black_|_client_"
);
if
(appThread ==
null
|| !appThread.isBinderAlive()) {
return
false
;
}
attachClientL(record, appThread);
createProc(record);
return
true
;
}
@Nullable
@Override
public
Bundle call(
@NonNull
String method,
@Nullable
String arg,
@Nullable
Bundle extras) {
if
(method.equals(
"_Black_|_init_process_"
)) {
assert
extras !=
null
;
extras.setClassLoader(AppConfig.
class
.getClassLoader());
AppConfig appConfig = extras.getParcelable(AppConfig.KEY);
BActivityThread.currentActivityThread().initProcess(appConfig);
Bundle bundle =
new
Bundle();
BundleCompat.putBinder(bundle,
"_Black_|_client_"
, BActivityThread.currentActivityThread());
return
bundle;
}
return
super
.call(method, arg, extras);
}
@Nullable
@Override
public
Bundle call(
@NonNull
String method,
@Nullable
String arg,
@Nullable
Bundle extras) {
if
(method.equals(
"_Black_|_init_process_"
)) {
assert
extras !=
null
;
extras.setClassLoader(AppConfig.
class
.getClassLoader());
AppConfig appConfig = extras.getParcelable(AppConfig.KEY);
BActivityThread.currentActivityThread().initProcess(appConfig);
Bundle bundle =
new
Bundle();
BundleCompat.putBinder(bundle,
"_Black_|_client_"
, BActivityThread.currentActivityThread());
return
bundle;
}
return
super
.call(method, arg, extras);
}
public
void
initProcess(AppConfig appConfig) {
synchronized
(mConfigLock) {
if
(
this
.mAppConfig !=
null
&& !
this
.mAppConfig.packageName.equals(appConfig.packageName)) {
throw
new
RuntimeException(
"reject init process: "
+ appConfig.processName
+
", this process is : "
+
this
.mAppConfig.processName);
}
this
.mAppConfig = appConfig;
IBinder iBinder = asBinder();
try
{
iBinder.linkToDeath(
new
DeathRecipient() {
@Override
public
void
binderDied() {
synchronized
(mConfigLock) {
try
{
iBinder.linkToDeath(
this
,
0
);
}
catch
(RemoteException ignored) {
}
mAppConfig =
null
;
}
}
},
0
);
}
catch
(RemoteException e) {
e.printStackTrace();
}
}
}
public
void
initProcess(AppConfig appConfig) {
synchronized
(mConfigLock) {
if
(
this
.mAppConfig !=
null
&& !
this
.mAppConfig.packageName.equals(appConfig.packageName)) {
throw
new
RuntimeException(
"reject init process: "
+ appConfig.processName
+
", this process is : "
+
this
.mAppConfig.processName);
}
this
.mAppConfig = appConfig;
IBinder iBinder = asBinder();
try
{
iBinder.linkToDeath(
new
DeathRecipient() {
@Override
public
void
binderDied() {
synchronized
(mConfigLock) {
try
{
iBinder.linkToDeath(
this
,
0
);
}
catch
(RemoteException ignored) {
}
mAppConfig =
null
;
}
}
},
0
);
}
catch
(RemoteException e) {
e.printStackTrace();
}
}
}
private
Intent getStartStubActivityIntentInner(
Intent intent,
int
vpid,
int
userId, ProxyActivityRecord target, ActivityInfo activityInfo) {
Intent shadow =
new
Intent();
TypedArray typedArray =
null
;
try
{
Resources resources =
PackageManagerCompat.getResources(SandBoxCore.getContext(), activityInfo.applicationInfo);
int
id;
if
(activityInfo.theme !=
0
) {
id = activityInfo.theme;
}
else
{
id = activityInfo.applicationInfo.theme;
}
assert
resources !=
null
;
typedArray = resources.newTheme().obtainStyledAttributes(id, BRRstyleable.get().Window());
boolean
windowIsTranslucent =
typedArray.getBoolean(BRRstyleable.get().Window_windowIsTranslucent(),
false
);
if
(windowIsTranslucent) {
shadow.setComponent(
new
ComponentName(
SandBoxCore.getHostPkg(), ProxyManifest.TransparentProxyActivity(vpid)));
}
else
{
shadow.setComponent(
new
ComponentName(SandBoxCore.getHostPkg(), ProxyManifest.getProxyActivity(vpid)));
}
Slog.d(TAG, activityInfo +
", windowIsTranslucent: "
+ windowIsTranslucent);
}
catch
(Throwable e) {
e.printStackTrace();
shadow.setComponent(
new
ComponentName(SandBoxCore.getHostPkg(), ProxyManifest.getProxyActivity(vpid)));
}
finally
{
if
(typedArray !=
null
) {
typedArray.recycle();
}
}
ProxyActivityRecord.saveStub(
shadow, intent, target.mActivityInfo, target.mActivityRecord, target.mUserId);
return
shadow;
}
private
Intent getStartStubActivityIntentInner(
Intent intent,
int
vpid,
int
userId, ProxyActivityRecord target, ActivityInfo activityInfo) {
Intent shadow =
new
Intent();
TypedArray typedArray =
null
;
try
{
Resources resources =
PackageManagerCompat.getResources(SandBoxCore.getContext(), activityInfo.applicationInfo);
int
id;
if
(activityInfo.theme !=
0
) {
id = activityInfo.theme;
}
else
{
id = activityInfo.applicationInfo.theme;
}
assert
resources !=
null
;
typedArray = resources.newTheme().obtainStyledAttributes(id, BRRstyleable.get().Window());
boolean
windowIsTranslucent =
typedArray.getBoolean(BRRstyleable.get().Window_windowIsTranslucent(),
false
);
if
(windowIsTranslucent) {
shadow.setComponent(
new
ComponentName(
SandBoxCore.getHostPkg(), ProxyManifest.TransparentProxyActivity(vpid)));
}
else
{
shadow.setComponent(
new
ComponentName(SandBoxCore.getHostPkg(), ProxyManifest.getProxyActivity(vpid)));
}
Slog.d(TAG, activityInfo +
", windowIsTranslucent: "
+ windowIsTranslucent);
}
catch
(Throwable e) {
e.printStackTrace();
shadow.setComponent(
new
ComponentName(SandBoxCore.getHostPkg(), ProxyManifest.getProxyActivity(vpid)));
}
finally
{
if
(typedArray !=
null
) {
typedArray.recycle();
}
}
ProxyActivityRecord.saveStub(
shadow, intent, target.mActivityInfo, target.mActivityRecord, target.mUserId);
return
shadow;
}
<
activity
android:name
=
".proxy.ProxyActivity$P0"
android:configChanges
=
"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
android:exported
=
"true"
android:process
=
":p0"
android:supportsPictureInPicture
=
"true"
android:taskAffinity
=
"com.hello.sandbox.task_affinity"
android:theme
=
"@style/BTheme"
/>
<
activity
android:name
=
".proxy.ProxyActivity$P1"
android:configChanges
=
"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
android:exported
=
"true"
android:process
=
":p1"
android:supportsPictureInPicture
=
"true"
android:taskAffinity
=
"com.hello.sandbox.task_affinity"
android:theme
=
"@style/BTheme"
/>
<
activity
android:name
=
".proxy.ProxyActivity$P0"
android:configChanges
=
"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
android:exported
=
"true"
android:process
=
":p0"
android:supportsPictureInPicture
=
"true"
android:taskAffinity
=
"com.hello.sandbox.task_affinity"
android:theme
=
"@style/BTheme"
/>
<
activity
android:name
=
".proxy.ProxyActivity$P1"
android:configChanges
=
"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
android:exported
=
"true"
android:process
=
":p1"
android:supportsPictureInPicture
=
"true"
android:taskAffinity
=
"com.hello.sandbox.task_affinity"
android:theme
=
"@style/BTheme"
/>
SandBoxCore.getContext().startActivity(shadow);
SandBoxCore.getContext().startActivity(shadow);
addInjector(
new
HCallbackProxy());
addInjector(
new
HCallbackProxy());
private
Handler getH() {
Object currentActivityThread = SandBoxCore.mainThread();
return
BRActivityThread.get(currentActivityThread).mH();
}
private
Handler.Callback getHCallback() {
return
BRHandler.get(getH()).mCallback();
}
@Override
public
void
injectHook() {
mOtherCallback = getHCallback();
if
(mOtherCallback !=
null
&& (mOtherCallback ==
this
|| mOtherCallback.getClass().getName().equals(
this
.getClass().getName()))) {
mOtherCallback =
null
;
}
BRHandler.get(getH())._set_mCallback(
this
);
}
private
Handler getH() {
Object currentActivityThread = SandBoxCore.mainThread();
return
BRActivityThread.get(currentActivityThread).mH();
}
private
Handler.Callback getHCallback() {
return
BRHandler.get(getH()).mCallback();
}
@Override
public
void
injectHook() {
mOtherCallback = getHCallback();
if
(mOtherCallback !=
null
&& (mOtherCallback ==
this
|| mOtherCallback.getClass().getName().equals(
this
.getClass().getName()))) {
mOtherCallback =
null
;
}
BRHandler.get(getH())._set_mCallback(
this
);
}
public
synchronized
void
handleBindApplication(String packageName, String processName) {
if
(isInit())
return
;
try
{
CrashHandler.create();
}
catch
(Throwable ignored) {
}
PackageInfo packageInfo =
SandBoxCore.getBPackageManager()
.getPackageInfo(packageName, PackageManager.GET_PROVIDERS, BActivityThread.getUserId());
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
if
(packageInfo.providers ==
null
) {
packageInfo.providers =
new
ProviderInfo[] {};
}
mProviders.addAll(Arrays.asList(packageInfo.providers));
Slog.d(TAG,
"handleBindApplication mProviders="
+ mProviders);
Object boundApplication = BRActivityThread.get(SandBoxCore.mainThread()).mBoundApplication();
Context packageContext = createPackageContext(applicationInfo);
Object loadedApk = BRContextImpl.get(packageContext).mPackageInfo();
BRLoadedApk.get(loadedApk)._set_mSecurityViolation(
false
);
BRLoadedApk.get(loadedApk)._set_mApplicationInfo(applicationInfo);
int
targetSdkVersion = applicationInfo.targetSdkVersion;
if
(targetSdkVersion < Build.VERSION_CODES.GINGERBREAD) {
StrictMode.ThreadPolicy newPolicy =
new
StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy()).permitNetwork().build();
StrictMode.setThreadPolicy(newPolicy);
}
if
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if
(targetSdkVersion < Build.VERSION_CODES.N) {
StrictModeCompat.disableDeathOnFileUriExposure();
}
}
if
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
WebView.setDataDirectorySuffix(getUserId() +
":"
+ packageName +
":"
+ processName);
}
VirtualRuntime.setupRuntime(processName, applicationInfo);
BRVMRuntime.get(BRVMRuntime.get().getRuntime())
.setTargetSdkVersion(applicationInfo.targetSdkVersion);
if
(BuildCompat.isS()) {
BRCompatibility.get().setTargetSdkVersion(applicationInfo.targetSdkVersion);
}
NativeCore.init(Build.VERSION.SDK_INT);
assert
packageContext !=
null
;
IOCore.get().enableRedirect(packageContext);
AppBindData bindData =
new
AppBindData();
bindData.appInfo = applicationInfo;
bindData.processName = processName;
bindData.info = loadedApk;
bindData.providers = mProviders;
ActivityThreadAppBindDataContext activityThreadAppBindData =
BRActivityThreadAppBindData.get(boundApplication);
activityThreadAppBindData._set_instrumentationName(
new
ComponentName(bindData.appInfo.packageName, Instrumentation.
class
.getName()));
activityThreadAppBindData._set_appInfo(bindData.appInfo);
activityThreadAppBindData._set_info(bindData.info);
activityThreadAppBindData._set_processName(bindData.processName);
activityThreadAppBindData._set_providers(bindData.providers);
mBoundApplication = bindData;
if
(BRNetworkSecurityConfigProvider.getRealClass() !=
null
) {
Security.removeProvider(
"AndroidNSSP"
);
BRNetworkSecurityConfigProvider.get().install(packageContext);
}
Application application;
try
{
onBeforeCreateApplication(packageName, processName, packageContext);
if
(BuildCompat.isT()){
BEnvironment.getAllDex(packageName).forEach(
new
Consumer<String>() {
@Override
public
void
accept(String s) {
new
File(s).setReadOnly();
}
});
}
application = BRLoadedApk.get(loadedApk).makeApplication(
false
,
null
);
mInitialApplication = application;
BRActivityThread.get(SandBoxCore.mainThread())._set_mInitialApplication(mInitialApplication);
ContextCompat.fix(
(Context) BRActivityThread.get(SandBoxCore.mainThread()).getSystemContext());
ContextCompat.fix(mInitialApplication);
installProviders(mInitialApplication, bindData.processName, bindData.providers);
try
{
fixAiLiaoPhoto(mInitialApplication);
}
catch
(Throwable e) {
e.printStackTrace();
}
onBeforeApplicationOnCreate(packageName, processName, application);
AppInstrumentation.get().callApplicationOnCreate(application);
onAfterApplicationOnCreate(packageName, processName, application);
NativeCore.init_seccomp();
HookManager.get().checkEnv(HCallbackProxy.
class
);
if
(BuildConfig.DEBUG) {
Log.d(
TAG,
"Instrumentation class name "
+ AppInstrumentation.get().getCurrInstrumentation().getClass().getName());
}
}
catch
(Exception e) {
e.printStackTrace();
throw
new
RuntimeException(
"Unable to makeApplication"
, e);
}
}
public
synchronized
void
handleBindApplication(String packageName, String processName) {
if
(isInit())
return
;
try
{
CrashHandler.create();
}
catch
(Throwable ignored) {
}
PackageInfo packageInfo =
SandBoxCore.getBPackageManager()
.getPackageInfo(packageName, PackageManager.GET_PROVIDERS, BActivityThread.getUserId());
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
if
(packageInfo.providers ==
null
) {
packageInfo.providers =
new
ProviderInfo[] {};
}
mProviders.addAll(Arrays.asList(packageInfo.providers));
Slog.d(TAG,
"handleBindApplication mProviders="
+ mProviders);
Object boundApplication = BRActivityThread.get(SandBoxCore.mainThread()).mBoundApplication();
Context packageContext = createPackageContext(applicationInfo);
Object loadedApk = BRContextImpl.get(packageContext).mPackageInfo();
BRLoadedApk.get(loadedApk)._set_mSecurityViolation(
false
);
BRLoadedApk.get(loadedApk)._set_mApplicationInfo(applicationInfo);
int
targetSdkVersion = applicationInfo.targetSdkVersion;
if
(targetSdkVersion < Build.VERSION_CODES.GINGERBREAD) {
StrictMode.ThreadPolicy newPolicy =
new
StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy()).permitNetwork().build();
StrictMode.setThreadPolicy(newPolicy);
}
if
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if
(targetSdkVersion < Build.VERSION_CODES.N) {
StrictModeCompat.disableDeathOnFileUriExposure();
}
}
if
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
WebView.setDataDirectorySuffix(getUserId() +
":"
+ packageName +
":"
+ processName);
}
VirtualRuntime.setupRuntime(processName, applicationInfo);
BRVMRuntime.get(BRVMRuntime.get().getRuntime())
.setTargetSdkVersion(applicationInfo.targetSdkVersion);
if
(BuildCompat.isS()) {
BRCompatibility.get().setTargetSdkVersion(applicationInfo.targetSdkVersion);
}
NativeCore.init(Build.VERSION.SDK_INT);
assert
packageContext !=
null
;
IOCore.get().enableRedirect(packageContext);
AppBindData bindData =
new
AppBindData();
bindData.appInfo = applicationInfo;
bindData.processName = processName;
bindData.info = loadedApk;
bindData.providers = mProviders;
ActivityThreadAppBindDataContext activityThreadAppBindData =
BRActivityThreadAppBindData.get(boundApplication);
activityThreadAppBindData._set_instrumentationName(
new
ComponentName(bindData.appInfo.packageName, Instrumentation.
class
.getName()));
activityThreadAppBindData._set_appInfo(bindData.appInfo);
activityThreadAppBindData._set_info(bindData.info);
activityThreadAppBindData._set_processName(bindData.processName);
activityThreadAppBindData._set_providers(bindData.providers);
mBoundApplication = bindData;
if
(BRNetworkSecurityConfigProvider.getRealClass() !=
null
) {
Security.removeProvider(
"AndroidNSSP"
);
BRNetworkSecurityConfigProvider.get().install(packageContext);
}
Application application;
try
{
onBeforeCreateApplication(packageName, processName, packageContext);
if
(BuildCompat.isT()){
BEnvironment.getAllDex(packageName).forEach(
new
Consumer<String>() {
@Override
public
void
accept(String s) {
new
File(s).setReadOnly();
}
});
}
application = BRLoadedApk.get(loadedApk).makeApplication(
false
,
null
);
mInitialApplication = application;
BRActivityThread.get(SandBoxCore.mainThread())._set_mInitialApplication(mInitialApplication);
ContextCompat.fix(
(Context) BRActivityThread.get(SandBoxCore.mainThread()).getSystemContext());
ContextCompat.fix(mInitialApplication);
installProviders(mInitialApplication, bindData.processName, bindData.providers);
try
{
fixAiLiaoPhoto(mInitialApplication);
}
catch
(Throwable e) {
e.printStackTrace();
}
onBeforeApplicationOnCreate(packageName, processName, application);
AppInstrumentation.get().callApplicationOnCreate(application);
onAfterApplicationOnCreate(packageName, processName, application);
NativeCore.init_seccomp();
HookManager.get().checkEnv(HCallbackProxy.
class
);
if
(BuildConfig.DEBUG) {
Log.d(
TAG,
"Instrumentation class name "
+ AppInstrumentation.get().getCurrInstrumentation().getClass().getName());
}
}
catch
(Exception e) {
e.printStackTrace();
throw
new
RuntimeException(
"Unable to makeApplication"
, e);
}
}
public
synchronized
void
handleBindApplication(String packageName, String processName) {
if
(isInit())
return
;
try
{
CrashHandler.create();
}
catch
(Throwable ignored) {
}
PackageInfo packageInfo =
SandBoxCore.getBPackageManager()
.getPackageInfo(packageName, PackageManager.GET_PROVIDERS, BActivityThread.getUserId());
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
if
(packageInfo.providers ==
null
) {
packageInfo.providers =
new
ProviderInfo[] {};
}
mProviders.addAll(Arrays.asList(packageInfo.providers));
Slog.d(TAG,
"handleBindApplication mProviders="
+ mProviders);
Object boundApplication = BRActivityThread.get(SandBoxCore.mainThread()).mBoundApplication();
Context packageContext = createPackageContext(applicationInfo);
Object loadedApk = BRContextImpl.get(packageContext).mPackageInfo();
BRLoadedApk.get(loadedApk)._set_mSecurityViolation(
false
);
BRLoadedApk.get(loadedApk)._set_mApplicationInfo(applicationInfo);
int
targetSdkVersion = applicationInfo.targetSdkVersion;
if
(targetSdkVersion < Build.VERSION_CODES.GINGERBREAD) {
StrictMode.ThreadPolicy newPolicy =
new
StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy()).permitNetwork().build();
StrictMode.setThreadPolicy(newPolicy);
}
if
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if
(targetSdkVersion < Build.VERSION_CODES.N) {
StrictModeCompat.disableDeathOnFileUriExposure();
}
}
if
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
WebView.setDataDirectorySuffix(getUserId() +
":"
+ packageName +
":"
+ processName);
}
VirtualRuntime.setupRuntime(processName, applicationInfo);
BRVMRuntime.get(BRVMRuntime.get().getRuntime())
.setTargetSdkVersion(applicationInfo.targetSdkVersion);
if
(BuildCompat.isS()) {
BRCompatibility.get().setTargetSdkVersion(applicationInfo.targetSdkVersion);
}
NativeCore.init(Build.VERSION.SDK_INT);
assert
packageContext !=
null
;
IOCore.get().enableRedirect(packageContext);
AppBindData bindData =
new
AppBindData();
bindData.appInfo = applicationInfo;
bindData.processName = processName;
bindData.info = loadedApk;
bindData.providers = mProviders;
ActivityThreadAppBindDataContext activityThreadAppBindData =
BRActivityThreadAppBindData.get(boundApplication);
activityThreadAppBindData._set_instrumentationName(
new
ComponentName(bindData.appInfo.packageName, Instrumentation.
class
.getName()));
activityThreadAppBindData._set_appInfo(bindData.appInfo);
activityThreadAppBindData._set_info(bindData.info);
activityThreadAppBindData._set_processName(bindData.processName);
activityThreadAppBindData._set_providers(bindData.providers);
mBoundApplication = bindData;
if
(BRNetworkSecurityConfigProvider.getRealClass() !=
null
) {
Security.removeProvider(
"AndroidNSSP"
);
BRNetworkSecurityConfigProvider.get().install(packageContext);
}
Application application;
try
{
onBeforeCreateApplication(packageName, processName, packageContext);
if
(BuildCompat.isT()){
BEnvironment.getAllDex(packageName).forEach(
new
Consumer<String>() {
@Override
public
void
accept(String s) {
new
File(s).setReadOnly();
}
});
}
application = BRLoadedApk.get(loadedApk).makeApplication(
false
,
null
);
mInitialApplication = application;
BRActivityThread.get(SandBoxCore.mainThread())._set_mInitialApplication(mInitialApplication);
ContextCompat.fix(
(Context) BRActivityThread.get(SandBoxCore.mainThread()).getSystemContext());
ContextCompat.fix(mInitialApplication);
public
synchronized
void
handleBindApplication(String packageName, String processName) {
if
(isInit())
return
;
try
{
CrashHandler.create();
}
catch
(Throwable ignored) {
}
PackageInfo packageInfo =
SandBoxCore.getBPackageManager()
.getPackageInfo(packageName, PackageManager.GET_PROVIDERS, BActivityThread.getUserId());
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
if
(packageInfo.providers ==
null
) {
packageInfo.providers =
new
ProviderInfo[] {};
}
mProviders.addAll(Arrays.asList(packageInfo.providers));
Slog.d(TAG,
"handleBindApplication mProviders="
+ mProviders);
Object boundApplication = BRActivityThread.get(SandBoxCore.mainThread()).mBoundApplication();
Context packageContext = createPackageContext(applicationInfo);
Object loadedApk = BRContextImpl.get(packageContext).mPackageInfo();
BRLoadedApk.get(loadedApk)._set_mSecurityViolation(
false
);
BRLoadedApk.get(loadedApk)._set_mApplicationInfo(applicationInfo);
int
targetSdkVersion = applicationInfo.targetSdkVersion;
if
(targetSdkVersion < Build.VERSION_CODES.GINGERBREAD) {
StrictMode.ThreadPolicy newPolicy =
new
StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy()).permitNetwork().build();
StrictMode.setThreadPolicy(newPolicy);
}
if
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if
(targetSdkVersion < Build.VERSION_CODES.N) {
StrictModeCompat.disableDeathOnFileUriExposure();
}
}
if
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
WebView.setDataDirectorySuffix(getUserId() +
":"
+ packageName +
":"
+ processName);
}
VirtualRuntime.setupRuntime(processName, applicationInfo);
BRVMRuntime.get(BRVMRuntime.get().getRuntime())
.setTargetSdkVersion(applicationInfo.targetSdkVersion);
if
(BuildCompat.isS()) {
BRCompatibility.get().setTargetSdkVersion(applicationInfo.targetSdkVersion);
}
NativeCore.init(Build.VERSION.SDK_INT);
assert
packageContext !=
null
;
IOCore.get().enableRedirect(packageContext);
AppBindData bindData =
new
AppBindData();
bindData.appInfo = applicationInfo;
bindData.processName = processName;
bindData.info = loadedApk;
bindData.providers = mProviders;
ActivityThreadAppBindDataContext activityThreadAppBindData =
BRActivityThreadAppBindData.get(boundApplication);
activityThreadAppBindData._set_instrumentationName(
new
ComponentName(bindData.appInfo.packageName, Instrumentation.
class
.getName()));
activityThreadAppBindData._set_appInfo(bindData.appInfo);
activityThreadAppBindData._set_info(bindData.info);
activityThreadAppBindData._set_processName(bindData.processName);
activityThreadAppBindData._set_providers(bindData.providers);
mBoundApplication = bindData;
if
(BRNetworkSecurityConfigProvider.getRealClass() !=
null
) {
Security.removeProvider(
"AndroidNSSP"
);
BRNetworkSecurityConfigProvider.get().install(packageContext);
}
Application application;
try
{
onBeforeCreateApplication(packageName, processName, packageContext);
if
(BuildCompat.isT()){
BEnvironment.getAllDex(packageName).forEach(
new
Consumer<String>() {
@Override
public
void
accept(String s) {
new
File(s).setReadOnly();
}
});
}
application = BRLoadedApk.get(loadedApk).makeApplication(
false
,
null
);
mInitialApplication = application;
BRActivityThread.get(SandBoxCore.mainThread())._set_mInitialApplication(mInitialApplication);
ContextCompat.fix(
(Context) BRActivityThread.get(SandBoxCore.mainThread()).getSystemContext());
ContextCompat.fix(mInitialApplication);
int
taskId =
BRIActivityManager.get(BRActivityManagerNative.get().getDefault())
.getTaskForActivity(token,
false
);
SandBoxCore.getBActivityManager()
.onActivityCreated(taskId, token, stubRecord.mActivityRecord);
int
taskId =
BRIActivityManager.get(BRActivityManagerNative.get().getDefault())
.getTaskForActivity(token,
false
);
SandBoxCore.getBActivityManager()
.onActivityCreated(taskId, token, stubRecord.mActivityRecord);
public
void
onActivityCreated(
ProcessRecord processRecord,
int
taskId, IBinder token, ActivityRecord record) {
synchronized
(mLaunchingActivities) {
mLaunchingActivities.remove(record);
mHandler.removeMessages(LAUNCH_TIME_OUT, record);
}
synchronized
(mTasks) {
synchronizeTasks();
TaskRecord taskRecord = mTasks.get(taskId);
if
(taskRecord ==
null
) {
taskRecord =
new
TaskRecord(taskId, record.userId, ComponentUtils.getTaskAffinity(record.info));
taskRecord.rootIntent = record.intent;
mTasks.put(taskId, taskRecord);
}
record.token = token;
record.processRecord = processRecord;
record.task = taskRecord;
taskRecord.addTopActivity(record);
Log.d(TAG,
"onActivityCreated : "
+ record.component.toString());
}
}
public
void
onActivityCreated(
ProcessRecord processRecord,
int
taskId, IBinder token, ActivityRecord record) {
synchronized
(mLaunchingActivities) {
mLaunchingActivities.remove(record);
mHandler.removeMessages(LAUNCH_TIME_OUT, record);
}
synchronized
(mTasks) {
synchronizeTasks();
TaskRecord taskRecord = mTasks.get(taskId);
if
(taskRecord ==
null
) {
taskRecord =
new
TaskRecord(taskId, record.userId, ComponentUtils.getTaskAffinity(record.info));
taskRecord.rootIntent = record.intent;
mTasks.put(taskId, taskRecord);
}
record.token = token;
record.processRecord = processRecord;
record.task = taskRecord;
taskRecord.addTopActivity(record);
Log.d(TAG,
"onActivityCreated : "
+ record.component.toString());
}
}
LaunchActivityItemContext launchActivityItemContext = BRLaunchActivityItem.get(r);
launchActivityItemContext._set_mIntent(stubRecord.mTarget);
launchActivityItemContext._set_mInfo(activityInfo);
LaunchActivityItemContext launchActivityItemContext = BRLaunchActivityItem.get(r);
launchActivityItemContext._set_mIntent(stubRecord.mTarget);
launchActivityItemContext._set_mInfo(activityInfo);
@Override
public
boolean
handleMessage(
@NonNull
Message msg) {
if
(!mBeing.getAndSet(
true
)) {
try
{
if
(BuildCompat.isPie()) {
if
(msg.what == BRActivityThreadH.get().EXECUTE_TRANSACTION()) {
final
Boolean a = handleLaunchActivity(msg);
if
(a !=
null
&& a) {
getH().sendMessageAtFrontOfQueue(Message.obtain(msg));
return
true
;
}
}
}
else
{
if
(msg.what == BRActivityThreadH.get().LAUNCH_ACTIVITY()) {
final
Boolean a = handleLaunchActivity(msg);
if
(a !=
null
&& a) {
getH().sendMessageAtFrontOfQueue(Message.obtain(msg));
return
true
;
}
}
}
if
(msg.what == BRActivityThreadH.get().CREATE_SERVICE()) {
return
handleCreateService(msg.obj);
}
if
(mOtherCallback !=
null
) {
return
mOtherCallback.handleMessage(msg);
}
return
false
;
}
finally
{
mBeing.set(
false
);
}
}
return
false
;
}
@Override
public
boolean
handleMessage(
@NonNull
Message msg) {
if
(!mBeing.getAndSet(
true
)) {
try
{
if
(BuildCompat.isPie()) {
if
(msg.what == BRActivityThreadH.get().EXECUTE_TRANSACTION()) {
final
Boolean a = handleLaunchActivity(msg);
if
(a !=
null
&& a) {
getH().sendMessageAtFrontOfQueue(Message.obtain(msg));
return
true
;
}
}
}
else
{
if
(msg.what == BRActivityThreadH.get().LAUNCH_ACTIVITY()) {
final
Boolean a = handleLaunchActivity(msg);
if
(a !=
null
&& a) {
getH().sendMessageAtFrontOfQueue(Message.obtain(msg));
return
true
;
}
}
}
if
(msg.what == BRActivityThreadH.get().CREATE_SERVICE()) {
return
handleCreateService(msg.obj);
}
if
(mOtherCallback !=
null
) {
return
mOtherCallback.handleMessage(msg);
}
return
false
;
}
finally
{
mBeing.set(
false
);
}
}
return
false
;
}
public
Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
if
(ThreadedRenderer.sRendererEnabled
&& (r.activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) !=
0
) {
HardwareRenderer.preload();
}
WindowManagerGlobal.initialize();
GraphicsEnvironment.hintActivityLaunch();
final
Activity a = performLaunchActivity(r, customIntent);
return
a;
}
public
Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
if
(ThreadedRenderer.sRendererEnabled
&& (r.activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) !=
0
) {
HardwareRenderer.preload();
}
WindowManagerGlobal.initialize();
GraphicsEnvironment.hintActivityLaunch();
final
Activity a = performLaunchActivity(r, customIntent);
return
a;
}
[培训]科锐逆向工程师培训第53期2025年7月8日开班!