Principio de ServiceManager: combinación de código de Android 12 S

ServiceManager es la parte central de la comunicación de Binder y proporciona funciones de consulta y registro de servicios. En versiones anteriores a Android 11, utiliza directamente API como open, mmap e ioctl para interactuar con el controlador de carpeta. A partir de Android 11, ServiceManager abandona el uso de estas interfaces de nivel inferior y recurre a la biblioteca libbinder y AIDL.

Tabla de contenido

Tabla de contenido

1. análisis de archivos rc

2. Diagrama de clases de ServiceManager

2.1 Introducción al directorio ServiceManager

2.2 Introducción al diagrama de clases de ServiceManager

Introducción a la ruta del archivo de implementación específica final de 2.3 Bn, Bp

3. Proceso de inicio de ServiceManager

3.1 Iniciar entrada

3.2 Introducción a initWithDriver

3.3 Introducción a ProcessState::init

3.4 Introducción al constructor de ProcessState

3.5 introducción a open_driver

3.6 Diagrama de flujo general de inicio de ServiceManager

4. Introducción a IServicManager

4.1 Introducción al directorio de IServiceManager

4.2 Introducción a bp de IServiceManager

4.3 Introducción a defaultServiceManager

4.4 Introducción a la implementación de interface_cast y asInterface

4.5 Introducción a otras interfaces de IServiceManager

5. Otros servicios registran/obtienen servicios a través de IServicManager

5.1: Servicios de registro

5.1.1 Ejemplo de agregar otros servicios a ServiceManager

5.1.2 Introducción a addService en Cliente

5.1.3 Proceso de asignación de mTheRealServiceManager

5.1.4 Introducción al addService de IServiceManager, proceso completo desde Bp->Bn

5.1.5 Introducción a remoto() en remoto()->transact de BpServiceManager en el lado del cliente

5.1.6 Introducción de transacciones de BpBinder en el lado del cliente

5.1.6 Introducción a la charla del cliente con el controlador

5.1.7 ¿Cómo sabe el servidor que hay un cambio de datos en /dev/binder y lo lee?

5.1.8 Introducción a LooperCallback heredado por BinderCallback en ServiceManager

5.1.9 Introducción a BinderCallback en ServiceManager

5.1.10 Proceso posterior de handleEvent en BinderCallback en ServiceManager

5.1.11 Introducción a onTransact de BnServiceManager en el lado del servidor

5.1.12 Introducción a addService en el lado del servidor

5.1.13 Introducción para agregar un mapa de lista de servicios en el lado del servidor

5.2 Obtención de servicios

5.2.1 Ejemplo de obtención de servicio a través de IServiceManager

5.2.2 Introducción a la interfaz getService del lado del cliente

5.2.3 proceso getServiceice Bp->Bn en IServiceManager 

5.2.4 Introducción a getService del lado del servidor


1. análisis de archivos rc

ServiceManager se inicia mediante init a través del archivo rc, y el contenido de rc es el siguiente: frameworks/native/cmds/servicemanager/servicemanager.rc

service servicemanager /system/bin/servicemanager
    class core animation
    user system
    group system readproc
    critical//表明这个Service对设备至关重要,如果Service在四分钟内退出超过4次,则设备将重启进入recovery模式
    //onrestart在重启时执行一条命令。
    onrestart restart apexd
    onrestart restart audioserver
    onrestart restart gatekeeperd
    onrestart class_restart main
    onrestart class_restart hal
    onrestart class_restart early_hal
    writepid /dev/cpuset/system-background/tasks
    shutdown critical//设置Service进程的关闭行为

2. Diagrama de clases de ServiceManager

2.1 Introducción al directorio ServiceManager

ServiceManager se encuentra en el siguiente directorio
frameworks/native/cmds/servicemanager/
 Access.cpp  
 Access.h  
 Android.bp  
 main.cpp  
 ServiceManager.cpp  
 ServiceManager.h  
 servicemanager.rc  
 TEST_MAPPING  
 test_sm.cpp  
 vndservicemanager.rc

2.2 Introducción al diagrama de clases de ServiceManager

El diagrama de clases de ServiceManager es el siguiente:

Introducción a la ruta del archivo de implementación específica final de 2.3 Bn, Bp

La implementación de BpServiceManager se encuentra en el siguiente directorio, y otros archivos relacionados /soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm64_armv8XXX/gen/aidl/android/os se generan automáticamente en este directorio Aidl.

BnClientCallback.h   
BnServiceDebugInfo.h  
BpClientCallback.h   
BpServiceDebugInfo.h  
IClientCallback.cpp  
IServiceCallback.cpp  
IServiceManager.cpp  
ServiceDebugInfo.cpp
BnServiceCallback.h  
BnServiceManager.h    
BpServiceCallback.h  
BpServiceManager.h    
IClientCallback.h    
IServiceCallback.h    
IServiceManager.h    
ServiceDebugInfo.h


Entre ellos, BnServiceManager es el lado del servidor y su clase de implementación se llama ServiceManager.cpp.

3. Proceso de inicio de ServiceManager

3.1 Iniciar entrada

ServiceManager es el servidor. Después de iniciarse, primero llama a la función principal. El directorio es el siguiente

marcos/nativo/cmds/servicemanager/main.cpp

int main(int argc, char** argv) {
    if (argc > 2) {
        LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
    }
    //从servicemanager.rc中可看到,启动servicemanager时没有多余的参数,所以次数arvc=1,则driver为"/dev/binder"。
    const char* driver = argc == 2 ? argv[1] : "/dev/binder";

    //打开并映射binder驱动, open mmap 和以前的binder不同的地方
    sp<ProcessState> ps = ProcessState::initWithDriver(driver);
    //设置thread poll的最大线程数量
    ps->setThreadPoolMaxThreadCount(0);
    //设置调用限制,FATAL_IF_NOT_ONEWA意思是:在阻塞调用时中止进程
    //oneway 限制,ServiceManager发起的 Binder 调用必须是单向,否则打印堆栈日志提示
    ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
    //实例化ServiceManager, Access为鉴权
    sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
    if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
        LOG(ERROR) << "Could not self register servicemanager";
    }
    //设置全局变量给IPCThreadState
    IPCThreadState::self()->setTheContextObject(manager);
    //将自己设置为管理员,handle是0
    ps->becomeContextManager();
    //准备looper
    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
    //以前是 binder_loop死 循环接收驱动的消息,现在是 通知驱动BC_ENTER_LOOPER,监听驱动fd,有消息时回调到handleEvent处理binder调用
    BinderCallback::setupTo(looper);
    //服务的注册监听相关
    ClientCallbackCallback::setupTo(looper, manager);
    //无限循环等待消息
    while(true) {
        looper->pollAll(-1);
    }

    // should not be reached
    return EXIT_FAILURE;
}

3.2 Introducción a initWithDriver

frameworks/native/libs/binder/ProcessState.cpp
sp<ProcessState> ProcessState::initWithDriver(const char* driver)
{     //devuelve un objeto ProcessState sp     return init(driver, true /*requireDefault*/);}


3.3 Introducción a ProcessState::init

marcos/native/libs/binder/ProcessState.cpp

sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{     [[clang::no_destroy]] static sp<ProcessState> gProcess;     [[clang::no_destroy]] static std::mutex gProcessMutex;

    if (driver == nullptr) {         std::lock_guard<std::mutex> l(gProcessMutex);         devolver gProceso;     }


    [[clang::no_destroy]] static std::once_flag gProcessOnce;
    //call_once garantiza que la función o el fragmento de código solo deba ejecutarse una vez en un entorno multiproceso
    std::call_once(gProcessOnce, [&](){   //juicio/ Si dev/binder es legible, 0 para éxito, -1 para falla.         if (access(driver, R_OK) == -1) {             ALOGE("El controlador de Binder %s no está disponible. Se usa /dev/binder en su lugar .", controlador);             controlador = "/dev/binder";         }
     



        std::lock_guard<std::mutex> l(gProcessMutex);
       //实例化ProcessState
        gProcess = sp<ProcessState>::make(driver);

    });

    if (requireDefault) {         // Detecta si estamos intentando inicializar con un controlador diferente y         // lo considera un error. ProcessState solo se inicializará una vez arriba.         LOG_ALWAYS_FATAL_IF(gProcess->getDriverName() != controlador,                             "ProcessState ya se inicializó con %s",                             "no se puede inicializar con %s.",                             gProcess->getDriverName().c_str(), driver);     }






    devolver gProceso;
}

3.4 Introducción al constructor de ProcessState

marcos/native/libs/binder/ProcessState.cpp

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    //abrir controlador
    , mDriverFD(open_driver(driver))
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0 )
    , mWaitingForThreads(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
    , mStarvationStartTimeMs(0)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
    , mCallRestriction(CallRestriction::NONE)
{     if (mDriverFD >= 0) {         // mmap la carpeta, proporcionando un trozo de espacio de direcciones virtuales para recibir transacciones.


        // Mapeo de memoria virtual, finalmente llame a la función binder_mmap()
        // El tamaño de la memoria mapeada:

       //#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
        //1M-2 páginas del tamaño normal de una aplicación
        mVMStart = mmap(nullptr, BINDER_VM_SIZE , PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0 );
        if (mVMStart == MAP_FAILED) {             // *suspiro*             ALOGE("Falló el uso de %s: no se pudo mapear la memoria de transacciones.\n", mDriverName.c_str());             close(mDriverFD);             mDriverFD = -1;             mDriverName.clear();         }     }






#ifdef __ANDROID__
    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "No se pudo abrir el controlador de carpeta '%s'. Terminando.", driver);
#endif
}

3.5 introducción a open_driver

marcos/native/libs/binder/ProcessState.cpp

static int open_driver(const char *driver)
{   //Abrir /dev/binder, leer y escribir, y habilitar el indicador close-on-exec (close-on-exec) para el descriptor de archivo recién creado para evitar el tiempo involuntario del descriptor de archivo fugas al proceso hijo creado por fork     int fd = open(driver, O_RDWR | O_CLOEXEC);     if (fd >= 0) {         int vers = 0;         //Obtenga la versión de Binder y finalmente llame a la función binder_ioctl()         status_t result = ioctl (fd, BINDER_VERSION, &vers);         if (resultado == -1) {             ALOGE("Binder ioctl para obtener la versión falló: %s", strerror(errno));             close(fd);             fd = -1;         }         if ( resultado != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
 











          ALOGE("¡El protocolo del controlador de Binder(%d) no coincide con el protocolo del espacio de usuario(%d)! Valor de retorno de ioctl(): %d",
                vers, BINDER_CURRENT_PROTOCOL_VERSION, resultado);
            cerrar(fd);
            fd = -1;
        }
        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
        //设置最大threads数量
        resultado = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
        if (resultado == -1) {             ALOGE("Binder ioctl para establecer el número máximo de subprocesos falló: %s", strerror(errno));         }         uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;         // resultado unidireccional         = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);





        if (resultado == -1) {             ALOGD("Binder ioctl para habilitar la detección de spam unidireccional falló: %s", strerror(errno));         }     } else {         ALOGW("Error al abrir '%s': %s\n", controlador, strerror(errno));     }     devolver fd; }






3.6 Diagrama de flujo general de inicio de ServiceManager

El proceso anterior está organizado en un diagrama de flujo de la siguiente manera: se puede ver que las operaciones open, ioctl y mmap se realizan en initWithDriver.

4. Introducción a IServicManager

4.1 Introducción al directorio de IServiceManager

El código de IServiceManager se encuentra en el siguiente directorio
frameworks/native/libs/binder

Android.bp
Binder.cpp
BpBinder.cpp
IInterface.cpp
IPCThreadState.cpp
IServiceManager.cpp
Parcel.cpp
ProcessState.cpp

frameworks/native/libs/binder/aidl/android/os/
IClientCallback.aidl  
IServiceCallback.aidl  
IServiceManager.aidl  
ServiceDebugInfo.aidl

4.2 Introducción a bp de IServiceManager

IServiceManager se compila en libbinder.so, que hace referencia a libbinder_aidl, y el archivo Aidl utilizado en el servicio ServiceManager superior también hace referencia a este libbinder_aidl.

marcos/native/libs/binder/Android.bp

cc_library { 
name: "libbinder",

// for vndbinder

vendor_available: true, vndk: { enabled: true, },
...
    srcs: [
        "Binder.cpp",
        "BpBinder.cpp",
        "IInterface.cpp",
        "IPCThreadState.cpp",
        "IServiceManager.cpp",
...

        ":libbinder_aidl",//引用aidl文件
],
    aidl: {//输出aidl头文件

        export_aidl_headers: true,

    },
},
// AIDL interface between libbinder and framework.jar
filegroup {
    name: "libbinder_aidl",
    srcs: [//aidl文件
        "aidl/android/os/IClientCallback.aidl",
        "aidl/android/os/IServiceCallback.aidl",
        "aidl/android/os/IServiceManager.aidl",
        "aidl/android/os/ServiceDebugInfo.aidl",
    ],
    path: "aidl",
}

 IServiceManager se basa en AIDL y libbinder, y la clase ServiceManagerShim hereda IServiceManager. ServiceManagerShim reenvía las solicitudes de los clientes. Porque el cliente obtiene el objeto IServiceManager a través del método defaultServiceManager ().

4.3 Introducción a defaultServiceManager

La implementación de defaultServiceManager es la siguiente: puede ver que el puntero del objeto ServiceManagerShim se devuelve al final, por lo que ServiceManagerShim reenvía todas las solicitudes del lado del cliente.

marcos/native/libs/binder/IServiceManager.cpp

sp<IServiceManager> defaultServiceManager()
{
    std::call_once(gSmOnce, []() {
        sp<AidlServiceManager> sm = nullptr;
        while (sm == nullptr) {
            //拿到客户端BpServiceManager(new BpBinder(0))的实例
            sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
            if (sm == nullptr) {
                ALOGE("Waiting 1s on context object on %s.", ProcessState::self()->getDriverName().c_str());
                sleep(1);
            }
        }
        //new ServiceManagerShim,拿到BpServiceManager
        gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);
    });

    return gDefaultServiceManager;
}

Luego hable sobre cómo obtener el objeto de carpeta del lado bp en defaultServiceManager, obtener BpBinder (0) a través de ProcessState :: self () -> getContextObject (nullptr) y luego obtener BpServiceManager a través de interface_cast.

marcos/native/libs/binder/ProcessState.cpp

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
//获取handler为0的IBinder
    sp<IBinder> context = getStrongProxyForHandle(0);
...
    return context;
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    //加锁
    AutoMutex _l(mLock);
    handle_entry* e = lookupHandleLocked(handle);
    if (e != nullptr) {
        IBinder* b = e->binder;
        if (b == nullptr || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
                IPCThreadState* ipc = IPCThreadState::self();
                CallRestriction originalCallRestriction = ipc->getCallRestriction();
                //设置调用限制
                ipc->setCallRestriction(CallRestriction::NONE);

                Parcel data;
                //PING_TRANSACTION
                status_t status = ipc->transact(
                        0, IBinder::PING_TRANSACTION, data, nullptr, 0);

                ipc->setCallRestriction(originalCallRestriction);
                //如果object死亡,就返回空
                if (status == DEAD_OBJECT)
                   return nullptr;
            }
            //new BpBinder(0)
            sp<BpBinder> b = BpBinder::create(handle);
            e->binder = b.get();
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
...
        }
    }
    //返回客户端BpBinder
    return result;
}

4.4 Introducción a la implementación de interface_cast y asInterface

¿Cómo se implementa interface_cast? Veamos cómo se ve el código fuente. asInterface se devuelve en la función interface_cast, es decir, se devuelve un nuevo objeto proxy Bp. Cuando se define el servicio, debe tener la siguiente declaración.

DECLARE_META_INTERFACE(CustomizeManagerService); 
IMPLEMENT_META_INTERFACE(CustomizeManagerService, NATIVESERVICE_NAME);

frameworks/native/libs/binder/include/binder/IInterface.h

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)                                                                                                                              
{
    return INTERFACE::asInterface(obj);
}
//在服务中声明
#define DECLARE_META_INTERFACE(INTERFACE)
    static ::android::sp<I##INTERFACE> asInterface(                     \                                                                                                                
            const ::android::sp<::android::IBinder>& obj);   
//在服务中声明
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) 
   ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
            const ::android::sp<::android::IBinder>& obj)               \
    {                                                                   \
        ::android::sp<I##INTERFACE> intr;                               \
        if (obj != nullptr) {                                           \
            intr = ::android::sp<I##INTERFACE>::cast(                   \
                obj->queryLocalInterface(I##INTERFACE::descriptor));    \
            if (intr == nullptr) {                                      \
                //new Bp的代理对象并返回
                intr = ::android::sp<Bp##INTERFACE>::make(obj);         \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    } 

4.5 Introducción a otras interfaces de IServiceManager

Algunas interfaces se definen en IServiceManager, que hereda IInterface, por lo que las interfaces de funciones en el lado del cliente y el lado del servidor deben ser consistentes con estas interfaces, y debe haber implementaciones específicas en el lado del servidor.

marcos/native/libs/binder/IServiceManager.cpp

#include <binder/IServiceManager.h>
#include <android/os/BnServiceCallback.h>
#include <android/os/IServiceManager.h>
//ServiceManagerShim继承IServiceManager
class ServiceManagerShim : public IServiceManager
{
public:
    explicit ServiceManagerShim (const sp<AidlServiceManager>& impl);

    sp<IBinder> getService(const String16& name) const override;
    sp<IBinder> checkService(const String16& name) const override;
    status_t addService(const String16& name, const sp<IBinder>& service,
                        bool allowIsolated, int dumpsysPriority) override;
    Vector<String16> listServices(int dumpsysPriority) override;
    sp<IBinder> waitForService(const String16& name16) override;
    bool isDeclared(const String16& name) override;
    Vector<String16> getDeclaredInstances(const String16& interface) override;
    std::optional<String16> updatableViaApex(const String16& name) override;
    IBinder* onAsBinder() override {
        return IInterface::asBinder(mTheRealServiceManager).get();
    }
};

marcos/native/libs/binder/include/binder/IServiceManager.h

clase IServiceManager: IInterfaz pública

...

5. Otros servicios registran/obtienen servicios a través de IServicManager

5.1: Servicios de registro

5.1.1 Ejemplo de agregar otros servicios a ServiceManager

Primero mire un ejemplo de un servicio de registro, como se muestra en la figura siguiente, puede ver que el servicio de registro se realiza a través de la interfaz addService de IServiceManager.

sp<ProcessState> proc(ProcessState::self());
//获取BpServiceManager指针
sp<IServiceManager> sm = defaultServiceManager();

sp<CustomizeManagerService> mService = new CustomizeManagerService();
//通过IServiceManager注册服务
sm->addService(String16(NATIVESERVICE_NAME), mService, false);

ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();

5.1.2 Introducción a addService en Cliente

En este ejemplo, cuando el servicio CustomizeManagerService registra el servicio a través de IServiceManager, obtiene el puntero de objeto de BpServiceManager a través de la interfaz defaultServiceManager () y luego agrega el servicio a través de la interfaz addService. El código addService es el siguiente:

frameworks/native/libs/binder/IServiceManager.cpp
status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service,
                                        bool allowIsolated, int dumpsysPriority)
{
    //mTheRealServiceManager为BpServiceManager
    Status status = mTheRealServiceManager->addService(
        String8(name).c_str(), service, allowIsolated, dumpsysPriority);
    return status.exceptionCode();
}

5.1.3 Proceso de asignación de mTheRealServiceManager

¿Cómo surgió mTheRealServiceManager? Echemos un vistazo al proceso de asignación de mTheRealServiceManager.

frameworks/native/libs/binder/IServiceManager.cpp
//两者等价
using AidlServiceManager = android::os::IServiceManager;

// From the old libbinder IServiceManager interface to IServiceManager.
class ServiceManagerShim : public IServiceManager
{
...
//变量声明
    sp<AidlServiceManager> mTheRealServiceManager;
};

sp<IServiceManager> defaultServiceManager()
{
...
        sp<AidlServiceManager> sm = nullptr;
        while (sm == nullptr) {
            sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
...
        }
        //此处将sm传入了,即也就赋值给了mTheRealServiceManager
        gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);
...
}

ServiceManagerShim::ServiceManagerShim(const sp<AidlServiceManager>& impl)
 : mTheRealServiceManager(impl)//impl赋给mTheRealServiceManager
{}
De lo anterior se puede ver que mTheRealServiceManager es equivalente a impl, que es el objeto ServiceManager de Bp.

5.1.4  Introducción al addService de IServiceManager, proceso completo desde Bp->Bn

Luego hable sobre el proceso addService y luego vaya a IServiceManager.cpp y ejecútelos de acuerdo con las siguientes etiquetas 1, 2, 3, 4 y 5.

 out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm64_armv8-a_shared/gen/aidl/android/os/IServiceManager.cpp

#include <android/os/IServiceManager.h>
#include <android/os/BpServiceManager.h>
namespace android {
namespace os {
DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager")
}  // namespace os
}  // namespace android
#include <android/os/BpServiceManager.h>
#include <android/os/BnServiceManager.h>
#include <binder/Parcel.h>
#include <android-base/macros.h>
BpServiceManager::BpServiceManager(const ::android::sp<::android::IBinder>& _aidl_impl)
    : BpInterface<IServiceManager>(_aidl_impl){
}
1. 先走Bp的addService方法
::android::binder::Status BpServiceManager::addService(const ::std::string& name, const ::android::sp<::android::IBinder>& service, bool allowIsolated, int32_t dumpPriority) {
  ::android::Parcel _aidl_data;
  _aidl_data.markForBinder(remoteStrong());
  ::android::Parcel _aidl_reply;
  ::android::status_t _aidl_ret_status = ::android::OK;
  ::android::binder::Status _aidl_status;
  //标注远程服务名称,getInterfaceDescriptor为远程服务端接口描述
  _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = _aidl_data.writeStrongBinder(service);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = _aidl_data.writeBool(allowIsolated);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = _aidl_data.writeInt32(dumpPriority);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  2. 调用transact方法,与服务端进行通信,此处remote()后面会解释
  _aidl_ret_status = remote()->transact(BnServiceManager::TRANSACTION_addService, _aidl_data, &_aidl_reply, 0);
  if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IServiceManager::getDefaultImpl())) {
     return IServiceManager::getDefaultImpl()->addService(name, service, allowIsolated, dumpPriority);
  }
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  if (!_aidl_status.isOk()) {
    return _aidl_status;
  }
  _aidl_error:
  _aidl_status.setFromStatusT(_aidl_ret_status);
  return _aidl_status;
}
}  // namespace os
}  // namespace android

namespace android {
namespace os {
BnServiceManager::BnServiceManager()
{
  ::android::internal::Stability::markCompilationUnit(this);
}
3. 走Bn端的onTransact
::android::status_t BnServiceManager::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) {
  ::android::status_t _aidl_ret_status = ::android::OK;
  switch (_aidl_code) {
4. 根据Bp端的transact中关键字走进此处case
  case BnServiceManager::TRANSACTION_addService:
  {
    ::std::string in_name;
    ::android::sp<::android::IBinder> in_service;
    bool in_allowIsolated;
    int32_t in_dumpPriority;
    if (!(_aidl_data.checkInterface(this))) {
      _aidl_ret_status = ::android::BAD_TYPE;
      break;
    }
    _aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
    if (((_aidl_ret_status) != (::android::OK))) {
      break;
    }
    _aidl_ret_status = _aidl_data.readStrongBinder(&in_service);
    if (((_aidl_ret_status) != (::android::OK))) {
      break;
    }
    _aidl_ret_status = _aidl_data.readBool(&in_allowIsolated);
    if (((_aidl_ret_status) != (::android::OK))) {
      break;
    }
    _aidl_ret_status = _aidl_data.readInt32(&in_dumpPriority);
    if (((_aidl_ret_status) != (::android::OK))) {
      break;
    }
    5. 调用Bn端的getService方法
    ::android::binder::Status _aidl_status(addService(in_name, in_service, in_allowIsolated, in_dumpPriority));
    _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
    if (((_aidl_ret_status) != (::android::OK))) {
      break;
    }
    if (!_aidl_status.isOk()) {
      break;
    }
  }
...
}  // namespace os
}  // namespace android

5.1.5 Introducción a remoto() en remoto()->transact de BpServiceManager en el lado del cliente

Se puede ver en el paso 2 que la siguiente comunicación se lleva a cabo llamando a remoto()->transact(BnServiceManager::TRANSACTION_getService, _aidl_data, &_aidl_reply, 0).

¿Qué es remoto()? Se puede ver por su implementación que es mRemote.

marcos/native/libs/binder/include/binder/Binder.h

 class BpRefBase : public virtual RefBase
{
    inline IBinder* remote() const { return mRemote; }
    IBinder* const          mRemote;
};

mRemote se asigna con el siguiente método, puede ver que o.get() está asignado a mRemote.

frameworks/native/libs/binder/include/binder/IInterface.h

BpRefBase::BpRefBase(const sp<IBinder>& o)
    : mRemote(o.get()), mRefs(nullptr), mState(0)                                                                                                                                        
{... }

¿Dónde está la creación de instancias de BpRefBase? A continuación, podemos ver que el parámetro de entrada remoto está asignado a BpRefBase en el constructor de BpInterface.
frameworks/native/libs/binder/include/binder/IInterface.h

template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
    : BpRefBase(remote)                                                                                                                                                                  
{}

Como se puede ver en el siguiente archivo, BpServiceManager hereda BpInterface, entonces, ¿dónde se crea una instancia de BpServiceManager? En la explicación anterior de defaultServiceManager, se puede ver claramente que el parámetro entrante es BpBinder.

/out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm64_armv8-a_shared/gen/aidl/android/os/BpServiceManager.h

#include <binder/IBinder.h>
#include <binder/IInterface.h>
#include <utils/Errors.h>
#include <android/os/IServiceManager.h>
namespace android {
namespace os {
class BpServiceManager : public ::android::BpInterface<IServiceManager> {
...
};  // class BpServiceManager
}  // namespace os
}  // namespace android

De lo anterior se puede ver que remoto () es BpBinder. Esto también ingresó al método de transacción de BpBinder.

5.1.6 Introducción de transacciones de BpBinder en el lado del cliente

marcos/native/libs/binder/BpBinder.cpp

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
...
        status_t status;
...
            status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
...
    return DEAD_OBJECT;
}

frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
... //cmd为BC_TRANSACTION
    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
...
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
...
}

status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
    binder_transaction_data tr;

    tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
    tr.target.handle = handle;
    tr.code = code;
    tr.flags = binderFlags;
    tr.cookie = 0;
    tr.sender_pid = 0;
    tr.sender_euid = 0;

    const status_t err = data.errorCheck();
    if (err == NO_ERROR) {
        tr.data_size = data.ipcDataSize();
        tr.data.ptr.buffer = data.ipcData();
        tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
        tr.data.ptr.offsets = data.ipcObjects();
    } else if (statusBuffer) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr.offsets_size = 0;
        tr.data.ptr.offsets = 0;
    } else {
        return (mLastError = err);
    }
//cmd为BC_TRANSACTION
    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));

    return NO_ERROR;
}

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
...     //和Driver通信
        if ((err=talkWithDriver()) < NO_ERROR) break;
...
}

5.1.6 Introducción a la charla del cliente con el controlador

status_t IPCThreadState::talkWithDriver(bool doReceive)
{ ...

//Comunícate con /dev/binder, fd es mProcess->mDriverFD
        if (ioctl( mProcess->mDriverFD , BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
...
}


Hasta ahora, el flujo de datos en el lado del cliente ha finalizado, entonces, ¿cómo sabe el lado del servidor que hay un cambio de datos en /dev/binder y lo lee?

5.1.7 ¿Cómo sabe el servidor que hay un cambio de datos en /dev/binder y lo lee?

3: En el proceso de inicio de ServiceManager  , se puede ver que cuando se inicia el lado del servidor, se registran dos devoluciones de llamada, una de las cuales es BinderCallback, y el lado del servidor conoce los cambios de datos en /dev/binder a través de BinderCallback y notifica al ServerManager que léelo.

5.1.8 Introducción a LooperCallback heredado por BinderCallback en ServiceManager

     BinderCallback hereda LooperCallback. LooperCallback puede ver la implementación principal de Handler en la capa C ++ y conocerá la función de LooperCallback. Hay dos funciones importantes en Handler, a saber, addFd y handleEvent.

system/core/libutils/include/utils/Looper.h
clase LooperCallback: RefBase virtual pública { ...     virtual int handleEvent(int fd, int events, void* data) = 0; };


clase Looper: RefBase pública {

público:

    int addFd(int fd, int ident, int events, devolución de llamada Looper_callbackFunc, datos void*);
    int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data);

...

Cuando se llama a la función addFd, pasa un fd para agregarlo al grupo de escucha de eventos epoll del Looper correspondiente, monitorea los eventos de interés en el fd y el resultado del monitoreo se devolverá al oyente entrante.

La función handleEvent se usa para manejar el evento de encuesta del descriptor de archivo especificado, es decir, después de epoll_wait en el looper, esta función se llamará cuando el fd que agregamos tenga datos.

5.1.9 Introducción a BinderCallback en ServiceManager

Echemos un vistazo a cómo funciona BinderCallback en el lado del servidor.

marcos/nativo/cmds/servicemanager/main.cpp

class BinderCallback : public LooperCallback {
public:
    static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
        sp<BinderCallback> cb = sp<BinderCallback>::make();

        int binder_fd = -1;
        //这个binder_fd是哪个fd呢
        IPCThreadState::self()->setupPolling(&binder_fd);
        LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);
        //向looper中添加binder_fd,并传入callback监听器
        int ret = looper->addFd(binder_fd,
                                Looper::POLL_CALLBACK,
                                Looper::EVENT_INPUT,
                                cb,
                                nullptr /*data*/);
        LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper");

        return cb;
    }
    //当binder_fd有变化时,会回调该函数
    int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
        //收到变化时,调用此函数
        IPCThreadState::self()->handlePolledCommands();
        return 1;  // Continue receiving callbacks.
    }
};

frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::setupPolling(int* fd)
{
...
    //此处对fd进行了赋值
    *fd = mProcess->mDriverFD;
    return 0;
}

Se puede ver en el código anterior que en el método setupTo de BinderCallback, se llama al método addFd y mProcess->mDriverFD se asigna a binder_fd y se pasa al looper, de modo que sea exactamente igual que el fd anterior. talkWithDriver , es decir, cuando mProcess->mDriverFD Cuando el contenido en mDriverFD cambia, se llamará al método handleEvent para notificar al ServiceManager del lado del servidor.

¿Qué fd de nodo es mDriverFD?mDriverFD se asigna cuando se ejecuta el método open_driver(driver) cuando ProcessState ejecuta el constructor.

Estado de proceso::Estado de proceso(const char *controlador)
    : mDriverName(String8(controlador))
    , mDriverFD(open_driver(controlador))

Como se explicó anteriormente, se llama a open_driver cuando se crea una instancia de ProcessState después de ejecutar el método ProcessState::initWithDriver(driver) en main.cpp, y el controlador entrante es "/dev/binder". Hasta ahora, ¿comprende mejor el principio de Binder?

frameworks/native/cmds/servicemanager/main.cpp
    const char* controlador = argc == 2? argv[1] : "/dev/encuadernador" ;
    sp<ProcessState> ps = ProcessState::initWithDriver( controlador );

frameworks/native/libs/binder/ProcessState.cpp
static int open_driver(const char *driver)
{     // driver就是"/dev/binder"     int fd = open( driver , O_RDWR | O_CLOEXEC); ...     devolver fd; }




Cada vez hay más cosas de qué hablar, si no lo entiende, léalo varias veces.

En este punto, el ServiceManager del lado del servidor ya sabe que el contenido de la memoria compartida en /dev/binder ha cambiado y luego comenzará la operación de lectura real.

5.1.10 Proceso posterior de handleEvent en BinderCallback en ServiceManager

IPCThreadState::self()->handlePolledCommands() se llama en handleEvent en BinderCallback.

frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::handlePolledCommands()
{     status_t resultado;

    hacer {         resultado = getAndExecuteCommand ();     } mientras (mIn.dataPosition() < mIn.dataSize());

    procesoPendingDerefs();
    comandos de descarga();
    resultado de devolución;
}

frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::getAndExecuteCommand()
{     status_t resultado;     int32_tcmd;

    resultado = talkWithDriver();
    if (resultado >= NO_ERROR) { ...         cmd = mIn.readInt32();//cmd es BR_TRANSACTION, hay una explicación al frente ...


        resultado = ejecutarComando(cmd);

...
}

sp<BBinder> the_context_object ;
status_t IPCThreadState:: ejecutarCommand (int32_t cmd)
{ ...     cambiar ((uint32_t)cmd) { caso BR_TRANSACTION:         { ...


   

            } else {                 //sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());                 //IPCThreadState::self()->setTheContextObject(manager);//将manager设置给了the_context_object,所以the_context_object就是Server端ServerManager对象//                调用BBinder的transact                 error = the_context_object->transact(tr.code, buffer, &responder, tr.flags);             } ... } frameworks/native/libs/binder/Binder.cpp status_t BBinder::transact (     código uint32_t, const Parcel& data, Parcel* respuesta, banderas uint32_t) {     status_t err = NO_ERROR;     cambiar (código) { ...














            err = onTransact (código, datos, respuesta, banderas);
            romper;
    }

5.1.11 Introducción a onTransact de BnServiceManager en el lado del servidor

Finalmente, se llama al método onTransact de BnServiceManager , que es el tercer paso anterior.

out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm64_armv8-a_shared/gen/aidl/android/os/BnServiceManager.h #include <
binder/IInterface.h>
#include <android/os/IServiceManager. h>
espacio de nombres android { espacio de nombres sistema operativo { clase BnServiceManager : public ::android:: BnInterface <IServiceManager> { ...     ::android::status_t onTransact (uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android:: Parcel* _aidl_reply, uint32_t _aidl_flags) anulación;



...

frameworks/native/libs/binder/include/binder/IInterface.h
clase BnInterface : INTERFAZ pública, BBinder público

marcos/native/libs/binder/include/binder/Binder.h

clase BBinder : IBinder
público {

...
    virtual status_t     onTransact (código uint32_t,
                                    datos constantes de Parcel&,
                                    respuesta de Parcel*,
                                    banderas uint32_t = 0);

...

5.1.12 Introducción a addService en el lado del servidor

Cuando se ejecuta el paso 5, ingresará frameworks/native/cmds/servicemanager/ServiceManager.cpp en el lado Bn, es decir, en la implementación del código del servidor Bn.

marcos/nativo/cmds/servicemanager/ServiceManager.cpp

 Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool enableIsolated, int32_t dumpPriority) { auto     ctx = mAccess->getCallingContext(); ...     //Agrega el nombre del servicio a En la estructura     // Sobrescribe el servicio antiguo si existe



    mNameToService[nombre] = Servicio {         .binder = binder,         .allowIsolated = enableIsolated,         .dumpPriority = dumpPriority,         .debugPid = ctx.debugPid,     }; ...     devolver Estado::ok(); }







5.1.13 Introducción para agregar un mapa de lista de servicios en el lado del servidor

La declaración de mNameToService es la siguiente, es decir, el servicio final se agrega al mapa

marcos/nativo/cmds/servicemanager/ServiceManager.h

usando ServiceMap = std:: map <std::string, Service>;
Mapa de servicios mNameToService;

    Servicio de estructura {         sp<IBinder> carpeta; // no nulo         bool enableIsolated;         int32_t dumpPrioridad;         bool tieneClientes = falso; // notificaciones enviadas en verdadero -> falso.         bool garantiaCliente = false; // fuerza la verificación del cliente a verdadero         pid_t debugPid = 0; // el proceso en el que se ejecuta este servicio





        // el número de clientes del servicio, incluido el propio servicemanager
        ssize_t getNodeStrongRefCount();
    };

5.2 Obtención de servicios

5.2.1 Ejemplo de obtención de servicio a través de IServiceManager

El ejemplo de obtención del servicio es el siguiente, y el objeto de servicio correspondiente también se obtiene a través de IServiceManager.

sp<IServiceManager> sm = defaultServiceManager();
//获取服务
sp<ICustomizeManagerService> mService = ICustomizeManagerService::asInterface(sm->getService(String16("customizeManagerservice")));
if(mService != NULL)
{
    //获取到服务的binder对象,然后调用服务的接口
    mService.customize();
}

¿Cómo se implementa asInterface? Se ha explicado anteriormente, puedes buscarlo.

5.2.2 Introducción a la interfaz getService del lado del cliente

En la interfaz getService, si el servicio no se inicia, lo iniciará, pero esperará hasta 5 segundos.

frameworks/native/libs/binder/IServiceManager.cpp
sp<IBinder> ServiceManagerShim::getService(const String16& name) const
{
    sp<IBinder> svc = checkService(name)
......
    //有5s超时机制
    constexpr int64_t timeout = 5000;
    int64_t startTime = uptimeMillis();
    ......
    int n = 0;
    while (uptimeMillis() - startTime < timeout) {
        n++;
        usleep(1000*sleepTime);

        sp<IBinder> svc = checkService(name);
        if (svc != nullptr) {
            ALOGI("Waiting for service '%s' on '%s' successful after waiting %" PRIi64 "ms",
                  String8(name).string(), ProcessState::self()->getDriverName().c_str(),
                  uptimeMillis() - startTime);
...
}

sp<IBinder> ServiceManagerShim::checkService(const String16& name) const
{
    sp<IBinder> ret;
    //checkService
    if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
        return nullptr;
    }
    return ret;
}

5.2.3 proceso getServiceice Bp->Bn en IServiceManager 

#include <android/os/BpServiceManager.h>
#include <android/os/BnServiceManager.h>
#include <binder/Parcel.h>
#include <android-base/macros.h>
namespace android {
namespace os {
BpServiceManager::BpServiceManager(const ::android::sp<::android::IBinder>& _aidl_impl)
    : BpInterface<IServiceManager>(_aidl_impl){
}
1. Bp端getService
::android::binder::Status BpServiceManager::getService(const ::std::string& name, ::android::sp<::android::IBinder>* _aidl_return) {
  ::android::Parcel _aidl_data;
  _aidl_data.markForBinder(remoteStrong());
  ::android::Parcel _aidl_reply;
  ::android::status_t _aidl_ret_status = ::android::OK;
  ::android::binder::Status _aidl_status;
  _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
2. write name
  _aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
3. BpBinder->transact
  _aidl_ret_status = remote()->transact(BnServiceManager::TRANSACTION_getService, _aidl_data, &_aidl_reply, 0);
  if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IServiceManager::getDefaultImpl())) {
     return IServiceManager::getDefaultImpl()->getService(name, _aidl_return);
  }
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  if (!_aidl_status.isOk()) {
    return _aidl_status;
  }
  _aidl_ret_status = _aidl_reply.readNullableStrongBinder(_aidl_return);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_error:
  _aidl_status.setFromStatusT(_aidl_ret_status);
  return _aidl_status;
}
}  // namespace os
}  // namespace android

#include <android/os/BnServiceManager.h>
#include <binder/Parcel.h>
#include <binder/Stability.h>
namespace android {
namespace os {
BnServiceManager::BnServiceManager()
{
  ::android::internal::Stability::markCompilationUnit(this);
}
4.Bn->onTransact
::android::status_t BnServiceManager::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) {
  ::android::status_t _aidl_ret_status = ::android::OK;
  switch (_aidl_code) {
  case BnServiceManager::TRANSACTION_getService:
  {
    ::std::string in_name;
    ::android::sp<::android::IBinder> _aidl_return;
    if (!(_aidl_data.checkInterface(this))) {
      _aidl_ret_status = ::android::BAD_TYPE;
      break;
    }
5. read name
    _aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
    if (((_aidl_ret_status) != (::android::OK))) {
      break;
    }
6.调用Bn端实现类getService
    ::android::binder::Status _aidl_status(getService(in_name, &_aidl_return));
    _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
    if (((_aidl_ret_status) != (::android::OK))) {
      break;
    }
    if (!_aidl_status.isOk()) {
      break;
    }
7.将reply write进去
    _aidl_ret_status = _aidl_reply->writeStrongBinder(_aidl_return);
    if (((_aidl_ret_status) != (::android::OK))) {
      break;
    }
  }
  break;
...


5.2.4 Introducción a getService del lado del servidor

Eventualmente será llamado al lado Bn.

Bn服务端
frameworks/native/cmds/servicemanager/ServiceManager.cpp
Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) {
    *outBinder = tryGetService(name, false);
    return Status::ok();
}


sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) {
    auto ctx = mAccess->getCallingContext();

    sp<IBinder> out;
    Service* service = nullptr;
//去mNameToService查找name名字的service
    if (auto it = mNameToService.find(name); it != mNameToService.end()) {
        service = &(it->second);

        if (!service->allowIsolated) {
            uid_t appid = multiuser_get_app_id(ctx.uid);
            bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END;

            if (isIsolated) {
                return nullptr;
            }
        }
        out = service->binder;
    }

    if (!mAccess->canFind(ctx, name)) {
        return nullptr;
    }

    if (!out && startIfNotFound) {
//启动服务
        tryStartService(name);
    }

    if (out) {
        // Setting this guarantee each time we hand out a binder ensures that the client-checking
        // loop knows about the event even if the client immediately drops the service
        service->guaranteeClient = true;
    }

    return out;
}

Supongo que te gusta

Origin blog.csdn.net/weixin_41028555/article/details/130316582
Recomendado
Clasificación