アクティビティの起動#
// 指定されたアクティビティを起動する
void startBootActivity() {
Intent i = new Intent(this, BootActivity.class);
startActivity(i);
}
アクティビティが ActivityTaskManagerService を呼び出す#
アクティビティは ActivityTaskManagerService に直接接触することはなく、Instrumentation を介して Activity#startActivity メソッドを呼び出します:最終的には Activity#startActivityForResult メソッドに導かれ、Instrumentation を介してアクティビティの起動を要求します。
ここでの重要な点は、現在のプロセスの ApplicationThread が渡されることです。もう一つは mToken
パラメータで、これは現在のアプリケーションが AMS 内で ActivityManager の代表を表します。
// Activity.java
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
...省略部分のインターフェース {
/*package*/ ActivityThread mMainThread;
private Instrumentation mInstrumentation;
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
&& mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
... 省略部分
}
// @ startActivityForResult の分析
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1);
}
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
// @ Instrumentation#execStartActivity 関数を追跡、mMainThread は ActivityThread
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
// @ getApplicationThread メソッドを確認
this, mMainThread.getApplicationThread(),
mToken, // IBinder 型、ActivityRecord の代理オブジェクト
this,
intent, requestCode, options);
... 省略部分
} else {
... 省略部分
}
}
}
// ---------------------------------------------------------
// ActivityThread .java
public final class ActivityThread extends ClientTransactionHandler
implements ActivityThreadInternal {
// アプリケーションスレッドは一つだけ
final ApplicationThread mAppThread = new ApplicationThread();
public ApplicationThread getApplicationThread()
{
return mAppThread;
}
private class ApplicationThread extends IApplicationThread.Stub {
... 省略詳細
}
}
アクティビティの要求はすべて Instrumentation クラスを介して行われます(これはフックのようなものです)、アプリケーションとシステム AMS の相互作用を監視するために使用されます。
Instrumentation#execStartActivity
メソッド:最終的にActivityTaskManager#startActivity
メソッドを呼び出し、代理クラスと ATMS プロセスの通信を取得します(ATMS は SystemServer プロセスに属します)。
// Instrumentation.java
public class Instrumentation {
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
... 省略部分
try {
...省略部分
// ActivityTaskManager#startActivity 関数を起動
// whoThread は IApplicationThread です
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
// AMS によるアクティビティ起動結果のチェック
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("システムからの失敗", e);
}
return null;
}
}
Instrumentation の動作は主に ActivityTaskManager を介して Binder 代理クラスを取得し、ActivityTaskManagerService と通信します。
// Instrumentation.java
public static void checkStartActivityResult(int res, Object intent) {
if (!ActivityManager.isStartResultFatalError(res)) {
return;
}
switch (res) {
// Android Manifest に登録されていない
case ActivityManager.START_INTENT_NOT_RESOLVED:
case ActivityManager.START_CLASS_NOT_FOUND:
if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
throw new ActivityNotFoundException(
"明示的なアクティビティクラスを見つけられませんでした "
+ ((Intent)intent).getComponent().toShortString()
+ "; このアクティビティを AndroidManifest.xml に宣言しましたか?");
throw new ActivityNotFoundException(
"ハンドルするアクティビティが見つかりませんでした " + intent);
// 権限が拒否された
case ActivityManager.START_PERMISSION_DENIED:
throw new SecurityException("アクティビティを起動することは許可されていません "
+ intent);
// リクエストの衝突
case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw new AndroidRuntimeException(
"FORWARD_RESULT_FLAG が使用されている間に結果を要求しています");
... 省略部分
default:
throw new AndroidRuntimeException("不明なエラーコード "
+ res + " アクティビティの起動時に " + intent);
}
}
ActivityTaskManager は Binder メカニズムを介して最終的に システムプロセス の ActivityTaskManagerService (AIDL のサーバー側) に到達します。
重要なパラメータ | 説明 |
---|---|
caller | 呼び出し元 |
intent | 呼び出すアクティビティの情報 |
resultTo | 呼び出し元の AMS 内の ActivityRecord |
// ActivityTaskManagerService.java
// SystemService によって起動されるシステムプロセス
// IActivityTaskManager.Stub はサービス側の実装
public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // IActivityTaskManager は IDE 自動生成クラス
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions) {
// @ startActivityAsUser の分析
return startActivityAsUser(caller, // 呼び出し元 IApplicationThread
callingPackage,
callingFeatureId,
intent, // 呼び出すアクティビティの情報
resolvedType,
resultTo, // 呼び出し元の AMS 内の ActivityRecord
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
}
ActivityStartController - アクティビティの起動準備#
startActivity
(ユーザーのプロセス) -> Binder -> startActivityAsUser
(システムプロセス)、最終的に ActivityStartController を介して指定されたアクティビティを起動します。
// ActivityTaskManagerService.java
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/**
* @call 呼び出し元の IBinder(アプリケーションプロセスの Binder サーバー)、
* 対応するのは ActivityThread#ApplicationThread(内部クラス)
*/
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions) {
// @ startActivityAsUser を確認
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
@Override
public int startActivityAsUser(IApplicationThread caller, String callingPackage,
/*省略部分のパラメータ*/) {
// @ startActivityAsUser を確認
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
true /*validateIncomingUser*/);
}
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
/*省略部分のパラメータ*/) {
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// obtainStarter は ActivityStarter クラスを返します
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
.execute(); // ActivityStarter#execute 関数を直接確認
}
}
ActivityStartController から再利用(obtain)される ActivityStarter クラス
ここで ActivityStartController は ファクトリーパターン を使用しており、目標は ActivityStarter を生成することです。
ActivityStarter は ビルダーパターン を使用しており、アクティビティを呼び出すためのオプションを設定できます。
ActivityStarter#execute
には主に二つのアクションがあります:
- 目標アクティビティが重いかどうかを判断する
- アプリケーション(APP)プロセスのアクティビティ起動要求を実行する
// ActivityStarter.java
private final ActivityTaskSupervisor mSupervisor;
// Request は内部クラス
Request mRequest = new Request();
class ActivityStarter {
int execute() {
try {
int res;
if (mRequest.activityInfo == null) {
// @ resolveActivity メソッドの分析
mRequest.resolveActivity(mSupervisor);
}
// スレッドロック
synchronized (mService.mGlobalLock) {
... 省略部分
//次の小節でこの二つのメソッドを分析します
// 1. 目標アクティビティが重いかどうかを判断する
res = resolveToHeavyWeightSwitcherIfNeeded();
if (res != START_SUCCESS) {
return res;
}
// 2. アクティビティ要求を実行する
res = executeRequest(mRequest);
... 省略部分
}
}
}
static class Request {
ActivityInfo activityInfo;
void resolveActivity(ActivityTaskSupervisor supervisor) {
...
// @ resolveIntent メソッドの分析
resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId,
0 /* matchFlags */,
computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid));
...
activityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags,
profilerInfo);
}
}
}
ActivityTaskSupervisor#resolveActivity
:PackageManagerService で対応するアクティビティ情報(すなわち ActivityInfo)を見つけます。
// ActivityTaskSupervisor.java
final ActivityTaskManagerService mService;
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags,
int filterCallingUid) {
try {
... 省略部分
final long token = Binder.clearCallingIdentity();
try {
// PKMS を介して ResolveInfo を取得
return mService.getPackageManagerInternalLocked().resolveIntent(
intent, resolvedType, modifiedFlags, privateResolveFlags, userId, true,
filterCallingUid);
} finally {
Binder.restoreCallingIdentity(token);
}
} /* 省略 finally */
}
ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags,
ProfilerInfo profilerInfo) {
// ActivityInfo は ResolveInfo 内にあります
final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null;
...
return aInfo;
}
ActivityStarter - execute の起動準備#
ActivityStarter#resolveToHeavyWeightSwitcherIfNeeded
:目標アクティビティが重いかどうかを判断し、現在システムに存在する重いプロセスがあり、その中に必要なアクティビティがある場合は直接返します。
もし起動しようとしているアクティビティが重いプロセスで存在しない場合は、次のステップに進み新しい Intent を与えます。
// ActivityStarter.java
private final ActivityTaskManagerService mService;
/**
* これは重いプロセスであり、異なる重いプロセスがすでに実行されている場合、
* 重いスイッチャーのリクエストを更新します
*/
private int resolveToHeavyWeightSwitcherIfNeeded() {
... 省略部分
// すでに起動しているかどうかを判断
final WindowProcessController heavy = mService.mHeavyWeightProcess;
if (heavy == null ||
(heavy.mInfo.uid == mRequest.activityInfo.applicationInfo.uid
&& heavy.mName.equals(mRequest.activityInfo.processName))
) {
return START_SUCCESS;
}
... 省略部分
// 新しい Intent を作成
final Intent newIntent = new Intent();
if (mRequest.requestCode >= 0) {
// 呼び出し元が結果を要求しています。
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
}
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT, new IntentSender(target));
heavy.updateIntentForHeavyWeightActivity(newIntent);
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
mRequest.activityInfo.packageName);
newIntent.setFlags(mRequest.intent.getFlags());
newIntent.setClassName("android" /* packageName */,
HeavyWeightSwitcherActivity.class.getName());
mRequest.intent = newIntent;
... 省略部分
return START_SUCCESS;
}
ActivityStarter#executeRequest
:アクティビティ起動アクションを実行し、以下の実行アクションは次のように分けられます。
呼び出し元(呼び出し元プロセス)がまだ生存しているかどうかを判断し、呼び出し元(APP)がシステムによって殺されたり、異常終了したりする可能性があるため、この時点で呼び出し元が消えることがあります。
Intent フラグ FLAG_ACTIVITY_FORWARD_RESULT
を処理し、FLAG_ACTIVITY_FORWARD_RESULT
は横断的な伝達機能を持ち、これが有効な場合、setResult の結果は元のアクティビティに戻ります。
その Intent をサポートしているかどうかを判断します(複数の判断)。
ActivityTaskManagerService、ActivityTaskSupervisor を介して起動権限を判断します。
ActivityRecord オブジェクトを作成し、startActivityUnchecked メソッドを呼び出します。
// ActivityStarter.java
private final ActivityTaskManagerService mService;
private final ActivityTaskSupervisor mSupervisor;
private int mLastStartActivityResult;
private int executeRequest(Request request) {
// ユーザー APP プロセス
final IApplicationThread caller = request.caller;
// アクティビティ関連情報
ActivityInfo aInfo = request.activityInfo;
// アクティビティが属するタスク(スタック)
Task inTask = request.inTask;
// 1. 呼び出し元が存在するかどうかを判断
WindowProcessController callerApp = null;
if (caller != null) {
callerApp = mService.getProcessController(caller);
if (callerApp != null) {
callingPid = callerApp.getPid();
callingUid = callerApp.mInfo.uid;
} else {
// 呼び出し元が存在しない場合は START_PERMISSION_DENIED
err = ActivityManager.START_PERMISSION_DENIED;
}
}
... 省略部分
ActivityRecord sourceRecord = null; // 起動元
ActivityRecord resultRecord = null; // 目標結果
if (resultTo != null) {
sourceRecord = mRootWindowContainer.isInAnyStack(resultTo);
... デバッグメッセージ
if (sourceRecord != null) {
if (requestCode >= 0 && !sourceRecord.finishing) {
resultRecord = sourceRecord;
}
}
}
final int launchFlags = intent.getFlags();
// 2. FLAG_ACTIVITY_FORWARD_RESULT は横断的な伝達機能を持つ
if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
// startActivityForResult メソッドを再度使用することはできません
if (requestCode >= 0) {
// そうでなければ START_FORWARD_AND_REQUEST_CONFLICT エラーが発生します
SafeActivityOptions.abort(options);
return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
}
resultRecord = sourceRecord.resultTo;
if (resultRecord != null && !resultRecord.isInStackLocked()) {
resultRecord = null;
}
// setResult の結果を元のアクティビティに変換します
resultWho = sourceRecord.resultWho;
requestCode = sourceRecord.requestCode;
sourceRecord.resultTo = null;
if (resultRecord != null) {
resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
}
if (sourceRecord.launchedFromUid == callingUid) {
callingPackage = sourceRecord.launchedFromPackage;
callingFeatureId = sourceRecord.launchedFromFeatureId;
}
}
... 省略部分
// 3. その Intent をサポートしているかどうかを判断
if (err == ActivityManager.START_SUCCESS && aInfo == null) {
err = ActivityManager.START_CLASS_NOT_FOUND;
}
if (err == ActivityManager.START_SUCCESS && sourceRecord != null
&& sourceRecord.getTask().voiceSession != null) {
// 音声関連
if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
&& sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
try {
intent.addCategory(Intent.CATEGORY_VOICE); // 音声
if (!mService.getPackageManager().activitySupportsIntent(
intent.getComponent(), intent, resolvedType)) {
Slog.w(TAG, "現在の音声タスクで起動されるアクティビティは "
+ "音声をサポートしていません: " + intent);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
} catch (RemoteException e) {
Slog.w(TAG, "音声機能の確認中に失敗しました", e);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
}
}
...省略部分
// 4. 三つの判断を経て、呼び出し元がアクティビティを起動する権限を持っているかどうかを判断
boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
requestCode, /* 省略部分のパラメータ*/);
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
callingPackage);
boolean restrictedBgActivity = false;
if (!abort) {
try {
restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
request.originatingPendingIntent, request.allowBackgroundActivityStart,
intent);
} /* 省略 finally */
}
... 省略部分
// 5. ActivityRecord を作成し、さまざまな判断結果を記録します
final ActivityRecord r = new ActivityRecord.Builder(mService)
.setCaller(callerApp)
.setLaunchedFromPid(callingPid)
.setLaunchedFromUid(callingUid)
.setLaunchedFromPackage(callingPackage)
.setLaunchedFromFeature(callingFeatureId)
.setIntent(intent)
.setResolvedType(resolvedType)
.setActivityInfo(aInfo)
.setConfiguration(mService.getGlobalConfiguration())
.setResultTo(resultRecord)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setComponentSpecified(request.componentSpecified)
.setRootVoiceInteraction(voiceSession != null)
.setActivityOptions(checkedOptions)
.setSourceRecord(sourceRecord)
.build();
mLastStartActivityRecord = r;
... 省略部分
final ActivityStack resultStack = resultRecord == null
? null : resultRecord.getRootTask();
// @ startActivityUnchecked メソッドの分析
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
restrictedBgActivity, intentGrants);
...
return mLastStartActivityResult;
}
}
ActivityStarter は ActivityRecord#Builder
に依存しており、ビルダーパターンを介して ActivityRecord オブジェクトを作成します。このアクティビティには呼び出し元、目標アクティビティが記録されます。
説明者 | 代表アクティビティクラス |
---|---|
PKMS | ActivityInfo (AndroidManifest 内のノード情報) |
AMS | ActivityRecord |
ActivityStarter - アクティビティ起動フロー#
重要な点には以下が含まれます:
- アクティビティの目標タスクを決定する
- アクティビティ起動アニメーションを表示する
- RootWindowContainer にアクティビティのウィンドウを起動することを通知する
- executeRequest 関数内で、最終的に startActivityUnchecked メソッドが呼び出され、以下のメソッドの機能を簡単に説明します。
ActivityStarter 重要メソッド | 機能 |
---|---|
executeRequest | 権限、Caller (クライアント側の IBinder) などをチェックします |
startActivityUnchecked | チェック後、アクティビティを起動する準備をします。起動に失敗した場合も責任を持って削除します |
startActivityInner | 主にアクティビティスタックの制御を行い、アクティビティをスタックに追加するか、Intent に通知します |
// ActivityStarter.java
// executeRequest がこの関数を呼び出します
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
int result = START_CANCELED;
final Task startedActivityRootTask;
...
try {
...
// @ startActivityInner メソッドの分析
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
...
} finally {
...
startedActivityRootTask = handleStartResult(r, result);
...
}
postStartActivityProcessing(r, result, startedActivityStack);
return result;
}
ActivityStarter#startActivityInner
メソッド:他のフラグが設定されていない場合、最終的に Task#startActivityLocked
メソッドを起動します。このメソッドには二つの重要な点があります。
ActivityStarter の mSourceRootTask
、mTargetRootTask
メンバーを定義し、アクティビティの出所と目標スタック (タスク) を決定します。
// ActivityStarter.java
private Task mSourceRootTask; // 出所
private Task mTargetRootTask; // 起動目標
ActivityRecord mStartActivity;
private final ActivityTaskManagerService mService;
private final RootWindowContainer mRootWindowContainer;
int startActivityInner(final ActivityRecord r,
ActivityRecord sourceRecord,
/* 省略部分のパラメータ */) {
...省略部分
// 再利用可能なタスクを取得
final Task reusedTask = getReusableTask();
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
// 新しいタスクを作成するかどうか
final boolean newTask = targetTask == null;
mTargetTask = targetTask;
computeLaunchParams(r, sourceRecord, targetTask);
// 現在の ActivtyRecord が目標タスクで起動できるかどうかを判断
int startResult = isAllowedToStart(r, newTask, targetTask);
if (startResult != START_SUCCESS) {
return startResult;
}
// 再利用タスクの場合、目標スタックのアクティビティを取得します(まだ終了していない)
final ActivityRecord targetTaskTop = newTask
? null : targetTask.getTopNonFinishingActivity();
if (targetTaskTop != null) {
// タスクを再利用
startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);
if (startResult != START_SUCCESS) {
return startResult;
}
} else {
mAddingToTask = true;
}
...
if (mTargetRootTask == null) {
mTargetRootTask = getLaunchRootTask(mStartActivity, mLaunchFlags, targetTask, mOptions);
}
// 現在の分析状況に応じて、新しいタスクを起動します
if (newTask) {
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
// 新しいタスクを設定
setNewTask(taskToAffiliate);
} else if (mAddingToTask) {
addOrReparentStartingActivity(targetTask, "adding to task");
}
...省略部分
return START_SUCCESS;
}
Intent を分析し、アクティビティの起動画面を設定します startActivityLocked
、アクティビティを起動します resumeFocusedTasksTopActivities
。
// ActivityStarter.java
private Task mSourceRootTask;
private Task mTargetRootTask;
ActivityRecord mStartActivity;
private final ActivityTaskManagerService mService;
private final RootWindowContainer mRootWindowContainer;
int startActivityInner(final ActivityRecord r,
ActivityRecord sourceRecord, // 呼び出し元の情報
/* 省略部分のパラメータ */) {
...
// @ 1. Intent を分析し、アクティビティの起動画面を設定します(最初に分析)
mTargetRootTask.startActivityLocked(mStartActivity,
topStack != null ? topStack.getTopNonFinishingActivity() : null, newTask,
mKeepCurTransition, mOptions);
if (mDoResume) { // このアクティビティが存在する場合
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
if (!mTargetRootTask.isTopActivityFocusable()
|| (topTaskActivity != null && topTaskActivity.isTaskOverlay()
&& mStartActivity != topTaskActivity)) {
// もしフォーカスできない場合は再開できませんが、
// それでもこのアクティビティを表示可能にします
// つまり、表示される一時停止状態です
mTargetRootTask.ensureActivitiesVisible(null /* starting */,
0 /* configChanges */, !PRESERVE_WINDOWS);
mTargetRootTask.mDisplayContent.executeAppTransition();
} else {
// スタックのトップアクティビティがフォーカスされていない場合は、前面に移動します
if (mTargetRootTask.isTopActivityFocusable()
&& !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
mTargetRootTask.moveToFront("startActivityInner");
}
// 2. @ 新しいアクティビティを開始します(後で分析)
mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
}
}
...
return START_SUCCESS;
}
タスク Intent の分析 - アクティビティ起動画面の追加#
Task#startActivityLocked メソッド:主に ユーザーが設定した Intent を判断し、アクティビティ初期ロードの画面を設定します。最後に ActivityRecord を介してアクティビティの開始アニメーションを起動します。
// TaskFragment.java
class TaskFragment extends WindowContainer<WindowContainer> {
final ActivityTaskSupervisor mTaskSupervisor;
...
}
// ------------------------------------------------------
// Task.java
class Task extends TaskFragment {
void startActivityLocked(ActivityRecord r, @Nullable ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options,
@Nullable ActivityRecord sourceRecord) {
Task rTask = r.getTask();
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
final boolean isOrhasTask = rTask == this || hasChild(rTask);
...
final Task activityTask = r.getTask();
if (task == activityTask && mChildren.indexOf(task) != (getChildCount() - 1)) {
mStackSupervisor.mUserLeaving = false;
...
}
task = activityTask;
... 省略 デバッグメッセージ
// {@code allowMoveToFront} が false の場合、遷移アニメーションと開始ウィンドウは必要ありません
// アクティビティは表示されないからです。
if ((!isHomeOrRecentsStack() ||
hasActivity()) && allowMoveToFront) {
final DisplayContent dc = getDisplay().mDisplayContent;
... 省略 デバッグメッセージ
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
// アニメーションなし
dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
// アニメーションなしの intent を追加
mStackSupervisor.mNoAnimActivities.add(r);
} else {
// 遷移アニメーションが必要
int transit = TRANSIT_ACTIVITY_OPEN;
if (newTask) {
if (r.mLaunchTaskBehind) {
transit = TRANSIT_TASK_OPEN_BEHIND;
} else if (getDisplay().isSingleTaskInstance()) {
transit = TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
keepCurTransition = false;
} else {
if (canEnterPipOnTaskSwitch(focusedTopActivity,
null /* toFrontTask */, r, options)) {
focusedTopActivity.supportsEnterPipOnTaskSwitch = true;
}
transit = TRANSIT_TASK_OPEN;
}
}
dc.prepareAppTransition(transit, keepCurTransition);
mStackSupervisor.mNoAnimActivities.remove(r);
}
boolean doShow = true;
if (newTask) { // 新しいスタックを起動
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
resetTaskIfNeeded(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r;
}
} else if (options != null && options.getAnimationType()
== ActivityOptions.ANIM_SCENE_TRANSITION) {
doShow = false;
}
if (r.mLaunchTaskBehind) {
...
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {
...
// @ showStartingWindow メソッドを追跡
// r は ActivityRecord
r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));
}
} else {
...
}
}
}
RootWindowContainer スタックのトップアクティビティを起動#
RootWindowContainer#resumeFocusedTasksTopActivities メソッド:タスクスタックのトップアクティビティを見つけて表示します(フォーカス可能なアクティビティ)。
// RootWindowContainer.java
ActivityTaskSupervisor mTaskSupervisor;
boolean resumeFocusedTasksTopActivities(
Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions) {
// @ resumeFocusedTasksTopActivities を追跡
return resumeFocusedTasksTopActivities(targetRootTask, target, targetOptions,
false /* deferPause */);
}
boolean resumeFocusedTasksTopActivities(
Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
boolean deferPause) {
if (!mTaskSupervisor.readyToResume()) {
return false;
}
boolean result = false;
if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
|| getTopDisplayFocusedRootTask() == targetRootTask)) {
result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
deferPause);
}
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
final boolean curResult = result;
boolean[] resumedOnDisplay = new boolean[1];
display.forAllRootTasks(rootTask -> {
// 頂層アクティビティ
final ActivityRecord topRunningActivity =
rootTask.topRunningActivity();
if (!rootTask.isFocusableAndVisible() || topRunningActivity == null) {
return;
}
if (rootTask == targetRootTask) {
// すでに resumed 状態である場合、再度 resumed しません
resumedOnDisplay[0] |= curResult;
return;
}
if (rootTask.getDisplayArea().isTopRootTask(rootTask)
&& topRunningActivity.isState(RESUMED)) {
// MoveTaskToFront 操作からの遅延アプリ遷移を開始しますが、
// トップタスクとルートタスクのみを考慮します。
rootTask.executeAppTransition(targetOptions);
} else {
resumedOnDisplay[0] |= topRunningActivity.makeActiveIfNeeded(target);
}
});
result |= resumedOnDisplay[0];
if (!resumedOnDisplay[0]) { // まだ起動していない
// display は DisplayContent オブジェクトです
final Task focusedRoot = display.getFocusedRootTask();
if (focusedRoot != null) {
// @ resumeTopActivityUncheckedLocked メソッドを続けて分析
result |= focusedRoot.resumeTopActivityUncheckedLocked(target, targetOptions);
} else if (targetRootTask == null) {
// ... タスクが見つからない場合、HomeActivity を起動します
result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
display.getDefaultTaskDisplayArea());
}
}
}
return result;
}
タスクとウィンドウの関係を見てみましょう。タスクは ActivityRecord に関連付けられ、複数のタスクを連結し、ActivityRecord は複数のウィンドウ画面を管理できます。
Task#resumeTopActivityUncheckedLocked 関数を呼び出し、目的はタスクの末端ノードを見つけ、resumeTopActivityInnerLocked
関数を実行します。
// Task.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
if (mInResumeTopActivity) {
// 再帰を開始しないでください。
return false;
}
boolean someActivityResumed = false;
try {
// 再帰を防ぐために保護します。
mInResumeTopActivity = true;
// 末端ノードを見つけます
if (isLeafTask()) {
if (isFocusableAndVisible()) {
// 再帰終了 & 利用可能なアクティビティが見つかれば起動します
// @ resumeTopActivityInnerLocked メソッドを分析
someActivityResumed = resumeTopActivityInnerLocked(
prev,
options,
deferPause);
}
} else {
int idx = mChildren.size() - 1;
while (idx >= 0) {
final Task child = (Task) getChildAt(idx--);
// トップでフォーカス可能なアクティビティを見つけます
if (!child.isTopActivityFocusable()) {
continue;
}
// このタスクは表示されません
if (child.getVisibility(null /* starting */) != TASK_VISIBILITY_VISIBLE) {
break;
}
// resumeTopActivityUncheckedLocked 関数を再帰的に呼び出します
someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,
deferPause);
if (idx >= mChildren.size()) {
idx = mChildren.size() - 1;
}
}
}
// スタックのトップアクティビティ
final ActivityRecord next = topRunningActivity(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
checkReadyForSleep();
}
} finally {
mInResumeTopActivity = false;
}
return someActivityResumed;
}
目標の葉ノードを見つけた後、Task#resumeTopActivityInnerLocked メソッドはアクティビティの起動エントリポイントです。この関数は attachedToProcess
を介して目標プロセスが接続可能かどうかを判断します。
- すでに起動している場合は、
scheduleTransaction
を介してアクティビティを復元します。 - 起動していない場合は、
startSpecificActivity
を介してアクティビティを起動します。
// Task.java
final ActivityTaskManagerService mAtmService;
final ActivityTaskSupervisor mTaskSupervisor;
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
ActivityRecord next = topRunningActivity(true /* focusableOnly */);
... 省略部分
// アプリプロセスに接続できるかどうかを判断します
if(next.attachedToProcess()) {
// 前のアクティビティが半透明の場合は、可視性を強制的に更新し、WM の起動アプリリストに追加します
final boolean lastActivityTranslucent = lastFocusedRootTask != null
&& (lastFocusedRootTask.inMultiWindowMode()
|| (lastFocusedRootTask.mLastPausedActivity != null
&& !lastFocusedRootTask.mLastPausedActivity.occludesParent()));
if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) {
// 可視性を設定します
next.setVisibility(true);
}
// 遅いアプリに関する情報を収集するために起動 ticks をスケジュールします。
next.startLaunchTickingLocked();
ActivityRecord lastResumedActivity =
lastFocusedRootTask == null ? null : lastFocusedRootTask.getResumedActivity();
final ActivityState lastState = next.getState();
mAtmService.updateCpuStats();
... 省略 Log
// State を Resumed に設定します
next.setState(RESUMED, "resumeTopActivityInnerLocked");
boolean notUpdated = true;
... 省略部分
try {
// クライアント側に送信される情報
// next.appToken は目標アプリの ApplicationThread(Binder サーバークラス)です
final ClientTransaction transaction =
ClientTransaction.obtain(
next.app.getThread(),
next.appToken
);
// すべての保留中の結果を配信します。
ArrayList<ResultInfo> a = next.results;
if (a != null) {
final int N = a.size();
if (!next.finishing && N > 0) {
... 省略 Log メッセージ
// コールバックを追加します
// 注意 ActivityResultItem はアプリ側で呼び出されます
transaction.addCallback(ActivityResultItem.obtain(a));
}
}
if (next.newIntents != null) {
transaction.addCallback(
NewIntentItem.obtain(next.newIntents, true /* resume */));
}
// アプリの停止状態をクリアします
next.notifyAppResumed(next.stopped);
... 省略 Log
mAtmService.getAppWarningsLocked().onResumeActivity(next);
... 省略部分
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
dc.isNextTransitionForward()));
// @ 1. scheduleTransaction を分析 !!
mAtmService.getLifecycleManager().scheduleTransaction(transaction);
... 省略 Log
} catch (Exception e) {
... 省略部分
// アクティビティを再起動します
mTaskSupervisor.startSpecificActivity(next, true, false);
return true;
}
... 省略部分
} else {
... 省略部分
// @ 2. startSpecificActivity を分析し、新しいアクティビティを起動します
mTaskSupervisor.startSpecificActivity(next, true, true);
}
return true;
}
既存のアクティビティを起動#
Task#resumeTopActivityInnerLocked 関数は目標 ActivityRecord がすでに起動しているかどうかを判断し、すでに起動している場合は ClientLifecycleManager#scheduleTransaction
を介してアクティビティを復元します。
ClientLifecycleManager - scheduleTransaction#
最初の重点は Binder クライアントとサーバーの変換 です。ここでは ClientTransaction
を介してアプリ側の Binder サーバー(すなわち ActivityThread#ApplicationThread
クラス)を呼び出します。
// ClientLifecycleManager.java
class ClientLifecycleManager {
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
// IApplicationThread はアプリ側
final IApplicationThread client = transaction.getClient();
transaction.schedule();
if (!(client instanceof Binder)) {
// クライアントが Binder でない場合、これはリモート呼び出しであり、このオブジェクトは回収可能です
// オブジェクトが Binder であれば、クライアント(アプリ)側で自分で回収します
transaction.recycle();
}
}
}
ClientTransaction は目標アプリの ApplicationThread(すなわち目標アプリの Binder サーバー)を呼び出します。
// ClientTransaction.java
/** ターゲットクライアント。 */
private IApplicationThread mClient; // IApplicationThread は目標アプリの Binder サーバー
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}
ApplicationThread - scheduleTransaction アクティビティを起動#
ApplicationThread は ActivityThread の内部クラスであり、Binder サーバーの部分を実装しています(各アプリには ApplicationThread の実装があり、AMS がアクティビティを制御できるようにします)
// ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler
implements ActivityThreadInternal {
// AIDL の IApplicationThread.Stub クラスを実装
private class ApplicationThread extends IApplicationThread.Stub {
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
// ClientTransactionHandler の親クラスを確認
ActivityThread.this.scheduleTransaction(transaction);
}
}
}
呼び出された ActivityThread の親クラスの scheduleTransaction メソッド(すなわち ClientTransactionHandler、ClientTransactionHandler は AMS からの情報を処理します)。
// ClientTransactionHandler.java
public abstract class ClientTransactionHandler {
// 目標アクティビティの起動を準備します
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
// 主に sendMessage 関数を見ます
// 次に EXECUTE_TRANSACTION を渡すと最終的にどう処理されるかを見てみましょう
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
// ActivityThread によって実装されます
abstract void sendMessage(int what, Object obj);
}
ActivityThread は sendMessage メソッドを実装し、アクティビティの起動に関しては Handler に EXECUTE_TRANSACTION 情報を渡します。次に TransactionExecutor#execute 関数が処理します。
// ActivityThread.java
final H mH = new H();
private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
// H は Handler
class H extends Handler {
public static final int EXECUTE_TRANSACTION = 159;
public void handleMessage(Message msg) {
switch (msg.what) {
... 省略部分
case EXECUTE_TRANSACTION:
// AMS から渡された ClientTransaction オブジェクトに対応
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// システムプロセスの場合、クライアント側でオブジェクトを回収します、
// ClientLifecycleManager では回収しません
// この関数の情報が処理される前に回収されるのを避けるためです!!
transaction.recycle();
}
break;
}
}
private void sendMessage(int what,
Object obj, // EXECUTE_TRANSACTION
int arg1, int arg2, boolean async) {
... 省略 Log メッセージ
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
TransactionExecutor#execute 関数:すべての ClientTransactionItem (AMS から送信された) の execute 関数を実行します。
// TransactionExecutor.java
private ClientTransactionHandler mTransactionHandler;
public void execute(ClientTransaction transaction) {
... 省略部分
// executeCallbacks を分析します
executeCallbacks(transaction);
executeLifecycleState(transaction);
... 省略部分
}
public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
...省略部分
for (int i = 0; i < size; ++i) {
// ClientTransactionItem は抽象で、実装は ActivityResultItem です
final ClientTransactionItem item = callbacks.get(i);
... 省略部分
item.execute(mTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);
... 省略部分
}
}
ActivityResultItem - execute 呼び出し Instrumentation#
ここでの ClientTransactionItem は抽象クラスであり、渡されるオブジェクトによって異なる実装の詳細があります。
// ActivityResultItem.java
public class ActivityResultItem extends ActivityTransactionItem {
@Override
public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
// @ handleSendResult メソッドを分析
client.handleSendResult(r, mResultInfoList, "ACTIVITY_RESULT");
}
}
// ---------------------------------------------------------------
// ActivityThread.java
@Override
public void handleSendResult(ActivityClientRecord r, List<ResultInfo> results, String reason) {
final boolean resumed = !r.paused;
if (!r.activity.mFinished && r.activity.mDecor != null
&& r.hideForNow && resumed) {
updateVisibility(r, true);
}
if (resumed) {
try {
// 現在はアイドルです。
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"アクティビティ " + r.intent.getComponent().toShortString()
+ " は super.onPause() を呼び出しませんでした。");
}
} /*省略 catch*/
}
checkAndBlockForNetworkAccess();
deliverResults(r, results, reason);
if (resumed) {
// 目標 ++ onResume ++ を実行します
r.activity.performResume(false, reason);
}
}
// ---------------------------------------------------------------
// Activity.java
final void performResume(boolean followedByPause, String reason) {
... 省略部分
// mResumed はインストゥルメンテーションによって設定されます
mInstrumentation.callActivityOnResume(this);
... 省略部分
}
Instrumentation 呼び出し onResume#
最終的に Activity#onResume
関数は Instrumentation を介して呼び出されます。
// /app/Instrumentation.java
public void callActivityOnResume(Activity activity) {
activity.mResumed = true;
// Activity#onResume 関数を呼び出します
activity.onResume();
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
am.match(activity, activity, activity.getIntent());
}
}
}
}
ActivityThread#
実際の起動クラスは ActivityThread.java であり、その内部には私たちがよく知っている main メソッドがあります。ここでは Main が使用する Looper を見ることができ、Looper を起動し、もう一つの重要な点は attach 関数です。
/**
* ActivityThread.java
* パス: ./frameworks/base/core/java/android/app/ActivityThread.java
*/
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
...省略部分
// MainLooper
Looper.prepareMainLooper(); // # Main Looper を準備
ActivityThread thread = new ActivityThread();
thread.attach(false); //@ attach を追跡
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop(); // # Looper を起動
throw new RuntimeException("メインスレッドループが予期せず終了しました");
}
ActivityThread - attach の開始#
直接的に重要な部分に注目します。つまり attachApplication 関数です。Android は Binder(詳細は別のトピックを参照)メカニズムを介して、代理人(ActivityManagerProxy)を取得し、サービス側に呼び出して ActivityManagerService クラスにジャンプします。
// ActivityThread.java
private void attach(boolean system) { // # main から false が渡される
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
// ビュー管理者
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
...省略部分
// AMS の代理オブジェクトを取得し、これを介して AMS と通信します
final IActivityManager mgr = ... // # AIDL, サービスポート
try {
// アプリケーションを渡す
mgr.attachApplication(mAppThread); // @ 重要 ! ActivityManagerService.class にジャンプ
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...省略部分
} else {
// SystemServer のみが true を渡します
...省略、なぜなら main から渡されるのは false だからです
}
// DropBox ロギングを libcore に追加します
DropBox.setReporter(new DropBoxReporter());
// @ ビュー管理者のコールバックを登録します
ViewRootImpl.addConfigCallback(...);
}
attachApplication 関数は mAppThread
というパラメータも受け取ります。これは ApplicationThread であり、後のバインディングアプリケーションで使用されます。
ActivityManagerService クラス - attachApplication#
AMS クラスは AMS のサーバー側として、IActivityManager.Stub メソッドを実装する必要があります。attachApplication 関数は非常に長く、重要な点は以下の通りです。
- bindApplication、アプリケーション側のアプリケーションをバインドし、AMS がアクティビティを直接制御できるようにします。
- attachApplicationLocked(アクティビティを接続します)
// ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock {
public ActivityTaskManagerInternal mAtmInternal;
... 省略他の関数
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
if (thread == null) {
throw new SecurityException("無効なアプリケーションインターフェース");
}
synchronized (this) {
// 呼び出し元の PID
int callingPid = Binder.getCallingPid();
// 呼び出し元の UID
final int callingUid = Binder.getCallingUid();
// AMS の PID/UID に呼び出し元の PID/UID を設定します
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
// 呼び出し元の PID/UID に戻します
Binder.restoreCallingIdentity(origId);
}
}
private boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
try {
... 省略部分
// # 1. バインドします。ここでも Binder メカニズムを使用し、アプリケーションスレッドの bindApplication を呼び出します
// つまり ApplicationThread 内の bindApplication を呼び出します
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
} /* 省略 catch */
...省略
if (normalMode) {
try {
// @ 2. アクティビティを接続します
if (mAtmInternal.attachApplication(app)) {
didSomething = true;
}
} /* 省略 catch */
}
}
}
bindApplication はアプリケーション側のサービスにバインドされます(すなわち ApplicationThread)、しかしこの部分は今は気にしないでおきましょう。まずは attachApplication を見てみましょう。これはアクティビティをバインドし、アクティビティを起動するさまざまな操作を行います(後で使用される二つを提起します)。
Binder のセキュリティは呼び出し元の情報を持ち、この情報はシステムによって設定され、呼び出し元が呼び出す権限を持っているかどうかを検証するために使用されます。
Http セキュリティ CS アーキテクチャでは、アプリケーション層の設定情報が使用され、その情報は改ざんされる可能性があります。
ActivityTaskManagerInternal - バインド&アクティビティの起動#
上記の AMS では attachApplicationLocked#attachApplication
メソッドを呼び出し、ActivityTaskManagerInternal クラスは抽象クラスであり、その実装は ActivityTaskManagerService#LocalService です。
// ActivityTaskManagerService.java
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
RootWindowContainer mRootWindowContainer;
... 省略部分
final class LocalService extends ActivityTaskManagerInternal {
@Override
public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
synchronized (mGlobalLockWithoutBoost) {
// 省略 trace
try {
return mRootWindowContainer.attachApplication(wpc);
} finally {
... 省略 trace
}
}
}
}
}
RootWindowContainer#attachApplication
// RootWindowContainer.java
boolean attachApplication(WindowProcessController app) throws RemoteException {
boolean didSomething = false;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
mTmpRemoteException = null;
mTmpBoolean = false; // アクティビティが開始された場合は true に設定します。
final DisplayContent display = getChildAt(displayNdx);
display.forAllRootTasks(rootTask -> {
if (mTmpRemoteException != null) {
return;
}
if (rootTask.getVisibility(null /*starting*/) == TASK_VISIBILITY_INVISIBLE) {
return;
}
// startActivityForAttachedApplicationIfNeeded 関数を確認します
final PooledFunction c = PooledLambda.obtainFunction(
RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
PooledLambda.__(ActivityRecord.class), app,
rootTask.topRunningActivity());
rootTask.forAllActivities(c);
c.recycle();
});
...省略部分
}
...省略部分
return didSomething;
}
private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
WindowProcessController app, ActivityRecord top) {
... 省略部分
try {
if (mTaskSupervisor.realStartActivityLocked(r, app,
top == r && r.isFocusable() /*andResume*/, true /*checkConfig*/)) {
mTmpBoolean = true;
}
} /* 省略 catch */
return false;
}
}
realStartActivityLocked 関数:ここではいくつかの起動前の準備、検証を行い、準備が整ったら Binder を介して ApplicationThread を呼び出してアクティビティを起動します(アプリ側が自分自身の Binder を AMS に渡したことを思い出してください)。
// RootWindowContainer.java
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
if (!allPausedActivitiesComplete()) {
...省略 デバッグメッセージ
return false;
}
if (andResume) { //# true
r.startFreezingScreenLocked(app, 0); //# freeze haven't start activity
mWindowManager.setAppVisibility(r.appToken, true);
// 遅いアプリに関する情報を収集するために起動 ticks をスケジュールします。
r.startLaunchTickingLocked(); // # cellection of app's data who start slowly
}
if (checkConfig) { // # true, 設定情報をチェック
Configuration config = mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
r.mayFreezeScreenLocked(app) ? r.appToken : null);
mService.updateConfigurationLocked(config, r, false, true /* deferResume */);
}
// # ActivityRecord は ProcessRecord からデータを設定します。二つのパラメータが渡されます
r.app = app;
app.waitingToKill = null;
r.launchCount++;
r.lastLaunchTime = SystemClock.uptimeMillis();
int idx = app.activities.indexOf(r);
if (idx < 0) {
app.activities.add(r);
}
mService.updateLruProcessLocked(app, true, null);
mService.updateOomAdjLocked();
... 省略部分
final ActivityStack stack = task.stack;
try {
... 省略部分
//# アクティビティがホームの場合、このアクティビティをタスクの底に追加します(ホームプロセスはタスクのルートプロセスです)
if (r.isHomeActivity()) {
mService.mHomeProcess = task.mActivities.get(0).app;
}
... 省略部分
// スケジュールされたアクティビティ起動トランザクションを作成します。
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.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
} /* 省略 catch */
アプリ側 - ApplicationThread#
ApplicationThread は ActivityThread のプライベート内部クラスであり、ApplicationThreadNative(Binder サーバー)を継承しています。ここでの主な機能は IApplicationThread インターフェースを実装することです。ここがアプリ側の Binder の実装です。
/**
* AcitivtyThread.class
*/
public final class AcitivtyThread {
/**
* AcitivtyThread#ApplicationThread.class
*/
private class ApplicationThread extends ApplicationThreadNative {
@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 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); //@ アクティビティ起動のメッセージを送信し、H.class を呼び出します
}
}
}
ここで注意すべき二つの点があります。
ActivityClientRecord(ActivityThread の静的内部クラス)を作成し、起動に関するすべての情報を記録します。
Handler メカニズムを介して LAUNCH_ACTIVITY 情報を送信します。
/**
* ActivityThread.class
* 最終的に外部 ActivityThread の sendMessage メソッドを呼び出します
*/
private void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
/**
* ActivityThread#H.class
* 最終的に ActivityThread のプライベート内部クラス H を呼び出します
*/
private class H extends Handler {
public void handleMessage(Message msg) {
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;
...省略他
}
}
/**
* ActivityThread.class
* handleLaunchActivity は主に performLaunchActivity メソッドを呼び出します
*/
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...省略部分
// アクティビティを作成する前に初期化します
WindowManagerGlobal.initialize();
Activity a = performLaunchActivity(r, customIntent); //@ アクティビティを起動します
...省略部分
}
performLaunchActivity - アクティビティの作成#
performLaunchActivity 関数は ActivityThread クラスに存在し、主にここでアクティビティ、アプリケーションなどのオブジェクトを作成し、バインドします。
/**
* ActivityThread.class
*/
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
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);
}
// アクティビティ参照を作成し、返す準備をします
Activity activity = null;
try {
// LoadedApk - クラスを取得し、packageInfo は LoadedApk です
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(
"アクティビティをインスタンス化できませんでした " + component
+ ": " + e.toString(), e);
}
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation); //# アプリケーションオブジェクトを取得します
...省略部分
if (activity != null) {
// # createBaseContextForActivity メソッドは ContextImpl クラスを返します
Context appContext = createBaseContextForActivity(r, activity);
...省略部分
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
// # アプリケーションとコンテキストをアクティビティオブジェクトにバインドします !
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