Android Activity起動プロセスの詳細(上)


あなたが探しているactivityの知識はここにあります超詳細Fragment知識総括FragmentManagerとFragmentTransactionの最下層実装Androidシステム起動プロセス詳細Activity起動プロセス詳細(上)AppがActivityを起動する場合、システムに要求起動信号を送信する必要があります.この要求を処理するサービスはAMS(Activity Management Service)であり、この操作はプロセスをまたいでいます.前回の記事を考えてみると、init解析rcスクリプトはZygoteを起動し、そのプロセスapp_プロセス(後にzygoteと改名)のZygoteInitはforkSystemServerによってプロセスを作成し、AMSを含む様々なシステムサービスを開始する.ZygoteInitはforkAndSpecializeを介して新しく起動したアプリケーションごとに独自のプロセスを生成し、handleChildProcメソッドでアプリケーション自体のコードを実行するので、Activityを起動するプロセスはプロセスにまたがる.
呼び出しを表示する例としてstartActivityメソッドを使用してActivityを起動します.
    Intent intent = new Intent(this, DemoActivity.class);
    startActivity(intent);

① android.app.Activity#startActivity、startActivityにはいくつかのリロードメソッドがありますが、startActivity ForResultメソッドが呼び出されます.
    @Override
    public void startActivity(Intent intent) {
     
        this.startActivity(intent, null);
    }

② android.app.Activity#startActivity(Intent intent, @Nullable Bundle options)
    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
     
        if (options != null) {
     
            startActivityForResult(intent, -1, options);
        } else {
     
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

③ android.app.Activity#startActivity ForResultは、ここではmParent==nullに注目するだけでよい.mParentはActivity Groupを表し、Activity Groupは1つのインタフェースに複数のサブActivityを埋め込むために使用され始めたが、API 13では廃棄され、Fragmentに置き換えられる.
   public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
     
        if (mParent == null) {
     
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
     
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            ...
            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
     
            ...
        }
    }

④ android.app.Instrumentation#execStartActivityは、プロセス間でActivity Management ServiceのstartActivityメソッドを呼び出します(android 10ではAMSのstartActivityがmActivity TaskManager.startActivityを呼び出し、Activityを起動するタスクをATMSに渡します).具体的なコード実装を参照してください.checkStartActivity Resultメソッドの役割は、Activityを起動した結果を確認することであり、Activityを正常に起動できないと異常情報が投げ出され、詳細は見られなくなります.
    @UnsupportedAppUsage
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
     
       ...
        try {
     
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            int result = ActivityTaskManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
     
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

⑤上のActivity TaskManager.を分析するSingletonが単一のモードクラスであるget()メソッドを呼び出すと、オブジェクトがすでに存在する場合は既存の値を直接返し、そうでない場合はcreate()メソッドを呼び出すことによってIActivityTaskManagerオブジェクトを作成して返すという内部判断が行われます.
    public static IActivityTaskManager getService() {
     
        return IActivityTaskManagerSingleton.get();
    }
       
    @UnsupportedAppUsage(trackingBug = 129726065)
    private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
            new Singleton<IActivityTaskManager>() {
     
                @Override
                protected IActivityTaskManager create() {
     
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
                    return IActivityTaskManager.Stub.asInterface(b);
                }
            };

⑥ここではServiceManagerによるgetServiceでActivity ManagementのIBinderオブジェクトを取得する場合、sCacheがgetServiceの履歴クエリーの結果を記録するために使用する場合、getServiceは毎回ここでレコードをめくってクエリーの速度を速め、存在しない場合はrawGetServiceメソッド内のgetiserviceManager()を通過する.getService(name)はSMにクエリーを開始します.
    @UnsupportedAppUsage
    public static IBinder getService(String name) {
     
        try {
     
            IBinder service = sCache.get(name);
            if (service != null) {
     
                return service;
            } else {
     
                return Binder.allowBlocking(rawGetService(name));
            }
        } catch (RemoteException e) {
     
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

    private static IBinder rawGetService(String name) throws RemoteException {
     
        final long start = sStatLogger.getTime();
        final IBinder binder = getIServiceManager().getService(name);
        ...
        return binder;
    }

⑦getiserviceManagerメソッドは、まず、sServiceManagerが空であるかどうかを判断し、複数回の重複操作を防止します.その後、ServiceManagerNativeを通過する.asInterfaceは、IServiceManagerオブジェクトを取得します.このIServiceManagerオブジェクトは、Binderドライバとの通信を担当するSMエージェントServiceManagerProxyです.具体的なコードは次のとおりです.

    @UnsupportedAppUsage
    private static IServiceManager getIServiceManager() {
     
        if (sServiceManager != null) {
     
            return sServiceManager;
        }
        // Find the service manager
        sServiceManager = ServiceManagerNative
                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
        return sServiceManager;
    }

⑧asInterfaceメソッドは、BinderオブジェクトをIServiceManagerに変換し、必要に応じてServiceManagerProxyを作成します.これは、Binderとの通信を駆動するための当社のServiceManagerのエージェントです.
    @UnsupportedAppUsage
    static public IServiceManager asInterface(IBinder obj)
    {
     
        if (obj == null) {
     
            return null;
        }
        IServiceManager in =
            (IServiceManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
     
            return in;
        }
        return new ServiceManagerProxy(obj);
    }

⑨上記のrawGetServiceメソッドに戻るgetiserviceManager().getService(name)メソッドは、SMエージェントのgetServiceメソッドにより、まずParcelでデータをパッケージ化します.次にIBinderのtransactを介して要求を送信し、具体的にはjniを介して対応するBpBinderを呼び出し、さらにProcessStateとIPCThreadStateの関連インタフェースを用いてSMとの通信を完了する.その後、結果が得られます(ここでIBinderはAMSのIBinderオブジェクトです).ここではブロック関数呼び出しです.プロセス間通信なので、結果はすぐには得られません.Binderドライバは、結果が出るまで呼び出しスレッドを停止します.
class ServiceManagerProxy implements IServiceManager {
     
    public ServiceManagerProxy(IBinder remote) {
     
        mRemote = remote;
    }
    public IBinder asBinder() {
     
        return mRemote;
    }
    @UnsupportedAppUsage
    public IBinder getService(String name) throws RemoteException {
     
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }
    ...
    @UnsupportedAppUsage
    private IBinder mRemote;
}

⑩allowBlockingの役割は、現在のIBinderがBinderProxyであるか否かを判断し、mWarnOnBlockingフラグビットを変更することである.
    public static IBinder allowBlocking(IBinder binder) {
     
        try {
     
            if (binder instanceof BinderProxy) {
     
                ((BinderProxy) binder).mWarnOnBlocking = false;
            } else if (binder != null && binder.getInterfaceDescriptor() != null
                    && binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
     
                Log.w(TAG, "Unable to allow blocking on interface " + binder);
            }
        } catch (RemoteException ignored) {
     
        }
        return binder;
    }
 }

⑪次にAMS内startActivityがどのように実現されているかを見てみましょう.AMSがATMSに実装を委託していることがわかりますが、このようなメリットは、職責がより単一になり、AMSが肥大化しすぎず、OO設計の原則に合致することを避けることです.
    @Override
    public int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
     
        return mActivityTaskManager.startActivity(caller, callingPackage, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions);
    }

Activity TaskManagerServiceのstartActivityメソッドでは、startActivity AssUserメソッドが呼び出されます.
    @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());
    }

➊これはstartActivity AssUserのメソッドです:getActivity StartController()メソッドは現在持っているActivity StartControllerオブジェクトを返し、obtainStarterメソッドはActivity Starter内部クラスDefaultFactoryを呼び出す.Obtain()メソッドはActivity Starterオブジェクトを作成し、Activity StarterのsetIntent(intent)を呼び出す.setReason(reason)などの属性付与は,最後にActivity Starterのexecuteメソッドを呼び出し,ここではコードを示さない.
    int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
            boolean validateIncomingUser) {
     
        ...
        userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();
    }

⑪setMayWaitメソッドでは、Activity Starter内部クラスRequestのmayWaitフィールドをtrueに設定します.
    ActivityStarter setMayWait(int userId) {
     
        mRequest.mayWait = true;
        mRequest.userId = userId;
        return this;
    }

⑪checkTargetUserメソッド内、validateIncomingUserはtrue、targetUserIdは現在の呼び出し元のユーザID値であり、UserHandle.getCallingUserId()Binderメカニズム取得、UserHandleはaidlファイルであり、handleIncomingUserは呼び出し者がこの操作を実行する権利があるかどうかをチェックします.
    int checkTargetUser(int targetUserId, boolean validateIncomingUser,
            int realCallingPid, int realCallingUid, String reason) {
     
        if (validateIncomingUser) {
     
            return mService.handleIncomingUser(
                    realCallingPid, realCallingUid, targetUserId, reason);
        } else {
     
            mService.mAmInternal.ensureNotSpecialUser(targetUserId);
            return targetUserId;
        }
    }

⑨Activity Starterのexecuteのメソッドです.startActivity MayWaitメソッド、mRequestが呼び出されます.mayWaitは前述の起動パラメータです.
    int execute() {
     
        try {
     
            if (mRequest.mayWait) {
     
                return startActivityMayWait(...);
            } else {
     
                ...
        } finally {
     
            onExecutionComplete();
        }
    }

⑯startActivity MayWaitメソッドでは、26パラメータのstartActivityメソッドが呼び出され、10パラメータのstartActivityメソッドが呼び出され、startActivityメソッドが呼び出され、mTargetStackが呼び出されます.startActivity Lockedメソッドは、Activityの起動プロセスをActivity Stackに移行します.
Todo:startActivity Lockedは論理的に複雑で、次回は起動モードと組み合わせて、AMSが上層Activityと新旧Activityの切り替えをどのように回復し、呼び出し者に通知したのかを整理します.
参考1、林学森、Android内核設計思想を深く理解する:人民郵電出版社2、任玉剛、Android開発芸術探索:中国工信出版グループ