훅 메커니즘 학습(3) - weishu 블로그 학습 노트(AMS & PMS 훅)
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);
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.