主目錄見:Android高級進階知識(這是總目錄索引)
?今天開始我們將漸漸進入Framework的學習,然后進而為以后的插件化做準備,要學會如何開發一套插件化框架,顯然這是第一步,我們今天就來講講應用程序內啟動Activity的流程,首先呢,我先把整個流程的圖給大家看看,以便于大家學習源碼的時候能有一個對照:
從圖中可以看出,我們的中間跨進程交互都是用的AIDL的知識,如果大家不了解AIDL的話,那么我推薦看下從framework分析AIDL生成文件這篇文章或者看下更基礎點的文章,大家自己決定,想必大家看完應該會知道。
一.目標
分析源碼當然得有目標,我們的目標很明確:
1.了解整套Activity的啟動過程;
2.為插件化框架開發做準備知識。
二.啟動流程分析
我們先來明確下應用程序Activity啟動的兩個主要方式:
1.在Home桌面點擊應用程序圖標啟動程序即launcher啟動程序的主Activity。
2.在應用程序中調用startActivity()和startActivityForResult()來啟動另外一個Activity。這個應用程序可以位于同個應用程序或者其他應用程序。
我們今天主要是講第二種方式
public class MainActivity extends Activity implements OnClickListener {
......
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,TargetActivity.class);
startActivity(intent);
}
}
1.因為MainActivity繼承了Activity所以我們看Activity的startActivity()方法,然后經過startActivityForResult和execStartActivity最終會調用到Instrumentation的execStartActivity:
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);
}
//省略掉自動測試所添加的ActivityMonitor類相關代碼
.........
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
//獲取遠程AMS(ActivityManagerService)
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
//檢查Activity啟動是否成功
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
這里我們要注意這里面傳的參數,這樣我們接下來要走的話不會迷失:
whoThread:Binder對象,是主進程的Context對象;
token:一個Binder對象,指向了服務端一個ActivityRecord對象;
target:目標Activity即要啟動的Activity;
options:要傳輸的Bundle對象,里面攜帶數據。
2 .我們程序這里的ActivityManagerNative.getDefault()這里獲取到的是ActivityManagerService的遠程接口的代理即ActivityManagerProxy對象(如果不清楚可以看下AIDL的相關知識),所以這里的就是調用ActivityManagerProxy的startActivity方法:
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
這里的參數也比較多,這里的resolvedType,resultWho,profilerInfo均為null,參數caller為ApplicationThread類型的Binder實體,resultTo是為一個Binder實體的遠程接口,參數requestCode為-1,startFlags為0,options為null。最后通過ActivityManagerProxy對象調用startActivity方法的實質是調用BinderProxy.transact向Binder驅動發送START_ACTIVITY_TRACSACTION命令。然后我們應用程序就到AMS中了。
3.過Binder驅動程序就進入到ActivityManagerService的startActivity方法來了,我們來看看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());
}
4.我們看到這個方法又調用了內部的startActivityAsUser然后會調用ActivityStarter(這個類是新版的android我這里版本是android-25才有的)的一系列方法:startActivityMayWait=>startActivityLocked=>startActivityUnchecked然后會到達ActivityStackSupervisor類的resumeFocusedStackTopActivityLocked方法接著到達ActivityStack類的resumeTopActivityUncheckedLocked=>resumeTopActivityInnerLocked接著又會走到ActivityStack類的resumeTopActivityInnerLocked方法然后會先調用startPausingLocked來停掉前面一個Activity即前一個Activity要先執行onPause方法:
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming, boolean dontWait) {
........
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
........
}
5.這里的prev.app.thread是一個ApplicationThread對象的遠程接口,通過調用這個遠程接口的schedulePauseActivity(ApplicationThreadProxy.schedulePauseActivity)來通知前面一個Activity進入Paused狀態。我們這里指的這里也是一個AIDL交互,我們不詳細說明,我們直接看ActivityThread中的schedulePauseActivity方法:
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
int seq = getLifecycleSeq();
if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this
+ " operation received seq: " + seq);
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
configChanges,
seq);
}
6.這里的sendMessage是發送一條消息,主要是發送到內部類H里面的handleMessage方法里面這里的消息code是PAUSE_ACTIVITY:
case PAUSE_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != 0, args.argi2,
(args.argi1 & DONT_REPORT) != 0, args.argi3);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
7.這樣程序就調用了handlePauseActivity方法:
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport, int seq) {
ActivityClientRecord r = mActivities.get(token);
..........
// Tell the activity manager we have paused.
if (!dontReport) {
try {
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
mSomeActivitiesChanged = true;
}
}
8.我們看到程序通過AIDL( ActivityManagerNative.getDefault()獲取的是AMS的遠程代理)調用到AMS的activityPaused方法:
@Override
public final void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
stack.activityPausedLocked(token, false);
}
}
Binder.restoreCallingIdentity(origId);
}
9.我們看到這里調用了ActivityStack的activityPausedLocked方法:
final void activityPausedLocked(IBinder token, boolean timeout) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
"Activity paused: token=" + token + ", timeout=" + timeout);
final ActivityRecord r = isInStackLocked(token);
if (r != null) {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if (mPausingActivity == r) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + r
+ (timeout ? " (due to timeout)" : " (pause complete)"));
completePauseLocked(true, null);
return;
} else {
..........
}
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
10.我們看到程序這里會調用completePauseLocked方法來停止然后接著調用ActivityStackSupervisor類的resumeFocusedStackTopActivityLocked方法接著到達ActivityStack類的resumeTopActivityUncheckedLocked=>resumeTopActivityInnerLocked接著又會走到ActivityStack類的resumeTopActivityInnerLocked方法然后又轉到ActivityStackSupervisor類的startSpecificActivityLocked:
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.task.stack.setLaunchTime(r);
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
11.前面首先會判斷要啟動的Activity的進程是否啟動起來了,如果已經啟動起來了會直接調用realStartActivityLocked,進行Activity的啟動就可以了。但是如果我們配置了process這個屬性,由于這是我們第一次啟動Activity,所以進程還是沒有開啟的,所以我們程序會調用AMS的startProcessLocked方法:
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */,
null /* entryPoint */, null /* entryPointArgs */);
}
我們認真注意傳進來的參數分別是什么值其中entryPoint為null,然后我們直接看另一個startProcessLocked方法:
ActivityManagerService.startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs){
......
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
......
}
所以在調用上面方法的時候這里因為entryPoint傳過來的是null的,所以我們的entryPoint是為android.app.ActivityThread的值,這個時候我們通過Process.start()傳入的第一個參數是android.app.ActivityThread,這個參數在我們進程啟動完成之后,來決定后續代碼的執行 。
12.我們知道android的進程是通過zygote孵化出來的,而ActivityManagerService是運行在System進程,Zygote是運行在Zygote進程中的。Process.start方法的實現是在zygoteSendArgsAndGetResult函數最終實現的,是向socket服務端寫數據,把創建進程的請求通過socket通訊方式來讓zygote的管理進程創建新進程。在向zygote進程發送的通信請求時,需要組裝數據,具體實現我們看Process類的start方法:
private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
//省略參數拼裝的一些方法
.............
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
以上的方法省略了一些拼裝參數的方法,程序最終調用zygoteSendArgsAndGetResult()方法來向socket服務端發送創建進程的請求,這樣zygote就會來創建新的進程。
private static ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
// Throw early if any of the arguments are malformed. This means we can
// avoid writing a partial response to the zygote.
int sz = args.size();
for (int i = 0; i < sz; i++) {
if (args.get(i).indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx("embedded newlines not allowed");
}
}
/**
* See com.android.internal.os.ZygoteInit.readArgumentList()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure, followed by boolean to
* indicate whether a wrapper process was used.
*/
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
writer.flush();
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
13.這里就會向我們的zygote發送一個創建進程請求。然后創建新的進程就會在zygote進行,這里我們不過多去解析zygote怎么創建新的進程。最后程序會在ActivityStackSupervisor的attachApplicationLocked方法里面調用realStartActivityLocked方法:
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
......
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
......
}
14.這里的app.thread是ApplicationThread,所以這里會調用ApplicationThread的scheduleLaunchActivity方法最后調用到ActivityThread的handleLaunchActivity方法:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
.......
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
.......
} else {
// If there was an error, for any reason, tell the activity manager to stop us.
try {
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
15.我們看到上面方法里面會調用performLaunchActivity方法,這個方法就是真正啟動Activity了,我們看下這個具體方法:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
Activity activity = null;
try {
//這里調用Instrumentation的newActivity來創建一個新的Activity
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
......
} catch (Exception e) {
......
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
........
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
if (r.isPersistable()) {
//這個方法里面會調用目標Activity的onCreate方法
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
r.stopped = true;
.......
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
......
}
return activity;
}
16.我們看到這個方法就是真正創建Activity的地方了,首先會調用Instrumentation的newActivity方法:
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
17.這里很容易看懂就是用類加載器加載一個新的class,然后返回他的實例。到這一步Activity的實例也就被創建出來了,接著我們看會調用Activity的onCreate方法,這個會在Instrumentation的callActivityOnCreate方法里面:
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
我們看到這個方法里面會調用activity的performCreate方法,這個方法如下:
final void performCreate(Bundle icicle) {
restoreHasCurrentPermissionRequest(icicle);
onCreate(icicle);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
到這里我們的Activity就啟動完畢了,如果你中間有什么過程不懂的可以參照我們前面畫的圖來對照,基本流程就知道了,也不至于被繞暈。
總結:這次的Activity啟動講解主要是讓大家有個流程上的認識,到時如果在插件化框架上有用到我會認真把某一個地方拿出來講解,如果有講解的不對的地方歡迎大家指出哈,希望大家共同進步。