The working principle of Binder and the four major components Service, BroadCastReceiver, ContentProvider

Service working principle

Service has two sets of processes, one is the startup process and the other is the binding process. All our students doing App development should know

Insert image description here

1) Start Service in a new process

Let's first look at the Service startup process. Assume that the Service to be started is in a new process, which is divided into 5 stages:

  1. App sends a message to AMS to start the Service.
  2. AMS checks whether the process that started the Service exists. If it does not exist, it first saves the Service information and then creates a new process.
  3. After the new process is started, AMS is notified that I can do it.
  4. AMS sends the Service information just saved to the new process
  5. New process starts Service
Stage 1

Insert image description here
Very similar to Activity, the Service information to be started is still sent to AMS through AMM/AMP.

Stage 2
  1. AMS checks whether the Service is declared in the Manifest. If not, an error will be reported directly.

  2. AMS checks whether the process that started the Service exists. If it does not exist, it first saves the Service information and then creates a new process.

  3. In AMS, each Service is saved using a ServiceRecord object.

Stage 3

The process of starting the new process where the Service is located is similar to the process of starting the App introduced earlier.

After the new process is started, a new ActivityThread will also be created, and then the ActivityThread object will be passed to AMS through AMP, telling AMS that the new process has been started successfully.

Stage 4

AMS transforms the passed ActivityThread object into ApplicationThreadProxy, which is ATP. Through ATP, it sends the Service information to be started to the new process.

Stage 5

Insert image description here
The new process receives the AMS information through ApplicationThread, which is the same as the last step of starting the Activity introduced earlier. With the help of ActivityThread and H, the onCreate method of Service is executed. During this period, the Context object is created for the Service and associated with the Service.

What needs to be focused on is the handleCreateService method of ActivityThread.
Insert image description here

You will find that this code is similar to the handleLaunchActivity introduced earlier. It takes out the package information packageInfo from the PMS, which is a LoadedApk object, and then gets its classloader and reflects a class object. What is reflected here is Service. .

The logic of the four major components is the same, so we need to make it plug-in. We can make a fuss here and change it to the classloader of the plug-in to load the four major components in the plug-in.

At this point, we have started a Service in a new process.

2) Start the Service of the same process

If the Service is started in the current process, the above steps are simplified to:

  1. App sends a message to AMS to start the Service.

  2. AMS performs routine checks, such as whether the Service is declared, and registers the Service with AMS. AMS finds that the Service to be started is the Service where the App is located, and notifies the App to start this Service.

  3. App starts Service.

3) Bind Service in the same process

If the Service is bound in the same process, the process is:

  1. App sends a message bound to the Service to AMS.

  2. AMS performs routine checks, such as whether the Service is declared, and registers the Service with AMS. AMS discovers that the Service to be started is the Service of the process in which the App is located, and then notifies the App to start the Service, and then notifies the App to bind the Service.

  3. App receives the first message from AMS and starts Service.

  4. App receives the second message from AMS, binds the Service, and passes a Binder object to AMS.

  5. AMS sends the received Binder object to the App

  6. The App receives the Binder object and can use it.

You may ask, if they are all in the same process, wouldn’t it be better to use the Binder object directly inside the App? Actually, we have to consider the scenario of not being in the same process, and we cannot write two copies of the code and two sets of logic, so we put them all together. , even in the same process, you have to go around the AMS.

Phase 1: App sends a message binding Service to AMS.
Insert image description here
Stage 4: Processing the second message
Insert image description here
Stage 5 and Stage 6:
This step needs to be explained carefully, because AMS passes the Binder object to the App. ATP and APT are not used here, but AIDL is used to implement this. The name of AIDL is IServiceConnection.
Insert image description here
The connect method of ServiceDispatcher will eventually call the onServiceConnected method of ServiceConnectiont. We are very familiar with this method. App developers get the connection in this method and can do their own thing.

How BroadCast Receiver works

Receiver is divided into two types: static broadcast and dynamic broadcast.

The Receiver declared in the Manifest is a static broadcast:
Insert image description here
the registration code manually written in the program is a dynamic broadcast:
Insert image description here
both have the same function, but are written in different ways. In this case, we can change all static broadcasts to dynamic broadcasts, which saves the need to declare them in the Manifest file and avoids AMS checks. What comes to your mind next? Yes, Receiver’s plug-in solution is based on this idea.

Next, let's see how Receiver deals with AMS. It is divided into two parts, one is registration, and the other is sending broadcast.

Only if you register for this broadcast can you be notified and the onReceive method executed when this broadcast is sent.

Let's take the music player as an example. Register the Receiver in the Activity and send the broadcast in the Service. When the Service plays the next piece of music, it will notify the Activity to modify the name of the currently playing music.

The registration process is as follows:

  1. In the Activity, register the Receiver and notify AMS.
    Insert image description here

Here Activity uses the registerReceiver method provided by Context, and then passes a receiver to AMS through AMN/AMP.

When creating this Receiver object, you need to specify an IntentFilter for the receiver. This filter is the Receiver's ID card and is used to describe the receiver.

In the registerReceiver method of Context, it uses PMS to obtain the package information, which is the LoadedApk object.

It is this LoadedApk object, and its getReceiverDispatcher method encapsulates the Receiver into a Binder object that implements the IIntentReceiver interface.

We just pass this Binder object and filter to AMS.

It's not enough to just pass the Receiver to AMS. When sending a broadcast, AMS doesn't know who to send it to? Therefore, the process where the Activity is located also needs to send its own object to AMS.

  1. After AMS receives the message, it will store the above information in a list, which stores all Receivers.

Attention, I have been busy here for a long time, registering dynamic receivers.
When was the static receiver registered to AMS? It is when the App is installed. PMS will parse the four major component information in the Manifest and store the receiver among them.
Dynamic receiver and static receiver are stored in different variables of AMS respectively. When sending a broadcast, the two receivers will be merged together and then sent. Among them, dynamic ones are ranked before static ones, so dynamic receivers always receive messages before static receivers.

In addition, every time the Android system starts, it will also register static broadcast receivers to AMS. Because every time the Android system starts, all apks will be reinstalled.

The process of sending a broadcast is as follows:
  1. In Service, broadcast is sent to AMS through AMM/AMP, and the broadcast carries Filter.

  2. After AMS receives this broadcast, it finds the corresponding receiver according to the filter in the receiver list, which may be multiple, and puts them all into a broadcast queue. Finally, send a message to the AMS message queue.

    When the message in the message queue is processed, AMS finds the appropriate receiver from the broadcast queue and sends the broadcast to the process where the broadcast receiver is located.

  3. When the process where the receiver is located receives the broadcast, it does not send the broadcast directly to the receiver. Instead, it encapsulates the broadcast into a message and sends it to the message queue of the main thread. When the message is processed, the broadcast in the message is Send to receiver.

Let’s take a closer look at these three stages through the diagram below:

Step 1, Service sends a broadcast to AMS

Insert image description here
The broadcast is sent through the Intent parameter, which carries the Filter, thereby telling AMS what kind of receiver can accept the broadcast.

Step 2, AMS receives the broadcast and sends the broadcast.

Receiving broadcasts and sending broadcasts are not synchronized. Every time AMS receives a broadcast, it throws it into the broadcast sending queue. As for whether the sending is successful, it does not care.

Because receivers are divided into unordered receivers and ordered receivers, the broadcast sending queue is also divided into two, and these two broadcasts are sent separately.

AMS sends a broadcast to the client, which is another cross-process communication, or sends the message to APT through ATP. Because the Receiver object needs to be passed, it is also a Binder object and can be passed. As we said before, when registering the Receiver to AMS, the Receiver will be encapsulated into a Binder object of the IIntentReceiver interface. Then, AMS will pass back the IIntentReceiver interface object.

Step 3, App handles broadcast
Insert image description here

This process is described as follows:

  1. The message is transmitted from AMS to the client, and the IIntentReceiver interface object in AMS is converted into an InnerReceiver object. This is the receiver. This is an AIDL cross-process communication.

  2. Then encapsulate an Args object in ReceiverDispatcher (this is a Runnable object, to implement the run method), including all the information needed by the broadcast receiver, and hand it over to ActivtyThread for sending

  3. The next step is what we are familiar with. ActivtyThread throws the Args message into the H Hanlder and sends the message to the main thread message queue. When the Args message is executed, the run method of Args is naturally executed.

  4. In the run method of Args, instantiate a Receiver object and call its onReceiver method.

  5. Finally, in the run method of Args, as the onReceiver method call of Receiver ends, a message will be sent to AMS through AMN/AMP, telling AMS that the broadcast was sent successfully. After AMS is notified, it sends a broadcast to the next Receiver.

Note: InnerReceiver is the stub of IIntentReceiver and is the receiving end of the Binder object.

Type of broadcast

Android broadcasts are classified into three types according to the sending method: unordered broadcast, ordered broadcast (OrderedBroadcast) and sticky broadcast (StickyBroadcast).

  1. Out-of-order broadcast is the most common type of broadcast.

  2. Ordered broadcast differs from unordered broadcast in that it can specify priority.

These two receivers exist in different variables of AMS and can be considered as two receiver sets that send different types of broadcasts.

  1. Sticky broadcast is a type of out-of-order broadcast.

We don’t see many sticky broadcasts, but you’ll understand when I talk about one scenario: battery power. When the battery level is less than 20%, the user will be prompted.
Obtaining battery power information is achieved through broadcasting.
But in general broadcasting, it’s over once it’s sent out. We need to have such a broadcast that can continue to exist after it is sent out, and future registrants can also receive this broadcast. This kind of broadcast is a sticky broadcast.

Since a dynamic receiver can only be registered and receive broadcasts when the Activity's onCreate() method is called, it cannot receive broadcasts when the program is not running; but static registration does not depend on whether the program is running.

How ContentProvider works

1.How to use CP

Let’s quickly review how to use CP in the App.
Insert image description here

  1. App1 that defines CP
    defines a CP subclass MyContentProvider in App1 and declares it in Manifest. To this end, four methods of adding, deleting, modifying and checking CP must be implemented in MyContentProvider:

Insert image description here

Insert image description here

  1. App2 using CP:
    App2 accesses the CP defined in App1. To do this, ContentResolver is used, which also provides four methods of adding, deleting, modifying and checking for accessing the CP defined in App1:
    Insert image description here

First, let’s take a look at the underlying implementation of the four methods of adding, deleting, modifying, and checking ContentResolver. In fact, they all communicate with AMS, and finally call the four methods of adding, deleting, modifying, and checking of CP of App1. We will talk about this process later.

Secondly, URI is the CP’s ID card and unique identifier.

We declare the URI for CP in App1, that is, the value of authorities is baobao. If we want to use it in App2, we specify the URI in the four methods of Add, Delete, Modify and Check in ContentResolver. The format is:

uri = Uri.parse("content://baobao/");

Next, put both Apps into debug mode, and you can debug from App2 to App1, for example, query operation.

2.The essence of CP

Various data sources come in various formats, such as text messages and address books. They are different data tables in SQLite. However, for external users, they need to be encapsulated into a unified access method, such as for data collections. In other words, four methods of addition, deletion, modification, and query must be provided, so we encapsulated a layer on top of SQLite, which is CP.

3. Anonymous Shared Memory (ASM)

CP reads data using anonymous shared memory, abbreviated as ASM in English, so you can see that CP and AMS are very busy communicating above, but in fact, there is a different scenery below.

Regarding the concept of ASM, it is actually a Binder communication. I will draw a picture and you will understand:

Insert image description here
The CursorWindow here is anonymous shared memory.

The process, simply put, is this:

1) There is a CursorWindow object inside the Client. When sending a request, this CursorWindow type object is passed over. This object is temporarily empty.

2) Server receives the request, collects data, and fills it into the CursorWindow object.

3) Client reads the internal CursorWindow object and obtains the data.

It can be seen that this CursorWindow object is anonymous shared memory, which is the same anonymous memory.

To give an example in life, you order milk and put a box at your door. The milkman puts a bag of milk into the box every morning. When you wake up, you go to get the milk from the box. This milk crate is anonymous shared memory.

4.Communication process between CP and AMS

Let's take the example of App2 wanting to access the CP defined in App1. Let’s look at the insert method of CP.
Insert image description here
The above 5 lines of code include two parts: starting CP and executing the CP method. The watershed is the insert method. The implementation of the insert method. The first half is still starting the CP. When the CP is started, the proxy object of the CP is obtained. The second half is Through the proxy object, call the insert method.

The overall process is shown in the figure below:

Insert image description here
1) App2 sends a message to AMS and wants to access the CP in App1.

2) AMS check found that the CP in App1 has not been started. Therefore, a new process was opened to start App1, and then the CP started by App1 was obtained, and the proxy object of the CP was returned to App2.

3) App2 gets the proxy object of CP, which is IContentProvider, and calls its four methods of adding, deleting, modifying, and checking. The next step is to use ASM to transmit data or modify data, which is the CursorWindow class mentioned above. Obtain Data or operation results are enough. As an App developer, you don’t need to know too many underlying details and it’s not useful.

Guess you like

Origin blog.csdn.net/jxq1994/article/details/130410469