virtualapp-啓動VA中安裝的app

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一起傳到VAMSstartActivity中,代碼如下:

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記錄, 對應系統ActivityStackArrayList<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
   ...
 }
  1. 創建一個ActivityRecord targetRecordtargetRecord內部存儲了前面提到的ActivityInfo數據和intent,並設置了targetRecord.component=ComponentInfo{com.hgy.ndk/com.hgy.ndk.MainActivity}
  2. 調用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);
}
  1. 調用VAMS.startProcessIfNeedLocked

VAMS.startProcessIfNeedLocked根據包名首先取得 PackageSetting psApplicationInfo info數據, 這些數據在安裝時就會被保存。
然後創建一個新的ProcessRecord app,ProcessRecord 記錄了 ApplicationInfo infovuid等信息。並通過mProcessNamesmPidsSelfLocked記錄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;

—>由VAMSinitProcess發起的啓動新進程: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系統函數設置,這個在後續分析。
之後進入ShadowContentProvidercall初始化, 取得由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, IVClientIApplicationThread都賦值給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中調用。

  1. 調用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 記錄了 前面提到的intentActivityInfo infouserIdtargetRecord所有數據。

繼續回到上層函數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了,這裏可以提前解釋下,在後面的HCallbackStubLAUNCH_ACTIVITY中有如下代碼:

   ActivityThread.ActivityClientRecord.intent.set(r, intent);
   ActivityThread.ActivityClientRecord.activityInfo.set(r, info);

其中intent是原始的,這裏可以貼下改變前面的值:
在這裏插入圖片描述
調用 ActivityThread.ActivityClientRecord.intent.set(r, intent)改變後:
在這裏插入圖片描述
也就是在啓動activity前,又換回原始的intentinfo數據,從而正常啓動。

在lulubox4.3的插件化中有類似的實現: 位於plugin-base-cmplugin-host-libraryAndroidHack.java

這時VA中設置的hook函數開始準備攔截了。

2.hook 函數處理

hook函數框架可以參考InvocationStubManager相關

2.0 預先處理的hook函數

startActivity後到HCallbackStubLAUNCH_ACTIVITY之前要處理幾個函數的hook:

2.0.1 addPackageDependency

mInitialApplication = LoadedApk.makeApplication中會調用getClassLoadergetClassLoader內部會調用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就直接使用系統的,否則和VAMSstartActivity類似,使用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.Hcallback函數,實現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就是我們前面VAMSstartActivity傳出的destIntent, 如下所示:
在這裏插入圖片描述
所以就可以在這裏把VAMS中綁定的StubActivityRecordintent(原始的)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線程中調用bindApplicationNoCheckbindApplicationNoCheck主要完成了以下任務:

  1. setupUncaughtHandler 設置異常捕獲,由外部VCore設置CrashHandler,內部默認沒有設置。
  2. fixInstalledProviders會檢查我們的provider,如果authority不是io.busniess.va.virtual_stub_開頭,則利用ProviderHook生成provider代理取代原始的provider。理論上都是以io.busniess.va.virtual_stub_開頭。
  3. VDeviceManager.get().applyBuildProp設置虛擬的設備信息。
  4. VirtualCore.mainThreadmInitialApplication變量設置爲null。
  5. 設置InstalledAppInfo,ApplicationInfo, List<ProviderInfo>等基礎數據到VClient中。
  6. 通過VirtualRuntime.setupRuntime改變進程的argv[0] 參數爲進程名(com.hgy.ndk), 設置app名字爲進程名(com.hgy.ndk)。
    原始的app名字爲io.busniess.va:p0
  7. 設置AlarmManager.mTargetSdkVersion 爲被安裝apk的targetSdkVersion,原始值爲va的targetSdkVersion
  8. 設置系統緩存的臨時目錄爲/data/data/io.busniess.vatools/virtual/data/user/userId/packageName/cache, userId爲0,1,…。
  9. 調用startIORelocaterstartIORelocater的作用就是可以在java層設置路徑白名單,黑名單,要替換的名單,然後把這些路徑列表傳到NDK層,並hook所有的帶路徑的libc函數以及linker下的dlopen函數,並在hook函數中對路徑做相應放過,禁止,替換。
  10. 調用launchEngine替換java native函數對應的NDK jni函數
  11. 設置codeCacheDir/data/data/io.busniess.va/virtual/data/user/0/com.hgy.ndk/code_cache
  12. AppBindData mBoundApplication傳入ActivityThread.mBoundApplication對象,即 設置appInfoprocessNameinstrumentationNameinfo等到對象, 其中info由臨時創建的context獲取。
  13. 設置LoadedApk.mSecurityViolationfalse
  14. 調用VMRuntime.setTargetSdkVersion設置 targetSdkVersion
  15. 調用AppCallback.beforeStartApplication對外接口,可以看出傳出的context爲前面臨時創建的。
  16. 利用LoadedApk.makeApplication創建mInitialApplication,並設置到ActivityThread.mInitialApplication中。
  17. 利用ContextFixerContextImpl.mBasePackageNameContextImplKitkat.mOpPackageNameContentResolverJBMR2.mPackageName的包名(原始爲com.hgy.ndk)改爲io.busniess.va
  18. 調用AppCallback.beforeApplicationCreate對外接口。
  19. 調用 mInstrumentation.callApplicationOnCreate會首先把ActivityThread.mInstrumentation替換成VClient的mInstrumentation
  20. 調用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.redirectFileNativeEngine.redirectDirectoryNativeEngine.forbidNativeEngine.whitelistNativeEngine.enableIORedirect
四者 用於區分傳入的是文件和文件夾在於路徑最後有沒有/

NativeEngine.forbid最終調到NDK的jni_nativeIOForbidjni_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_nativeIOWhitelistjni_nativeIOWhitelist把傳入的路徑統一加入到keep_items數組中,forbidden_items數組同樣由PathItem構成,和上面的加入類似。

NativeEngine.redirectFileNativeEngine.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保存,再調用startIOHookhook所有的包含路徑的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邏輯如下:

  1. 使用canonicalize_path把路徑轉成規範的路徑,比如傳入的路徑可能有//這種重複斜槓或./
  2. keep_items(白名單,對應上層的 NativeEngine.whitelist)中遍歷,看是否符合,如符合,直接返回原始路徑。
  3. forbidden_items(黑名單,對應上層的 NativeEngine.forbid)中遍歷,看是否符合,如符合,直接返回NULL
  4. replace_items(替換名單, 對應上層的NativeEngine.redirectFileNativeEngine.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, 不同版本的linkerdlopen對應的symbol不同,這個可以通過IDA來查看確認。

startIORelocater的作用是可以在java層設置路徑白名單,黑名單,要替換的名單,然後把這些路徑列表傳到NDK層,並hook所有的帶路徑的libc函數以及linker下的dlopen函數,並在hook中對路徑做相應放過,禁止,替換。

2.1.1.3 launchEngine

NativeEngine.launchEngine會調用jni_nativeLaunchEngine, 傳入參數如下:

1> method:java層的native函數列表:

  1. gOpenDexFileNative: DexFile.javaopenDexFileNative函數地址
  2. gCameraNativeSetup: Camera.javanative_setup函數地址
  3. gAudioRecordNativeCheckPermission: AudioRecord.javanative_check_permission函數地址
  4. gMediaRecorderNativeSetup: MediaRecorder.javanative_setup函數地址
  5. gAudioRecordNativeSetup: AudioRecord.javanative_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 函數的封裝, 邏輯如下:

  1. 自定義一個空的hook函數mark, 並RegisterNatives綁定NativeEngine.nativeMarkmark。然後遍歷計算NativeEngine.nativeMarkmark的偏移,參考函數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;
        }
}
  1. 以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主要完成了以下任務:

  1. hook Binder.javagetCallingUid,調用NativeEngine. onGetCallingUid返回自定義的Uid
  2. hook DexFile.javaopenDexFileNative, 調用NativeEngine. onOpenDexFileNative
  3. hook Camera.javanative_setup, 替換它的String參數爲傳入的包名
  4. hook MediaRecorder.javanative_setup, 替換它的String參數爲傳入的包名
  5. hook AudioRecord.javanative_setup, 替換它的String參數爲傳入的包名
  6. 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

這個函數首次觸發是在前面提到的initProcessProviderCall.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, 如果我們沒有安裝過,但是屬於以下三類:

  1. va自身
  2. 系統app
  3. 使用外部包的app, 其中3的解釋如下
    比如內部微信調用QQ分享,但是內部沒有QQ,如果沒用addVisibleOutsidePackage,那麼提示沒有安裝QQ,如果用了addVisibleOutsidePackage,則屬於外部包,啓動外部的QQ
    這三類都會通過ComponentFixer.fixOutsideApplicationInfoApplicationInfo.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

參考 VirtualApp之Activity棧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章