以com.hgy.ndk
新安装在VA上的app启动为例:
LaunchpadAdapter.onBindViewHolder
设置了点击VA已安装app监听事件,如下代码:
public void onBindViewHolder(ViewHolder holder, int position) {
...
holder.itemView.setOnClickListener(v -> {
if (mAppClickListener != null) {
mAppClickListener.onAppClick(position, data);
}
});
...
}
—>在HomeActivity
中设置了mAppClickListener
,如下代码:
mLaunchpadAdapter.setAppClickListener((pos, data) -> {
if (!data.isLoading()) {
...
mPresenter.launchApp(data);
}
});
—>调用到HomePresenterImpl.launchApp
函数,传入参数为AppData
(实际为PackageAppData
), AppData
可能包含以下参数:
icon
name = "ndk"
packageName = "com.hgy.ndk"
isFirstOpen = true
isLoading = false
userid默认为0
—>这内部可能涉及到权限申请等延迟操作,但最后都会调用到VActivityManager.launchApp
函数,它主要是构造一个intent
, intent
的主要内容差不多如下:
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
intentToResolve.setPackage("com.hgy.ndk");
intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
final Intent intent = new Intent(intentToResolve);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName("com.hgy.ndk", "com.hgy.ndk.MainActivity"); // intent.setClassName(info.packageName, info.name);
很明显,是增加以下两个属性:
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
—>然后跨进程从VPMS
中取得ActivityInfo
数据,并和intent
一起传到VAMS
的startActivity
中,代码如下:
public int startActivity(Intent intent, int userId) {
// ...
ActivityInfo info = VirtualCore.get().resolveActivityInfo(intent, userId);
return startActivity(intent, info, null, null, null, 0, userId);
}
---> VAMS的startActivity:
public int startActivity(Intent intent, ActivityInfo info, ...) {
return mActivityStack.startActivityLocked(userId, intent, info, resultTo, options, resultWho, requestCode, VBinder.getCallingUid());
}
上面的参数除了ActivityInfo
数据和intent
,其余全为null或0。
—>传入ActivityStack.startActivityLocked
中还有个参数是callingUid
,默认是9999, 代码如下:
// eg: 第一次点击 callingUid = Constants.OUTSIDE_APP_UID 9999
int startActivityLocked(int userId, Intent intent, ActivityInfo info, IBinder resultTo, Bundle options,
String resultWho, int requestCode, int callingUid) { // 173
synchronized (mHistory) {
// 把不存活的task从mHistory中干掉
optimizeTasksLocked();
}
...
if (reuseTask == null || reuseTask.isFinishing()) { // eg: 新的app启动task会走这个条件
return startActivityInNewTaskLocked(mLauncherFlags, userId, intent, info, options, callingUid);
}
...
其中ActivityStack.mHistory
保存了正在运行的TaskRecord
记录, 对应系统ActivityStack
中 ArrayList
。
—> 上面函数有一堆逻辑判断,但都是查找最近有没有打开过这个app。
新的app启动可以忽略这个函数,直接进入ActivityStack.startActivityInNewTaskLocked
,其中mLauncherFlags = 0
, 代码如下:
private int startActivityInNewTaskLocked(...) {
ActivityRecord targetRecord = newActivityRecord(intent, info, null); // 1
final Intent destIntent = startActivityProcess(userId, targetRecord, intent, info, callingUid); // 2
...
}
ActivityRecord targetRecord
, targetRecord
内部存储了前面提到的ActivityInfo
数据和intent
,并设置了targetRecord.component=ComponentInfo{com.hgy.ndk/com.hgy.ndk.MainActivity}
。ActivityStack.startActivityProcess
, 它主要调用两个函数, 代码如下:private Intent startActivityProcess(int userId, ActivityRecord targetRecord, Intent intent, ActivityInfo info, int callingUid) {
// 3
ProcessRecord targetApp = mService.startProcessIfNeedLocked(info.processName, userId, info.packageName, -1, callingUid);
// 4
return getStartStubActivityIntentInner(intent, targetApp.is64bit, targetApp.vpid, userId, targetRecord, info);
}
VAMS.startProcessIfNeedLocked
VAMS.startProcessIfNeedLocked
根据包名首先取得 PackageSetting ps
和 ApplicationInfo info
数据, 这些数据在安装时就会被保存。
然后创建一个新的ProcessRecord app
,ProcessRecord
记录了 ApplicationInfo info
和vuid
等信息。并通过mProcessNames
和mPidsSelfLocked
记录app
, 最后调用initProcess
创建新进程, 关键代码如下:
app = new ProcessRecord(info, processName, vuid, vpid, callingUid, is64bit);
mProcessNames.put(app.processName, app.vuid, app);
mPidsSelfLocked.add(app);
if (initProcess(app)) {
return app;
—>由VAMS
的initProcess
发起的启动新进程:p0
(第一个启动是:p0
,依次+1), 代码如下:
private boolean initProcess(ProcessRecord app) {
...
Bundle extras = new Bundle();
extras.putParcelable("_VA_|_client_config_", app.getClientConfig());
Bundle res = ProviderCall.callSafely(app.getProviderAuthority(), "_VA_|_init_process_", null, extras);
app.getProviderAuthority()
对应AndroidManifest.xml
中:p0-:p99
的100个provider
。
它会先进入VirtualCore.startup
流程,做一些hook系统函数设置,这个在后续分析。
之后进入ShadowContentProvider
的call
初始化, 取得由ProcessRecord
转换的clientConfig
,并设置到VClient
中, 同时把VClient
对象和pid
绑定到Bundle返回到VAMS
中, 代码如下:
public Bundle call(String method, String arg, Bundle extras) {
if ("_VA_|_init_process_".equals(method)) {
return initProcess(extras);
}
}
--->
private Bundle initProcess(Bundle extras) {
VirtualCore.get().waitStartup(); // 等街startup完成
extras.setClassLoader(ClientConfig.class.getClassLoader());
ClientConfig clientConfig = extras.getParcelable("_VA_|_client_config_");// 取得由ProcessRecord转换的clientConfig
VClient client = VClient.get();
client.initProcess(clientConfig); // 将clientConfig设置到VClient中
Bundle res = new Bundle();
BundleCompat.putBinder(res, "_VA_|_client_", client.asBinder()); // 将"_VA_|_client_"和client绑定
res.putInt("_VA_|_pid_", Process.myPid()); // 将"_VA_|_pid_"和pid绑定
return res;
}
---->返回到VAMS
中的initProcess
函数, 此函数后续把:po
传过来的pid
, IVClient
,IApplicationThread
都赋值给ProcessRecord
, 代码如下:
app.pid = res.getInt("_VA_|_pid_"); // 得到pid
IBinder clientBinder = BundleCompat.getBinder(res, "_VA_|_client_");// 得到IClient.IBinder对象
return attachClient(app, clientBinder);
--->attachClient实现如下:
private boolean attachClient(final ProcessRecord app, final IBinder clientBInder) { // 734
IVClient client = IVClient.Stub.asInterface(clientBInder);
...
app.client = client;
// 对应IApplicationThread
app.appThread = ApplicationThreadCompat.asInterface(client.getAppThread());
...
return true;
}
其中client.getAppThread()
是跨进程在po
中调用。
ActivityThread.getStartStubActivityIntentInner
---->返回后调用getStartStubActivityIntentInner
, 设置targetIntent
, targetIntent
设置的代码如下:
Intent targetIntent = new Intent();
targetIntent.setClassName("io.busniess.va", "com.lody.virtual.client.stub.ShadowActivity$P0")
targetIntent.setType("com.hgy.ndk/com.hgy.ndk.MainActivity")
StubActivityRecord saveInstance = new StubActivityRecord(intent, info, userId, targetRecord);
saveInstance.saveToIntent(targetIntent); // 把saveInstance中数据保存到targetIntent
可以看出targetIntent
记录了 前面提到的intent
, ActivityInfo info
, userId
,targetRecord
所有数据。
继续回到上层函数startActivityInNewTaskLocked
, 它会继续对返回的targetIntent
增加flags
,主要内容差不多如下:
private int startActivityInNewTaskLocked(...) {
ActivityRecord targetRecord = newActivityRecord(intent, info, null);
// destIntent即前面提到的targetIntent
final Intent destIntent = startActivityProcess(userId, targetRecord, intent, info, callingUid);
destIntent.addFlags(0);// launcherFlags = 0
destIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
destIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
destIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
destIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
destIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
VirtualCore.get().getContext().startActivity(destIntent);
}
最后进入系统的startActivity
,因为targetIntent.setClassName("io.busniess.va", "com.lody.virtual.client.stub.ShadowActivity$P0")
,所以它会在po
进程中启动startActivity
。
但是这里有个问题,因为设置的是 "com.lody.virtual.client.stub.ShadowActivity$P0"
,那理论上启动的是ShadowActivity
,而不是我们原始的com.hgy.ndk.MainActivity
了,这里可以提前解释下,在后面的HCallbackStub
的LAUNCH_ACTIVITY
中有如下代码:
ActivityThread.ActivityClientRecord.intent.set(r, intent);
ActivityThread.ActivityClientRecord.activityInfo.set(r, info);
其中intent
是原始的,这里可以贴下改变前面的值:
调用 ActivityThread.ActivityClientRecord.intent.set(r, intent)
改变后:
也就是在启动activity
前,又换回原始的intent
和info
数据,从而正常启动。
在lulubox4.3的插件化中有类似的实现: 位于plugin-base-cmplugin-host-library中AndroidHack.java。
这时VA中设置的hook函数开始准备拦截了。
hook函数框架可以参考InvocationStubManager相关
在startActivity
后到HCallbackStub
的LAUNCH_ACTIVITY
之前要处理几个函数的hook:
在 mInitialApplication = LoadedApk.makeApplication
中会调用getClassLoader
,getClassLoader
内部会调用addPackageDependency
,如下图:
将参数args
从"com.hgy.ndk
"换成“io.busniess.va
”再传入调用:
public Object call(Object who, Method method, Object... args) throws Throwable {
MethodParameterUtils.replaceFirstAppPkg(args); // args由原始的包名转换成io.busniess.va
return method.invoke(who, args);
}
如果是va自身的service
就直接使用系统的,否则和VAMS
中startActivity
类似,使用VAMS
中的startService
,先自己起一个子进程p0(如果p0被占用就依此类推),再 intent.setClassName(com.lody.virtual.client.stub.ShadowService$P0, serviceName);
绑定到子进程。
根据名字判断如果是va自身的contentprovider
就直接使用系统的,否则和前面的一样,使用VAMS
中的initProcess
,先自己起一个子进程p0(如果p0被占用就依此类推), 然后把getContentProvider
的第二个参数name
设置为io.busniess.vatools.virtual_stub_${vpid}
。
首先取得运行进程list, 遍历, 如果是va的app进程,则更新RunningAppProcessInfo
中的数据为va变化的数据:
if (processName != null) {
info.importanceReasonCode = 0;
info.importanceReasonPid = 0;
info.importanceReasonComponent = null;
info.processName = processName;
}
info.pkgList = pkgList.toArray(new String[0]);
info.uid = vuid;
ActivityThread
有个很重要的变量,final H mH = new H();
, 它的实现如下:
private class H extends Handler {
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
...
}
}
简单的说就是处理各种消息, HCallbackStub
就是设置了ActivityThread.H
的callback
函数,实现handleMessage
拦截。
首先到达的LAUNCH_ACTIVITY
消息,其中 Msg.object
就是ActivityClientRecord r
对象
Intent stubIntent;
if (BuildCompat.isPie()) {
stubIntent = LaunchActivityItem.mIntent.get(r);
} else {
stubIntent = ActivityThread.ActivityClientRecord.intent.get(r);
}
这里得到的stubIntent
就是我们前面VAMS
中startActivity
传出的destIntent
, 如下所示:
所以就可以在这里把VAMS
中绑定的StubActivityRecord
,intent(原始的)
, ActivityInfo info
都取出来,前面流程提到过如何绑定, 代码如下:
StubActivityRecord saveInstance = new StubActivityRecord(stubIntent);
// intent是原始的,没有调用setClassName改变的
Intent intent = saveInstance.intent;
IBinder token;
if (BuildCompat.isPie()) { //android 9.0
token = ClientTransaction.mActivityToken.get(msg.obj);
} else {
token = ActivityThread.ActivityClientRecord.token.get(r);
}
ActivityInfo info = saveInstance.info;
这时还会判断:p0
进程是否已初始化,如果没有就尝试重启p0进程,代码如下:
if (VClient.get().getClientConfig() == null) { // 理论上不会成立,除非px进程挂了,因为clientConfig会在call时赋值给VClient
InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(info.packageName, 0);
// 让VAMS再次initProcess,重启:px进程
VActivityManager.get().processRestarted(info.packageName, info.processName, saveInstance.userId);
getH().sendMessageAtFrontOfQueue(Message.obtain(msg));// 重发消息
return false;
}
继续就会进行到比较重要的一步,调用 VClient.get().bindApplication
,然后重新触发LAUNCH_ACTIVITY
消息。之后调用
VClient.get().bindApplication
总是在主UI线程中调用bindApplicationNoCheck
,bindApplicationNoCheck
主要完成了以下任务:
setupUncaughtHandler
设置异常捕获,由外部VCore
设置CrashHandler
,内部默认没有设置。fixInstalledProviders
会检查我们的provider
,如果authority
不是io.busniess.va.virtual_stub_
开头,则利用ProviderHook
生成provider代理
取代原始的provider
。理论上都是以io.busniess.va.virtual_stub_
开头。VDeviceManager.get().applyBuildProp
设置虚拟的设备信息。VirtualCore.mainThread
的mInitialApplication
变量设置为null。InstalledAppInfo
,ApplicationInfo
, List
等基础数据到VClient
中。VirtualRuntime.setupRuntime
改变进程的argv[0]
参数为进程名(com.hgy.ndk
), 设置app名字为进程名(com.hgy.ndk
)。io.busniess.va:p0
。AlarmManager.mTargetSdkVersion
为被安装apk的targetSdkVersion
,原始值为va的targetSdkVersion
。/data/data/io.busniess.vatools/virtual/data/user/userId/packageName/cache
, userId为0,1,…。startIORelocater
, startIORelocater
的作用就是可以在java层设置路径白名单,黑名单,要替换的名单,然后把这些路径列表传到NDK层,并hook
所有的带路径的libc
函数以及linker
下的dlopen
函数,并在hook
函数中对路径做相应放过,禁止,替换。launchEngine
替换java native函数对应的NDK jni函数。codeCacheDir
为/data/data/io.busniess.va/virtual/data/user/0/com.hgy.ndk/code_cache
。AppBindData mBoundApplication
传入ActivityThread.mBoundApplication
对象,即 设置appInfo
, processName
, instrumentationName
, info
等到对象, 其中info
由临时创建的context
获取。LoadedApk.mSecurityViolation
为false
。VMRuntime.setTargetSdkVersion
设置 targetSdkVersion
。AppCallback.beforeStartApplication
对外接口,可以看出传出的context
为前面临时创建的。LoadedApk.makeApplication
创建mInitialApplication
,并设置到ActivityThread.mInitialApplication
中。ContextFixer
把 ContextImpl.mBasePackageName
,ContextImplKitkat.mOpPackageName
, ContentResolverJBMR2.mPackageName
的包名(原始为com.hgy.ndk
)改为io.busniess.va
。AppCallback.beforeApplicationCreate
对外接口。mInstrumentation.callApplicationOnCreate
会首先把ActivityThread.mInstrumentation
替换成VClient的mInstrumentation
。AppCallback.afterApplicationCreate
对外接口。仍以com.hgy.ndk
为例,逻辑:
在deviceConfig.enable时触发
NativeEngine.redirectFile("/sys/class/net/wlan0/address",“/data/data/io.busniess.va/virtual/data/user/0/system/wifiMacAddress”);
NativeEngine.redirectFile("/sys/class/net/eth0/address",“/data/data/io.busniess.va/virtual/data/user/0/system/wifiMacAddress”);
NativeEngine.redirectFile("/sys/class/net/wifi/address",“/data/data/io.busniess.va/virtual/data/user/0/system/wifiMacAddress”);
NativeEngine.redirectFile("/proc/stat", "/data/data/io.busniess.vatools/virtual/proc/stat");
NativeEngine.forbid("/proc/" + info.pid + "/maps", true);
NativeEngine.forbid("/proc/" + info.pid + "/cmdline", true);
NativeEngine.redirectDirectory("/tmp/", "/data/data/io.busniess.va/virtual/data/user/0/com.hgy.ndk/cache/");
NativeEngine.redirectDirectory("/data/data/com.hgy.ndk","/data/data/io.busniess.va/virtual/data/user/0/com.hgy.ndk/");
NativeEngine.redirectDirectory("/data/user/0/com.hgy.ndk","/data/data/io.busniess.va/virtual/data/user/0/com.hgy.ndk/");
// user_de在android7.0以后
NativeEngine.redirectDirectory("/data/user_de/0/com.hgy.ndk","/data/data/io.busniess.va/virtual/data/user_de/0/com.hgy.ndk/");
if (appLibConfig == SettingConfig.AppLibConfig.UseOwnLib) {// 默认不成立
NativeEngine.redirectDirectory("/data/data/com.hgy.ndk/lib/","/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/lib/");
NativeEngine.redirectDirectory("/data/user/0/com.hgy.ndk/lib/","/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/lib/");
}
NativeEngine.redirectDirectory("/data/data/io.busniess.va/virtual/data/user/0/com.hgy.ndk/lib","/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/lib/");
NativeEngine.whitelist("/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/lib");
NativeEngine.whitelist("/data/user/0/com.hgy.ndk/lib/");
最后调用NativeEngine.enableIORedirect()
。
关键函数是NativeEngine.redirectFile
及NativeEngine.redirectDirectory
及NativeEngine.forbid
及NativeEngine.whitelist
及NativeEngine.enableIORedirect
。
四者 用于区分传入的是文件和文件夹在于路径最后有没有/
。
NativeEngine.forbid
最终调到NDK的jni_nativeIOForbid
, jni_nativeIOForbid
会把传入的路径统一加入到forbidden_items
数组中,forbidden_items
数组由PathItem
构成, 代码如下:
typedef struct PathItem {
char *path;
bool is_folder;
size_t size;
} PathItem;
--->
PathItem &item = forbidden_items[forbidden_item_count];
item.path = strdup(path);
item.size = strlen(path);
item.is_folder = (path[strlen(path) - 1] == '/'); // 根据最后有没有斜杠判断是否为文件夹
NativeEngine.whitelist
最终调到NDK的jni_nativeIOWhitelist
, jni_nativeIOWhitelist
把传入的路径统一加入到keep_items
数组中,forbidden_items
数组同样由PathItem
构成,和上面的加入类似。
NativeEngine.redirectFile
及NativeEngine.redirectDirectory
都是把原始文件(夹)和要重定位的文件(夹)路径放在REDIRECT_LISTS
列表中。
最后由NativeEngine.enableIORedirect
来触发:
NativeEngine.enableIORedirect
首先会把REDIRECT_LISTS
排序(第一个字符串从长到短), 然后遍历REDIRECT_LISTS
,并调用NativeEngine.nativeIORedirect
,再调到NDK的jni_nativeIORedirect
把传入的原始路径和要替换的路径统一加入到replace_items
数组中, 代码如下:
typedef struct ReplaceItem {
char *orig_path;
size_t orig_size;
char *new_path;
size_t new_size;
bool is_folder;
} ReplaceItem;
--->
ReplaceItem &item = replace_items[replace_item_count];
item.orig_path = strdup(orig_path);
item.orig_size = strlen(orig_path);
item.new_path = strdup(new_path);
item.new_size = strlen(new_path);
item.is_folder = (orig_path[strlen(orig_path) - 1] == '/');
最后调用NDK的jni_nativeEnableIORedirect
, 传入参数基本如下:
soPath = /data/app/io.busniess.va-2/lib/x86/libv++.so
soPath64 = /data/app/io.busniess.va-2/lib/x86/libv++_64.so
nativePath = /data/data/io.busniess.va/virtual/.native 或 /data/data/io.busniess64.va/virtual/.native
jni_nativeEnableIORedirect
在内部调用IOUniformer::startUniformer
,先把前面传入参数使用setenv
保存,再调用startIOHook
来hook
所有的包含路径的c库函数,这些函数在调用的时候,可能会替换路径为新路径。由于hook
的是libc
的函数,java层和虚拟机的文件访问最终也会调用到这里,从而受到影响, 代码如下:
void startIOHook(int api_level) {
void *handle = dlopen("libc.so", RTLD_NOW);
if (handle) {
...
HOOK_SYMBOL(handle, faccessat);
HOOK_SYMBOL(handle, __openat);
HOOK_SYMBOL(handle, fchmodat);
...
#ifdef __arm__
if (!relocate_linker()) {
findSyscalls("/system/bin/linker", on_found_linker_syscall_arm);
}
#endif
#endif
dlclose(handle);
}
}
HOOK_SYMBOL
内部调用了MSHookFunction
,也就是著名的Cydia
的hook库, 代码如下:
#define HOOK_SYMBOL(handle, func) hook_function(handle, #func, (void*) new_##func, (void**) &orig_##func)
--->
void hook_function(void *handle, const char *symbol, void *new_func, void **old_func) {
void *addr = dlsym(handle, symbol);
MSHookFunction(addr, new_func, old_func);
}
以faccessat
为例,代码如下:
HOOK_DEF(int, faccessat, int dirfd, const char *pathname, int mode, int flags) {
char temp[PATH_MAX];
const char *relocated_path = relocate_path(pathname, temp, sizeof(temp));
if (relocated_path && !(mode & W_OK && isReadOnly(relocated_path))) {
return syscall(__NR_faccessat, dirfd, relocated_path, mode, flags);
}
errno = EACCES;
return -1;
}
内部relocate_path
是关键的替换路径函数,代码如下:
const char *relocate_path(const char *path, char *const buffer, const size_t size) {
const char *result = relocate_path_internal(path, buffer, size);
return result;
}
--->relocate_path_internal代码:
relocate_path_internal
逻辑如下:
canonicalize_path
把路径转成规范的路径,比如传入的路径可能有//
这种重复斜杠或./
。keep_items
(白名单,对应上层的 NativeEngine.whitelist
)中遍历,看是否符合,如符合,直接返回原始路径。forbidden_items
(黑名单,对应上层的 NativeEngine.forbid
)中遍历,看是否符合,如符合,直接返回NULL
。replace_items
(替换名单, 对应上层的NativeEngine.redirectFile
和NativeEngine.redirectDirectory
)中遍历,看是否符合,如符合,这里会分几种情况,不过最后总是返回被替换的路径。一般会把被替换的路径保存到前面传入的temp
中。比较函数代码如下:
bool match_path(bool is_folder, size_t size, const char *item_path, const char *path, size_t path_len) {
if (is_folder) {
if (path_len < size) {
// ignore the last '/'
return strncmp(item_path, path, size - 1) == 0;
} else {
return strncmp(item_path, path, size) == 0;
}
} else {
return strcmp(item_path, path) == 0;
}
}
relocate_linker
的作用是:从/proc/self/maps
中取得/system/bin/linker
的基地址,再遍历/system/bin/linker
文件的symbol
查找dlopen
的文件偏移,再加上基地址做hook
, 不同版本的linker
的dlopen
对应的symbol
不同,这个可以通过IDA
来查看确认。
startIORelocater
的作用是可以在java层设置路径白名单,黑名单,要替换的名单,然后把这些路径列表传到NDK层,并hook
所有的带路径的libc
函数以及linker
下的dlopen
函数,并在hook
中对路径做相应放过,禁止,替换。
NativeEngine.launchEngine
会调用jni_nativeLaunchEngine
, 传入参数如下:
1> method
:java层的native函数列表:
gOpenDexFileNative
: DexFile.java中openDexFileNative
函数地址gCameraNativeSetup
: Camera.java中native_setup
函数地址gAudioRecordNativeCheckPermission
: AudioRecord.java中native_check_permission
函数地址gMediaRecorderNativeSetup
: MediaRecorder.java中native_setup
函数地址gAudioRecordNativeSetup
: AudioRecord.java中native_setup
函数地址2> VirtualCore.get().getHostPkg
:va的包名io.busniess.va
3> isArt
:是否为art
4> Build.VERSION.SDK_INT
: 设备版本号
5> gCameraMethodType
: gCameraNativeSetup
函数参数列表中String参数的位置 + 0x10
6> gAudioRecordMethodType
: 区分gAudioRecordNativeSetup
的版本,9个参数为1,10个参数为2
jni_nativeLaunchEngine
内部做了一套hook native
函数的封装, 逻辑如下:
mark
, 并RegisterNatives
绑定NativeEngine.nativeMark
到mark
。然后遍历计算NativeEngine.nativeMark
到mark
的偏移,参考函数measureNativeOffset
:void measureNativeOffset(JNIEnv *env, bool isArt) {
jmethodID markMethod = env->GetStaticMethodID(nativeEngineClass, "nativeMark", "()V");
size_t start = (size_t) markMethod;
size_t target = (size_t) mark;
int offset = 0;
bool found = false;
while (true) {
if (*((size_t *) (start + offset)) == target) {
found = true;
break;
}
offset += 4;
if (offset >= 100) {
ALOGE("Error: Cannot find the jni function offset.");
break;
}
}
if (found) {
patchEnv.native_offset = offset;
}
}
getCallingUid
为例,首先取得原始的getCallingUid
地址public static final native int getCallingUid()
--->得到native函数getCallingUid的地址
jclass binderClass = env->FindClass("android/os/Binder");
jmethodID getCallingUid = env->GetStaticMethodID(binderClass, "getCallingUid", "()I");
然后调用hookJNIMethod
做hook, vmGetJNIFunction
通过相同的偏移量得到ndk层中原始jni函数地址, vmUseJNIFunction
替换为新的jni函数地址。
hookJNIMethod(getCallingUid,
(void *) new_getCallingUid,
(void **) &patchEnv.orig_getCallingUid
--->
void hookJNIMethod(jmethodID method, void *new_jni_func, void **orig_jni_func) {
*orig_jni_func = vmGetJNIFunction(method);
vmUseJNIFunction(method, new_jni_func);
}
---> vmGetJNIFunction得到原始的jni函数地址
void *vmGetJNIFunction(jmethodID method) {
void **funPtr = (void **) (reinterpret_cast<size_t>(method) + patchEnv.native_offset);
return *funPtr;
}
--->vmUseJNIFunction替换为新的jni函数地址
void vmUseJNIFunction(jmethodID method, void *jniFunction) {
void **funPtr = (void **) (reinterpret_cast<size_t>(method) + patchEnv.native_offset);
*funPtr = jniFunction;
}
jni_nativeLaunchEngine
主要完成了以下任务:
getCallingUid
,调用NativeEngine. onGetCallingUid
返回自定义的UidopenDexFileNative
, 调用NativeEngine. onOpenDexFileNative
native_setup
, 替换它的String参数为传入的包名native_setup
, 替换它的String参数为传入的包名native_setup
, 替换它的String参数为传入的包名nativeLoad
, 替换它的文件路径
launchEngine
的作用是替换java native函数对应的ndk层jni函数,具体如上所述。
在VClient.bindApplication
调用之前,默认返回0,之后判断va中是否使用系统已安装的apk进行安装(默认是),如果是,则放过
public Object call(Object who, Method method, Object... args) throws Throwable {
if (!VClient.get().isAppUseOutsideAPK()) {
return 0;
}
return super.call(who, method, args);
}
判断取得的 List
是否有我们自定义的TaskInfo
,如果有,就强制修改List,再返回, 修改如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
info.topActivity = taskInfo.topActivity;
info.baseActivity = taskInfo.baseActivity;
}
info.origActivity = taskInfo.baseActivity;
info.baseIntent = taskInfo.baseIntent;
这个函数首次触发是在前面提到的initProcess
中ProviderCall.callSafely
创建新进程:p0
, 这时默认是直接返回的:
public Object call(Object who, Method method, Object... args) throws Throwable {
int nameIdx = getProviderNameIndex(); // nameIndex = 1
String name = (String) args[nameIdx]; // name = io.busniess.va.virtual_stub_0
if ((name.startsWith(StubManifest.STUB_CP_AUTHORITY)
|| name.startsWith(StubManifest.STUB_CP_AUTHORITY_64BIT)
|| name.equals(getConfig().get64bitHelperAuthority()))
|| name.equals(getConfig().getBinderProviderAuthority())) {
return method.invoke(who, args);
...
// todo,待续.
之后进入了新进程:p0
的相关hook
取得原始系统分配的uid
,初始使用系统分配的uid
,在初始化完成后,使用ProcessRecord
中的vuid
, 这个也可以从后面打印的日志看出。
public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {
int uid = (int) result;
return NativeEngine.onGetUid(uid);
}
-->
public static int onGetUid(int uid) {
if (!VClient.get().isAppRunning()) {// 在点击启动va中的apk开始时,isAppRunning=false
return uid;
}
return VClient.get().getBaseVUid();// 取得ProcessRecord中的vuid
}
默认返回我们VPMS
中创建的ApplicationInfo
, 如果我们没有安装过,但是属于以下三类:
addVisibleOutsidePackage
,那么提示没有安装QQ,如果用了addVisibleOutsidePackage
,则属于外部包,启动外部的QQComponentFixer.fixOutsideApplicationInfo
把ApplicationInfo.uid
设置为9999。 public Object call(Object who, Method method, Object... args) throws Throwable {
String pkg = (String) args[0]; // eg: com.hgy.ndk
int flags = (int) args[0]; // 1024
if (getHostPkg().equals(pkg)) { // getHostPkg = io.busniess.va
return method.invoke(who, args);
}
int userId = VUserHandle.myUserId(); // eg: userId = 0
ApplicationInfo info = VPackageManager.get().getApplicationInfo(pkg, flags, userId);
if (info != null) {
return info; // 默认返回我们VPMS中创建的ApplicationInfo
}
info = (ApplicationInfo)method.invoke(who, args);
// isVisiblePackage表明了三类可见app,1.va自身 2.系统app 3.使用外部包的app, 其中3的解释如下
// 外部安装了应用,但是内部没有安装(双开),内部应用在调用外面的应用,需要先addVisibleOutsidePackage,否则会相当于没有安装
if (info == null || !isVisiblePackage(info)) {
return null;
}
ComponentFixer.fixOutsideApplicationInfo(info);
return info;
}
我们可以把HookInvocationHandler.invoke
稍改造下,让它所有的hook函数都打印出日志:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodProxy methodProxy = getMethodProxy(method.getName());
if (methodProxy != null) {
methodProxy.setInvocationloggingCondition(LogInvocation.Condition.ALWAYS);
}
在VirtualCore.startup
中加入等待断点:
public void startup(Context context, SettingConfig config) throws Throwable {
...
detectProcessType();
if (isVAppProcess()) {
VLog.e(TAG, "startup0");
android.os.Debug.waitForDebugger();
VLog.e(TAG, "startup1");
}
}
点击VA中安装的APK启动,附加断点,把Logcat切到当前的io.busniess.va:px
日志,观察它的整个hook函数列表:
在附加之前,我们的:x
服务进程,它的日志如下:
08-26 02:24:13.594 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getActivityDisplayId(android.os.BinderProxy@640bff7) => 0
08-26 02:24:13.603 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.setTaskDescription(android.os.BinderProxy@640bff7, TaskDescription Label: null Icon: null colorPrimary: -1644826) => void
08-26 02:24:13.605 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.overridePendingTransition(android.os.BinderProxy@640bff7, io.busniess.va, 0, 0) => void
08-26 02:24:13.616 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@640bff7) => null
08-26 02:24:13.620 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@640bff7) => null
08-26 02:24:13.622 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.checkPermission(android.permission.INTERACT_ACROSS_USERS, 3006, 10058) => -1
08-26 02:24:13.623 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.checkPermission(android.permission.INTERACT_ACROSS_USERS_FULL, 3006, 10058) => -1
08-26 02:24:13.646 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.activityResumed(android.os.BinderProxy@640bff7) => void
08-26 02:24:13.825 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.activityIdle(android.os.BinderProxy@640bff7, {1.0 310mcc260mnc en_US ldltr sw392dp w392dp h713dp 440dpi nrml long port finger -keyb/v/h dpad/v s.6}, false) => void
08-26 02:24:13.992 3006-3030/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@4d02da, android.app.ActivityManager$RecentTaskInfo@644d30b, android.app.ActivityManager$RecentTaskInfo@91d65e8]
附加后,它的新增日志为:
08-26 02:25:22.163 3006-3030/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getContentProvider(android.app.ActivityThread$ApplicationThread@b14e927, io.busniess.va.virtual_stub_0, 0, false) => android.app.IActivityManager$ContentProviderHolder@14401
08-26 02:25:23.659 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.removeContentProvider(android.os.BinderProxy@1eb94e7, false) => void
08-26 02:25:23.714 3006-3030/io.busniess.va:x I/MethodInvocationStub: IActivityManager.startActivity(android.app.ActivityThread$ApplicationThread@b14e927, io.busniess.va, Intent { typ=com.hgy.ndk/com.hgy.ndk.MainActivity flg=0x18290000 cmp=io.busniess.va/com.lody.virtual.client.stub.ShadowActivity$P0 (has extras) }, com.hgy.ndk/com.hgy.ndk.MainActivity, null, null, -1, 0, null, null) => 0
08-26 02:25:23.726 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.activityPaused(android.os.BinderProxy@640bff7) => void
08-26 02:25:23.728 3006-3018/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@d3d1f3d, android.app.ActivityManager$RecentTaskInfo@8b91332, android.app.ActivityManager$RecentTaskInfo@5529883, android.app.ActivityManager$RecentTaskInfo@6f50a00]
08-26 02:25:23.743 3006-3018/io.busniess.va:x I/MethodInvocationStub: IActivityManager.startActivity(android.app.ActivityThread$ApplicationThread@b14e927, io.busniess.va, Intent { typ=com.hgy.ndk/com.hgy.ndk.MainActivity flg=0x18290000 cmp=io.busniess.va/com.lody.virtual.client.stub.ShadowActivity$P0 (has extras) }, com.hgy.ndk/com.hgy.ndk.MainActivity, null, null, -1, 0, null, null) => 0
08-26 02:25:23.779 3006-3031/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@b617239, android.app.ActivityManager$RecentTaskInfo@a61307e, android.app.ActivityManager$RecentTaskInfo@79c39df, android.app.ActivityManager$RecentTaskInfo@8a0c62c]
08-26 02:25:23.780 3006-3031/io.busniess.va:x I/MethodInvocationStub: IActivityManager.broadcastIntent(android.app.ActivityThread$ApplicationThread@b14e927, Intent { act=virtual.intent.action.APP_LAUNCHED (has extras) }, null, null, -1, null, null, null, -1, null, false, false, 0) => 0
08-26 02:25:23.895 3006-3018/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@addf8f5, android.app.ActivityManager$RecentTaskInfo@4dbd68a, android.app.ActivityManager$RecentTaskInfo@5b494fb, android.app.ActivityManager$RecentTaskInfo@86a1918]
08-26 02:25:24.031 3006-3030/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@9622f71, android.app.ActivityManager$RecentTaskInfo@ba8d156, android.app.ActivityManager$RecentTaskInfo@52d85d7, android.app.ActivityManager$RecentTaskInfo@e73aec4, android.app.ActivityManager$RecentTaskInfo@61951ad]
08-26 02:25:24.033 3006-3030/io.busniess.va:x I/MethodInvocationStub: IActivityManager.broadcastIntent(android.app.ActivityThread$ApplicationThread@b14e927, Intent { act=virtual.intent.action.APP_LAUNCHED (has extras) }, null, null, -1, null, null, null, -1, null, false, false, 0) => 0
08-26 02:25:24.079 3006-3018/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@878ace2, android.app.ActivityManager$RecentTaskInfo@8daa873, android.app.ActivityManager$RecentTaskInfo@5ef330, android.app.ActivityManager$RecentTaskInfo@da65ba9, android.app.ActivityManager$RecentTaskInfo@d78b52e]
08-26 02:25:24.316 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.finishActivity(android.os.BinderProxy@640bff7, 0, null, false) => true
08-26 02:25:24.328 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.activityStopped(android.os.BinderProxy@640bff7, Bundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@32d58cf}}]}], null, null) => void
对于被启动的进程com.hgy.ndk(io.busniess.va:p0)
,它的日志如下:
08-26 02:25:22.150 3032-3032/io.busniess.va:p0 I/MethodInvocationStub: Os.getuid(ul) => 10058
08-26 02:25:22.161 3032-3032/io.busniess.va:p0 I/MethodInvocationStub: Os.getuid(ul) => 10058
08-26 02:25:22.163 3032-3032/io.busniess.va:p0 I/MethodInvocationStub: IActivityManager.publishContentProviders(android.app.ActivityThread$ApplicationThread@6fbd30e, [android.app.IActivityManager$ContentProviderHolder@e5b512f]) => void
08-26 02:25:22.165 3032-3032/io.busniess.va:p0 I/MethodInvocationStub: IActivityManager.removeContentProvider(android.os.BinderProxy@2ec0c41, false) => void
08-26 02:25:23.746 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getRunningAppProcesses(ul) => [android.app.ActivityManager$RunningAppProcessInfo@446f18, android.app.ActivityManager$RunningAppProcessInfo@b8ccd71, android.app.ActivityManager$RunningAppProcessInfo@7f21756]
08-26 02:25:23.755 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.757 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getApplicationInfo(com.hgy.ndk, 1024, 0) => ApplicationInfo{d0c4bde com.hgy.ndk}
08-26 02:25:23.757 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.757 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.757 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.performDexOptIfNeeded(com.hgy.ndk, x86) => false
08-26 02:25:23.757 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.addPackageDependency(com.hgy.ndk) => void
08-26 02:25:23.758 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/data/app/com.hgy.ndk-1/base.apk) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.758 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/data/app/com.hgy.ndk-1/base.apk) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.759 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/vendor/lib) => StructStat[st_atime=1499889343,st_blksize=4096,st_blocks=8,st_ctime=1499889343,st_dev=64768,st_gid=2000,st_ino=1583,st_mode=16877,st_mtime=1499889343,st_nlink=4,st_rdev=0,st_size=4096,st_uid=0]
08-26 02:25:23.759 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/system/lib) => StructStat[st_atime=1499889365,st_blksize=4096,st_blocks=16,st_ctime=1566472418,st_dev=64768,st_gid=0,st_ino=889,st_mode=16877,st_mtime=1566472418,st_nlink=5,st_rdev=0,st_size=8192,st_uid=0]
08-26 02:25:23.759 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/data/app/com.hgy.ndk-1/lib/x86) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=8,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16586,st_mode=16877,st_mtime=1566480905,st_nlink=2,st_rdev=0,st_size=4096,st_uid=1000]
08-26 02:25:23.759 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/vendor/lib) => StructStat[st_atime=1499889343,st_blksize=4096,st_blocks=8,st_ctime=1499889343,st_dev=64768,st_gid=2000,st_ino=1583,st_mode=16877,st_mtime=1499889343,st_nlink=4,st_rdev=0,st_size=4096,st_uid=0]
08-26 02:25:23.760 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/system/lib) => StructStat[st_atime=1499889365,st_blksize=4096,st_blocks=16,st_ctime=1566472418,st_dev=64768,st_gid=0,st_ino=889,st_mode=16877,st_mtime=1566472418,st_nlink=5,st_rdev=0,st_size=8192,st_uid=0]
08-26 02:25:23.761 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/data/app/com.hgy.ndk-1/base.apk) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.768 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.769 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getPackageInfo(com.hgy.ndk, 0, 0) => PackageInfo{a3889b7 com.hgy.ndk}
08-26 02:25:23.769 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.778 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getTaskForActivity(android.os.BinderProxy@a58f8af, false) => 19
08-26 02:25:23.780 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.780 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.782 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.fstat(FileDescriptor[26]) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.782 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.fstat(FileDescriptor[26]) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.783 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.fstat(FileDescriptor[26]) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.787 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityDisplayId(android.os.BinderProxy@a58f8af) => 0
08-26 02:25:23.787 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.788 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.788 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.789 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.789 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.791 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.791 3032-3032/com.hgy.ndk I/MethodInvocationStub: IUserManager.getProfiles(0, false) => []
08-26 02:25:23.793 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.setTaskDescription(android.os.BinderProxy@a58f8af, TaskDescription Label: null Icon: null colorPrimary: -16743049) => void
08-26 02:25:23.795 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getTaskForActivity(android.os.BinderProxy@a58f8af, true) => 19
08-26 02:25:23.795 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.796 3032-3032/com.hgy.ndk I/MethodInvocationStub: IUserManager.getProfiles(0, false) => []
08-26 02:25:23.796 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.setTaskDescription(android.os.BinderProxy@a58f8af, TaskDescription Label: ndk Icon: android.graphics.Bitmap@800eaa1 colorPrimary: 0) => void
08-26 02:25:23.797 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getRequestedOrientation(android.os.BinderProxy@a58f8af) => -1
08-26 02:25:23.809 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getActivityInfo(ComponentInfo{com.hgy.ndk/com.hgy.ndk.MainActivity}, 128, 0) => ActivityInfo{dda98f1 com.hgy.ndk.MainActivity}
08-26 02:25:23.812 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.812 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.813 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.checkPermission(android.permission.INTERACT_ACROSS_USERS, 3032, 10001) => -1
08-26 02:25:23.813 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.814 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.checkPermission(android.permission.INTERACT_ACROSS_USERS_FULL, 3032, 10001) => -1
08-26 02:25:23.814 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.814 3032-3032/com.hgy.ndk I/MethodInvocationStub: IAccessibilityManager.addClient(android.view.accessibility.AccessibilityManager$1@76ed32d, 0) => 0
08-26 02:25:23.872 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getPackageInfo(com.dts.freefireth, 0, 0) => null
08-26 02:25:23.874 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@a58f8af) => null
08-26 02:25:23.874 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@a58f8af) => null
08-26 02:25:23.876 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.880 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowManager.openSession(android.view.WindowManagerGlobal$1@ee7b73a, android.view.inputmethod.InputMethodManager$1@358dfeb, android.view.inputmethod.InputMethodManager$ControlledInputConnectionWrapper@bd32148) => android.view.IWindowSession$Stub$Proxy@69dc51d
08-26 02:25:23.886 3032-3032/com.hgy.ndk I/MethodInvocationStub: IGraphicsStats.requestBufferForProcess(com.hgy.ndk, android.os.Binder@97f6163) => {ParcelFileDescriptor: FileDescriptor[32]}
08-26 02:25:23.894 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowSession.addToDisplay(android.view.ViewRootImpl$W@7ad160, 0, WM.LayoutParams{(0,0)(fillxfill) ty=1 fl=#81810100 wanim=0x103045b needsMenuKey=2}, 4, 0, Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), uninitialized) => 3
08-26 02:25:23.896 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityResumed(android.os.BinderProxy@a58f8af) => void
08-26 02:25:23.897 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.901 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityPaused(android.os.BinderProxy@a58f8af) => void
08-26 02:25:23.920 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowSession.relayout(android.view.ViewRootImpl$W@7ad160, 0, WM.LayoutParams{(0,0)(fillxfill) sim=#20 ty=1 fl=#81810100 wanim=0x103045b needsMenuKey=2}, 1080, 2028, 0, 0, Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), Rect(0, 66 - 0, 132), Rect(0, 0 - 0, 0), Rect(0, 66 - 0, 132), Rect(0, 0 - 0, 0), {1.0 ?mcc?mnc ?locale ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}, Surface(name=null)/@0xbbb6953) => 7
08-26 02:25:24.030 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getTaskForActivity(android.os.BinderProxy@d9c3789, false) => 20
08-26 02:25:24.033 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.034 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.034 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityDisplayId(android.os.BinderProxy@d9c3789) => 0
08-26 02:25:24.035 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.037 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.038 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.042 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.042 3032-3032/com.hgy.ndk I/MethodInvocationStub: IUserManager.getProfiles(0, false) => []
08-26 02:25:24.042 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.setTaskDescription(android.os.BinderProxy@d9c3789, TaskDescription Label: null Icon: null colorPrimary: -16743049) => void
08-26 02:25:24.043 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getTaskForActivity(android.os.BinderProxy@d9c3789, true) => 20
08-26 02:25:24.043 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.043 3032-3032/com.hgy.ndk I/MethodInvocationStub: IUserManager.getProfiles(0, false) => []
08-26 02:25:24.044 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.setTaskDescription(android.os.BinderProxy@d9c3789, TaskDescription Label: ndk Icon: android.graphics.Bitmap@90947af colorPrimary: 0) => void
08-26 02:25:24.059 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getRequestedOrientation(android.os.BinderProxy@d9c3789) => -1
08-26 02:25:24.061 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getActivityInfo(ComponentInfo{com.hgy.ndk/com.hgy.ndk.MainActivity}, 128, 0) => ActivityInfo{887c345 com.hgy.ndk.MainActivity}
08-26 02:25:24.072 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getPackageInfo(com.dts.freefireth, 0, 0) => null
08-26 02:25:24.073 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@d9c3789) => null
08-26 02:25:24.074 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@d9c3789) => null
08-26 02:25:24.074 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.078 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowSession.addToDisplay(android.view.ViewRootImpl$W@35f9e4a, 0, WM.LayoutParams{(0,0)(fillxfill) ty=1 fl=#81810100 wanim=0x103045b needsMenuKey=2}, 4, 0, Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), uninitialized) => 3
08-26 02:25:24.079 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityResumed(android.os.BinderProxy@d9c3789) => void
08-26 02:25:24.188 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowSession.relayout(android.view.ViewRootImpl$W@35f9e4a, 0, WM.LayoutParams{(0,0)(fillxfill) sim=#20 ty=1 fl=#81810100 wanim=0x103045b needsMenuKey=2}, 1080, 2028, 0, 0, Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), Rect(0, 66 - 0, 132), Rect(0, 0 - 0, 0), Rect(0, 66 - 0, 132), Rect(0, 0 - 0, 0), {1.0 ?mcc?mnc ?locale ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}, Surface(name=null)/@0x3f9d511) => 7
08-26 02:25:24.252 3032-3032/com.hgy.ndk I/MethodInvocationStub: IInputMethodManager.windowGainedFocus(android.view.inputmethod.InputMethodManager$1@358dfeb, android.view.ViewRootImpl$W@35f9e4a, 260, 32, -2122252032, android.view.inputmethod.EditorInfo@c711676, null) => InputBindResult{null com.android.inputmethod.latin/.LatinIME sequence:29 userActionNotificationSequenceNumber:1}
08-26 02:25:24.270 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityIdle(android.os.BinderProxy@d9c3789, {1.0 310mcc260mnc en_US ldltr sw392dp w392dp h713dp 440dpi nrml long port finger -keyb/v/h dpad/v s.6}, false) => void
08-26 02:25:24.271 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityIdle(android.os.BinderProxy@a58f8af, {1.0 310mcc260mnc en_US ldltr sw392dp w392dp h713dp 440dpi nrml long port finger -keyb/v/h dpad/v s.6}, false) => void
08-26 02:25:24.306 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowSession.relayout(android.view.ViewRootImpl$W@7ad160, 0, null, 1080, 2160, 8, 0, Rect(0, 0 - 1080, 2160), Rect(0, 0 - 0, 0), Rect(0, 66 - 0, 132), Rect(0, 66 - 0, 132), Rect(0, 66 - 0, 132), Rect(0, 0 - 0, 0), {1.0 310mcc260mnc en_US ldltr sw392dp w392dp h713dp 440dpi nrml long port finger -keyb/v/h dpad/v}, Surface(name=null)/@0xbbb6953) => 5
08-26 02:25:24.326 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityStopped(android.os.BinderProxy@a58f8af, Bundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@9ae7868, 2131165190=android.support.v7.widget.Toolbar$SavedState@692481, 2131165192=android.view.AbsSavedState$1@9ae7868, 2131165198=android.view.AbsSavedState$1@9ae7868, 2131165232=android.view.AbsSavedState$1@9ae7868}}], android:fragments=android.app.FragmentManagerState@2aa0926}], null, null) => void
其中参数为
null
会被截取打印成ul
,如Os.getuid(ul) => 10058
参考 VirtualApp之Activity栈