O Binder funciona com um dos quatro componentes principais

Encadernador

Composição do fichário

A arquitetura do Binder é mostrada na figura
Insira a descrição da imagem aqui

ServiceManager é responsável por registrar o Binder Server em um contêiner.

Podemos entender o relacionamento entre Cliente, Servidor, ServiceManager e Binder Driver assim:

Compare o ServiceManager a uma central telefônica, que armazena os números de telefone fixo de cada residência. Quando Zhang San liga para Li Si, o número de telefone será transferido para a central telefônica. A operadora da central telefônica pode verificar o endereço desse número. Como o número de telefone de Li Si foi registrado na central telefônica, a ligação pode ser feita ; se não houver cadastro, avisará que o número não existe.

Zhang San é o cliente, Li Si é o servidor, a central telefônica é o ServiceManager e a operadora é o Binder Driver.

Processo de comunicação do Binder

O processo de comunicação e a rota de interação do Binder são mostrados na figura abaixo
Insira a descrição da imagem aqui

  1. O servidor está registrado no contêiner ServiceManager

  2. Se o Cliente quiser chamar o método add do Servidor, ele precisa primeiro obter o objeto Servidor, porém o ServiceManager não retornará o objeto Servidor real para o Cliente, mas retornará um objeto proxy do Servidor para o Cliente, ou seja , Procurador.

  3. O Cliente chama o método add do Proxy, e o driver Binder o ajudará a chamar o método add do Servidor e retornar o resultado ao Cliente.

Insira a descrição da imagem aqui

AIDL

Criar classe Livro

Construa um pacote aidl sob o pacote principal especificamente para armazenar dados usados ​​para comunicação de processos. A classe Book herda a interface Parcelable (motivo: AIDL só pode transferir classes que herdam a interface 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];
        }
    };
}

Crie Book.aidl, IBookManager.aidl

Por que existe a classe Book.aidl?Porque somente quando a classe é declarada em aidl, o AIDL pode chamar a classe Book. Portanto, para que o AIDL possa transmitir classes customizadas, você precisa 1. Herdar a interface Parcelable e 2. Criar um arquivo .aidl com o mesmo nome para se declarar.

package com.example.zs.ipcdemo.aidl;

parcelable Book;

IBookManager.aidl define a interface que o cliente pode chamar.

package com.example.zs.ipcdemo.aidl;

import com.example.zs.ipcdemo.aidl.Book;

interface IBookManager{
    List<Book> getBookList();
    void addBook(in Book book);
}

Há um ponto aqui onde você deve prestar atenção ao tipo in no método addBook. Vamos falar brevemente sobre a diferença entre o tipo in, o tipo out e os dados inout no arquivo AIDL.

  • in: Entrada de parâmetro do cliente: atribui o valor do parâmetro real ao parâmetro de linha, portanto, modificações no parâmetro de linha não afetarão o valor do parâmetro real.
  • out: Entrada de parâmetros no lado do servidor: Após a passagem, os parâmetros de linha e os parâmetros reais são o mesmo objeto, mas seus nomes são diferentes.As modificações nos parâmetros de linha afetarão os valores dos parâmetros reais.
  • inout: Isso pode ser chamado de parâmetros de entrada e saída, que podem ser inseridos pelo cliente e pelo servidor. Depois que o cliente insere os parâmetros no servidor, o servidor também pode modificar os parâmetros, etc. Por fim, o que é obtido no cliente são os parâmetros gerados pelo servidor.

Reconstruímos manualmente nosso sistema de projeto neste diretório app\build\generated\source\aidl\debug para gerar automaticamente IBookManger.java para nós. A seguir, vamos dar uma olhada na verdadeira face do 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;
}

É um pouco confuso no início, não se preocupe, vamos analisar passo a passo. O arquivo IBookManager inclui duas interfaces de IBookManager.aidl, bem como duas classes, Stub e Proxy, que implementam a interface IBookManager. Stub é definido em a interface IBookManager e Proxy é definido na classe Stub.

Insira a descrição da imagem aqui

Processo de execução do cliente

1. Quando a conexão de serviço é estabelecida, o cliente executa o código. IBookManager.Stub.asInterface(service)A função deste código é determinar se o IBinderobjeto de parâmetro recebido está no mesmo processo que ele mesmo. Caso contrário, o IBinderparâmetro é empacotado em um Proxyobjeto. Neste momento, o método de é chamado Stube o método de é chamado getBookList()indiretamente . Dê uma olhada no código.ProxygetBookList()

// 连接服务
    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. ProxyEm seu próprio getBookList()método, você usará Parcelablepara preparar os dados, escrever o nome da função e os parâmetros da função _datae _replyreceber o valor de retorno da função. Por fim, use IBindero transactmétodo () de para passar os dados até o final Binderde 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;
            }

mRemoteO que isso significa?
Quando um é criado, ele também cria uma referência ao Servidor Server Binderno driver Binder . Quando o cliente deseja acessar, ele deve primeiro obter a referência do Servidor no Binder . Após obter a referência, ele pode enviar uma mensagem ao servidor através do método.mRemoteClientServermRemotemRemote.transact()

transactFez as seguintes coisas

  • Envie os parâmetros passados ​​pelo cliente para o servidor no modo de comunicação de mensagens entre threads.
  • Suspender o thread do cliente atual e aguardar a notificação após o thread do servidor concluir a execução (notificar)
  • Receba notificação de thread do servidor, continue executando o thread do cliente e retorne os resultados da execução
Processo de execução do servidor

O Servidor recebe os dados do processo Cliente através do método onTransact(), incluindo o nome da função e os parâmetros da função, encontra a função correspondente, aqui está getBookList(), alimenta os parâmetros, obtém o resultado e retorna. Portanto, a função onTransact() passou pelo processo de leitura dos dados, execução da função a ser chamada e gravação do resultado da execução nos dados.

 @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);
        }

Como funcionam os quatro componentes principais

Como funciona a atividade
Como iniciar o aplicativo

Clique no ícone de um aplicativo na tela do celular, supondo que seja o aplicativo Douyu, e a página inicial do aplicativo será exibida diante de nós. Por trás dessa operação aparentemente simples, há um processo repetido de comunicação entre Atividade e AM. O primeiro passo é entender que a tela do celular é uma Activity. O aplicativo onde essa Activity está localizada é chamado de Launcher na indústria. O Launcher é fornecido pelos principais fabricantes de celulares.

O Launcher fornece as informações de Intent necessárias para iniciar o aplicativo para cada ícone do aplicativo, como: nome do pacote, endereço da página inicial, categoria, etc. Essas informações são lidas quando o aplicativo é instaladoPackageManagerServicenos arquivos em cada pacote apkAndroidManifest

Iniciar processo

①O Launcher notifica o ATMS que deseja iniciar o aplicativo Douyu e especifica em qual página iniciar o aplicativo

②Após o ATMS receber a mensagem, ele registra a página a ser lançada.

③A página atual do Launcher entra no estado Pausado e notifica o ATMS: "Vá encontrar o aplicativo correspondente."

④ATMS verifica se o aplicativo Douyu foi iniciado. Em caso afirmativo, ele acessará o aplicativo Douyu. Caso contrário, iniciará um novo processo. Crie um objeto ActivityThread no novo processo onde o ATMS está localizado e inicie a função principal correspondente.

⑤Depois que o aplicativo for iniciado, notifique o ATMS: "Eu comecei."

⑥ATMS extrai o valor registrado anteriormente (a página a ser iniciada) e informa ao aplicativo Douyu para iniciar esta página.

⑦O aplicativo Douyu inicia a página inicial, cria um Contexto e o associa à Atividade da página inicial e, em seguida, chama a função onCreate da Atividade que inicia a página.

O processo agora está concluído e dividido em duas partes, Estágios 1 a 3: Launcher e AMS se comunicam entre si, e Estágios 4 a 7: Aplicativo Douyu e AMS se comunicam entre si.

Fase 1: Launcher notifica ATMS

Depois de clicar no aplicativo no Launcher, o método startActivitySafely do Launcher será chamado. Na verdade, o método startActivity da Activity ainda será chamado. O método startActivity precisa passar o parâmetro Intent. A intenção carrega as principais informações necessárias para iniciar o aplicativo , como: a página inicial. Nome da classe, etc., então por que você precisa especificar a ação e a categoria na página inicial do Manifesto? O Launcher encontrará essas informações importantes para iniciar ao iniciar.

pacotes/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;
}

Finalmente, o método startActivity de Activity é chamado:

# 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);
    }
}

Ao iniciar o aplicativo, o método startActivityForResult da Activity será chamado após muitas chamadas. O código de startActivityForResult é o seguinte:

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 {
            //省略部分代码
        }
    }

Cada atividade contém um objeto de instrumentação, a variável mMainThread. Este é um ActivityThreadtipo de variável, que é o thread principal, que é o thread da interface do usuário . Ele representa o aplicativo inteiro. Os leitores não podem deixar de perguntar se ele representa ActivityThreado aplicativo App . , Applicationo que a classe representa? ? Na verdade, Applicationnão é tão importante para o sistema Android, é apenas um contexto, Applicationo contexto do aplicativo Contexte Activityo contexto do aplicativo.

MamainThread.getApplicationThread() é passado para esta função, e o que ela obtém é a classe interna ApplicationThread de ActivityThread. Este é um objeto Binder que representa o launcherprocesso do aplicativo em que está. É mTokentambém um Binderobjeto que representa launchera Activity e também é passado Instumentationpara o ATMS. O ATMS consulta o registro para saber quem enviou a solicitação ao ATMS. Em seguida, o ATMS se comunica com o aplicativo por meio deste objeto (ApplicationThread)

Método View mInstrumentation.execStartActivity, com a ajuda execStartActivityde Activity passará os dados para ActivityTaskManager.
ActivityTaskManager.getService()É obtido através de AIDL IActivityTaskManager. É ActivityTaskManagerServiceuma referência de fichário. A função chamada aqui é chamada remotamente ActivityTaskManagerService. É uma interface que implementa IInterface, que define o ciclo de vida dos quatro componentes principais. Ao iniciar a Atividade, o mecanismo de comunicação com 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 é um objeto que faz proxy do Binder no lado do ATMS e, em seguida, o ATMS inicia startActivity. Neste ponto, termina o processo do Launcher solicitando ao ATMS para iniciar uma Atividade.

Fase 2: ATMS processa as informações do Launcher

1: O Launcher se comunica com o AMS por meio de AIDL e deve fazer coisas diferentes a cada vez. Por exemplo, desta vez o Launcher deseja iniciar o aplicativo Douyu, então o método startActivity do Launcher eventualmente obterá o startActivity chamado pelo proxy IActivityTaskManager do ATSM e, em seguida, entrará no sistema ATMS startActivity no processo do servidor, o ATMS sabe qual atividade iniciar coletando informações de Intent

2: AMS diz: "Ok, entendi", então ele irá verificar o arquivo AndroidManifest para verificar se a Activity a ser iniciada existe, e caso não exista, lançará uma mensagem de exceção Activity not found.

3: AMS notificou o Launcher: "Não há nada de errado com você, apenas vá para a cama." Então, como a AMS disse ao Launcher? A conclusão é: o AMS envia mensagens através do proxy do IApplicationThread, e o lado App recebe a mensagem através do ApplicationThread, ainda no modo AIDL.

Voltando ao código, ActivityTaskManagerServicea startActivitychamada é finalmente chamada startActivityAsUser, obtendo o ActivityStarter através de uma série de construtores e definindo os parâmetros correspondentes, e finalmente executando o método execute do ActivityStarter. A função da função execute é iniciar o aplicativo com base no anterior parâmetros de solicitação fornecidos.

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();

    }
AtividadeStarter

ActivityStarter: Responsável pela operação de inicialização de uma Activity. Suas principais funções incluem análise de Intent, criação de ActivityRecord e, se possível, criação de TaskRecord.
O tipo retornado por getStarter é ActivityStarter, e a função de sua função de execução é iniciar o aplicativo com base nos parâmetros de solicitação fornecidos anteriormente.

Caminho de chamada principal:

execute===>> executeRequest====>> startActivityUnchecked===>>startActivityInner

  • exexute: interface para processamento de solicitações de inicialização de atividades;
  • executeRequest: realiza uma série de verificações de permissão e continua apenas para solicitações legítimas;
  • startActivityUnchecked: Quando este método é chamado, significa que a maioria das verificações preliminares de permissão foram concluídas, o Trace foi executado e o tratamento de exceções foi executado;
  • startActivityInner: inicia a atividade e atualiza as informações do quadro da pilha de tarefas globais;

Ignore o código para gerenciamento de janelas de tarefas, como ActivityStack e WindowContainer, e concentre-se apenas naqueles que realmente iniciam o aplicativo:

  • mRootWindowContainer.resumeFocusedTasksTopActivities()

resumeFocusedStacksTopActivities() Primeiro mova a pilha de atividades de destino para o primeiro plano, depois crie a atividade e coloque-a na pilha. O usuário pode vê-la diretamente. Portanto, a lógica de criação da atividade ainda está em 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);
}
Pilha de atividades

ActivityStack: gerencia TaskRecord, contém vários TaskRecord · ActivityStackSupervisor: gerencia 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);
    ...
}

O método startPausingLocked notifica principalmente o Launcher para entrar no estado de pausa. Anteriormente aprendemos sobre a comunicação entre o Launcher e o ATMS. Agora vamos ver como o ATMS se comunica com o 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() retorna ClientLifecycleManager;
PauseActivityItem herda de ActivityLifecycleItem, que encapsula uma série de operações IPC;

ClienteLifecycleManager

Esta classe é capaz de combinar múltiplas solicitações e/ou retornos de chamada de transição de ciclo de vida e executá-los como uma única transação. A principal função são as chamadas de gerenciamento do ciclo de vida.

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();
    }
}

Chame ClientTransaction .schedule():

public void schedule() throws RemoteException {
    //mClient就是IApplicationThread,接下来会通过IPC的方式调用
    //Launcher的ActivityThread.ApplicationThread.scheduleTransaction方法;
    //从AMS进程,进入App进程
    mClient.scheduleTransaction(this);
}

A partir daqui, voltamos do processo do sistema para o processo de aplicação.

IApplicationThread: é o objeto proxy Binder de ApplicationThread no processo do aplicativo mantido pelo processo do sistema.

A implementação do método mClient.scheduleTransaction() está no ApplicationThread do cliente, e a seguir entraremos ActivityThread.ApplicationThread;

ApplicationThread

ApplicationThread: Classe interna do ActivityThread. Depois que o AMS chama o método em ApplicationThread por meio do proxy fichário, ele notifica o thread principal para chamar o método relevante por meio da pesquisa de mensagens do manipulador aberta no thread principal (método principal em ActivityThread). A implementação específica dos métodos de ciclo de vida relevantes do thread principal será delegada à classe Instrumentação.Na classe Instrumentação, serão chamados os métodos de ciclo de vida relevantes de componentes específicos.

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 envia uma mensagem EXECUTE_TRANSACTION para H de ActivityThread, e ActivityThread e ApplicationThread se comunicam por meio do Handler.


case EXECUTE_TRANSACTION:
    //取出传递过来的ClientTransaction
    final ClientTransaction transaction = (ClientTransaction) msg.obj;
    //执行transaction
    mTransactionExecutor.execute(transaction);
    if (isSystem()) {
        transaction.recycle();
    }
    break;

Obtenha ClientTransaction no lado ATMS e chame 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():
Por exemplo, para uma determinada Atividade A, seu ciclo de vida atual é o estágio onCreate, representado por 1; lifecycleItem.getTargetState() está relacionado ao tipo de lifecycleItem. Os valores de retorno de getTargetState() de PauseActivityItem e ResumeActivityItem são diferentes. Se o lifecycleItem aqui for ResumeActivityItem, e o ciclo de vida correspondente a ResumeActivityItem for onResume da Activity. O valor de retorno de lifecycleItem.getTargetState() é 3. Como onCreate representa 1, a diferença entre 1 e 3 é 2 , então ainda há uma diferença entre onCreate e onResume.Ciclo de vida, esse ciclo de vida é onStart();

Após uma série de chamadas de método, o método execute ===>> executeLifecycleState ===> cycleToPath ===> lifecycleItem.execute
é chamadoPauseActivityItem.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);
}

Voltar para 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;
}

Continue observando performPauseActivityIfNeeded(r, reason) em performPauseActivity():

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 delega o trabalho de pausa à Instrumentação. Cada atividade contém uma Instrumentação e, finalmente, a entrega ao performPause da Atividade.

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()");
    }
}
Resumir

Inicie uma chamada de processo cruzado do fichário por meio do método SchedulePauseActivity de IApplicationThread, insira o método SchedulePauseActivity de ApplicationThread do processo de aplicativo (este método é executado no pool de encadeamentos do fichário do cliente) e, em seguida, alterne os dados para o processo principal do processo de aplicativo por meio mH para execução, que é executado por ActivityThread O método handlePauseActivity é processado e, em seguida, o método callActivityOnPause da Instrumentação é chamado internamente por meio de performPauseActivity. O método performPause da Activity é chamado internamente e o método onPause do Launcher é chamado de volta.

A terceira etapa: o Launcher adormece e notifica o ATMS: "Fui dormir".

Quando o Launcher está no estado onPause, ele precisa notificar o processo AMS para executar a próxima etapa e chamar PauseActivityItem.postExecute():

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();
    }
}
Fase 4: ATMS inicia novo processo

Em seguida, o ATMS precisa iniciar a página inicial do aplicativo Douyu. Como este aplicativo não está no processo em segundo plano, ele precisa iniciar um novo processo. O método Process.start é chamado aqui e a função principal de ActivityThread é designada como a função de entrada .

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");
}

A quinta etapa: o novo processo é iniciado, com a função principal do ActivityThread como ponto de entrada

Iniciar um novo processo significa iniciar um novo aplicativo e criar um objeto ActivityThread para esse processo. Este é o thread principal da UI com o qual estamos familiarizados. Depois de criar o thread de UI, entre imediatamente na função principal de ActivityThread e faça duas coisas importantes:

  • ①Crie um Looper de thread principal, ou seja, MainLooper. MainLooper é criado aqui

  • ②Criar aplicativo, o aplicativo também é criado aqui

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");
}

Criou ActivityThread e chamou o método attachment:

final ApplicationThread mAppThread = new ApplicationThread();
private void attach(boolean system, long startSeq) {
    ......
    if (!system) {
        //这一步是获取AMS实例
        final IActivityManager mgr = ActivityManager.getService();
        //然后跨进程通信
        mgr.attachApplication(mAppThread, startSeq);
    } 
}

Ao obter o AMS, execute a comunicação entre processos e chame o método attachmentApplication do AMS.

Em AMS.attachApplication(), ActivityThread.ApplicationThread.bindApplication() será chamado:

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);
}

Crie um objeto LoadedApk por meio de getPackageInfoNoCheck() e salve-o em data.info.
O aplicativo é criado por meio de data.info.makeApplication(data.restrictedBackupMode, null).
app.onCreate(); é chamado por meio de mInstrumentation.callApplicationOnCreate(app) e o aplicativo é criado.

Depois de receber a mensagem, o thread principal cria um objeto correspondente (marcando as informações do apk atual) BIND_APPLICATIONcom base na mensagem passada e, em seguida, cria o objeto (marcando o ambiente do processo atual) e, em seguida, cria o aplicativo de destino por meio de reflexão e chama seu método anexar para adicionar ContextImpl O objeto é definido como o contexto do aplicativo de destino e, finalmente, a função Application é chamada para fazer algum trabalho de inicialização.ApplicationInfoLoadedApkContextImplonCreate

A alma do App é ActivityTreado thread principal, que não é utilizado pelos desenvolvedores de aplicativos, mas alguns comportamentos desta classe podem ser modificados usando reflexão.

O bindApplication do APP inicializa principalmente AppBindData, depois envia BIND_APPLICATION para o thread principal BIND_APPLICATION do APP e, finalmente, executa handleBindApplication. Este método configura principalmente alguns dos recursos de hardware do aplicativo no processo do aplicativo, incluindo os atributos solicitados, as pastas do aplicativo, etc. noções básicas do App. Inicialização de informações

Anexar aplicativo ATMS

A última etapa na criação de um aplicativo é dizer ao ATMS: "Eu o iniciei." Ao mesmo tempo, envie seu ActivityThreadobjeto para o ATMS. Essas novas informações de registro do aplicativo serão adicionadas à lista telefônica do ATMS. No futuro, o ATMS irá use este objeto ActivityThread para enviar mensagens para este App. Envie uma mensagem. Esta parte do código está em:

//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;
}

No AttachApplication() do ATMS, após ActivityThread.ApplicationThread.bindApplication() ser executado por meio do IPC, mStackSupervisor.attachApplicationLocked(app) será chamado. mStackSupervisor é ActivityStackSupervisor e, finalmente, o método realStartActivityLocked de ActivityStackSupervisor é chamado.

  • O ActivityRecord é melhorado aqui e o processo e outras informações são definidos. De modo geral, pode-se entender que ActivityRecord, ProcessRecord, etc. devem ser gerenciados pelo AMS/ATMS, e a aplicação está vinculada ao ATMS aqui.
  • Objeto ClientTransaction criado
  • O retorno de chamada de ClientTransaction é definido, que é um objeto LaunchActivityItem criado.
  • Defina o ciclo de vida do objeto lifecycleItem criado
  • Envie uma solicitação por meio de mService.getLifecycleManager().scheduleTransaction(clientTransaction). O mService aqui é ATMS, e o mService.getLifecycleManager() aqui é ClientLifecycleManager.
  • Após criar a Aplicação, vincule-a ao ATMS através de attachmentApplication(). Ainda está no processo do sistema.
Etapa 6: ATMS informa ao novo aplicativo qual atividade iniciar

O ATMS converte o objeto ActivityThread de entrada em um objeto ApplicationThread para futura comunicação entre processos com o aplicativo. No sexto estágio, o AtMS descobre qual atividade iniciar a partir dos registros anteriores e, em seguida, informa ao aplicativo por meio do ATP.

No método realStartActivityLocked do ActivityStackSupervisor, a solicitação é enviada através de mService.getLifecycleManager().scheduleTransaction(clientTransaction), ou seja, o ClientLifecycleManager é chamado para enviar a solicitação.
O próximo processo é o mesmo da suspensão do Launcher. Verifique o método scheduleTransaction do 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 é uma interface IApplicationThread. Também analisamos acima que sua implementação é ApplicationThread. Aqui voltamos ao 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);
    }

A mensagem EXECUTE_TRANSACTION é enviada para a classe H do ActivityThread no método scheduleTransaction.

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();
            }
    ......
}

Esta mensagem é processada através de handleMessage, que chama o método execute de TransactionExecutor:

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);
 }

Em realStartActivityLocked() acima, o conjunto de retorno de chamada é o objeto LaunchActivityItem. Aqui execute() finalmente é executado para execute() do LaunchActivityItem.

//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);
}

O cliente aqui é ActivityThread. Então fui para handleLaunchActivity() do ActivityThread

//ActivityThread.java:
public Activity handleLaunchActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions, Intent customIntent) {
    ......
    final Activity a = performLaunchActivity(r, customIntent);
    ......
    return a;
}
 

Leia

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);
        }
    ......
}

Após uma série de chamadas de método execute->executeCallbacks->cycleToPath->performLifecycleSequence, finalmente vemos algo familiar, um monte de ciclos de vida de atividades.

Para resumir a história, o processo principal é:

  • Crie o contexto da aplicação (Context) e obtenha o ClassLoader;
  • A criação de um objeto Activity é essencialmente classLoader.loadClass(name).newInstance(), onde a classe Activity é inicializada e o método do objeto é chamado para executar o código no bloco estático na classe alvo;
  • Crie um objeto Application baseado no AndroidManifest.xml do aplicativo e chame seu retorno de chamada onCreate;
  • Chame o retorno de chamada onCreate da atividade correspondente;
Etapa 7: iniciar a atividade da página inicial do Douyu

Insira a descrição da imagem aqui

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);
        }
    ......
}

O que o método performLaunchActivity faz?

①Crie a instância de Activity a ser iniciada através do método newActivity de Instrumentation.

②Crie um objeto Contexto para esta Atividade e associe-o à Atividade

③Através do método callActivityOnCreate de Instrumentaction, execute o método onCreate da atividade para iniciar a atividade. Neste ponto, o aplicativo é iniciado. Este processo passa por vários apertos de mão. O aplicativo e o ATMS frequentemente enviam mensagens um para o outro e o mecanismo para enviar mensagens é estabelecido no Binder.com base em.

Salto de página dentro do aplicativo

A seguir veremos o salto para a página interna do App.

Ao saltar de ActivityA para ActivityB, ActivityA pode realmente ser considerada como Launcher, então este processo de salto é muito semelhante ao processo de inicialização do App.

Com base na análise anterior, você descobrirá que este processo não requer a reinicialização de um novo processo, portanto, algumas etapas do processo de inicialização do aplicativo podem ser omitidas e o processo é simplificado da seguinte forma:

  1. ActivityA envia uma mensagem ao AMS para iniciar ActivityB.
  2. O AMS salva as informações da ActivityB e notifica o aplicativo que você pode dormir (onPaused).
  3. A ActivityA adormece e notifica o AMS de que fui dormir.
  4. O AMS descobre que o processo onde a ActivityB está localizada é o processo onde a ActivityA está localizada, portanto, não há necessidade de reiniciar um novo processo, portanto, ele notificará o aplicativo para iniciar a ActivityB.
  5. O aplicativo inicia a ActivityB.

Insira a descrição da imagem aqui
A análise acima é limitada a ActivityA e ActivityB no mesmo processo. Se você especificar no Manifesto que essas duas atividades não estão no mesmo processo, então será outro conjunto de processos, mas o processo geral é semelhante.

Contextohistória familiar

Tanto Activity quanto Service têm Context. Essas três classes, assim como Application, são na verdade parentes.
Insira a descrição da imagem aqui

Como a Activity possui uma camada de Theme, existe um ContextThemeWrapper no meio, que equivale a ser sobrinho de Service e Application.

ContextWrapper é apenas uma classe wrapper sem nenhuma implementação específica. A lógica real está em ContextImpl.

O número de Contextos incluídos em uma aplicação: o número de Serviços + o número de Atividades + 1 (a própria classe Application corresponde a um objeto Context).

O aplicativo contém vários objetos ContextImpl e sua variável interna mPackageInfo aponta para o mesmo objeto PackageInfo.

A diferença entre atividade e contexto

Vamos tomar Activity como exemplo para ver a conexão e a diferença entre Activity e Context.

Sabemos que pular para uma nova Activity deve ser escrito assim:
Insira a descrição da imagem aqui

Também sabemos que você também pode usar métodos em Activity getApplicationContextpara obter informações de Contexto e, em seguida, usar o método startActivity de Context para iniciar uma nova Activity:
Insira a descrição da imagem aqui
Qual é a diferença entre os dois?

Durante a atividade:

@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);
        }
    }

Não importa qual método startActivity é usado na Activity, ele chamará o próprio método da Activity, portanto é o mesmo.

Porém, a implementação em outras subclasses de Context, como ContextImpl.java, irá verificar se Flag: FLAG_ACTIVITY_NEW_TASK está definido, caso contrário um erro será relatado:

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);
    }

Acho que você gosta

Origin blog.csdn.net/jxq1994/article/details/130404518
Recomendado
Clasificación