バインダー
バインダーの構成
Binder のアーキテクチャを図に示します。
ServiceManager は、Binder Server をコンテナに登録する役割を果たします。
クライアント、サーバー、ServiceManager、およびバインダー ドライバーの関係は次のように理解できます。
ServiceManager を、各住宅の固定電話番号を保存する電話交換局にたとえてください。張三が李斯に電話すると、その電話番号は電話交換局に転送され、電話局のオペレーターはこの番号のアドレスを確認することができます。李斯の電話番号は電話局に登録されているため、電話をかけることができます。 ; if 登録がない場合は、番号が存在しないことを示すメッセージが表示されます。
Zhang San がクライアント、Li Si がサーバー、電話交換機が ServiceManager、オペレーターがバインダー ドライバーです。
バインダーのコミュニケーションプロセス
Binder の通信プロセスと対話ルートを次の図に示します。
-
サーバーはServiceManagerコンテナに登録されています
-
クライアントがサーバーの add メソッドを呼び出したい場合は、最初にサーバー オブジェクトを取得する必要がありますが、ServiceManager は実際のサーバー オブジェクトをクライアントに返すのではなく、サーバーのプロキシ オブジェクトをクライアントに返します。 、 プロキシ。
-
クライアントはプロキシの add メソッドを呼び出し、バインダー ドライバーはクライアントがサーバーの add メソッドを呼び出し、結果をクライアントに返すのを支援します。
AIDL
Bookクラスの作成
特にプロセス通信に使用されるデータを保存するために、メイン パッケージの下に AIDL パッケージを構築します。Book クラスは Parcelable インターフェイスを継承します (理由: AIDL は Parcelable インターフェイスを継承するクラスのみを転送できます)。
package com.example.zs.ipcdemo.aidl;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
private String bookId;
private String bookName;
public String getBookId() {
return bookId;
}
public void setBookId(String bookId) {
this.bookId = bookId;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public static Creator<Book> getCREATOR() {
return CREATOR;
}
public Book(String bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
protected Book(Parcel in) {
bookId = in.readString();
bookName = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(bookId);
dest.writeString(bookName);
}
public void readFromParcel(Parcel in) {
bookId = in.readString();
bookName = in.readString();
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
}
Book.aidl、IBookManager.aidl を作成する
Book.aidl クラスが存在するのはなぜですか? AIDL でクラスが宣言されている場合にのみ、AIDL が Book クラスを呼び出すことができるからです。したがって、AIDL がカスタム クラスを送信できるようにするには、1. Parcelable インターフェイスを継承し、2. 同じ名前で .aidl ファイルを作成して自分自身を宣言する必要があります。
package com.example.zs.ipcdemo.aidl;
parcelable Book;
IBookManager.aidl は、クライアントが呼び出しを許可されるインターフェイスを設定します。
package com.example.zs.ipcdemo.aidl;
import com.example.zs.ipcdemo.aidl.Book;
interface IBookManager{
List<Book> getBookList();
void addBook(in Book book);
}
ここでaddBookメソッドのin型に注目する必要があるので、AIDLファイルのin型、out型、inoutデータの違いについて簡単に説明しておきます。
- in: クライアント パラメータ入力: 実際のパラメータの値を行パラメータに割り当てるため、行パラメータを変更しても実際のパラメータの値には影響しません。
- out: サーバー側のパラメータ入力: 渡した後、行パラメータと実パラメータは同じオブジェクトですが、名前が異なります。行パラメータを変更すると、実パラメータの値に影響します。
- inout: これは入力パラメータと出力パラメータと呼ばれ、クライアントとサーバーが入力できます。クライアントがサーバーにパラメーターを入力した後、サーバーはパラメーターなどを変更することもできます。最終的にクライアントで取得されるのは、サーバーが出力したパラメーターです。
このディレクトリ app\build\generated\source\aidl\debug でプロジェクト システムを手動で再構築し、IBookManger.java を自動的に生成します。次に、IBookManger.java の素顔を見てみましょう。
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: E:\\GitHub\\IPCDemo\\app\\src\\main\\aidl\\com\\example\\zs\\ipcdemo\\aidl\\IBookManager.aidl
*/
package com.example.zs.ipcdemo.aidl;
public interface IBookManager extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.example.zs.ipcdemo.aidl.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.example.zs.ipcdemo.aidl.IBookManager";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.zs.ipcdemo.aidl.IBookManager interface,
* generating a proxy if needed.
*/
public static com.example.zs.ipcdemo.aidl.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.zs.ipcdemo.aidl.IBookManager))) {
return ((com.example.zs.ipcdemo.aidl.IBookManager) iin);
}
return new com.example.zs.ipcdemo.aidl.IBookManager.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.zs.ipcdemo.aidl.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.example.zs.ipcdemo.aidl.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.zs.ipcdemo.aidl.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.zs.ipcdemo.aidl.IBookManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public java.util.List<com.example.zs.ipcdemo.aidl.Book> getBookList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.zs.ipcdemo.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.zs.ipcdemo.aidl.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.example.zs.ipcdemo.aidl.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void registerListener(com.example.zs.ipcdemo.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void unregisterListener(com.example.zs.ipcdemo.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_unregisterListener, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<com.example.zs.ipcdemo.aidl.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.example.zs.ipcdemo.aidl.Book book) throws android.os.RemoteException;
}
最初は少し混乱しますが、心配しないで、段階的に分析してみましょう。IBookManager ファイルには、IBookManager.aidl の 2 つのインターフェイスと、IBookManager インターフェイスを実装する 2 つのクラス、Stub および Proxy が含まれています。スタブは次のように定義されています。 IBookManager インターフェイス、および Proxy は Stub クラスで定義されます。
クライアント実行プロセス
1. サービス接続が確立されると、クライアントはコードを実行します。IBookManager.Stub.asInterface(service)
このコードの機能は、受信パラメータIBinder
オブジェクトがそれ自体と同じプロセス内にあるかどうかを判断することです。そうでない場合、IBinder
パラメータはオブジェクトにパッケージ化されますProxy
。このとき、 のメソッドが呼び出されStub
、のメソッドがgetBookList()
間接的にProxy
呼び出されますgetBookList()
。コードを見てください。
// 连接服务
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(final ComponentName name, IBinder service) {
// IBinder 通过 asInterface 判断
// asInterface方法的作用是判断参数——也就是IBinder对象,和自己是否在同一个进程:
// 是: 则直接转换、直接使用,接下来就跟 Binder 跨进程通信无关啦
// 否: 则把这个IBinder参数包装成一个 Proxy 对象,这时调用 Stub 的方法,间接调用Proxy的方法
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try {
mBookManager = bookManager;
bookManager.getBookList();
Log.d(TAG, "get books count:" + bookManager.getBookList().size());
bookManager.registerListener(arrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBookManager = null;
}
};
public static com.example.zs.ipcdemo.aidl.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
// 作用是判断传入的参数 IBinder 对象和自己是否在同一个进程
if (((iin != null) && (iin instanceof com.example.zs.ipcdemo.aidl.IBookManager))) {
return ((com.example.zs.ipcdemo.aidl.IBookManager) iin);
}
return new com.example.zs.ipcdemo.aidl.IBookManager.Stub.Proxy(obj);
}
2.Proxy
独自のgetBookList()
メソッドでは、 を使用してParcelable
データを準備し、関数名と関数パラメータを記述し_data
、_reply
関数の戻り値を受け取ります。最後に、 の () メソッドを使用してIBinder
、transact
データを の最後に渡しBinder
ますServer
。
@Override
public java.util.List<com.example.zs.ipcdemo.aidl.Book> getBookList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.zs.ipcdemo.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
// 通知服务器调用该方法
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
/** 调用mRemote.transact()方法后,Binder驱动会挂起当前客户端线程,
* 并向服务端发送一个消息,这个消息就包括客户端传递的参数。
* 服务端接收到消息,解析数据执行完相关任务后会把执行结果写入reply中,
**/ 然后向Binder驱动发送一个notify消息,Binder驱动从挂起处唤醒客户端线程继续执行。
_reply.readException();
_result = _reply.createTypedArrayList(com.example.zs.ipcdemo.aidl.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
mRemote
それはどういう意味ですか?
サーバーが作成されると、Server Binder
バインダー ドライバー内にmRemote
サーバーへの参照も作成されます。Client
クライアントがアクセスする場合、Server
まず Binder でサーバーの参照を取得する必要がありmRemote
、参照を取得した後、mRemote.transact()
メソッドを通じてサーバーにメッセージを送信できます。
transact
次のことを行いました
- クライアントから渡されたパラメータをスレッド間メッセージ通信モードでサーバに送信します。
- 現在のクライアント スレッドを一時停止し、サーバー スレッドの実行完了後の通知を待ちます (通知)
- サーバースレッド通知を受信し、クライアントスレッドの実行を継続し、実行結果を返します。
サーバー実行プロセス
サーバーは、onTransact() メソッドを通じてクライアント プロセスから関数名と関数パラメーターを含むデータを受信し、対応する関数 (ここでは getBookList() です) を見つけて、パラメーターを供給し、結果を取得して返します。したがって、onTransact() 関数は、データを読み取り、呼び出される関数を実行し、実行結果をデータに書き込むというプロセスを経ています。
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
// 客户端调用指令 getBookList()
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
// 调用本地服务 getBookList() 方法
java.util.List<com.example.zs.ipcdemo.aidl.Book> _result = this.getBookList();
reply.writeNoException();
// 将数据传给客户端
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.example.zs.ipcdemo.aidl.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.zs.ipcdemo.aidl.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
return super.onTransact(code, data, reply, flags);
}
4 つの主要コンポーネントの仕組み
アクティビティの仕組み
アプリの起動方法
携帯電話の画面上でDouyuアプリのアイコンをクリックすると、そのアプリのホームページが目の前に表示されますが、この一見単純な操作の裏側では、アクティビティとアクティビティとの間で繰り返される通信プロセスが存在します。アムス。まず、携帯電話の画面がアクティビティであることを理解する必要があります。このアクティビティが配置されているアプリは、業界ではランチャーと呼ばれています。ランチャーは、大手携帯電話メーカーによって提供されています。
ランチャーは、パッケージ名、ホームページのアドレス、カテゴリなど、アプリのアイコンごとにアプリを起動するために必要なインテント情報を提供します。この情報はPackageManagerService
各 apk パッケージ内のファイルから、アプリのインストール時にAndroidManifest
開始プロセス
①ランチャーはATMSにDouyuアプリを起動したい旨を通知し、どのページでアプリを起動するかを指定します。
②ATMSはメッセージを受信後、起動するページを記録します。
③Launcher の現在のページは一時停止状態になり、ATMS に「対応するアプリを見つけてください」と通知します。
④ATMSはDouyuアプリが起動しているかどうかを確認し、起動していればDouyuアプリを呼び出し、起動していない場合は新しいプロセスを起動し、ATMSが配置されている新しいプロセスにActivityThreadオブジェクトを作成し、対応するmain関数を起動します。
⑤アプリ起動後、ATMSに「起動しました」を通知します。
⑥ATMSは、以前に記録された値(開始するページ)を取り出し、Douyuアプリにこのページを開始するように指示します。
⑦Douyu アプリはホームページを起動し、Context を作成してホームページのアクティビティに関連付け、ページを開始するアクティビティの onCreate 関数を呼び出します。
これでプロセスは完了し、ステージ 1 ~ 3: ランチャーと AMS の相互通信、およびステージ 4 ~ 7: Douyu アプリと AMS の相互通信の 2 つの部分に分かれています。
フェーズ 1: ランチャーが ATMS に通知する
ランチャーでアプリをクリックした後、ランチャーの startActivitySafely メソッドが呼び出されます。実際、アクティビティの startActivity メソッドは引き続き呼び出されます。startActivity メソッドはパラメーター Intent を渡す必要があります。インテントには、アプリの起動に必要な重要な情報が含まれています例: 開始するページ クラス名など では、なぜマニフェストのホーム ページのアクションとカテゴリを指定する必要があるのでしょうか? ランチャーは、起動時に開始するこの重要な情報を見つけます。
パッケージ/apps/Launcher3/src/com/android/launcher3/Launcher.java
# Launcher.java
@Override
public boolean startActivitySafely(View v, Intent intent, ItemInfo item,
@Nullable String sourceContainer) {
if (!hasBeenResumed()) {
addOnResumeCallback(() -> startActivitySafely(v, intent, item, sourceContainer));
if (mOnDeferredActivityLaunchCallback != null) {
mOnDeferredActivityLaunchCallback.run();
mOnDeferredActivityLaunchCallback = null;
}
return true;
}
// 调用了父类BaseDraggingActivity的startActivitySafely,最终会执行到父类Activity的startActivity
boolean success = super.startActivitySafely(v, intent, item, sourceContainer);
if (success && v instanceof BubbleTextView) {
BubbleTextView btv = (BubbleTextView) v;
btv.setStayPressed(true);
addOnResumeCallback(btv);
}
return success;
}
最後に、Activity の startActivity メソッドが呼び出されます。
# Activity.java
@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)) {
if (TextUtils.equals(getPackageName(),
intent.resolveActivity(getPackageManager()).getPackageName())) {
// Apply Autofill restore mechanism on the started activity by startActivity()
final IBinder token =
mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
// Remove restore ability from current activity
mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
// Put restore token
intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);
}
}
if (options != null) {
//-1为requestCode表明不需要知道是否启动成功
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1);
}
}
アプリを起動すると、アクティビティの startActivityForResult メソッドが何度も呼び出されてから呼び出されます。startActivityForResult のコードは次のとおりです。
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
//启动app时,因为是启动的第一个activity,所以mParent为空
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
//执行Instrumentation的execStartActivity
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
//向ActivityThread发送上一步的返回值
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
//省略部分代码
} else {
//省略部分代码
}
}
各アクティビティは、Instrumentation オブジェクトである mMainThread 変数を保持します。これは
ActivityThread
変数の一種であり、メイン スレッド、つまりUI スレッドです。アプリ全体を表します。読者は、それがActivityThread
アプリ アプリケーションを表すかどうかを尋ねずにはいられません。 、Application
クラスは何を表しますか? 実際、Application
これは Android システムにとってそれほど重要ではなく、単なるコンテキスト、Application
アプリのコンテキスト、Context
アプリActivity
のコンテキストにすぎません。
MamainThread.getApplicationThread() がこの関数に渡され、取得されるのは、ActivityThread の内部クラス ApplicationThread です。これは、アプリ プロセスを表す Binder オブジェクトです。また、
launcher
ActivitymToken
を表すBinder
オブジェクトでもあり、 ATMS にlauncher
渡されますInstumentation
。ATMS はレコードを照会して、誰が ATMS にリクエストを送信したかを確認します。その後、ATMS はこのオブジェクト (ApplicationThread) を通じてアプリと通信します。
View
mInstrumentation.execStartActivity
メソッドは、Activity の助けを借りて、execStartActivity
データを に渡しますActivityTaskManager
。
ActivityTaskManager.getService()
AIDL を通じて取得されますIActivityTaskManager
。バインダー参照ですActivityTaskManagerService
。ここで呼び出される関数は、リモートで呼び出されますActivityTaskManagerService
。これは、4 つの主要コンポーネントのライフ サイクルを定義する IInterface を実装するインターフェイスです。アクティビティを開始するとき、ATMS との通信メカニズムは次のとおりです。 AIDL。
# Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
// 流程就从Launcher进程进入到AMS所在的SystemServer进程了
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);
...
}
return null;
}
//=========ActivityTaskManager.java=========
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);
}
};
//=================Singleton.java=========
/**
* Singleton helper class for lazily initialization.
* ......
*/
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
IActivityTaskManager は ATMS 側で Binder を代理するオブジェクトであり、ATMS は startActivity を開始します。この時点で、Launcher が ATMS にアクティビティの開始を要求するプロセスが終了します。
フェーズ 2: ATMS は Launcher からの情報を処理します
1: Launcher は AIDL を介して AMS と通信し、毎回異なることを実行する必要があります。たとえば、今回は Launcher が Douyu アプリを起動しようとしている場合、Launcher の startActivity メソッドは最終的に ATSM のプロキシ IActivityTaskManager によって呼び出される startActivity を取得し、システム ATMS に入ります。サーバー プロセスの startActivity。ATMS はインテント情報を収集することでどのアクティビティを開始するかを認識します。
2: AMS は「わかりました。」と言うと、AndroidManifest ファイルをチェックして、開始するアクティビティが存在するかどうかを確認し、存在しない場合は、アクティビティが見つからないという例外メッセージをスローします。
3: AMS は Launcher に「何も問題ありません。そのまま寝てください。」と通知しました。では、AMS はどのように Launcher に伝えたのでしょうか? 結論は、AMS は IApplicationThread のプロキシを介してメッセージを送信し、アプリ側は引き続き AIDL 方式で ApplicationThread を介してメッセージを受信します。
コードに戻ります。最後にActivityTaskManagerService
呼び出しstartActivity
が呼び出されますstartActivityAsUser
。一連のビルダーを通じて ActivityStarter を取得し、対応するパラメーターを設定します。最後に、ActivityStarter の実行メソッドが実行されます。実行関数の機能は、次の内容に基づいてアプリケーションを開始します。以前に提供されたリクエストパラメータ。
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// TODO: Switch to user app stacks here.
// getActivityStartController().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: アクティビティの起動操作を担当します。その主な機能には、Intent の解析、ActivityRecord の作成、および可能であれば TaskRecord の作成が含まれます。obtainStarter
によって返される型は ActivityStarter であり、その実行関数の機能は、以前に提供された要求パラメータに基づいてアプリケーションを開始することです。
キー呼び出しパス:
execute
===>>executeRequest
====>>startActivityUnchecked
===>>startActivityInner
- exexute: アクティビティ起動リクエストを処理するためのインターフェース。
- executeRequest: 一連の権限チェックを実行し、正当なリクエストに対してのみ続行します。
- startActivityUnchecked: このメソッドが呼び出されると、事前の権限チェックのほとんどが完了し、トレースが実行され、例外処理が実行されることを意味します。
- startActivityInner: アクティビティを開始し、グローバル タスク スタック フレーム情報を更新します。
ActivityStack や WindowContainer などのタスク ウィンドウ管理のコードは無視し、実際にアプリケーションを開始するコードのみに注目します。
- mRootWindowContainer.resumeFocusedTasksTopActivities()
resumeFocusedStacksTopActivities
() まずターゲットのアクティビティスタックをフォアグラウンドに移動し、次にアクティビティを作成してスタックに配置します。ユーザーはそれを直接見ることができます。したがって、アクティビティを作成するロジックは依然としてresumeFocusedStacksTopActivities()にあります
boolean resumeFocusedStacksTopActivities(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (!mStackSupervisor.readyToResume()) { return false;}
......
if (targetStack != null && (targetStack.isTopStackInDisplayArea()
|| getTopDisplayFocusedStack() == targetStack)) {
result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
アクティビティスタック
ActivityStack: TaskRecord を管理し、複数の TaskRecord を含みます。 · ActivityStackSupervisor: ActivityStack を管理します
resumeTopActivityUncheckedLocked
===>>resumeTopActivityInnerLocked
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
...
if (mResumedActivity != null) {
// 暂停Launcher
pausing |= startPausingLocked(userLeaving, false , next);
}
// 启动Activity
mStackSupervisor.startSpecificActivity(next, true, true);
...
}
startPausingLocked メソッドは主に、Launcher に一時停止状態に入るように通知します。先ほど、Launcher と ATMS 間の通信について学びましたが、次に ATMS が Launcher とどのように通信するかを見てみましょう。
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming, boolean pauseImmediately) {
..........
if (prev.app != null && prev.app.thread != null) {//条件满足
............
try {
............
//下面的代码,就是暂停Launcher,这是AMS与ActivityThread交互的内容,暂时不讨论
//prev.appToken为IApplicationToken.Stub,prev.finishing为false,userLeaving为true,异步执行
mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken,
PauseActivityItem.obtain(prev.finishing, userLeaving,
prev.configChangeFlags, pauseImmediately));
.........
}
} else {
............
}
............
mService は ATMS です
mService.getLifecycleManager() は ClientLifecycleManager を返します;
PauseActivityItem は一連の IPC 操作をカプセル化する ActivityLifecycleItem から継承します。
クライアントライフサイクルマネージャー
このクラスは、複数のライフサイクル遷移リクエストやコールバックを結合し、単一のトランザクションとして実行できます。主な機能はライフサイクル管理呼び出しです。
void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken,
@NonNull ActivityLifecycleItem stateRequest) throws RemoteException {
//ClientTransaction封装传进来的参数
final ClientTransaction clientTransaction = transactionWithState(client, activityToken,
stateRequest);
//执行传输操作
scheduleTransaction(clientTransaction);
}
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
//client就是IApplicationThread
final IApplicationThread client = transaction.getClient();
//下面这句代码就是跨进程了
transaction.schedule();
if (!(client instanceof Binder)) {
transaction.recycle();
}
}
ClientTransaction .schedule() を呼び出します。
public void schedule() throws RemoteException {
//mClient就是IApplicationThread,接下来会通过IPC的方式调用
//Launcher的ActivityThread.ApplicationThread.scheduleTransaction方法;
//从AMS进程,进入App进程
mClient.scheduleTransaction(this);
}
ここからは実際にシステム処理からアプリケーション処理に戻ります。
IApplicationThread: システム プロセスが保持するアプリ プロセス内の ApplicationThread の Binder プロキシ オブジェクトです。
mClient.scheduleTransaction() メソッドの実装はクライアントの ApplicationThread にあり、次に、ActivityThread.ApplicationThread に入ります。
アプリケーションスレッド
ApplicationThread: ActivityThread の内部クラス。AMS は、バインダー プロキシを通じて ApplicationThread のメソッドを呼び出した後、メイン スレッド (ActivityThread のメイン メソッド) で開かれたハンドラー メッセージ ポーリングを通じて、関連するメソッドを呼び出すようにメイン スレッドに通知します。メイン スレッドの関連するライフ サイクル メソッドの具体的な実装は Instrumentation クラスに委任され、Instrumentation クラスでは、特定のコンポーネントの関連するライフ サイクル メソッドが呼び出されます。
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
//终于从AMS进程,进入到了App进程
ActivityThread.this.scheduleTransaction(transaction);
}
void scheduleTransaction(ClientTransaction transaction) {
//准备工作,它会执行ActivityLifecycleItem的preExecute()方法,这里就是PauseActivityItem
transaction.preExecute(this);
//发送通知,由ActivityThread接收
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
ApplicationThread は、ActivityThread の H に EXECUTE_TRANSACTION メッセージを送信し、ActivityThread と ApplicationThread は Handler を介して通信します。
case EXECUTE_TRANSACTION:
//取出传递过来的ClientTransaction
final ClientTransaction transaction = (ClientTransaction) msg.obj;
//执行transaction
mTransactionExecutor.execute(transaction);
if (isSystem()) {
transaction.recycle();
}
break;
ATMS 側で ClientTransaction を取得し、mTransactionExecutor.execute(transaction) を呼び出します。
public void execute(ClientTransaction transaction) {
//token就是IApplicationToken.Stub
final IBinder token = transaction.getActivityToken();
//执行Callbacks,后面分析的LaunchActivityItem就是在这里执行的,本例中暂时没有Callbacks
executeCallbacks(transaction);
//我们要看的是这个
executeLifecycleState(transaction);
mPendingActions.clear();
}
private void executeLifecycleState(ClientTransaction transaction) {
//得到ActivityLifecycleItem,本例中是PauseActivityItem
final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
if (lifecycleItem == null) {
// No lifecycle request, return early.
return;
}
log("Resolving lifecycle state: " + lifecycleItem);
//得到token
final IBinder token = transaction.getActivityToken();
final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
if (r == null) {
// Ignore requests for non-existent client records for now.
return;
}
//Activity.onStart方法就是在这里面调用的,后面会看到;
//本次流程中的lifecycleItem是PauseActivityItem,所以lifecycleItem.getTargetState()为4;
cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */);
//将动作传递给lifecycleItem执行,lifecycleItem在AMS进程当中,这里又进行了IPC
lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
//上面的execute方法主要是app进程中的pause操作,当app进程中的pause操作结束之后,需要通知AMS进程,进行下一步操作
lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}
①cycleToPath():
たとえば、あるアクティビティ A の場合、その現在のライフサイクルは 1 で表される onCreate ステージであり、lifecycleItem.getTargetState() は lifecycleItem のタイプに関連付けられます。 PauseActivityItemとResumeActivityItemの値が異なります。ここでのlifecycleItemがResumeActivityItemで、ResumeActivityItemに対応するライフサイクルがActivityのonResumeの場合、lifecycleItem.getTargetState()の戻り値は3です。onCreateは1を表すので、1と3の差は2です。したがって、onCreate と onResume の間にはまだ 1 つの違いがあります。ライフ サイクル、このライフ サイクルは onStart(); です。
一連のメソッド呼び出しの後、メソッドがexecute ===>> executeLifecycleState ===> cycleToPath ===> lifecycleItem.execute
呼び出されます。PauseActivityItem.execute()
PauseActivityItem.java
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
//client是在app进程中的,ActivityThread实现了ClientTransactionHandler.handlePauseActivity()方法
client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,
"PAUSE_ACTIVITY_ITEM");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
ActivityThread.handlePauseActivity() に戻ります。
ActivityThread.java
public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
int configChanges, PendingTransactionActions pendingActions, String reason) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
if (userLeaving) {//成立
//调用onUserInteraction()和onUserLeaveHint()函数
performUserLeavingActivity(r);
}
r.activity.mConfigChangeFlags |= configChanges;
//执行暂停Launcher的操作
performPauseActivity(r, finished, reason, pendingActions);
// Make sure any pending writes are now committed.
//isPreHoneycomb()判断SDK版本是否是HONEYCOMB之前的版本
if (r.isPreHoneycomb()) {
//等待要暂停的应用进程的异步操作完成,保持数据完整
QueuedWork.waitToFinish();
}
mSomeActivitiesChanged = true;
}
}
private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, String reason,
PendingTransactionActions pendingActions) {
...
final boolean shouldSaveState = !r.activity.mFinished && r.isPreHoneycomb();
//暂停前保存状态
if (shouldSaveState) {
//调用onSaveInstanceState()保存Activity的状态
callActivityOnSaveInstanceState(r);
}
//真正的暂停执行操作在这里
performPauseActivityIfNeeded(r, reason);
//通知OnActivityPausedListener执行其监听操作
ArrayList<OnActivityPausedListener> listeners;
synchronized (mOnPauseListeners) {
listeners = mOnPauseListeners.remove(r.activity);
}
int size = (listeners != null ? listeners.size() : 0);
for (int i = 0; i < size; i++) {
listeners.get(i).onPaused(r.activity);
}
final Bundle oldState = pendingActions != null ? pendingActions.getOldState() : null;
if (oldState != null) {
if (r.isPreHoneycomb()) {
r.state = oldState;
}
}
return shouldSaveState ? r.state : null;
}
引き続き、performPauseActivity() の PerformPauseActivityIfNeeded(r,reason) を見てみましょう。
private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
...
try {
r.activity.mCalled = false;
//重点在这里,Activity.onPause方法的调用
mInstrumentation.callActivityOnPause(r.activity);
...
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException("Unable to pause activity "
+ safeToComponentShortString(r.intent) + ": " + e.toString(), e);
}
}
//设置当前的状态为ON_PAUSE
r.setState(ON_PAUSE);
}
ActivityThread は一時停止の作業を Instrumentation に委任し、各アクティビティは Instrumentation を保持し、最終的にそれを Activity の PerformPause に渡します。
Instrumentation.java
public void callActivityOnPause(Activity activity) {
activity.performPause();
}
Activity.java
final void performPause() {
mDoReportFullyDrawn = false;
//改变Fragment的状态
mFragments.dispatchPause();
mCalled = false;
//调用Activity的生命周期onPause()方法
onPause();
writeEventLog(LOG_AM_ON_PAUSE_CALLED, "performPause");
//此时已经是非mResumed状态
mResumed = false;
if (!mCalled && getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.GINGERBREAD) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onPause()");
}
}
要約する
IApplicationThread のschedulePauseActivity メソッドを通じてバインダー クロスプロセス呼び出しを開始し、アプリケーション プロセスの ApplicationThread のスケジュールPauseActivity メソッドに入り (このメソッドはクライアントのバインダー スレッド プールで実行されます)、その後、データをアプリケーション プロセスのメイン プロセスに切り替えます。 ActivityThread によって実行される実行用の mH handlePauseActivity メソッドが処理され、その後、performPauseActivity を通じて Instrumentation の callActivityOnPause メソッドが内部的に呼び出され、Activity の PerformPause メソッドが内部的に呼び出され、Launcher の onPause メソッドがコールバックされます。
第 3 段階: ランチャーがスリープ状態になり、ATMS に「スリープ状態になりました」と通知します。
Launcher が onPause 状態にある場合、次のステップを実行して PauseActivityItem.postExecute() を呼び出すように AMS プロセスに通知する必要があります。
public void postExecute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
if (mDontReport) {
return;
}
try {
//调用ATMS的activityPaused()方法
ActivityTaskManager.getService().activityPaused(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
フェーズ 4: ATMS が新しいプロセスを開始する
次に、ATMS は Douyu アプリのホームページを起動する必要があります。このアプリはバックグラウンド プロセスにないため、新しいプロセスを開始する必要があります。ここで Process.start メソッドが呼び出され、ActivityThread のメイン関数がエントリ関数として指定されます。
ActivityStack.resumeTopActivityInnerLocked ===>> startSpecificActivity
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
// 获取启动的activity进程信息
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
boolean knownToBeDead = false;
//如果进程存在,并且进程中有线程存在,就启动一个同应用的activity
if (wpc != null && wpc.hasThread()) {
try {
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
knownToBeDead = true;
}
//否则通过AMS向Zygote进程请求创建新进程
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
final boolean isTop = andResume && r.isTopRunningActivity();
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
第 5 段階: ActivityThread のメイン関数をエントリ ポイントとして、新しいプロセスが開始されます。
新しいプロセスの開始とは、新しいアプリを開始し、このプロセスの ActivityThread オブジェクトを作成することを意味します。これは、私たちがよく知っている UI メイン スレッドです。UI スレッドを作成したら、すぐに ActivityThread のメイン関数に入り、次の 2 つの重要な作業を実行します。
-
①メインスレッドLooper、つまりMainLooperを作成します。
-
②アプリケーションの作成、ここでもアプリケーションを作成します
public static void main(String[] args) {
............
//设置临时进程名为<pre-initialized>
Process.setArgV0("<pre-initialized>");
//准备UI主线程的消息循环
Looper.prepareMainLooper();
............
//创建ActivityThread,并调用attach 方法,传入的参数为false
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
............
/// M: ANR Debug Mechanism
mAnrAppManager.setMessageLogger(Looper.myLooper());
//进入主线程消息循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
ActivityThread を作成し、attach メソッドを呼び出しました。
final ApplicationThread mAppThread = new ApplicationThread();
private void attach(boolean system, long startSeq) {
......
if (!system) {
//这一步是获取AMS实例
final IActivityManager mgr = ActivityManager.getService();
//然后跨进程通信
mgr.attachApplication(mAppThread, startSeq);
}
}
AMSを取得することでクロスプロセス通信を行い、AMSのattachApplicationメソッドを呼び出します。
AMS.attachApplication() では、ActivityThread.ApplicationThread.bindApplication() が呼び出されます。
public final void bindApplication(String processName, .........) {
............
//bindApplication将ActivityManagerService传入的数据封装到AppBindData中
AppBindData data = new AppBindData();
data.processName = processName;
............
//通过BIND_APPLICATION消息发送给应用程序主线程的消息循环中,由ActivityThread的H.handleMessage处理。
sendMessage(H.BIND_APPLICATION, data);
}
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
}
}
private void handleBindApplication(AppBindData data) {
............
// 创建一个对应的`LoadedApk`对象
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
//创建并初始化应用程序的ContextImpl
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
updateLocaleListFromAppContext(appContext,
mResourcesManager.getConfiguration().getLocales());
............
if (ii != null) {
............
} else {
//创建并且初始化mInstrumentation
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
}
............
Application app;
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
try {
//创建应用程序Application,对应AndroidManifest.xml的Application
app = data.info.makeApplication(data.restrictedBackupMode, null);
app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
//将第一个Application视为进程的初始Application
mInitialApplication = app;
//安装该应用程序的ContentProvider
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
try {
//调用Instrumentation的onCreate方法
mInstrumentation.onCreate(data.instrumentationArgs);
}
catch (Exception e) {
............
}
try {
//调用Application的onCreate方法
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
............
}
} finally {
............
}
............
}
//Application.java
public void onCreate() {
}
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
CompatibilityInfo compatInfo) {
return getPackageInfo(ai, compatInfo, null, false, true, false);
}
getPackageInfoNoCheck() を使用して LoadedApk オブジェクトを作成し、data.info に保存します。
アプリケーションは data.info.makeApplication(data.restrictedBackupMode, null) を通じて作成されます。
app.onCreate(); は mInstrumentation.callApplicationOnCreate(app) を通じて呼び出され、アプリケーションが作成されます。
メッセージを受信した後、メインスレッドは、BIND_APPLICATION
渡されたメッセージに基づいてApplicationInfo
対応するオブジェクト (現在の apk 情報をマーク) を作成LoadedApk
し、ContextImpl
そのオブジェクト (現在のプロセス環境をマーク) を作成してから、リフレクションを通じてターゲット アプリケーションを作成し、そのアプリケーションを呼び出します。 ContextImpl を追加するためのattachメソッド。オブジェクトはターゲットApplcationのコンテキストとして設定され、最後にApplicationonCreate
関数が呼び出されて初期化作業が行われます。
アプリの魂はActivityTread
メイン スレッドであり、アプリ開発者は使用しませんが、このクラスの一部の動作はリフレクションを使用して変更できます。
APP の bindingApplication は主に AppBindData を初期化し、次に BIND_APPLICATION を APP のメイン スレッド BIND_APPLICATION に送信し、最後に handleBindApplication を実行します。このメソッドは主に、適用される属性、アプリのフォルダーなど、アプリ プロセス内のアプリのハードウェア リソースの一部を構成して、アプリの基本情報の初期化
ATMSのアタッチアプリケーション
アプリを作成するときに最後に行う必要があるのは、ATMS に「開始しました」と伝えることです。同時に、独自のActivityThread
オブジェクトを ATMS に送信します。この新しいアプリの登録情報は ATMS 電話帳に追加されます。 ATMS は、今後この ActivityThread オブジェクトを使用して新しいアプリをアプリに送信します。メッセージを送信します。コードのこの部分は次の場所にあります。
//ActivityManagerService.java:
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
if (thread == null) {
throw new SecurityException("Invalid application interface");
}
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
long bindApplicationTimeMillis;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
......
final String processName = app.processName;
......
final BackupRecord backupTarget = mBackupTargets.get(app.userId);
try {
......
mAtmInternal.preBindApplication(app.getWindowProcessController());
final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
if (app.isolatedEntryPoint != null) {
// This is an isolated process which should just call an entry point instead of
// being bound to an application.
thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
} else if (instr2 != null) {
thread.bindApplication(processName, appInfo, providers,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions);
} else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions);
}
.......
} catch (Exception e) {
......
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
// mAtmInternal.attachApplication()最终调用的是ATMS中的 attachApplication()。
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
......
return true;
}
ATMS のattachApplication()では、IPCを介してActivityThread.ApplicationThread.bindApplication()が実行された後、mStackSupervisor.attachApplicationLocked(app)が呼び出されます。mStackSupervisorはActivityStackSupervisorであり、最後にActivityStackSupervisorのrealStartActivityLockedメソッドが呼び出されます。
- ここではActivityRecordを改良し、プロセスやその他の情報を設定します。一般的に言えば、ActivityRecord、ProcessRecordなどはAMS/ATMSによって管理されるべきであり、ここではアプリケーションはATMSにバインドされていると理解できます。
- ClientTransaction オブジェクトを作成しました
- 作成された LaunchActivityItem オブジェクトである ClientTransaction のコールバックが設定されます。
- 作成した lifecycleItem オブジェクトのライフサイクルを設定します。
- mService.getLifecycleManager().scheduleTransaction(clientTransaction) を通じてリクエストを送信します。ここでの mService は ATMS で、mService.getLifecycleManager() は ClientLifecycleManager です。
- アプリケーションを作成した後、attachApplication() を通じてそれを ATMS にバインドします。まだシステムプロセス中です。
ステージ 6: ATMS が新しいアプリにどのアクティビティを開始するかを指示します
ATMS は、アプリとの将来のクロスプロセス通信のために、受信した ActivityThread オブジェクトを ApplicationThread オブジェクトに変換します。第 6 段階では、AtMS は過去の記録からどのアクティビティを開始するかを見つけ、ATP を通じてアプリに指示します。
ActivityStackSupervisor の realStartActivityLocked メソッドでは、リクエストは mService.getLifecycleManager().scheduleTransaction(clientTransaction) を通じて送信されます。つまり、ClientLifecycleManager が呼び出されてリクエストが送信されます。
次のプロセスはランチャーを一時停止するときと同じです。ClientLifecycleManager のスケジュールトランザクション メソッドを確認します。
//ClientLifecycleManager.java:
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
final IApplicationThread client = transaction.getClient();
transaction.schedule();
if (!(client instanceof Binder)) {
// If client is not an instance of Binder - it's a remote call and at this point it is
// safe to recycle the object. All objects used for local calls will be recycled after
// the transaction is executed on client in ActivityThread.
transaction.recycle();
}
}
//ClientTransaction.java
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}
mClient は IApplicationThread インターフェイスであり、その実装が ApplicationThread であることも上で分析しました。ここで、ActivityThread に戻ります。
ApplicationThread.scheduleTransaction ===>> ClientTransactionHandler.scheduleTransaction
public abstract class ClientTransactionHandler {
// Schedule phase related logic and handlers.
/** Prepare and schedule transaction for execution. */
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
EXECUTE_TRANSACTION メッセージは、scheduleTransaction メソッドの ActivityThread の H クラスに送信されます。
android.app.ActivityThread
// An executor that performs multi-step transactions.
private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
......
class H extends Handler {
......
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// Client transactions inside system process are recycled on the client side
// instead of ClientLifecycleManager to avoid being cleared before this
// message is handled.
transaction.recycle();
}
......
}
このメッセージは、TransactionExecutor の実行メソッドを呼び出す handleMessage を通じて処理されます。
public void execute(ClientTransaction transaction) {
...
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
}
public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
...
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
// 在上面realStartActivityLocked()中,设置的callback是LaunchActivityItem对象。这里execute()最终执行到LaunchActivityItem的execute()。
final ClientTransactionItem item = callbacks.get(i);
...
item.execute(mTransactionHandler, token, mPendingActions);
}
}
private void executeLifecycleState(ClientTransaction transaction) {
final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
//生命周期的过渡
cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);
lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}
上記の realStartActivityLocked() では、コールバック セットは LaunchActivityItem オブジェクトです。ここで、execute()は最終的にLaunchActivityItemのexecute()を実行します。
//LaunchActivityItem.java:
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client, mAssistToken);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
ここでのクライアントは ActivityThread です。そこで、ActivityThreadのhandleLaunchActivity()に行きました。
//ActivityThread.java:
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
......
final Activity a = performLaunchActivity(r, customIntent);
......
return a;
}
読む
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
// 创建Activity实例
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);
}
}
......
执行attach,内部创建Window等
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,
r.assistToken);
......
// 执行了Activity的onCreate()方法
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
......
}
一連のメソッド呼び出しを実行した後、execute->executeCallbacks->cycleToPath->performLifecycleSequence を実行すると、最終的に見慣れたもの、つまりアクティビティのライフ サイクルの束が表示されます。
簡単に言うと、主なプロセスは次のとおりです。
- アプリケーション コンテキスト (Context) を作成し、ClassLoader を取得します。
- Activity オブジェクトの作成は基本的に classLoader.loadClass(name).newInstance() です。ここで、Activity クラスが初期化され、オブジェクトのメソッドが呼び出されて、ターゲット クラスの静的ブロック内のコードが実行されます。
- アプリケーションの AndroidManifest.xml に基づいて Application オブジェクトを作成し、その onCreate コールバックを呼び出します。
- 対応するアクティビティの onCreate コールバックを呼び出します。
ステージ 7: Douyu ホームページの活動を開始する
android.app.ActivityThread
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
......
final Activity a = performLaunchActivity(r, customIntent);
......
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
关键代码1
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);
}
}
......
执行attach,内部创建Window等
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,
r.assistToken);
......
关键代码2
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
......
}
PerformLaunchActivity メソッドは何をするのでしょうか?
①Instrumentati0onのnewActivityメソッドで起動するActivityインスタンスを作成します。
②このActivityのContextオブジェクトを作成し、Activityに関連付けます。
③InstrumentactionのcallActivityOnCreateメソッドを介して、アクティビティのonCreateメソッドを実行してアクティビティを開始します この時点でアプリが起動されます このプロセスは複数のハンドシェイクを経ます アプリとATMSは頻繁にメッセージを送信し、メッセージを送信する仕組みBinder.に基づいて確立されています。
アプリ内でのページジャンプ
次に、アプリの内部ページへのジャンプを見てみましょう。
ActivityA から ActivityB にジャンプする場合、ActivityA は実際には Launcher とみなすことができ、このジャンププロセスはアプリの起動プロセスと非常によく似ています。
前の分析に基づいて、このプロセスでは新しいプロセスを再起動する必要がないことがわかります。そのため、アプリの起動プロセスの一部の手順を省略でき、プロセスは次のように簡略化されます。
- ActivityA は、ActivityB を開始するために AMS にメッセージを送信します。
- AMS は、ActivityB の情報を保存し、スリープ可能 (onPaused) であることをアプリに通知します。
- ActivityA がスリープ状態になり、AMS にスリープ状態になったことを通知します。
- AMS は、ActivityB が配置されているプロセスが ActivityA が配置されているプロセスであることを検出し、新しいプロセスを再起動する必要がないため、アプリに ActivityB を開始するように通知します。
- アプリはアクティビティBを開始します。
上記の分析は、同じプロセス内のアクティビティ A とアクティビティ B に限定されています。これら 2 つのアクティビティが同じプロセス内にないことをマニフェストで指定すると、別のプロセスのセットになりますが、プロセス全体は類似しています。
背景家族の歴史
Activity と Service の両方に Context があり、これら 3 つのクラスと Application は実際には親戚です。
Activity には Theme という層があるため、真ん中に ContextThemeWrapper があり、Service と Application の甥に相当します。
ContextWrapper は、特定の実装を持たない単なるラッパー クラスであり、実際のロジックは ContextImpl にあります。
アプリケーションに含まれるContextの数:Serviceの数+Activityの数+1(Applicationクラス自体がContextオブジェクトに相当します)。
アプリケーションには複数の ContextImpl オブジェクトが含まれており、その内部変数 mPackageInfo は同じ PackageInfo オブジェクトを指します。
アクティビティとコンテキストの違い
アクティビティを例として、アクティビティとコンテキストの関係と違いを見てみましょう。
新しいアクティビティにジャンプするには次のように記述する必要があることがわかっています。
また、Activity のメソッドを使用してgetApplicationContext
Context 情報を取得し、Context の startActivity メソッドを使用して新しい Activity を開始することもできることもわかりました。
この 2 つの違いは何ですか?
Activity中:
@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);
}
}
Activity でどの startActivity メソッドを使用しても、Activity 独自のメソッドを呼び出すため、同じです。
ただし、ContextImpl.java などの他の Context サブクラスの実装では、Flag: FLAG_ACTIVITY_NEW_TASK が設定されているかどうかがチェックされ、設定されていない場合はエラーが報告されます。
ContextImpl中:
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
// Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
// generally not allowed, except if the caller specifies the task id the activity should
// be launched in. A bug was existed between N and O-MR1 which allowed this to work. We
// maintain this for backwards compatibility.
final int targetSdkVersion = getApplicationInfo().targetSdkVersion;
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& (targetSdkVersion < Build.VERSION_CODES.N
|| targetSdkVersion >= Build.VERSION_CODES.P)
&& (options == null
|| ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}