Android interview notes arrangement - Binder mechanism

Author: Ronin Notes

Questions you might ask in an interview

  1. Ask about the advantages of Binder from the way of IPC
  2. Why does zygote not use Binder for communication with other service processes
  3. Binder thread pool and Binder mechanism

Wait, these questions are based on your understanding of Binder and other IPC communications

How many IPC methods are there?

  • Traditional IPC methods include Socket, shared memory, pipeline, semaphore, etc.
  • What is unique to Android is Binderthat other systems also have their own definitions, such as window's wfc (Windows Communication Foundation)

Advantages of the Binder mechanism

Traditional IPC pipes and semaphores are relatively light, and basically cannot be used for complex IPC communication. Socket has a disadvantage that data needs to be copied twice. The first time is that process A is copied to the Socket channel, and the second time is the Socket channel. copied to process B. The disadvantage of shared memory is that it is inconvenient to manage. Frequent operations on shared memory may cause problems such as deadlock and starvation.

In order to solve this pain point, Android designed the communication mechanism of Binder to provide a more efficient, safe and reliable way. The figure below is a diagram of the Binder mechanism. You only need to copy it once in the kernel, which can be simply understood as a singleton mode . Everyone only needs to operate on the Binder memory area, and there is only one copy of the memory.

There are also some concepts, such as we should have heard that Binder is in the kernel, how is Binder used in the Android system, and then look at a picture

There are four roles here, which are actually well understood, two processes, one Binder kernel space, and one ServiceManager service. The C/S structure adopted by the two processes is one client and one server.

  1. BinderKernel space is a piece of memory that exists in the kernel area and is understood as a channel

  2. ServiceManagerIt is one of the core services of Android. AMS, PMS, and WMS are the same. It provides many thread pools. Binder thread pool is just one of them. It can be understood here that the management Binder provides a registration mechanism for external use to identify different processes. The following are several other thread pools

    • Activity Manager thread pool: used to handle activities such as starting and stopping to ensure the fluency of the UI interface.
    • JobScheduler thread pool: used to schedule and execute background tasks.
    • MediaServer thread pool: used to process media data such as audio and video.
    • SurfaceFlinger thread pool: used to handle UI interface drawing and other operations.

Have you ever thought about why there are so many thread pools and so many. In fact, it is easier to understand, because the ServiceManager class is used in many places, and it cannot be processed by a single thread, so it will be blocked. The reason why there are so many thread pools is because different functions are different. For example, some calls are more frequent and some require more cpu. If there is only one thread pool, it is easy to cause problems such as taking too long.

  1. server进程To provide a method to be called by others, it needs to be registered in the ServiceManager first.
  2. After the server is registered, it will provide an interface to client进程call

Coming here should answer the remaining two questions.

Binder thread pool and Binder mechanism

  • The Binder thread pool is provided by ServiceManager and uses the Binder kernel mechanism.
  • The Binder mechanism is a set of kernel-based IPC mechanisms implemented by Android in order to provide a more efficient, stable, and reliable way.

Why does the zygote process use socket instead of binder to communicate with other processes

  1. Although Binder is in the kernel, it is ServiceManager that provides services. At this time, if you want to provide Binder IPC to AMS, you need to wait for ServiceManager to be initialized first. It's even more troublesome.
  2. In addition, because the Zygote process only communicates with a few processes, the overhead of using Socket communication is relatively small, so it is more appropriate to choose Socket communication. And here is the optimized LocalSocket, which will be more efficient.

The above has been talking about kernel space, so what is the difference between kernel space and user space?

  1. The kernel program runs in the kernel space of the operating system, has higher authority and faster execution speed, and can realize lower-level operations, such as hardware drivers, file systems, etc., so it is usually used to realize the core functions of the operating system.

  2. User programs run in the user space of the operating system, have more degrees of freedom and portability, and can realize richer functions, such as applications, service processes, etc., so they are usually used for the realization of peripheral functions and applications of the operating system .

To put it simply, the kernel space has a method of manipulating memory, but this area is closed to the user space, and the operations in the user space are all services provided by the kernel. For example, those used for operating files 文件系统模块and those used for operating memory 内存管理模块. kmallocTake the sum used in the memory management module kfreeas an example. These two methods cannot be called in user space, which is the method of kernel encapsulation.

`kmalloc()` 和 `kfree()`: 内核内存分配器,用于在内核空间中动态分配和释放内存。
 // 这个还并不是c/c++的原生方法,是内核自己封装的

Let's take a look at it again. For example, when using Binder, we pass a serialized file, so how is it mapped to memory?

vm_map_ramThere are and these methods in the kernel vm_insert_pageto insert a file into a memory address. And if you need to deal with these in user space, you will use the memory management module mmap. mmapThe implementation is used in the kernel vm_area_struct. It means that the memory management module provides an external layer of encapsulation. So instead of being so troublesome, it is more appropriate to put it directly into the kernel.

These methods are actually not important, you just need to know that these methods are not available in the user process space


Binder-based IPC

Here are some basics, you can skip it. Because these are rarely used, it is convenient for you to look at them later

AIDL

Server

// IMyService.aidl
interface IMyService {
    int add(int a, int b);
}

// MyService.java
public class MyService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    private class MyBinder extends IMyService.Stub {
        @Override
        public int add(int a, int b) throws RemoteException {
            return a + b;
        }
    }
}

client

// MainActivity.java
public class MainActivity extends AppCompatActivity {
    private IMyService mService;

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mService = IMyService.Stub.asInterface(service);
            try {
                int result = mService.add(1, 2);
                Toast.makeText(MainActivity.this, "Result: " + result, Toast.LENGTH_SHORT).show();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, MyService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mConnection);
    }
}

Messenger

The lightweight AIDL can only be single-threaded server-side MessengerService.java:

public class MessengerService extends Service {
    private static class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    String clientMessage = (String) msg.obj;
                    Log.i("MessengerService", "Received message from client: " + clientMessage);

                    // Send a response back to the client
                    Messenger clientMessenger = msg.replyTo;
                    Message replyMessage = Message.obtain(null, 2);
                    Bundle bundle = new Bundle();
                    bundle.putString("serverResponse", "Hello from server!");
                    replyMessage.setData(bundle);
                    try {
                        clientMessenger.send(replyMessage);
                    } catch (RemoteException e) {
                        Log.e("MessengerService", "Failed to send message to client", e);
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    private final Messenger mMessenger = new Messenger(new IncomingHandler());

    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}

Client MessengerClient.java:

public class MessengerClient extends AppCompatActivity {
    private Messenger mMessenger;

    private static class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 2:
                    String serverMessage = msg.getData().getString("serverResponse");
                    Log.i("MessengerClient", "Received message from server: " + serverMessage);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    private final Messenger mClientMessenger = new Messenger(new IncomingHandler());

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mServiceConnection);
    }

    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mMessenger = new Messenger(service);
            sendMessageToServer();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mMessenger = null;
        }
    };

    private void sendMessageToServer() {
        if (mMessenger == null) {
            return;
        }

        Message message = Message.obtain(null, 1);
        message.obj = "Hello from client!";
        message.replyTo = mClientMessenger;
        try {
            mMessenger.send(message);
        } catch (RemoteException e) {
            Log.e("MessengerClient", "Failed to send message to server", e);
        }
    }
}

broadcaster, content provider

……

There are still many knowledge points about the truth of Android interview notes that cannot be displayed here one by one. In order to facilitate your review and reference, I have organized it into a document form here. You can refer to it:https://qr18.cn/CgxrRy

Guess you like

Origin blog.csdn.net/weixin_61845324/article/details/132306903