- 你想要找的activity知識都在這里了
- 一份超詳細的Fragment知識總結
- FragmentManager與FragmentTransaction底層實作
- Android 系統啟動程序詳解
- Activity 啟動程序詳解(上)
App 啟動 Activity 時,需要向系統發送請求啟動信號,處理該請求的服務就是 AMS (ActivityManagerService),這個操作是跨行程的,想想 上一篇 說的, init 決議 rc 腳本啟動 Zygote,其所在行程 app_process (后改名 zygote )的 ZygoteInit 通過 forkSystemServer 創建一個行程,來啟動各種系統服務,這里就包含 AMS;而 ZygoteInit 又通過 forkAndSpecialize 為每個新啟動的應用程式生成自己獨立的行程,并在 handleChildProc 方法中運行應用程式本身的代碼,所以說啟動 Activity 的程序是跨行程的,
我們通過 startActivity 方法來啟動一個 Activity ,這里以顯示呼叫為例:
Intent intent = new Intent(this, DemoActivity.class);
startActivity(intent);
① android.app.Activity#startActivity,startActivity 有幾種多載方法,但都會呼叫 startActivityForResult 方法,
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
② android.app.Activity#startActivity(Intent intent, @Nullable Bundle options)
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
③ android.app.Activity#startActivityForResult , 這里只需要關注 mParent == null 的即可,mParent 代表的是 ActivityGroup, ActivityGroup 開始被用來在一個界面中嵌入多個子 Activity,但在 API 13 被廢棄了,被 Fragment 代替,
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());
}
...
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
...
}
}
④ android.app.Instrumentation#execStartActivity ,之后就會跨行程呼叫 ActivityManagerService 的 startActivity 方法了(在 android10 內,AMS 的 startActivity 又會呼叫 mActivityTaskManager.startActivity ,將啟動 Activity 的任務交給 ATMS),具體代碼實作見下, checkStartActivityResult 方法的作用是檢查啟動 Activity 的結果,當無法正常啟動一個 Activity 時,會拋出例外資訊,這就不再細看了,
@UnsupportedAppUsage
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.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;
}
⑤ 接著分析上面的 ActivityTaskManager.getService() 方法,其中 Singleton 是單例模式類,當呼叫 get() 方法時,會進行內部判斷:如果該物件已存在,則直接回傳現有值,否則通過呼叫 create() 方法創建并回傳 IActivityTaskManager 物件 ,
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};
⑥ 在這里是通過 ServiceManager.getService 來獲取 ActivityManagerService 的 IBinder 物件的,當其中 sCache 用于記錄 getService 的歷史查詢結果,getService 每次都會首先在這里翻閱記錄,以加快查詢速度,如果不存在,則通過 rawGetService 方法內的 getIServiceManager().getService(name) 向 SM 發起查詢,
@UnsupportedAppUsage
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
private static IBinder rawGetService(String name) throws RemoteException {
final long start = sStatLogger.getTime();
final IBinder binder = getIServiceManager().getService(name);
...
return binder;
}
⑦ getIServiceManager 方法首先會判斷 sServiceManager 是否為空,防止多次重復操作,之后通過 ServiceManagerNative.asInterface 來獲取一個 IServiceManager 物件,這個 IServiceManager 物件就是負責與 Binder 驅動通信的 SM 代理 ServiceManagerProxy,具體代碼見下:
@UnsupportedAppUsage
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
⑧ asInterface 方法負責將 Binder 物件轉換成 IServiceManager,并在必要的時候創建 ServiceManagerProxy,這就是我們 ServiceManager 的代理,來負責與 Binder 驅動通信,
@UnsupportedAppUsage
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IServiceManager in =
(IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ServiceManagerProxy(obj);
}
⑨ 在回到上面的 rawGetService 方法內的 getIServiceManager().getService(name) 方法,通過 SM 代理的 getService 方法,首先通過 Parcel 打包資料;接著通過 IBinder 的 transact 將請求發送出去,具體會通過 jni 呼叫對應的 BpBinder,進而使用 ProcessState 和 IPCThreadState 的相關介面,完成與 SM 的通信;之后就可以獲取到結果了(這里的 IBinder 就是 AMS 的IBinder 物件了),因為這里是一種阻塞式函式呼叫,因為是行程間通信,結果并不會馬上就能獲取到,所以 Binder 驅動會先將呼叫者執行緒掛起,直到有了結果才會將它喚醒,
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
public IBinder asBinder() {
return mRemote;
}
@UnsupportedAppUsage
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
...
@UnsupportedAppUsage
private IBinder mRemote;
}
⑩ allowBlocking 的作用是判斷當前 IBinder 是否為 BinderProxy,是則改變 mWarnOnBlocking 標志位,
public static IBinder allowBlocking(IBinder binder) {
try {
if (binder instanceof BinderProxy) {
((BinderProxy) binder).mWarnOnBlocking = false;
} else if (binder != null && binder.getInterfaceDescriptor() != null
&& binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
Log.w(TAG, "Unable to allow blocking on interface " + binder);
}
} catch (RemoteException ignored) {
}
return binder;
}
}
? 接下來我們就來看 AMS 內 startActivity 是如何實作的呢?能夠看到 AMS 將實作委托給了 ATMS,這樣做的好處是職責變得更單一了,避免 AMS 過于臃腫,符合 OO 設計原則,
@Override
public int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return mActivityTaskManager.startActivity(caller, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions);
}
ActivityTaskManagerService 的 startActivity 方法又會呼叫 startActivityAsUser 方法:
@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());
}
? 這是 startActivityAsUser 的方法:其中 getActivityStartController() 方法會回傳當前持有的 ActivityStartController 物件,obtainStarter 方法會呼叫 ActivityStarter 內部類 DefaultFactory 的 .obtain() 方法創建 ActivityStarter 物件,隨后呼叫ActivityStarter 的 setIntent(intent).setReason(reason) 等的屬性賦值,最后呼叫 ActivityStarter 的 execute 方法,這里就不展示代碼了,
int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
boolean validateIncomingUser) {
...
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setMayWait(userId)
.execute();
}
? 其中 setMayWait 方法,會將 ActivityStarter 內部類 Request 的 mayWait 欄位設定為 true :
ActivityStarter setMayWait(int userId) {
mRequest.mayWait = true;
mRequest.userId = userId;
return this;
}
? checkTargetUser 方法內,其中 validateIncomingUser 為 true, targetUserId 是當前呼叫者的用戶ID 值,由 UserHandle.getCallingUserId() Binder 機制獲取,UserHandle 是 aidl 檔案,handleIncomingUser 會檢查呼叫者是否有權利執行這一操作,
int checkTargetUser(int targetUserId, boolean validateIncomingUser,
int realCallingPid, int realCallingUid, String reason) {
if (validateIncomingUser) {
return mService.handleIncomingUser(
realCallingPid, realCallingUid, targetUserId, reason);
} else {
mService.mAmInternal.ensureNotSpecialUser(targetUserId);
return targetUserId;
}
}
? 這是 ActivityStarter 的 execute 的方法,會呼叫 startActivityMayWait 方法,mRequest.mayWait 是前面提到的啟動引數,
int execute() {
try {
if (mRequest.mayWait) {
return startActivityMayWait(...);
} else {
...
} finally {
onExecutionComplete();
}
}
? 在 startActivityMayWait 方法內,會呼叫 26 個引數的 startActivity 方法,接著會呼叫 10 個引數的 startActivity 方法,接著會呼叫 startActivityUnchecked 方法,然后會呼叫 mTargetStack.startActivityLocked 方法,這樣就將 Activity 的啟動程序轉移到了 ActivityStack ,
Todo: startActivityLocked 邏輯復雜,下篇會結合啟動模式,來梳理下 AMS 是如何恢復上層 Activity 和 新舊 Activity 切換,并通知給呼叫者的,
參考
1、林學森,深入理解 Android 內核設計思想:人民郵電出版社
2、任玉剛,Android 開發藝術探索:中國工信出版集團
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/46325.html
標籤:其他
下一篇:用兩個堆疊實作佇列
