Further understanding of Binder principles (II) (I)

Create ServiceManagerProxy

Let’s go back to the getService process

/frameworks/base/core/java/android/os/ServiceManager.java

public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if(service ! =null) {
            return service;
        } else {
            returnBinder.allowBlocking(getIServiceManager().getService(name)); }}catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
}

private static IServiceManager getIServiceManager(a) {
    if(sServiceManager ! =null) {
        return sServiceManager;
    }

    // Find the service manager
    sServiceManager = ServiceManagerNative
        .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
    return sServiceManager;
}
Copy the code

We have seen BinderInternal. GetContextObject () the native method does two things: to the ServerManager PING_TRANSACTION messages sent, and to create BpBinder 0 for the address. The next step is to create the Java layer’s ServiceManager agent. Let’s look at the implementation process of asInterface.

/frameworks/base/core/java/android/os/ServiceManager.java

static public IServiceManager asInterface(IBinder obj)
{
    if (obj == null) {
        return null;
    }
    IServiceManager in =
        (IServiceManager)obj.queryLocalInterface(descriptor);
    if(in ! =null) {
        return in;
    }
    
    return new ServiceManagerProxy(obj);
}
Copy the code

As you can see, the asInterface method actually takes IBinder and creates the ServiceManagerProxy. At this point, the process of obtaining the ServerMananger and creating the ServiceManagerProxy is finished. With ServiceManagerProxy, applications can directly communicate with the ServiceManager process because ServiceManagerProxy encapsulates ServiceMananger’s Binder addresses.

Get ActivityManagerServer

Obtain ServiceManager’s Binder address and create ServiceManagerProxy with ServerMananger’s BpBinder. Then we can use ServiceManagerProxy to obtain ActivityManagerServer Binder address and create the corresponding ActivityManagerServer Proxy in the application process. By calling the ServiceManager. GetService (Context. ACTIVITY_SERVICE) function can obtain ActivityManagerServer agent.

/frameworks/base/core/java/android/os/ServiceManager.java

public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if(service ! =null) {
            return service;
        } else {
            returnBinder.allowBlocking(getIServiceManager().getService(name)); }}catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
}
Copy the code

Here the ServiceManager is the ServiceManagerProxy, so let’s go directly to the source of the ServiceManagerProxy object to see how getService is implemented.

/frameworks/base/core/java/android/os/ServiceManagerNative.java

int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
class ServiceManagerProxy implements IServiceManager {...public IBinder getService(String name) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }
    ……
}
Copy the code

Here mRemote’s transact function is called and the business protocol code transferred is GET_SERVICE_TRANSACTION. MRemote is just creating BpBinder and then seeing how BpBinder’s Transact function transfers data.

/frameworks/native/libs/binder/BpBinder.cpp

status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        // Call IPCThreadState to transfer data
        status_t status = IPCThreadState::self() - >transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}
Copy the code

BpBinder still calls the transact method of IPCThreadState to send data. The process of IPCThreadState calling the Transact method to send data has been described in the previous section.

The transact function of IPCThreadState encapsulates the data with writeTransactionData, goes through waitForResponse and talkWithDriver, and finally calls IOCtl to send the data to the Binder driver.

The Binder driver receives the data, goes through the binder_thread_write process, looks for the Binder of the target process, and executes the binder_transaction process to copy the data into the Binder buffer of the target process.

The target process is the ServiceMannager, which iterates through the buffer and parses the data. Let’s move on to see how ServerMnanager handles the GET_SERVICE_TRANSACTION protocol, whose handler is svCMgr_handler.

The ServiceManager responds to GET_SERVICE_TRANSACTION
int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int allow_isolated;


    if(txn->target.ptr ! = BINDER_SERVICE_MANAGER)return - 1;

    if (txn->code == PING_TRANSACTION)
        return 0;

    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);
    if (s == NULL) {
        return - 1;
    }

    if((len ! = (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        return - 1;
    }

    if (sehandle && selinux_status_updated(a) >0) {
        struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle(a);if (tmp_sehandle) {
            selabel_close(sehandle); sehandle = tmp_sehandle; }}switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return - 1;
        }
        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
        if(! handle)break;
        bio_put_ref(reply, handle);
        return 0;
    caseSVC_MGR_ADD_SERVICE:...caseSVC_MGR_LIST_SERVICES:...default:
        ALOGE("unknown code %d\n", txn->code);
        return - 1;
    }

    bio_put_uint32(reply, 0);
    return 0;
}
Copy the code

Svcmgr_handler calls do_find_service to find the target service, which in this case is the activity

uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
    struct svcinfo *si = find_svc(s, len);

    if(! si || ! si->handle) {return 0;
    }

    if(! si->allow_isolated) {uid_t appid = uid % AID_USER;
        if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
            return 0; }}if (!svc_can_find(s, len, spid, uid)) {
        return 0;
    }

    return si->handle;
}

struct svcinfo *svclist = NULL;

struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
    struct svcinfo *si;

    for (si = svclist; si; si = si->next) {
        if ((len == si->len) &&
            !memcmp(s16, si->name, len * sizeof(uint16_t))) {
            returnsi; }}return NULL;
}
Copy the code

The handle address of the target service is returned. This handle is the binder address. ServerMananger’s ioctl returns data to Clinet through the Binder driver, using binder_thread_write and then binder_transaction. Binder is inserted into Clinet’s binder_proc and data is written to Clinet’s binder_proc buffer.

Create a Proxy for ActivityManagerProxy

When through ServerMananger for binder of AMS information, call IActivityManager. The Stub. AsInterface (b) will create the AMS agent in the application process, IActivityManager is an AIDL document, A Proxy object and a Stub object are automatically generated when compiled. The Proxy object is used by the Client and the Stub is used by the Server.

/frameworks/base/core/java/android/app/IActivityManager.aidl

interface IActivityManager {...int startActivity(in IApplicationThread caller, in String callingPackage, in Intent intent,
                      in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,
                          int flags, in ProfilerInfo profilerInfo, in Bundle options); ... }Copy the code

The generated Proxy file is as follows.

public interface IActivityManager extends android.os.IInterface {
    /** * Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements android.app.IActivityManager {
        private static final java.lang.String DESCRIPTOR = "android.app.IActivityManager";

        /** * Construct the stub at attach it to the interface. */
        public Stub(a) {
            this.attachInterface(this, DESCRIPTOR);
        }

        /** * Cast an IBinder object into an android.app.IActivityManager interface, * generating a proxy if needed. */
        public static android.app.IActivityManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if(((iin ! =null) && (iin instanceof android.app.IActivityManager))) {
                return ((android.app.IActivityManager) iin);
            }
            return new android.app.IActivityManager.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder(a) {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            switch (code) {
                caseINTERFACE_TRANSACTION:...caseTRANSACTION_openContentUri:...caseTRANSACTION_handleApplicationCrash:...case TRANSACTION_startActivity: {
                    data.enforceInterface(DESCRIPTOR);
                    android.app.IApplicationThread _arg0;
                    _arg0 = android.app.IApplicationThread.Stub.asInterface(data.readStrongBinder());
                    java.lang.String _arg1;
                    _arg1 = data.readString();
                    android.content.Intent _arg2;
                    if ((0! = data.readInt())) { _arg2 = android.content.Intent.CREATOR.createFromParcel(data); }else {
                        _arg2 = null;
                    }
                    java.lang.String _arg3;
                    _arg3 = data.readString();
                    android.os.IBinder _arg4;
                    _arg4 = data.readStrongBinder();
                    java.lang.String _arg5;
                    _arg5 = data.readString();
                    int _arg6;
                    _arg6 = data.readInt();
                    int _arg7;
                    _arg7 = data.readInt();
                    android.app.ProfilerInfo _arg8;
                    if ((0! = data.readInt())) { _arg8 = android.app.ProfilerInfo.CREATOR.createFromParcel(data); }else {
                        _arg8 = null;
                    }
                    android.os.Bundle _arg9;
                    if ((0! = data.readInt())) { _arg9 = android.os.Bundle.CREATOR.createFromParcel(data); }else {
                        _arg9 = null;
                    }
                    int _result = this.startActivity(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }

                private static class Proxy implements android.app.IActivityManager {
                    private android.os.IBinder mRemote;

                    Proxy(android.os.IBinder remote) {
                        mRemote = remote;
                    }

                    @Override
                    public int startActivity(android.app.IApplicationThread caller, java.lang.String callingPackage, android.content.Intent intent, java.lang.String resolvedType, android.os.IBinder resultTo, java.lang.String resultWho, int requestCode, int flags, android.app.ProfilerInfo profilerInfo, android.os.Bundle options) throws android.os.RemoteException {
                        android.os.Parcel _data = android.os.Parcel.obtain();
                        android.os.Parcel _reply = android.os.Parcel.obtain();
                        int _result;
                        try{ _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder((((caller ! =null))? (caller.asBinder()) : (null)));
                            _data.writeString(callingPackage);
                            if((intent ! =null)) {
                                _data.writeInt(1);
                                intent.writeToParcel(_data, 0);
                            } else {
                                _data.writeInt(0);
                            }
                            _data.writeString(resolvedType);
                            _data.writeStrongBinder(resultTo);
                            _data.writeString(resultWho);
                            _data.writeInt(requestCode);
                            _data.writeInt(flags);
                            if((profilerInfo ! =null)) {
                                _data.writeInt(1);
                                profilerInfo.writeToParcel(_data, 0);
                            } else {
                                _data.writeInt(0);
                            }
                            if((options ! =null)) {
                                _data.writeInt(1);
                                options.writeToParcel(_data, 0);
                            } else {
                                _data.writeInt(0);
                            }
                            mRemote.transact(Stub.TRANSACTION_startActivity, _data, _reply, 0);
                            _reply.readException();
                            _result = _reply.readInt();
                        } finally {
                            _reply.recycle();
                            _data.recycle();
                        }
                        return _result;
                    }
                }
            }
        }
    }
}
Copy the code

As you can see, when the AMS Proxy calls startActivity, it wraps the data in a Parcel and then calls the mremote. transact function, which as mentioned above is the BpBinder created for the Server’s binder address. The process is the same as before, with IPCThreadState being called through several layers and finally passed to the Binder driver through the IOCtl function. Binder drivers copy data into ActivityManagerService’s binder_proc buffer from binder_transaction. AMS’s Binder threads loop through the buffer to find data. To parse and respond to the data.

ActivityManagerService start-up Activity

ActivityManagerService starts the Activity process. AIDL generates Proxy objects and Stub objects. Proyx objects are used by clients. Proxy encapsulates AMS’s binder address. When Proxy startActivity is called, data is encapsulated layer upon layer, and finally written to AMS by binder driver through ioctl functions. AMS essentially inherits iActivityManager.stub

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor.BatteryStatsImpl.BatteryCallback {...@Override
        public final int startActivity(IApplicationThread caller, String callingPackage,
                                       Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
                                       int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                                   resultWho, requestCode, startFlags, profilerInfo, bOptions,
                                   UserHandle.getCallingUserId());
    }
   ……
    
}
Copy the code

We are looking at the implementation of iActivityManager.sub

public interface IActivityManager extends android.os.IInterface {
    /** * Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements android.app.IActivityManager {
        private static final java.lang.String DESCRIPTOR = "android.app.IActivityManager";

        /** * Construct the stub at attach it to the interface. */
        public Stub(a) {
            this.attachInterface(this, DESCRIPTOR);
        }

        /** * Cast an IBinder object into an android.app.IActivityManager interface, * generating a proxy if needed. */
        public static android.app.IActivityManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if(((iin ! =null) && (iin instanceof android.app.IActivityManager))) {
                return ((android.app.IActivityManager) iin);
            }
            return new android.app.IActivityManager.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder(a) {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            switch (code) {
                caseINTERFACE_TRANSACTION:...caseTRANSACTION_openContentUri:...caseTRANSACTION_handleApplicationCrash:...case TRANSACTION_startActivity: {
                    data.enforceInterface(DESCRIPTOR);
                    android.app.IApplicationThread _arg0;
                    _arg0 = android.app.IApplicationThread.Stub.asInterface(data.readStrongBinder());
                    java.lang.String _arg1;
                    _arg1 = data.readString();
                    android.content.Intent _arg2;
                    if ((0! = data.readInt())) { _arg2 = android.content.Intent.CREATOR.createFromParcel(data); }else {
                        _arg2 = null;
                    }
                    java.lang.String _arg3;
                    _arg3 = data.readString();
                    android.os.IBinder _arg4;
                    _arg4 = data.readStrongBinder();
                    java.lang.String _arg5;
                    _arg5 = data.readString();
                    int _arg6;
                    _arg6 = data.readInt();
                    int _arg7;
                    _arg7 = data.readInt();
                    android.app.ProfilerInfo _arg8;
                    if ((0! = data.readInt())) { _arg8 = android.app.ProfilerInfo.CREATOR.createFromParcel(data); }else {
                        _arg8 = null;
                    }
                    android.os.Bundle _arg9;
                    if ((0! = data.readInt())) { _arg9 = android.os.Bundle.CREATOR.createFromParcel(data); }else {
                        _arg9 = null;
                    }
                    int _result = this.startActivity(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true; }... }}}}Copy the code

As mentioned earlier, the Client starts binder in onZygoteInit and gets stuck in a loop that parses data from other processes in the talkWithDriver function and passes it to executeCommand. AMS follows the same process. Its binder thread receives data from other processes in the talkWithDriver function, passes it through the executeCommand function, and finally passes it to the Stub object’s onTransact function for processing.

When TRANSACTION_startActivity is processed from onTransact, the this.startActivity() function is called directly, at which point AMS officially starts the activity startup process.

Server

The Process for ServiceManager and Clinet is similar. Binder drivers are opened, mMAP memory is opened, and ioctl functions are repeatedly called to read and write data. AMS in the system_server process and normal applications in the user process are almost identical in opening binder, sending messages, etc., through ProcessState and IPCThreadState.

Open the Binder

Let’s take a look at how the SYSTEM_server process where AMS is located opens binder. When Zygote is started, the system_server process is started in Zygote’s main function.

/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static void main(String argv[]) {...if (startSystemServer) {
		startSystemServer(abiList, socketName, zygoteServer);
	}
    ……
}
Copy the code

StartSystemServer is called from Zygote’s main function to startSystemServer

/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException {...// Set parameters
    String args[] = {
        "--setuid=1000"."--setgid=1000"."-- setgroups = 1001100 2100 3100 4100 5100 6100 7100 8100 9101 0101 8102 1103 2300 1300 2300 3300 6300 7"."--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server"."--runtime-args"."com.android.server.SystemServer"}; ZygoteConnection.Arguments parsedArgs =null;
    int pid;
    try {
        // It is used to parse the parameters and generate the target format
        parsedArgs = new ZygoteConnection.Arguments(args);
        ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
        ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

        // fork the child process, which is the system_server process [see section 2]
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    // Enter the subprocess system_server
    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }
        // Complete the remaining work of the system_server process
        handleSystemServerProcess(parsedArgs);
    }
    return true;
}
Copy the code

Here through the fork function Zygote, fork out system_server process, after completion of the fork, executes handleSystemServerProcess

/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

private static void handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs) throws ZygoteInit.MethodAndArgsCaller {

    closeServerSocket(); // Close the Socket copied from the parent zygote process

    Os.umask(S_IRWXG | S_IRWXO);

    if(parsedArgs.niceName ! =null) {
        Process.setArgV0(parsedArgs.niceName); // Set the current process name to "system_server".
    }

    final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
    if(systemServerClasspath ! =null) {
        // Perform dex optimization
        performSystemServerDexOpt(systemServerClasspath);
    }

    ……
  
    ClassLoader cl = null;
    if(systemServerClasspath ! =null) {
        // Create a classloader and assign it to the current thread
        cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
        Thread.currentThread().setContextClassLoader(cl);
    }

    RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);

}
Copy the code

HandleSystemServerProcess mainly some of the initialization of system_server process, the final executive RuntimeInit. ZygoteInit function.

/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
    commonInit(); // Generalize some initialization
    nativeZygoteInit(); / / onZygoteInit callback
    applicationInit(targetSdkVersion, argv, classLoader); // Apply initialization
}
Copy the code

We’re just going to focus on the nativeZygoteInit function in zygoteInit, which is a native function.

/frameworks/base/core/jni/AndroidRuntime.cpp

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz) {
    gCurRuntime->onZygoteInit(a); }Copy the code

GCurRuntime is the runtime environment for the current system_server process.

/frameworks/base/cmds/app_process/app_main.cpp

virtual void onZygoteInit(a)
{
    sp<ProcessState> proc = ProcessState::self(a); proc->startThreadPool(a); }Copy the code

Binder drivers of the system_server process are initialized after onZygoteInit is executed, and are now in a loop reading and writing data to the binder.

AMS applies to register Service

Let’s look at how AMS registers a Service in a ServiceManager. After the SystemServer process starts, it starts various services in the main function

/frameworks/base/services/java/com/android/server/SystemServer.java

public static void main(String[] args) {
        new SystemServer().run();
}

private void run(a) {
    mSystemServiceManager = newSystemServiceManager(mSystemContext); mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart); ...// Start services.
    traceBeginAndSlog("StartServices"); startBootstrapServices(); startCoreServices(); startOtherServices(); SystemServerInitThreadPool.shutdown(); ... }Copy the code

Our ActivityManagerService is located in BootstrapServices.

/frameworks/base/services/java/com/android/server/SystemServer.java

private void startBootstrapServices(a) {...// Activity manager runs the show.
    traceBeginAndSlog("StartActivityManager"); mActivityManagerService = mSystemServiceManager.startService( ActivityManagerService.Lifecycle.class).getService(); mActivityManagerService.setSystemServiceManager(mSystemServiceManager); ...// Set up the Application instance for the system process and get started.mActivityManagerService.setSystemProcess(); ... }Copy the code

When AMS starts, startBootstrapServices executes the setSystemProcess function.

/frameworks/base/services/java/com/android/server/SystemServer.java

public void setSystemProcess(a) {
    try {
        ServiceManager.addService(Context.ACTIVITY_SERVICE, this.true);
        ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
        ServiceManager.addService("meminfo".new MemBinder(this));
        ServiceManager.addService("gfxinfo".new GraphicsBinder(this));
        ServiceManager.addService("dbinfo".new DbBinder(this));
        if (MONITOR_CPU_USAGE) {
            ServiceManager.addService("cpuinfo".new CpuBinder(this));
        }
        ServiceManager.addService("permission".new PermissionController(this));
        ServiceManager.addService("processinfo".new ProcessInfoService(this));

        ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
            "android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY);
        mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());

        synchronized (this) {
            ProcessRecord app = newProcessRecordLocked(info, info.processName, false.0);
            app.persistent = true;
            app.pid = MY_PID;
            app.maxAdj = ProcessList.SYSTEM_ADJ;
            app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
            synchronized (mPidsSelfLocked) {
                mPidsSelfLocked.put(app.pid, app);
            }
            updateLruProcessLocked(app, false.null); updateOomAdjLocked(); }}catch (PackageManager.NameNotFoundException e) {
        throw new RuntimeException(
            "Unable to find android system package", e); }}Copy the code

In the setSystemProcess function we can see, which calls the ServiceManager addService function, registered keepalive activity, meminfo, GFXinfo and other services. The ServiceManager used here is the same object as the ServiceManager used in the previous Clinet side, so the addService implementation can be seen as obtaining the ServiceManager Proxy first. Then call the addService function in Proyx of ServiceManagerd.

/frameworks/base/core/java/android/os/ServiceManager.java

public static void addService(String name, IBinder service) {
    try {
        getIServiceManager().addService(name, service, false);
    } catch (RemoteException e) {
        Log.e(TAG, "error in addService", e); }}Copy the code

GetIServiceManager () gets the Proxy for the ServiceManager

/frameworks/base/core/java/android/os/ServiceManager.java

private static IServiceManager getIServiceManager(a) {
    if(sServiceManager ! =null) {
        return sServiceManager;
    }

    // Find the service manager
    sServiceManager = ServiceManagerNative
        .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
    return sServiceManager;
}
Copy the code

We then look at the implementation of the addService function in ServiceManagerNative.

/frameworks/base/core/java/android/os/ServiceManager.java

int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;

public void addService(String name, IBinder service, boolean allowIsolated)
    throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IServiceManager.descriptor);
    data.writeString(name);
    data.writeStrongBinder(service);
    data.writeInt(allowIsolated ? 1 : 0);
    mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
    reply.recycle();
    data.recycle();
}
Copy the code

As you can see, the service protocol called here is ADD_SERVICE_TRANSACTION. The following process has been described previously and will not be repeated.

ServiceMananger responds to Service registration requests

Let’s look at how the ServiceMananger responds to Service registration, but let’s go straight to its business protocol handler, svcmgr_handler.

/frameworks/native/cmds/servicemanager/service_manager.c

enum {
    /* Must match definitions in IBinder.h and IServiceManager.h */
    PING_TRANSACTION  = B_PACK_CHARS('_'.'P'.'N'.'G'),
    SVC_MGR_GET_SERVICE = 1,
    SVC_MGR_CHECK_SERVICE,
    SVC_MGR_ADD_SERVICE,
    SVC_MGR_LIST_SERVICES,
};


int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply)
{...switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    caseSVC_MGR_CHECK_SERVICE:...case SVC_MGR_ADD_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return - 1;
        }
        handle = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
        if (do_add_service(bs, s, len, handle, txn->sender_euid,
            allow_isolated, txn->sender_pid))
            return - 1;
        break;

    caseSVC_MGR_LIST_SERVICES:...default:
        return - 1;
    }

    bio_put_uint32(reply, 0);
    return 0;
}
Copy the code

The SVC_MGR_ADD_SERVICE in the svcmgr_handler function corresponds to the ADD_SERVICE_TRANSACTION protocol called in AMS. Let’s look at the implementation of do_add_service

/frameworks/native/cmds/servicemanager/service_manager.c

int do_add_service(struct binder_state *bs,
                   const uint16_t *s, size_t len,
                   uint32_t handle, uid_t uid, int allow_isolated,
                   pid_t spid)
{
    struct svcinfo *si;

    if(! handle || (len ==0) || (len > 127))
        return - 1;

    if (!svc_can_register(s, len, spid, uid)) {
        return - 1;
    }

    si = find_svc(s, len);
    if (si) {
        if (si->handle) {
            ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n".str8(s, len), handle, uid);
            svcinfo_death(bs, si);
        }
        si->handle = handle;
    } else {
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        if(! si) {ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n".str8(s, len), handle, uid);
            return - 1;
        }
        si->handle = handle;
        si->len = len;
        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
        si->name[len] = '\ 0';
        si->death.func = (void*) svcinfo_death;
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        si->next = svclist;
        svclist = si;
    }

    binder_acquire(bs, handle);
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}
Copy the code

Do_add_service does several things

  1. Check whether the added service exists. If yes, return the binder address of the service
  2. If not, create the svcinfo data structure for the Service and set the binder address (binder address is the binder address created in binder driver, as described earlier in binder_transaction). If the target binder_node does not exist, A binder_node is created for the target process and added to the queue.

At the end

This is all about Binder. Again, learning more about Binder is not just about how to use it, but about the design of Binder, how it’s structured, how it decouples, how it ensures security and performance. In Binder design, we can also see some borrowing from other places, such as ServiceManager is similar to DNS in network request, Binder protocol and business protocol encapsulation is similar to the layer of protocol encapsulation in network.

To summarize common points from different technologies, extract unique points and excellent points, and then reference, summarize and use, this is the growth path of architecture learning.