Activityの起動プロセスのstartActivityソース解析
57756 ワード
転載は出典を明記してください.http://blog.csdn.net/guangzq/article/details/74295752祝起光のブログより
一.概要
本明細書ではapi 24 startActivity簡略化版フローチャートに基づく
二.ソース解析
startActivityを入口として
方法:Activity->startActivity
最終的な方法はすべて呼び出したstartActivity ForResultです.続けてみてください.
方法:Acticity->startActivity ForResult
本当にActivityを開くのはexecStartActivityで実現されている以上、execStartActivityを見てみましょう.
方法:Instrumentation->execStartActivity
補足checkStartActivity Resultメソッドは,内部実装が様々な場合に投げ出す必要がある異常情報である.
前述のstartActivityに続いて、ActivityManagerNativeクラスにおける内部クラスActivityManagerProxyを定義するインタフェースIActivityManagerを定義する方法である
方法:Activity Management Proxy->startActivity
パラメータは多く、ここではIApplicationThreadパラメータに重点を置いており、インタフェースであり、重要な方法はscheduleLaunchActivityであり、実現と継承は以下の通りである.
方法:Activity Thread->ApplicationThread->scheduleLaunchActivity
この方法は主にactivityの様々なパラメータを記録し、activityを起動するメッセージを送信し、このメッセージの実装を見る.
本格的な処理がActivityのロジックを起動した
方法:ActvityThread->performLaunchActivity
performLaunchActivityの主な論理は3つあります. Activityの起動に関する情報を解析し、componentとpackageInfo を含む. ClassLoaderを介してターゲットactivityをロードし、activityオブジェクト をインスタンス化する mInstrumentationのcallActivity OnCreateによってターゲットactivityのonCreateメソッドを間接的に呼び出し、activityの宣言サイクルを実行します.
3.まとめ
startActivity全体のソースコード解析はこれで終わり、よく使われているapiについてもっと深く認識したのではないでしょうか.
一.概要
本明細書ではapi 24 startActivity簡略化版フローチャートに基づく
二.ソース解析
startActivityを入口として
方法:Activity->startActivity
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
@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) {
startActivityForResult(intent, requestCode, null);
}
最終的な方法はすべて呼び出したstartActivity ForResultです.続けてみてください.
方法:Acticity->startActivity ForResult
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
//mParent ActivityGroup, ActivityGroup , Activity
if (mParent == null) {
// Activity, mMainThread.getApplicationThread()。Instrumentation system application 。 activity
// Instrumentation
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
// onActivityResult
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.
// : result acitity , onCreate onResume acticity ,
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
//ActitityGroup Activity ,
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);
}
}
}
本当にActivityを開くのはexecStartActivityで実現されている以上、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);
}
if (mActivityMonitors != null) {
synchronized (mSync) {
// ActivityMonitor, Activity
final int N = mActivityMonitors.size();
for (int i=0; ifinal ActivityMonitor am = mActivityMonitors.get(i);
if (am.match(who, null, intent)) {
am.mHits++;
// // monitor activity , Activity return
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
//
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
// startActivity , whoThread scheduleLaunchActivity
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
// Activity , Activity AndroidManifest ,
// “...have you declared this activity in your AndroidManifest.xml?”
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
補足checkStartActivity Resultメソッドは,内部実装が様々な場合に投げ出す必要がある異常情報である.
public static void checkStartActivityResult(int res, Object intent) {
if (res >= ActivityManager.START_SUCCESS) {
return;
}
switch (res) {
case ActivityManager.START_INTENT_NOT_RESOLVED:
case ActivityManager.START_CLASS_NOT_FOUND:
if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
throw new ActivityNotFoundException(
"Unable to find explicit activity class "
+ ((Intent)intent).getComponent().toShortString()
+ "; have you declared this activity in your AndroidManifest.xml?");
throw new ActivityNotFoundException(
"No Activity found to handle " + intent);
case ActivityManager.START_PERMISSION_DENIED:
throw new SecurityException("Not allowed to start activity "
+ intent);
case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw new AndroidRuntimeException(
"FORWARD_RESULT_FLAG used while also requesting a result");
case ActivityManager.START_NOT_ACTIVITY:
throw new IllegalArgumentException(
"PendingIntent is not an activity");
case ActivityManager.START_NOT_VOICE_COMPATIBLE:
throw new SecurityException(
"Starting under voice control not allowed for: " + intent);
case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
throw new IllegalStateException(
"Session calling startVoiceActivity does not match active session");
case ActivityManager.START_VOICE_HIDDEN_SESSION:
throw new IllegalStateException(
"Cannot start voice activity on a hidden session");
case ActivityManager.START_CANCELED:
throw new AndroidRuntimeException("Activity could not be started for "
+ intent);
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
}
}
前述のstartActivityに続いて、ActivityManagerNativeクラスにおける内部クラスActivityManagerProxyを定義するインタフェースIActivityManagerを定義する方法である
方法:Activity Management Proxy->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;
}
パラメータは多く、ここではIApplicationThreadパラメータに重点を置いており、インタフェースであり、重要な方法はscheduleLaunchActivityであり、実現と継承は以下の通りである.
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread
private class ApplicationThread extends ApplicationThreadNative
方法:Activity Thread->ApplicationThread->scheduleLaunchActivity
@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 pendingResults, List pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
この方法は主にactivityの様々なパラメータを記録し、activityを起動するメッセージを送信し、このメッセージの実装を見る.
private class H extends 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);
// LAUNCH_ACTIVITY
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
}
本格的な処理がActivityのロジックを起動した
方法:ActvityThread->performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
// Activity , component packageInfo
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
// ClassLoader activity , activity
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
// Application
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
TAG, r + ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + r.packageInfo.getPackageName()
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());
if (activity != null) {
// activity
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
// context activity attach 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);
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()) {
// mInstrumentation callActivityOnCreate 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;
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);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
performLaunchActivityの主な論理は3つあります.
3.まとめ
startActivity全体のソースコード解析はこれで終わり、よく使われているapiについてもっと深く認識したのではないでしょうか.