一個月左右寫了圖像顯示深刻學習之文章開篇文章代表了本身近期的計劃,前半年從新學習了opengl es,c++以及Linux的一些知識,以爲是時候開始看圖像這一塊的源碼了,邊看邊補缺補漏吧。java
做爲該系列文章的第一篇開篇,總以爲仍是應該從Activity開始提及,畢竟圖像模塊跟Activity是分不開的。剛畢業時候也寫過Activity對應的文章,結果忘了放哪了,這裏就從新梳理一遍,加深記憶吧。ios
文章基於8.0源碼研究分析c++
文章思路基於三個方面依次進行研究學習:安全
從最開始接觸Acvtivity類從startActivity(...)
開始,那麼直接從這個方法若是追溯一下Activity啓動的運做過程。startActivity(...)
的實現類在ContextWrapper
中,由Activity繼承ContextThemeWrapper
進行重寫,關於Context的總結圖(圖片來自郭霖巨巨)以下:網絡
實現源碼以下所示:app
//Activity.java ... @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); } } ... 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); .... } ...
方法內部調用mInstrumentation.execStartActivity()
進行進一步處理。mMainThread是ActivityThread類的實例,一個應用程序對應着一個ActivityThread,ActvityThread能夠當作應用程序主線程理解。ApplicationThread爲ActivityThread的內部類,其繼承自IApplicationThread.Stub,是一個Binder對象,從Stub關鍵字就能夠推斷出,一個ActivityThread都有一個ApplicationThread,主要負責跟其它進程進行通訊。mToken來自於ActivityClientRecord.token變量,表明一個Binder對象,這個暫時推斷不出做用,先暫時留着。ide
mInstrumentation爲Instrumentation類實例,Instrumentation類用於監控應用程序和系統的交互(在Mainfest文件中,咱們能夠聲明Instrumentation節點來作一些事)。execStartActivity(...)
方法以下:學習
//Instrumentation.java 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); //whoThread爲ActivityThread中的ApplcaitionThread 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; }
方法中調用ActivityManager.getService()
得到一個IActivityManager,IActivityManager自己是一個aidl文件,文件路徑在/frameworks/base/core/app目錄下。ActivityManager中具體代碼實現以下:ui
//ActivityManager.java 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; } };
IActivityManager的實現類由ActivityManagerService擔任,在AMS源碼中能夠看到其繼承了IActivityManager.Stub。AMS與應用程序在不一樣的進程內,因此使用了Binder機制進行通訊。到此爲止,startActivity()在應用進程中的源碼走讀就已經完成了,接下來的工做交付給了AMS進行處理。this
在AMS中的startActivity(...)
實現以下:
//AMS.java @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()); } @Override public final int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) { enforceNotIsolatedCaller("startActivity"); //確認安全性 userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivity", null); // TODO: Switch to user app stacks here. return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, null, null, bOptions, false, userId, null, null, "startActivityAsUser"); }
這裏調到了mActivityStarter.startActivityMayWait(...)
中,ActivityStarter在AMS初始化時一同被初始化,其掌管着AMS內部處理Activity的start的邏輯。在研究以前先整理一下PackageInfo,ActivityInfo,ResolveInfo等的意義。
PackageInfo中包含的ActivityInfos,ServicesInfos,ApplicationInfo等信息,通常咱們經過PackManager能夠獲取到PackageInfo。
下面繼續查看mActivityStarter.startActivityMayWait(...)
,具體方法以下:
final int startActivityMayWait(IApplicationThread caller, int callingUid, String callingPackage, Intent intent, String resolvedType, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, WaitResult outResult, Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId, IActivityContainer iContainer, TaskRecord inTask, String reason) { ... //步驟1.解析獲取當前的ResolveInfo ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId); ... //步驟2.獲取要啓動的Activity的信息 ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo); ActivityOptions options = ActivityOptions.fromBundle(bOptions); //傳入的iContainer爲null ActivityStackSupervisor.ActivityContainer container = (ActivityStackSupervisor.ActivityContainer)iContainer; ... final ActivityRecord[] outRecord = new ActivityRecord[1]; //步驟3 int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, outRecord, container, inTask, reason); ... return res; } }
這一塊的代碼比較複雜,但也是核心的代碼,直接挑選重要的代碼片斷分析,較爲無關的這裏就略過了。
首先看步驟1,能夠了解的是該步驟的做用是爲了獲取一個ResolveIntent,調用mSupervisor.resolveIntent(...)
的方法內部會經過mService.getPackageManagerInternalLocked()
調用LocalService獲取PackageManagerInternal實現類PackageManagerInternal(該類實如今PackageManagerService內部),繼而調用其resolveIntent(...)
,最終解析得到ResolveIntent,關於內部的邏輯不深究進去,日後若是深刻再繼續研究便可。
步驟2獲取對應啓動的Activitynfo,在獲取ResolveInfo階段,其實就把對應的Activitynfo解析獲取到了,mSupervisor.resolveIntent(...)
會根據ResolveInfo獲取Activitynfo。
步驟3調用startActivityLock(....)
方法,該方法內會進而調用startActivity(...)
方法,在startActivity(...)
中會進行一些校驗性的工做,如目標Activity的合法性,Activity是否須要對應權限等等,而且還會爲原來的Activity生成一個ActivityRecord對象記錄對應信息,傳遞給下一層startActivity(...)
方法(這裏有兩個startActivity方法,不是筆誤),第二個startActivity(...)
中調用startActivityUnchecked(...)
:
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity) { //從新計算糾正mLaunchFlags,即LauchMode computeLaunchingTaskFlags(); //context.satrtActivityForResult(...)會用到,這裏不介紹 computeSourceStack(); mIntent.setFlags(mLaunchFlags); //獲取重用的ActivityRecord,主要在於咱們設置了NEW_TASK的IntentFlag的重用,能夠想一想singleTask的LaunchMode就能理解 ActivityRecord reusedActivity = getReusableIntentActivity(); //因爲咱們分析的場景在標準的LaunchMode下,因此忽略reusedActivity的處理 ... //mStartActivity賦值爲了r ... //singleTop下的處理忽略 final ActivityStack topStack = mSupervisor.mFocusedStack; final ActivityRecord topFocused = topStack.topActivity(); final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop); ... boolean newTask = false; final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null) ? mSourceRecord.getTask() : null; // Should this be considered a new task? int result = START_SUCCESS; if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) { newTask = true; result = setTaskFromReuseOrCreateNewTask( taskToAffiliate, preferredLaunchStackId, topStack); } else if (mSourceRecord != null) { result = setTaskFromSourceRecord(); } else if (mInTask != null) { result = setTaskFromInTask(); } else { // This not being started from an existing activity, and not part of a new task... // just put it in the top task, though these days this case should never happen. setTaskToCurrentTopOrCreateNewTask(); } if (result != START_SUCCESS) { return result; } ... mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition, mOptions); //mDoResume爲真 if (mDoResume) { final ActivityRecord topTaskActivity = mStartActivity.getTask().topRunningActivityLocked(); if (!mTargetStack.isFocusable() || (topTaskActivity != null && topTaskActivity.mTaskOverlay && mStartActivity != topTaskActivity)) { .... } else { // If the target stack was not previously focusable (previous top running activity // on that stack was not visible) then any prior calls to move the stack to the // will not update the focused stack. If starting the new activity now allows the // task stack to be focusable, then ensure that we now update the focused stack // accordingly. if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) { mTargetStack.moveToFront("startActivityUnchecked"); } mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions); } } else { mTargetStack.addRecentActivityLocked(mStartActivity); } ... return START_SUCCESS; }
上面仍是進行了一系列驗證工做而後調用到了 mSupervisor.resumeFocusedStackTopActivityLocked(...)
中:
boolean resumeFocusedStackTopActivityLocked() { return resumeFocusedStackTopActivityLocked(null, null, null); } boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { ... mFocusedStack.resumeTopActivityUncheckedLocked(null, null); } boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { if (mStackSupervisor.inResumeTopActivity) { ... result = resumeTopActivityInnerLocked(prev, options); ... } private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { ... mStackSupervisor.startSpecificActivityLocked(next, true, true); ... } //ActivityStackSupervisor.java void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { ... realStartActivityLocked(r, app, andResume, checkConfig); ... } final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException { ... //r.appToken是一個window manager token app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global and // override configs. mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo); ... }
通過一系列的調用,最終調用到了ActivityStackSuperviosr中的realStartActivityLocked(...)
方法中,在方法內調用了app.thread.scheduleLaunchActivity(....)
方法,在跟蹤代碼的過程當中會遇到關鍵幾個類,這裏總結一下:
總結一張圖(圖片來自網絡,侵刪)以下:
繼續分下,上面的app爲ProcessRecord,記錄中一個活動進程中的全部信息,app中的thread參數爲IApplicationThread,對應着ApplicationThread,也就是咱們一開始分析過的類,這裏回調scheduleLaunchActivity(...)
方法,即回調到客戶端進程中。
到這裏,由應用進程通知到對應ActivityManagerService後在AMS中的實現的源碼流程就串聯完畢了。對應的UML圖走一波:
從第二階段的分析後,咱們知道回調到了應用進程中的ApplicationThread.scheduleLaunchActivity(...)
方法:
// we use token to identify this activity without having to send the // activity itself back to the activity manager. (matters more with ipc) @Override public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) { updateProcessState(procState, false); //組裝一個ActivityClientRecord ActivityClientRecord r = new ActivityClientRecord(); //由AMS進程傳來的window manager token,這裏能夠解決上面提出的疑問了 r.token = token; ... sendMessage(H.LAUNCH_ACTIVITY, r); }
最終調到mH實例中,mH是一個Handler實現類,那麼這裏就知道回到了主線程當中,代碼實現以下:
public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { case LAUNCH_ACTIVITY: { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); final ActivityClientRecord r = (ActivityClientRecord) msg.obj; r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null, "LAUNCH_ACTIVITY"); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; .... }
再次調到了handleLaunchActivity(...)
:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) { ... //這個到時候研究圖像一塊會用到 WindowManagerGlobal.initialize(); //步驟1 Activity a = performLaunchActivity(r, customIntent); if (a != null) { ... //步驟2 handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason); ... }
這段代碼中主要分兩個步驟進行:
步驟1中調用performLaunchActivity (...)
對新啓動的Activity作初始化,主要代碼以下:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ... ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); ... Application app = r.packageInfo.makeApplication(false, mInstrumentation); ... if (activity != null) { CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (r.overrideConfig != null) { config.updateFrom(r.overrideConfig); } ... appContext.setOuterContext(activity); 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, r.configCallback); ... int theme = r.activityInfo.getThemeResource(); if (theme != 0) { activity.setTheme(theme); } activity.mCalled = false; if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } ... if (!r.activity.mFinished) { activity.performStart(); r.stopped = false; } if (!r.activity.mFinished) { if (r.isPersistable()) { if (r.state != null || r.persistentState != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState); } } else if (r.state != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } if (!r.activity.mFinished) { activity.mCalled = false; if (r.isPersistable()) { mInstrumentation.callActivityOnPostCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnPostCreate(activity, r.state); } ... return activity; }
該方法中主要涵蓋以下幾個初始化的過程:
activity.attach(...)
方法設置Activity的內部變量。onCreate(...)
,onStart(...)
,onRestoreInstanceState(...)
,onPostCreate(...)
這裏主要看activity.attach(...)
方法吧:
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) { ... mWindow = new PhoneWindow(this, window, activityConfigCallback); mWindow.setWindowControllerCallback(this); mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); ... mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); if (mParent != null) { mWindow.setContainer(mParent.getWindow()); } mWindowManager = mWindow.getWindowManager(); mCurrentConfig = config; mWindow.setColorMode(info.colorMode); }
主要的就是PhoneWindow在Activity調用attach(...)方法進行了初始化的工做,接來的文章須要用到該模塊的知識,因此在此記錄一下。
步驟2中調用handleResumeActivity (...)
:
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) { ActivityClientRecord r = mActivities.get(token); ... // TODO Push resumeArgs into the activity for consideration r = performResumeActivity(token, clearHide, reason); if (r != null) { final Activity a = r.activity; ... final int forwardBit = isForward ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0; //Activity中的mStartedActivity表明是requestCode是否大於0,在咱們分析的情境下爲false,那麼willBeVisible=true boolean willBeVisible = !a.mStartedActivity; ... //此時的r.window爲null if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow();//PhoneWindow View decor = r.window.getDecorView();//獲取DecorView decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; ... //mVisibleFromClient描述一個應用程序窗口是不是可見的 if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; //添加DecorView到window中 wm.addView(decor, l); } else { a.onWindowAttributesChanged(l); } } ... if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { ... WindowManager.LayoutParams l = r.window.getAttributes(); if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != forwardBit) { l.softInputMode = (l.softInputMode & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)) | forwardBit; //更新 if (r.activity.mVisibleFromClient) { ViewManager wm = a.getWindowManager(); View decor = r.window.getDecorView(); wm.updateViewLayout(decor, l); } } //設置可見 if (r.activity.mVisibleFromClient) { r.activity.makeVisible(); } } ... }
這裏作兩件事情,第一件爲回調activity.onResume(...)
方法,第二件是主要是對視圖進行更新的操做,涉及的類爲WindowManger,下面的章節介紹,這裏不細說。activity.onResume(...)
調用的位置在performResumeActivity(...)
中:
public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide, String reason) { ActivityClientRecord r = mActivities.get(token); ... r.activity.performResume(); synchronized (mResourcesManager) { for (int i = mRelaunchingActivities.size() - 1; i >= 0; i--) { final ActivityClientRecord relaunching = mRelaunchingActivities.get(i); if (relaunching.token == r.token && relaunching.onlyLocalRequest && relaunching.startsNotResumed) { relaunching.startsNotResumed = false; } } } ... return r; }
到此爲止,從Context.startActvity(...)
的調用到Activity.onResume(..)
的過程就已經分析完畢了。
上述的分析大致清理了一下Context.startActvity(...)
的調用到Activity.onResume(..)
的脈絡,涉及的知識點也不少,其中包括Binder機制,Activity的四大啓動模式(LaunchMode),PackageRecord,ResolveInfo等等存儲的信息以及Handler機制的運用等等等,相較於之前寫的文章,整體上的理解也更加深入了一些,證實本身的努力沒有白費吧,技術的路上仍是要RTFC。