훅 메커니즘 학습(3) - weishu 블로그 학습 노트(AMS & PMS 훅)

5624 단어

1: 훅 AMS


1.1 이론적 기초인ActivityManagerNative는ActivityManagerService라는 원격 대상의Binder 프록시 대상이다.AMS와 접촉해야 할 때마다 이 프록시 대상이 드라이브를 통해 IPC 호출을 완성해야 한다.예를 들어 Activity를 시작할 때 Activity ManagerNative를 통해getDefault() .startActivity()가 Activity 시작 요청을 Activity Manager Service에 전달
public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    // ...  
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess();
        // ----------------look here!!!!!!!!!!!!!!!!!!!
        int result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
    }
    return null;
}

ActivityManagerNative.getDefault (): gDefault이 호출되었습니다.get()
static public IActivityManager getDefault()
 {
     return gDefault.get();
 }

gDefault: gDefault는 하나의 예입니다.저장된 개체는 Iactivity Manager 단일 예입니다.실제로 ActivityManagerProxy가 반환됩니다.Ibinder b는 누드 Binder 객체로, 원격의 Binder 객체가 Binder 드라이브를 통해 전환된 후 App 프로세스로 되돌아오는 객체입니다.
private static final Singleton gDefault = new Singleton() {
      protected IActivityManager create() {
           IBinder b = ServiceManager.getService("activity");
     // IBinder b  Binder , Binder Binder App  。
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
          }
            IActivityManager am = asInterface(b);
            // ActivityManagerProxy
           if (false) {
               Log.v("ActivityManager", "default service = " + am);
           }
            return am;
       }
    };
}


1.2 훅 AMS에서 우리가 사용하는 AMS는 실제로Activity Manager Proxy이다. 훅을 떨어뜨리려면 훅이 gDefault에 단일 대상을 저장하면 된다.gDefault를 통해 얻을 수 있는 단일 예를 훅 대상으로 합니다. 싱글튼의 mInstance 필드를 훅 대상으로 설정해야 합니다.
Class> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");

//   gDefault  ,  
Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");
gDefaultField.setAccessible(true);
Object gDefault = gDefaultField.get(null);

// 4.x gDefault  android.util.Singleton ;  
Class> singleton = Class.forName("android.util.Singleton");
Field mInstanceField = singleton.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);

// ActivityManagerNative  gDefault  IActivityManager 
Object rawIActivityManager = mInstanceField.get(gDefault);

//  ,  ,  
Class> iActivityManagerInterface = Class.forName("android.app.IActivityManager");
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
        new Class>[] { iActivityManagerInterface }, new IActivityManagerHandler(rawIActivityManager));
mInstanceField.set(gDefault, proxy);

2. 훅 PMS


ContextImpl.getPackage Manager() PMS는 ContextImpl을 통해 가져옵니다.getPackage Manager에서 가져옵니다. mPackage Manager는 정적 필드가 아닙니다.그래서 이게 좋은 훅이 아니라 포장 대상인 Application Package Manager로 돌아가는 거예요.
public PackageManager getPackageManager() {
    if (mPackageManager != null) {
        return mPackageManager;
    }

    IPackageManager pm = ActivityThread.getPackageManager();
    if (pm != null) {
        // Doesn't matter if we make more than one instance.
        return (mPackageManager = new ApplicationPackageManager(this, pm));
    }
    return null;
}

ActivityThread.getPackage Manager () 는 서비스 매니저를 사용하여 IPackager Manager sPackage Manager를 가져옵니다.Activity Thead의 정적 필드입니다. 이 정적 필드를 훅에서 떨어뜨려서 훅이 PMS를 떨어뜨리는 목적을 달성합니다.Context 클래스의 getPackage Manager 방법을 통해 얻을 수 있는ApplicationPackage Manager 대상의 mPM 필드도 Hook이 필요합니다.
public static IPackageManager getPackageManager() {
    if (sPackageManager != null) {
        return sPackageManager;
    }
    IBinder b = ServiceManager.getService("package");
    sPackageManager = IPackageManager.Stub.asInterface(b);
    return sPackageManager;
}

훅 코드
//  ActivityThread 
Class> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
Object currentActivityThread = currentActivityThreadMethod.invoke(null);

//  ActivityThread  sPackageManager
Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
sPackageManagerField.setAccessible(true);
Object sPackageManager = sPackageManagerField.get(currentActivityThread);

//  ,  
Class> iPackageManagerInterface = Class.forName("android.content.pm.IPackageManager");
Object proxy = Proxy.newProxyInstance(iPackageManagerInterface.getClassLoader(),
        new Class>[] { iPackageManagerInterface },
        new HookHandler(sPackageManager));

// 1.  ActivityThread  sPackageManager  
sPackageManagerField.set(currentActivityThread, proxy);

// 2.   ApplicationPackageManager  mPM 
PackageManager pm = context.getPackageManager();
Field mPmField = pm.getClass().getDeclaredField("mPM");
mPmField.setAccessible(true);
mPmField.set(pm, proxy);

좋은 웹페이지 즐겨찾기