徹底搞懂AMS即ActivityManagerService,看這一篇就夠了
前言
最近那么多教學視頻(特別是搞車載的)都在講AMS,可能這也跟要快速啟動一個app(甚至是提高安卓系統啟動速度有關),畢竟作為安卓系統的核心系統服務之一,AMS以及PMS都是很重要的,而我之前在 應用的開端–PackageManagerService(PMS) 已經很詳細地講解過PMS,大家有興趣的可以去看看。
我們都知道當手機開機時,或者是安裝某個apk時,PMS會去掃描加載/data/app目錄和system/app里每個apk里的所有類信息并且進行解析,然后緩存到PMS它自己里面定義好的集合里,供AMS使用,AMS即ActivityManagerService就能根據PMS里面的這些類信息來進行創(chuàng)建入口Activity等四大組件類并啟動。下面將詳細講解AMS是怎樣工作的。
提示:以下是本篇文章正文內容
一、回顧PackageManagerService
講AMS之前,還是得回顧一下PMS的工作流程,PMS會把每個apk進行掃描,然后分別把每個apk里的信息都緩存在mPackages集合里:
它是PackageParser.Package類型,所以我們看看這個類里的內容:
public final static class Package implements Parcelable {
@UnsupportedAppUsage
public String packageName;
// The package name declared in the manifest as the package can be
// renamed, for example static shared libs use synthetic package names.
public String manifestPackageName;
...
// For now we only support one application per package.
@UnsupportedAppUsage
public ApplicationInfo applicationInfo = new ApplicationInfo();
@UnsupportedAppUsage
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
@UnsupportedAppUsage
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
@UnsupportedAppUsage
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
@UnsupportedAppUsage
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
@UnsupportedAppUsage
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
@UnsupportedAppUsage
public final ArrayList<Service> services = new ArrayList<Service>(0);
@UnsupportedAppUsage
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
@UnsupportedAppUsage
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
...
}
明顯可以看到這些集合都是分別緩存四大組件以及一些權限以及跳轉意圖等信息,每個apk對應一個Package:
Package是在PMS里,而PMS又是作為一個對象被SystemServer所擁有,SystemServer進程是被zygote進程所開啟的,而
zygote進程又是給init進程孵化的:
init進程是安卓手機開機后第一個啟動的進程:
我們可以從系統源碼中看看它的配置腳本文件init.rc寫了什么內容:
# Copyright (C) 2012 The Android Open Source Project
#
# IMPORTANT: Do not create world writable files or directories.
# This is a common source of Android security bugs.
#
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc
on early-init
# Set init and its forked children's oom_adj.
write /proc/1/oom_score_adj -1000
# Disable sysrq from keyboard
write /proc/sys/kernel/sysrq 0
# Set the security context of /adb_keys if present.
restorecon /adb_keys
# Shouldn't be necessary, but sdcard won't start without it. http://b/22568628.
mkdir /mnt 0775 root system
# Set the security context of /postinstall if present.
restorecon /postinstall
start ueventd
on init
sysclktz 0
# Mix device-specific information into the entropy pool
copy /proc/cmdline /dev/urandom
copy /default.prop /dev/urandom
# Backward compatibility.
symlink /system/etc /etc
symlink /sys/kernel/debug /d
# Link /vendor to /system/vendor for devices without a vendor partition.
symlink /system/vendor /vendor
# Mount cgroup mount point for cpu accounting
mount cgroup none /acct cpuacct
mkdir /acct/uid
# Create energy-aware scheduler tuning nodes
mkdir /dev/stune
mount cgroup none /dev/stune schedtune
mkdir /dev/stune/foreground
mkdir /dev/stune/background
mkdir /dev/stune/top-app
...
它里面是配置服務的邏輯,很多手機廠商在這里設置它們專屬的一些常駐服務的地方,就是在這里改動的,其中可以看到這里
import /init.${ro.zygote}.rc
配置了zygote進程,引入了zygote.rc文件,我們來看看32位下的zygote.rc文件:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
代碼很少,但可以看到,這里面它啟動了zygote進程服務的main方法。
那么再來總結一下整個系統啟動流程:
SystemServer的啟動服務、核心服務以及其他服務如下源碼所示啟動,啟動服務就包括PMS和AMS等這些服務:
...
// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
...
startBootstrapServices()方法里就是啟動AMS和PMS等:
...
// Activity manager runs the show.
traceBeginAndSlog("StartActivityManager");
// TODO: Might need to move after migration to WM.
ActivityTaskManagerService atm = mSystemServiceManager.startService(
ActivityTaskManagerService.Lifecycle.class).getService();
mActivityManagerService = ActivityManagerService.Lifecycle.startService(
mSystemServiceManager, atm);
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
mWindowManagerGlobalLock = atm.getGlobalLock();
traceEnd();
...
traceBeginAndSlog("StartPackageManagerService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
traceEnd();
...
但這里要注意的是PMS和AMS它們是作為一個對象被SystemServer所持有的:
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
main()方法只是一個普通的構造PackageManagerService它自己對象的方法,它是直接new的,并沒有開啟單獨的進程,AMS也是如此:
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
}
...
startService(service);
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
它也只是通過反射去實例化自己,而且都是在SystemServer里進行的。以下這些服務對象都被SystemServer所持有:
// TODO: remove all of these references by improving dependency resolution and boot phases
private PowerManagerService mPowerManagerService;
private ActivityManagerService mActivityManagerService;
private WindowManagerGlobalLock mWindowManagerGlobalLock;
private WebViewUpdateService mWebViewUpdateService;
private DisplayManagerService mDisplayManagerService;
private PackageManagerService mPackageManagerService;
private PackageManager mPackageManager;
...
既然我們都知道PMS會去掃描Apk文件,那么它的掃描方法就是使用Packageparser掃描的,最終得到Package:
所以我們完全可以通過反射PackageParser,然后調用它的parsePackage方法,傳apk路徑進去,然后得到Package對象,拿到這個Package對象后,你就可以通過DexClassLoader配合著Package對象去反射構造你想要的apk里的類對象,這樣一種思路是可以被用到很多應用場景的,比如熱修復、插件化以及換膚功能等。
DexClassLoader dexClassLoader = new DexClassLoader("apk路徑","apk被緩存后的dex文件路徑"
,null,classLoader類加載器 );
Class clazz = dexClassLoader.loadClass("要反射的類全類名路徑");
...
這樣就已經相當于把一個apk文件里的某個類文件對象給找出來了,當然還有很多細節(jié)以及具體用法就靠大家去自己琢磨了。
所以,總的來說,PMS它只是把apk里也就是清單文件里定義的四大組件以及一些權限、意圖信息等緩存在它里面的Package類里,然后供AMS去迅速定位到某一個類,然后創(chuàng)建它和啟動它,這樣就能確保我們啟動App時不會耗時太長。
二、ActivityManagerService
當我們安卓手機開機成功后,就處在桌面上,我們點擊某個app的圖標時,Launcher進程就會請求SystemServer進程里的AMS去創(chuàng)建這個app的入口(啟動)Activity,這時AMS就會請求zygote進程去孵化出該app應用進程:
只要是跟zygote進程通信的都采用socket方式之外,其他進程互相通信都是采用binder方式。使用過binder來進行進程間通信都知道,binder相當于強引用,客戶端能直接獲取到服務端引用,從而可直接接觸到服務端進程對象及其方法,從安全方面考慮這樣是不安全的;另外,zygote進程一旦掛掉,會影響到整個系統重啟,因此不能讓其他進程能輕易影響到zygote進程,本身Socket就相當于弱引用,只通過參數進行通信,安全性就較強,因此就采用socket方式來跟zygote進程通信。
我們來看看zygote進程的main方法:
@UnsupportedAppUsage
public static void main(String argv[]) {
ZygoteServer zygoteServer = null;
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
// Zygote goes into its own process group.
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
Runnable caller;
...
ZygoteServer里可以看到有一個叫LocalServerSocket變量:
/**
Server socket class for zygote processes.
Provides functions to wait for commands on a UNIX domain socket,
and fork off child processes that inherit the initial state of the VM.%
Please see ZygoteArguments for documentation on the client protocol.
*/
class ZygoteServer {
// TODO (chriswailes): Change this so it is set with Zygote or ZygoteSecondary as appropriate
public static final String TAG = "ZygoteServer";
...
/** The default value used for the USAP_POOL_SIZE_MIN device property */
private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1";
...
*/
private LocalServerSocket mZygoteSocket;
/**
* The name of the unspecialized app process pool socket to use if the USAP pool is enabled.
*/
private LocalServerSocket mUsapPoolSocket;
...
LocalServerSocket就是Socket對象:
package android.net;
...
/**
* Non-standard class for creating an inbound UNIX-domain socket
* in the Linux abstract namespace.
*/
public class LocalServerSocket implements Closeable {
private final LocalSocketImpl impl;
private final LocalSocketAddress localAddress;
/** 50 seems a bit much, but it's what was here */
private static final int LISTEN_BACKLOG = 50;
/**
* Creates a new server socket listening at specified name.
* On the Android platform, the name is created in the Linux
* abstract namespace (instead of on the filesystem).
*
* @param name address for socket
* @throws IOException
*/
public LocalServerSocket(String name) throws IOException
{
...
}
...
Launcher進程請求AMS創(chuàng)建該app進程的入口Activity時,AMS會請求Zygote進程孵化出該app應用進程先,然后AMS就會通過binder方式去跟該app應用進程進行通信,也就是在app應用進程里通過ActivityThead去創(chuàng)建入口Activity并啟動:
這里要注意的是app進程是不能逆向跟zygote通信,zygote是單向孵化出app進程,所以它們不是雙向的。只有一些系統服務進程才能直接跟zygoet通信。
三、源碼
接下來我們將從源碼的角度去分析整個啟動過程,首先來看整個過程的時序圖:
Launcher首先會去調用啟動Activity方法,由于第一次點擊啟動活動肯定是為空(就算是不為空),最終還是會去調用Instrumentation的execStartActivity()方法:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
點進去看該方法execStartActivity(),里面也是調用了一個ActivityTaskManager.getService()的startActivity()方法:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
而這里的getService返回的是IActivityManager對象,它其實是Binder接口對象,通過它可以拿到AMS對象:
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
所以現在就可以調用AMS的startActivity方法:
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
系統中的所有應用進程都是由Zygote進程fork出來的,SystemServer進程是系統進程,它里面有很多系統服務,例如ActivityManagerService、PackageManagerService、WindowManagerService等等都是存在SystemServer進程被創(chuàng)建后啟動;ActivityManagerServices(AMS)是一個服務端對象,負責所有的Activity的生命周期,AMS通過Binder機制與App應用進程通信,那就代表App應用進程是能夠拿到AMS對象,而AMS也就能調度App進程去創(chuàng)建Activity等這些組件并且啟動它們。
而ActivityThread是App應用進程里的類,是UI線程/主線程,它的main()方法是APP的真正入口;ApplicationThread是一個實現了IBinder接口的ActivityThread內部類,它跟ActivityThread之間是通過Handler機制通信的,這樣ApplicationThread就能讓ActivityThread和AMS的所在進程間通信(也就是應用進程與SystemServer進程通信);Instrumentation可以理解為ActivityThread的一個工具類,在ActivityThread中初始化,一個進程只存在一個Instrumentation對象,負責調用Activity的生命周期方法:
public void callActivityOnCreate(Activity activity, Bundle icicle,
PersistableBundle persistentState) {
prePerformCreate(activity);
activity.performCreate(icicle, persistentState);
postPerformCreate(activity);
}
activity隨后就執(zhí)行它的生命周期方法:
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
...
if (persistentState != null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle);
}
...
}
說到這里,我們也可以去看看29以下的版本的源碼是怎樣的,比如23里的Instrumentation調用的execsStartActivity方法:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess();
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
它的調用是由ActivityManagerNative.getDefault()來執(zhí)行,那么來跟蹤一下getDefault()方法:
//Retrieve the system's default/global activity manager.
static public IActivityManager getDefault() {
return gDefault.get();
}
這個gDefault是一個內部類,而且是static修飾的:
我們點進去看它的詳情:
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
它是一個抽象類Singleton,繼續(xù)看這個類的詳情:
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
看它的get方法,就可以推測到,它實際上就是一個單例,只不過是由實現它之后子類自己實現的create方法來決定具體邏輯,那么就來看實現了它的IActivityManager的create方法:
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
可以看到,里面是調用了ServiceManager.getService()方法。那么現在來看,當我們的App應用進程調用gDafault.get()方法時,返回的是一個單例對象Singleton,而這個單例對象對應的也就是IActivityManager對象(因為IActivityManager實現了Singleton),它在這里構造時如果是空的,則會調用抽象方法create方法生成,而具體的create實現方法里調用了ServiceManager的getService方法,這樣就通過IBinder擁有了AMS的引用了。
值得一提的是,作為app應用開發(fā)者,我們可以使用反射去獲取Singleton的mInstance變量,因為mInstance它就是AMS,而且它是單例的,即只有一份:
public abstract class Singleton<T> {
private T mInstance;
...
}
四、Hook
既然我們上面說到了可以去反射Singleton的mInstance變量,從而得到AMS,這個過程實際上就是常說的Hook技術。Hook技術其實是在A與B交流的過程中,在中途把消息給攔截,然后再做一些自定義操作,最后再把消息給傳去給B:
不過記住的是,hook之后,不能影響到后續(xù)流程,也就是說你的hook處理怎么處理都行,但不能影響到整個流程,否則就會導致整個流程錯亂而跑不動了,因為這是一個一環(huán)扣一環(huán)的流程,你現在是從中間hook進來,做了一些額外的處理,勢必會影響到流程,因此你的處理流程里必須要讓hook之后回到原來的流程順序,從而保證程序能繼續(xù)運行。
而hook一般是hook系統進程,這才有意義:
一般來說,自己開發(fā)的應用不需要hook,因為源碼就是我們自己寫的,直接使用就可以,而一些系統應用因為安全性是不直接開放給開發(fā)者的,但有時又確實是需要使用它里面的一些功能,那這時候就可以去hook它們,因此hook可以分類為:
1)根據Hook的API語言劃分(Hook Java、Hook Native)
2)根據Hook的進程劃分(應用進程、全局)
3)根據Hook的實現方式劃分
去hook java相對來說會比較容易,使用反射和代理實現,從而修改SDK代碼的執(zhí)行流程。
我們來看看怎么去hook一下AMS啟動應用的入口Activity流程,我們現在假設找到了系統的源碼,其中ActivityManager類如下(一段偽代碼):
//系統層
public class ActivityManager {
public IActivityManager activityManager = new IActivityManager();
class IActivityManager{
private String managerName;
...
}
...
}
它已經在我們應用中開始前就在系統里運行,該IActivityManager對象已經在內存中存在,而現在我們應用層里無論怎么new它,或者使用反射去構造它,都不是原來那個運行著的系統對象,我們構造的只是一個在應用層里全新的一個對象,因此這樣是不能夠hook AMS啟動應用的入口Activity的流程,也就是沒有hook點。那這種情況下要怎么去hook呢?答案是用static去修飾IActivityManager:
//系統層
public class ActivityManager {
public static IActivityManager activityManager = new IActivityManager();
class IActivityManager{
private String managerName;
...
}
}
這時應用層里,可以通過反射去獲取這個靜態(tài)對象,因為它是static修飾,只有一份,因此不管你是不是一早就在內存里運行還是后來構造,整個內存都是只此一份,它也就是系統進程里獨有的那個對象了。
所以hook點往往就是去hook那些static修飾的對象,因為只有一份,所以可以使用反射去獲取它,同理我們也可以這樣使用hook去獲取AMS對象。
我們在上文分析源碼時知道,gDefalut里的mInstance是AMS對象,是單例的,只有一份,因此可以反射來獲取它:
Field gDefault = null;
Class<?> ActivityManagerNativecls = Class.forName("android.app.ActivityManagerNative");
gDefault = ActivityManagerNativecls.getDeclaredField("gDefault");
gDefault.setAccessible(true);
Object defaultValue = gDefault.get(null);
Class<?> SingletonClass = Class.forName("android.util.Singleton");
Field mInstance = SingletonClass.getDeclaredField("mInstance");
mInstance.setAccessible(true);
先獲取gDefalut變量,然后再獲取Singleton變量,最后獲取它的mInstance變量對象即ActivityManager對象:
Object iActivityManagerObject = mInstance.get(defaultValue);
這樣也就獲得了AMS對象了。不過這是在安卓23版本的情況下的hook邏輯,當回到安卓28版本的時候,這時源碼有變動了,變成:
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
此時gDefalut變成了IActivityManagerSingleton,因此反射時就要做版本適配了,根據版本號的不同來反射對應的變量,進而取出它那唯一的AMS變量:
Field gDefault = null;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
Class<?> ActivityManagerNativecls = Class.forName("android.app.ActivityManagerNative");
gDefault = ActivityManagerNativecls.getDeclaredField("gDefault");
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
Class<?> activityManager = Class.forName("android.app.ActivityManager");
gDefault = activityManager.getDeclaredField("IActivityManagerSingleton");
} else {
//其他版本就交給大家自行去研究源碼了
}
...
繼續(xù)上面講到的拿到AMS對象后,我們就可以使用動態(tài)代理(之后會更新一篇專門講動態(tài)代理的文章,感興趣的大家可繼續(xù)期待)的方式來處理AMS對象了:
...
Object iActivityManagerObject = mInstance.get(defaultValue);
Class<?> IActivityManagerIntercept = Class.forName("android.app.IActivityManager");
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{IActivityManagerIntercept}, new AmsInvocationHandler(iActivityManagerObject));
mInstance.set(defaultValue, proxy);
class AmsInvocationHandler implements InvocationHandler {
private Object iActivityManagerObject;
public AmsInvocationHandler(Object iActivityManagerObject) {
this.iActivityManagerObject = iActivityManagerObject;
}
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
//Hook邏輯
return method.invoke(iActivityManagerObject,args);
}
}
使用動態(tài)代理是為了不影響到AMS對象,把處理過程都放在處理器來處理,起到隔離作用,還能監(jiān)聽AMS對象所執(zhí)行的方法。當啟動程序后,調用了hook方法后,系統使用AMS調用的方法都一一交由invoke方法去監(jiān)聽,然后我們返回method的invoke()方法讓它繼續(xù)執(zhí)行,不斷監(jiān)聽。
PMS同樣也是可以hook的,因為它也是static修飾的,只有一份:
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}
反射方式去獲取PMS對象跟AMS一樣:
// 獲取全局的ActivityThread對象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
Object currentActivityThread = currentActivityThreadMethod.invoke(null);//得到ActivityThread對象
// 獲取ActivityThread里面原始的 sPackageManager
Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
sPackageManagerField.setAccessible(true);
Object sPackageManager = sPackageManagerField.get(currentActivityThread);
...
//使用動態(tài)代理處理sPackageManager
然后同樣使用動態(tài)代理去接收與處理PMS對象:
class HookPmsHandler implements InvocationHandler {
private Object iPmsObject;
public HookHandler(Object iPmsObject) {
this.iPmsObject= iPmsObject;
}
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
Log.i("david","----------------pms------------ "+method.getName());
return method.invoke(iPmsObject,args);
}
}
這樣就能監(jiān)聽到PMS的執(zhí)行方法了。如果想獲取完整的hook代碼可以關我公號Pingred
現在我們通過動態(tài)代理來監(jiān)聽它整個啟動流程會執(zhí)行的各種方法,那其中肯定也包括startActivity方法,那我們自然就能利用它來修改Activity之間跳轉的邏輯,比如現在當我從MainActivity跳轉到TwoActivity時根據是否登錄狀態(tài)來決定要跳轉到登錄頁面還是直接跳轉到TwoActivity,那么上面AMS的動態(tài)代理方法就會觸發(fā),而我們就監(jiān)聽startActivity的方法,因為AMS肯定是會調用這個方法的,然后再判斷此時登錄狀態(tài)來進行對應的跳轉邏輯。
這樣就可以僅僅在一個地方進行管理和判斷所有Activity的登錄狀態(tài),然后實現是否要跳轉的集中式登錄判斷功能,這是非常好用的,這樣也就不需要在每個Activity上都要進行判斷,不過要注意的是我們上面已經講到了hook的原則,就是處理了你要處理的邏輯之后,還要讓它的后續(xù)流程能順利執(zhí)行下去,所以上面例子要修改跳轉到哪個Activity上可以通過修改它的Intent意圖參數來實現。還有很多這樣的場景就交由讀者自己去琢磨了。
五、總結
整個app啟動過程,所有參與的類以及它們的關系流程:文章來源:http://www.zghlxwxcb.cn/news/detail-529644.html
當點擊應用圖標的那刻起,Launcher進程會去發(fā)送請求AMS要啟動Activity(通過Binder方式通信),AMS這時會通過Socket方式請求Zygote去創(chuàng)建應用進程,應用進程被Zygote孵化后,應用進程就會通過binder方式去請求AMS通信,然后AMS就開始從PMS里去獲取需要啟動的Activity里的信息,然后把這些信息都通過binder方式發(fā)送給應用進程,應用進程里的ApplicationThread接受到后,就會通過Handler方式發(fā)送給ActivityThread去創(chuàng)建與啟動Activity,之后的具體實現就是由ActivityThread的Instrumentation去實現,進而啟動Activity。文章來源地址http://www.zghlxwxcb.cn/news/detail-529644.html
到了這里,關于手把手帶你搞懂AMS啟動原理的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!