For the concept of process, came here is the programming immortal, no longer worded, I believe that you can recite backwards, jumping, lying down, all kinds of posture.

Why use multiple processes when just one process is ok?

Believe that many students in the actual development, basic wouldn’t give the app division process, moreover, the use of multiple processes in Android, may also need to write additional code process communication, also may lead to additional bugs, no doubt increased the development workload, time limit for a project in a number of startups does not allow, this led to the entire app in a process.

What are the disadvantages of running the entire app in one process? In Android, there is a limit on the memory allocated to each process by the VIRTUAL machine (the value can be 32M, 48M, 64M, etc., depending on the model). Imagine adding a commonly used image selection module in the app for uploading pictures or profile pictures. Loading a large number of bitmaps will increase the memory usage of the app rapidly. If you also cache the images you have viewed in the memory, then the risk of OOM will greatly increase. If you need to use WebView to load a wave of web pages at this time, I ask you are afraid!

How do mainstream apps such as wechat and Weibo solve these problems? Wechat mobile development team said in the article “Android Memory optimization talk” : “For Webview, gallery, etc., because there are memory system leaks or occupy too much memory, we can use a separate process. Wechat also currently places them in a separate Tools process.”

Use ADB to check the process information of wechat and Weibo (for Android version 5.0 or lower, you can directly go to Settings -> Applications) :

After entering the adb shell, use the “ps | grep entry name” can filter out the process of want to see.

Therefore, the rational use of multiple processes is not only a matter of great benefit, I personally think it is very necessary.

Therefore, it is best to consider whether we need to split the process based on our circumstances. That’s the purpose of this article: to give you a multi-process approach to solve the problems and situations mentioned above, or to talk to the interviewer about this knowledge during the interview.

Why cross-process communication?

For example, if the selected image module is placed in a separate process, we can still use the startActivityForResult method to place the selected image in the Bundle and deliver it with the Intent. (See here, aren’t you planning on making your project’s image selection a separate process?)

However, the business of putting the “push notification Service” into a separate process is a little more complicated. In this case, a series of complex operations may occur, such as passing objects to the Service and calling Service methods.

Each process runs in a relatively independent memory space, so they cannot communicate directly, because variables and objects in the program have memory addresses after initialization. For example, reading the value of a variable is essentially to find the memory address of the variable and take out the stored value. Different processes, running in independent memory (in fact, it can be understood as two different applications), obviously cannot directly know the memory address of each other’s variables, objects, and so naturally cannot access each other’s variables, objects, and so on. When the two processes interact, they need to use cross-process communication to achieve it. Simply put, cross-process communication is a technology that allows processes to interact with each other.

What are the ways to communicate across processes?

  1. Transfer bundles between the four components;
  2. In file sharing mode, multiple processes read and write the same file and obtain the file content for interaction.
  3. Messenger, a lightweight cross-process communication solution, is implemented at the bottom using AIDL (the implementation is relatively simple, and the blogger thought about it before starting this article, but finally decided that it was not necessary, so let’s not talk about it at Google);
  4. Android Interface Definition Language (AIDL) is used to define the Interface for cross-process communication.
  5. Use ContentProvider, often used for multi-process sharing data, such as system albums, music, etc., we can also access through ContentProvider;
  6. Use sockets to transmit data.

This article will focus on using AIDL for multi-process communication, because AIDL is the standard cross-process communication API provided by Android. It is very flexible and powerful. . Messenger is also a cross-process approach using AIDL. As the name implies, Messenger is a serial messaging mechanism. It is a lightweight IPC scheme that can pass Message objects between different processes. We can easily communicate between processes by putting data that needs to be passed in Message. But when we need to invoke server-side methods, or when there are concurrent requests, Messenger is not appropriate. The four major components that deliver bundles need not be explained. Data that needs to be delivered can be wrapped in intEnts. Other methods are beyond the scope of this article.

Let’s start with AIDL. Are you ready to go?

Implement a multi-process message push using AIDL

For multi-process requirements such as image selection, we may not need to write additional process communication code and use the four components to transfer the Bundle. However, for requirements such as push service, which requires a high degree of interaction between processes, process communication can not be bypstepped. Here we use instant chat software as an example to manually implement a multi-process push example, the specific requirements are as follows:

  1. The UI and notification push services are divided into two processes;
  2. The UI process displays the specific message data, passes the message sent by the user to the message Service, and then sends it to the remote server.
  3. The Service sends and receives messages and maintains a long connection with the remote server. The UI process sends messages to the remote server through the Service. The Service receives messages from the remote server and notifies the UI process.
  4. Even if the UI process exits, the Service needs to stay running and receive messages from the server.

Implementation approach

Let’s sort out the implementation idea:

  1. Create UI processes (collectively referred to as clients);
  2. Create a message Service (hereinafter referred to as the server);
  3. Configure the server to a separate process (specify the process tag in androidmanifest.xml);
  4. Bind client and server (bindService);
  5. Let the client and server have the ability to interact. (use AIDL)

Example concrete implementation

For ease of reading, the code below will omit non-important parts, you can Clone the entire code to the local view of the article:

Step0. AIDL call process overview

Before we begin, let’s summarize the process of making multi-process calls using AIDL:

  1. The client uses the bindService method to bind the server.
  2. The server returns the Binder object in the onBind method;
  3. The client takes the Binder object returned by the server and makes cross-process method calls.

    AIDL calls the procedure

    The whole AIDL invocation process is summarized as the above three steps, and we will use the example described above to break these steps down and explain the details.

Step1. The client uses the bindService method to bind the server

1.1 Creating a Client and a server and configuring the server to another process
  1. Create client -> MainActivity;
  2. Create a server -> MessageService;
  3. -> Android :process= “:remote”

The client and server described above, and configuring the server to another process, are shown in androidmanifest.xml, as follows:

<manifest ... > <application ... > <activity android:name=".ui.MainActivity"/> <service android:name=".service.MessageService" android:enabled="true" android:exported="true" android:process=":remote" /> </application> </manifest>Copy the code

Enabling multiple processes is as simple as assigning the Android: Process tag to the four major components.

1.2 Binding MessageService to MainActivity

Create a MessageService. Null is returned in onBind. Next we will return an operable object to the client.

public class MessageService extends Service {
    public MessageService() {
    public IBinder onBind(Intent intent) {
        return null;
}Copy the code

The MainActivity client calls the bindService method to bind MessageService. This step is actually related to the Service component. Here is a brief introduction.

  1. Use bindService -> bindService(Intent Service, ServiceConnection conn, int flags);
  2. Use startService -> startService(Intent Service);

BindService and startService: With bindService, multiple clients can bind a Service at the same time, but when all the clients are unbind, the Service will exit. Usually, if you want to interact with a Service, you can use bindService. You can interact with a Service using an IBinder object in onServiceConnected; if you don’t need to interact with a Service, you can use the startService method.

As mentioned above, we need to interact with the Service, so we need to use the bindService method, but we want the Service to keep running after unbind. In this case, You can call both bindService and startService (such as the message Service in this example, which exits the UI process and still needs to receive the message) as follows:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    protected void onCreate(Bundle savedInstanceState) {
     * unbindService
    protected void onDestroy() {
     * bindService & startService
    private void setupService() {
        Intent intent = new Intent(this, MessageService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    ServiceConnection serviceConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected");
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected");
}Copy the code

Stpe2. The server returns Binder objects in onBind

2.1 First, what is a Binder?

Binder is the basic interface for remote objects. IBinder is the core of a lightweight remote procedure call mechanism that describes an abstract protocol for interacting with remote objects. Binder implements the IBinder interface. Binder is the Android SDK’s built-in multiprocess communication implementation class. Binder is not required to implement IBinder.

2.2 Second, where does the Binder object that needs to be returned in onBind come from?

Binder objects for AIDL multiprocess communication are generated automatically through our defined.adil interface file. You can go the other way and manually write a Binder class for cross-process communication, which is essentially an inherited class. Google provides AIDL interface to help us automatically generate Binder. In the following, we will continue our discussion on AIDL (can’t lead people astray 🙃).

2.3 Defining the AIDL Interface

Binder, which is automatically generated through the AIDL interface, is a good place to start.

Data types supported by AIDL:

  • All the basic data types in the Java programming language (such as int, Long, CHAR, Boolean, and so on)
  • String and CharSequence
  • Parcelable: Objects that implement the Parcelable interface
  • List: The elements need to be supported by AIDL. The actual concrete class received on the other end is always an ArrayList, but the generated methods use the List interface
  • Map: The elements need to be supported by AIDL, including keys and values. The actual concrete class received on the other end is always HashMap, but the generated method uses the Map interface

Other notes:

  • Objects passed in AIDL must implement the Parcelable serialization interface;
  • For objects passed in AIDL, you need to create a file with the same name and suffix. AIDL in the same path as the class file and declare the class in the file using the parcelable keyword.
  • With common interface differences: can only declare methods, can not declare variables;
  • All non-base data type parameters need to be tagged with the direction of the data. It can be in, out, or inout. The default underlying data type must be in, not any other direction.

Let’s continue with our example and start with AIDL

Create an AIDL interface that provides the method to send a message (Android Studio create AIDL: right-click project -> New -> AIDL -> AIDL File)
package com.example.aidl;
interface MessageSender {
    void sendMessage(in MessageModel messageModel);
}Copy the code

I have read a lot of articles, but none of them can explain the meaning of the three parameter directions: in, out, and inout. Later, I found a relatively understandable answer on StackOverflow. The parameter marked with “in” is the parameter that receives the actual data, which has the same meaning as our normal parameter passing. In AIDL “out” specifies a parameter is used only for output, in other words, this parameter is not concerned with the caller what data transfer to come over, but the value of this parameter can be in a method is invoked after filling (no matter what the caller has value, at the time of method execution, the parameters of the initial value is always empty). This is what “out” means, only for output. And “inout” is obviously a combination of “in” and “out”, input and output parameters. What is the use of distinguishing “in” and “out”? This is important because the contents of each parameter must be marshalled (serialized, transmitted, received, and deserialized). In/Out tags allow binders to skip marshalling steps for better performance.

MessageModel is the entity class of the message. This class is passed in AIDL and implements the Parcelable serialization interface. The code is as follows:

public class MessageModel implements Parcelable { private String from; private String to; private String content; . Setter & Getter ... @Override public int describeContents() { return 0; } / /... Serialization code //... }Copy the code

After creating MessageModel AS an entity class, do not forget that there is still one thing to do: For objects passed in AIDL, create a file with the same name but with the suffix. AIDL in the same path as the class file and declare the class in the file using the parcelable keyword. The code is as follows:

parcelable MessageModel;Copy the code

For those of you who have not been exposed to AIDL, it is confusing to just say so. Let’s take a look at the structure of the project.

The project structure

  • Messagesender. aidl -> defines the method for sending messages. Binder class messagesender. Stub is automatically generated and implemented on the server and returned to the client
  • -> Message entity class, passed from client to server, implements Parcelable serialization
  • Messagemodel. aidl -> declares that MessageModel can be passed in aiDL under the same package path as

OK, BELIEVE at this time meng force has been lifted ~

2.5 Create messagesender. aidl, a Binder object automatically generated by aiDL interface, on the server and return it to the client for invocation. The MessageService code on the server is as follows:
public class MessageService extends Service { private static final String TAG = "MessageService"; public MessageService() { } IBinder messageSender = new MessageSender.Stub() { @Override public void sendMessage(MessageModel messageModel) throws RemoteException { Log.d(TAG, "messageModel: " + messageModel.toString()); }}; @Override public IBinder onBind(Intent intent) { return messageSender; }}Copy the code

Stub is a Binder object automatically generated by Android Studio from our messagesender.aidl file. We need to return this Binder object to the client.

2.6 Client invokes remote methods after receiving Binder objects

The call steps are as follows:

  1. In the client’s onServiceConnected method, retrieve the Binder object returned by the server.
  2. Use the MessageSender. Stub. AsInterface method, obtains the MessageSender. Aidl corresponding operation interface;
  3. After retrieving the MessageSender object, you can simply call the method like a normal interface.

The client code is as follows:

public class MainActivity extends AppCompatActivity { private MessageSender messageSender; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setupService(); } / /... private void setupService() { Intent intent = new Intent(this, MessageService.class); bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); startService(intent); } ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName Name, IBinder service) {/ / asInterface method is used to obtain an AIDL corresponding operation interface messageSender = messageSender. The Stub. AsInterface (service); MessageModel MessageModel = new MessageModel(); messageModel.setFrom("client user id"); messageModel.setTo("receiver user id"); messageModel.setContent("This is message content"); / / call the remote Service sendMessage method, and the message entity object try {messageSender. SendMessage (messageModel); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; }Copy the code

In the client, we called MessageSender’s sendMessage method, sent a message to the server, and passed the generated MessageModel object as a parameter to the server. The final result printed by the server is as follows:

  1. The server has received the message from the client and printed it correctly.
  2. The server and client distinguish two processes, PID is different, process name is different.

At this point, we have completed the most basic cross-process method calls using AIDL, which is the entire elaboration of step.0. We can review step.0 again. Now that we have learned how to use it, let’s move on to… The end of the play…

Know what it is and why.

Let’s go through the above invocation process to see what happened from the client side to the server side, and see how the upper layers of Binder work. The lower layers of Binder are a very complex topic that this article will not delve into. (Binder if you’re wondering what Binder is, manually rewind the tape and look up…)

Let’s review the call flow from the client first:

  1. MessageSender messageSender = MessageSender.Stub.asInterface(service);
  2. messageSender.sendMessage(messageModel);

Aidl source code (the specific path is: a subdirectory in the build directory, find yourself, you are not happy to call me 😋)

Please look at the code and comments below, high energy warning ahead…

public interface MessageSender extends android.os.IInterface { public static abstract class Stub extends android.os.Binder implements com.example.aidl.MessageSender { private static final java.lang.String DESCRIPTOR = "com.example.aidl.MessageSender"; / * * * the IBinder object is converted into a com. Example. Aidl. * determine whether IBinder MessageSender interface in the same process, Same process returns a Stub implementation of com. Example. Aidl. MessageSender interface * different processes, It returns a Stub. The Proxy implementation of com. Example. Aidl. MessageSender interface * / public static com. The example. The aidl. MessageSender asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin ! = null) && (iin instanceof com.example.aidl.MessageSender))) { return ((com.example.aidl.MessageSender) iin); } return new com.example.aidl.MessageSender.Stub.Proxy(obj); } /** * If the same process does not trigger different processes, asInterface will return stub.proxy. Client calls the messageSender. SendMessage (messageModel) * essence is called the Stub in the Proxy of the sendMessage method, triggering across the data transmission process, * Eventually the Binder layer calls back the processed data to this method, Call our real sendMessage method */ @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_sendMessage: { data.enforceInterface(DESCRIPTOR); _arg0; if ((0 ! = data.readInt())) { _arg0 =; } else { _arg0 = null; } this.sendMessage(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.aidl.MessageSender { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; /** * Proxy does not call the sendMessage method we defined, but does Parcel reading and writing, and then calls mremote. transact, handing the data to Binder. When transact is finished, the onTransact method above is called, * onTransact gets the final parameter data, Call by our true sendMessage method * / @ Override public void sendMessage (com. Example. An aidl. Data. MessageModel MessageModel) 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 ((messageModel ! = null)) { _data.writeInt(1); messageModel.writeToParcel(_data, 0); } else { _data.writeInt(0); } // Call Binder's transact method for multi-process data transfer, Call onTransact method mremote. transact(stub.transaction_sendmessage, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_sendMessage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); } public void sendMessage( messageModel) throws android.os.RemoteException; }Copy the code

If you just look at the code, it may be a little confusing, but it will make sense if you combine the code with the flow chart below:

Knock on the board: The nature of object transfer across processes is serialization, transfer, reception, and deserialization. Is that why objects transferred across processes must implement the Parcelable interface

Cross-process callback interface

Now that we have implemented the function of sending messages from the client to the cross-process server, we need to pass the remote server messages received by the server to the client. Have students estimate will say: “is this a callback interface”, set the callback interface ideas are right, but the callback interface used here is a little different, passing in the AIDL interface, can’t be a common interface, can only be an AIDL interface, so we need to create a new AIDL interface to the service side, as a callback interface.

Create an AIDL interface for collecting messages messagereceiver. AIDL:

package com.example.aidl;
interface MessageReceiver {
    void onMessageReceived(in MessageModel receivedMessage);
}Copy the code

Next we register the callback interface with the server and modify our messagesender.aidl:

package com.example.aidl;
import com.example.aidl.MessageReceiver;
interface MessageSender {
    void sendMessage(in MessageModel messageModel);
    void registerReceiveListener(MessageReceiver messageReceiver);
    void unregisterReceiveListener(MessageReceiver messageReceiver);
}Copy the code

This is the final aiDL interface we have modified. Now we need to make corresponding changes:

  1. The method of adding MessageSender’s register and unregister interface in the server;
  2. The MessageReceiver interface is implemented in the client and registered to the server through MessageSender.


public class MainActivity extends AppCompatActivity { private MessageSender messageSender; @Override protected void onCreate(Bundle savedInstanceState) { //... } /** * unregisterListener * 2. UnbindService */ @override protected void onDestroy() {if (messageSender! = null && messageSender.asBinder().isBinderAlive()) { try { messageSender.unregisterReceiveListener(messageReceiver); } catch (RemoteException e) { e.printStackTrace(); } } unbindService(serviceConnection); super.onDestroy(); } private MessageReceiver MessageReceiver = new Messagereceiver.stub () {@override public void onMessageReceived(MessageModel receivedMessage) throws RemoteException { Log.d(TAG, "onMessageReceived: " + receivedMessage.toString()); }}; ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName Name, IBinder service) {/ / asInterface method is used to obtain an AIDL corresponding operation interface messageSender = messageSender. The Stub. AsInterface (service); MessageModel MessageModel = new MessageModel(); / /... Try {/ / callback interface to register to receive news server messageSender. RegisterReceiveListener (the messageReceiver); / / call the remote Service sendMessage method, and the message entity object messageSender. SendMessage (messageModel); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; }Copy the code

There are three major client changes:

  1. Added the messageReceiver object, which is used to listen to the message notification of the server.
  2. OnServiceConnected method, register messageReceiver with your Service.
  3. Unregister messageReceiver when onDestroy.

The following changes are made to the server MessageServie:

public class MessageService extends Service { private static final String TAG = "MessageService"; private AtomicBoolean serviceStop = new AtomicBoolean(false); Private RemoteCallbackList<MessageReceiver> listenerList = new RemoteCallbackList<>();  public MessageService() { } IBinder messageSender = new MessageSender.Stub() { @Override public void sendMessage(MessageModel messageModel) throws RemoteException { Log.e(TAG, "messageModel: " + messageModel.toString()); } @Override public void registerReceiveListener(MessageReceiver messageReceiver) throws RemoteException { listenerList.register(messageReceiver); } @Override public void unregisterReceiveListener(MessageReceiver messageReceiver) throws RemoteException { listenerList.unregister(messageReceiver); }}; @Override public IBinder onBind(Intent intent) { return messageSender; } @Override public void onCreate() { super.onCreate(); new Thread(new FakeTCPTask()).start(); } @Override public void onDestroy() { serviceStop.set(true); super.onDestroy(); Private class FakeTCPTask implements Runnable {@override public void run() {while (! serviceStop.get()) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } MessageModel messageModel = new MessageModel(); messageModel.setFrom("Service"); messageModel.setTo("Client"); messageModel.setContent(String.valueOf(System.currentTimeMillis())); BeginBroadcast and finishBroadcast must be paired with final int listenerCount = listenerList.beginBroadcast(); Log.d(TAG, "listenerCount == " + listenerCount); for (int i = 0; i < listenerCount; i++) { MessageReceiver messageReceiver = listenerList.getBroadcastItem(i); if (messageReceiver ! = null) { try { messageReceiver.onMessageReceived(messageModel); } catch (RemoteException e) { e.printStackTrace(); } } } listenerList.finishBroadcast(); }}}}Copy the code

Major changes to the server:

  1. Messagesender. Stub implements methods for registering and unregistering callback interfaces;
  2. Added RemoteCallbackList to manage the AIDL remote interface.
  3. FakeTCPTask simulates a long connection to notify a client of the arrival of a new message. (XMPP, Mina, Mars, Netty, etc.)

RemoteCallbackList is a common ArrayList. Of course not, or why the whole another RemoteCallbackList 🙃, registerReceiveListener and unregisterReceiveListener transmission to come over on the client objects, through Binder processing, When the server receives the is actually a new object, this leads to when unregisterReceiveListener ordinary ArrayList is unable to find a when registerReceiveListener added to the List of the object, But the underlying Binder objects are the same. RemoteCallbackList uses this feature to find the same object, so we can unregister the interface objects passed by the client. RemoteCallbackList automatically removes the listener registered by the client when the client process terminates. It also implements thread synchronization internally, so we do not need to consider thread synchronization when registering or unregistering. (As for the unwieldy use of ArrayList, you can try it yourself. For space reasons, I won’t demonstrate it here.)

At this point, the server to inform the client related code is also finished, the running result is nothing more than the correct printing 🙃 is not texture, you can Run, when printing attention to choose a different process, otherwise there is no log staring bad screen.


You think this is the end of it? Too young too simple…

I don’t know if you get the feeling, but the interaction between two processes always feels a little insecure… For example, if the server process crashes and the client process wants to call the server method, it cannot call it. Binder can set up a DeathRecipient object. When Binder unexpectedly dies, we can receive notification in the DeathRecipient interface callback method and perform corresponding operations, such as reconnecting services, etc.

DeathRecipient is used as follows:

  1. Declare the DeathRecipient object and implement its binderDied method, which will be called back when binder dies.
  2. Set the DeathRecipient object to Binder objects.

DeathRecipient on the client:

/** * Binders may die unexpectedly (e.g., Service Crash), DeathRecipient = new ibInder.DEAThrecipient () {@override public  void binderDied() { Log.d(TAG, "binderDied"); if (messageSender ! = null) { messageSender.asBinder().unlinkToDeath(this, 0); messageSender = null; } //// TODO: 2017/2/28 Reconnection of services or other operations setupService(); }}; ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //... Binder death listener messagesender.asbinder ().linktoDeath (deathRecipient, 0); } catch (RemoteException e) { e.printStackTrace(); }} / /... };Copy the code

Two important methods in Binder:

  1. LinkToDeath -> Set the death agent DeathRecipient object;
  2. UnlinkToDeath -> Binder dies in case of disarming the agent.

In addition, isBinderAlive in Binder can also determine if Binder is dead.

Permission to verify

Even if the bus, get on the bus also have to di card is not right, if you want our service process not like a bus who wants to get on, then we can add permission verification.

This section describes two common authentication methods:

  1. Verify the custom permission in onBind of the server. If it passes our check, Binder objects will be returned normally. If it fails to pass the check, null will be returned.
  2. Check the client package name in the onTransact method on the server. If the check is not passed, return false.

Add custom permission to androidmanifest.xml:

    android:protectionLevel="normal" />
<uses-permission android:name="com.example.aidl.permission.REMOTE_SERVICE_PERMISSION" />Copy the code

The server can check permissions by:

IBinder messageSender = new MessageSender.Stub() { //... @Override public boolean onTransact(int code, Parcel data, Parcel reply, Int flags) throws RemoteException {/** * packageName verification method */ String packageName = null; String[] packages = getPackageManager().getPackagesForUid(getCallingUid()); if (packages ! = null && packages.length > 0) { packageName = packages[0]; } if (packageName == null || ! PackageName. StartsWith ("com.example.aidl")) {log. d("onTransact", "reject:" + packageName); return false; } return super.onTransact(code, data, reply, flags); }}; @override public IBinder onBind(Intent Intent) {// Custom permission check permission if (checkCallingOrSelfPermission("com.example.aidl.permission.REMOTE_SERVICE_PERMISSION") == PackageManager.PERMISSION_DENIED) { return null; } return messageSender; }Copy the code

Do different initialization tasks for different processes

I believe that a few years ago many friends still use The Android-universal-image-loader to load images, which needs to be initialized in the Application class. For example, if we use it to load images, and we have an image selection process, what if we want to allocate more cache to the image selection process, or some other initialization that doesn’t need to be done in the image selection process?

Here’s a rough and easy way to do it, and bloggers do it… Directly get the process name to judge, make the corresponding operation can be:

public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); Log.d("process name", getProcessName()); } private String getProcessName() {ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses(); if (runningApps == null) { return null; } for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) { if ( == Process.myPid()) { return procInfo.processName; } } return null; }}Copy the code

The onCreate method of the Application will be called for each process created. This is an important point to note. We can also use the pid of the current process to determine the current process name, and then do some logic we need.

  1. Client process: com.example.aidl
  2. Server process: com.example.aidl:remote


  1. Multi-process APP can apply for more than one memory in the system, but it should be used reasonably. It is recommended to put some high-consumption but not commonly used modules into an independent process, and the unused process can be manually closed in time.
  2. Multiple processes can be implemented in a variety of ways: Bundle, Messenger, AIDL, etc.
  3. To realize multi-process communication in Android, Binder class provided by the system is recommended, which has realized multi-process communication without the need for us to do the underlying work;
  4. For multi-process applications, the Application will be created multiple times;


This article has been written intermittently for a long time, and I believe that not many students really use it, I choose such a topic is thankless… But I hope to provide a complete solution here. Simple multi-process use, and the effect is significant, such as the image selection and WebView configuration into a separate process, this I hope we can take action. There are a lot of knowledge points in this article, which may not be easy to understand. If you are interested, I suggest you write it manually, and then interrupt the point to see what the operation steps are if you don’t understand.

For those of you who are interviewing, if you talk about multi-process during the interview, you can also gain points by having a good conversation with the interviewer. Or in practical work, where using multi-process can better solve problems, you can bang the table in the meeting and say to the supervisor, “I have a bold idea…” (Of course, getting fired is not my problem…)