总贴 在这里。
支持应用多开
应用多开我们有找到几种解决办法。
- 修改包名
- 拓展ActivityStack
- 拓展Intent
修改包名
这是最简单的一种实现,因为包名在系统里面是一个唯一值,所以在安装的时候,做下手脚,就可以多开许许多多个。
存在的问题是:
1,改包名应用会有感知
2,无法解决资源的隔离问题
发现MuMu模拟器就是这样多开的,就是修改下包名,然后把资源都复制一遍,当作一个新的应用来起。但是他们,覆盖安装没处理好,只是升级了母包,没升级子包,
拓展ActivityStack
这个是在修改多个应用在前台的时候强哥发现的,就是6.0已经有支持多开。后面提到多个应用在前台
的细节在详细描述。
拓展Intent
我们知道,在打开应用的时候都是通过intent去调用的,在应用内部打开也是,所以在ActivityManagerServer中,拓展一下Intent,传多一个维度的参数,就可以实现多开。我们用的是这个方法。后面的网络隔离,端口隔离,文件隔离也都是基于这个修改的。这个要在zygote中做处理。
zygote代码在: framework/base/core/jni/com_android_internal_os_Zygote
重点的修改自然是在ActivityManagerServer.java
中,这里不展开讲。和市面上的应用多开hook的原理基本是一样的。(弄懂了四大组件就可以了的 )但是不同的是,这个是直接修改系统代码的,不用hook。
还是展开一点点吧 :)
final ProcessRecord startProcessLocked(String processName, int inst_no /* Lionfore for ML. */,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
return startProcessLocked(processName, inst_no, info, knownToBeDead, intentFlags, hostingType,
hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);
}
有个技巧,可以在proc中打开一个节点,然后当前进程中的所有函数都可以获取这个instance_no
/* Split it out to a separate function. Lionfore for ML, Jul 28th, 2017 */
static __inline__ int __set_process_inst_no (int inst_no)
{
int fd;
ssize_t err;
fd = open ("/proc/self/instance_no", O_WRONLY);
if (fd < 0)
return -1;
err = write (fd, &inst_no, sizeof (int));
if (err != sizeof (int)) {
int e = errno;
close (fd);
errno = e;
return -1;
}
close (fd);
return 0;
}
说个细节点吧,binder的修改。主要是在/framework/native/libs/binder/IPCThreadState.cpp
做一点修改:
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
...
tr.sender_inst_no = get_calling_inst_no (); /* Lionfore for ML. Jul 8th, 2017 */
...
}
...
status_t IPCThreadState::executeCommand(int32_t cmd)
{
...
switch ((uint32_t)cmd) {
...
case BR_TRANSACTION:
...
/* Lionfore for ML. Jul 28th, 2017 */
if (!this_is_android_user_app () /* System app also needs to be considered. Aug 21st, 2017 */) {
setCallingInstNo (tr.sender_inst_no); /* Set our inst_no to the sender's one. -- Lionfore for ML. Jul 8th, 2017 */
setCallingProcessAndroidFlags (tr.sender_android_flags); /* Set our android_flags to the sender's one. -- Lionfore for ML. Jul 28th, 2017 */
}
...
}
}
...
int IPCThreadState::setCallingInstNo (int inst_no)
{
int fd;
ssize_t err;
fd = open ("/proc/thread-self/calling_inst_no", O_WRONLY);
if (fd < 0)
return -errno;
err = write (fd, &inst_no, sizeof (int));
if (err != sizeof (int))
err = (ssize_t)(-errno);
close (fd);
return (int)err;
}
就是把多出来的这个维度记一下,传过去。为什么要这样做呢?
因为binder很多时候会调用到系统的进程,根据我们上面的描述,系统进程里面是没有这个instance_no的。所以
1,是为了找到对应的App实例进行回调。
2,为了设定每个instance_no下的那一堆APP不会混。
这样改完一轮之后,在修改下am start packgae_name
的指令就可以了。这个在framework/base/cmds/am/...Am.java
就是过滤下参数,然后构造intent而已。