文章目录
1.新进程启动流程
以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<TaskRecord> mTaskHistory = new 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函数开始准备拦截了。
2.hook 函数处理
hook函数框架可以参考InvocationStubManager相关
2.0 预先处理的hook函数
在startActivity后到HCallbackStub的LAUNCH_ACTIVITY之前要处理几个函数的hook:
2.0.1 addPackageDependency
在 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);
}
2.0.2 startService
如果是va自身的service就直接使用系统的,否则和VAMS中startActivity类似,使用VAMS中的startService,先自己起一个子进程p0(如果p0被占用就依此类推),再 intent.setClassName(com.lody.virtual.client.stub.ShadowService$P0, serviceName);绑定到子进程。
2.0.3 getContentProvider
根据名字判断如果是va自身的contentprovider就直接使用系统的,否则和前面的一样,使用VAMS中的initProcess,先自己起一个子进程p0(如果p0被占用就依此类推), 然后把getContentProvider的第二个参数name设置为io.busniess.vatools.virtual_stub_${vpid}。
2.0.4 getRunningAppProcesses
首先取得运行进程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;
2.1 client进程的HCallbackStub
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拦截。
2.1.1 LAUNCH_ACTIVITY消息
首先到达的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消息。之后调用
2.1.1.1 bindApplication初始化
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<ProviderInfo>等基础数据到VClient中。 - 通过
VirtualRuntime.setupRuntime改变进程的argv[0]参数为进程名(com.hgy.ndk), 设置app名字为进程名(com.hgy.ndk)。
原始的app名字为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对外接口。
2.1.1.2 startIORelocater重定位
仍以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中对路径做相应放过,禁止,替换。
2.1.1.3 launchEngine
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 函数的封装, 逻辑如下:
- 自定义一个空的hook函数
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;
}
}
- 以hook
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主要完成了以下任务:
- hook Binder.java中
getCallingUid,调用NativeEngine. onGetCallingUid返回自定义的Uid - hook DexFile.java中
openDexFileNative, 调用NativeEngine. onOpenDexFileNative - hook Camera.java中
native_setup, 替换它的String参数为传入的包名 - hook MediaRecorder.java中
native_setup, 替换它的String参数为传入的包名 - hook AudioRecord.java中
native_setup, 替换它的String参数为传入的包名 - hook Runtime.java中的
nativeLoad, 替换它的文件路径
launchEngine的作用是替换java native函数对应的ndk层jni函数,具体如上所述。
2.2.x进程中hook 函数处理
2.2.1. IActivityManager.overridePendingTransition
在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);
}
2.2.2. IActivityManager.getRecentTasks
判断取得的 List<ActivityManager.RecentTaskInfo>是否有我们自定义的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;
2.2.3. IActivityManager.getContentProvider
这个函数首次触发是在前面提到的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
2.3.Os.getuid
取得原始系统分配的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
}
2.1. IPackageManager.getApplicationInfo
默认返回我们VPMS中创建的ApplicationInfo, 如果我们没有安装过,但是属于以下三类:
- va自身
- 系统app
- 使用外部包的app, 其中3的解释如下
比如内部微信调用QQ分享,但是内部没有QQ,如果没用addVisibleOutsidePackage,那么提示没有安装QQ,如果用了addVisibleOutsidePackage,则属于外部包,启动外部的QQ
这三类都会通过ComponentFixer.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;
}
3. 打印hook的函数
我们可以把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
964

被折叠的 条评论
为什么被折叠?



