Android ServiceManager的启动和工作原理

ServiceManager启动

所有的系统服务都是需要在ServiceManager中进行注册的,而ServiceManager作为一个起始的服务,是通过init.rc来启动的。

  //system\core\rootdir\init.rc
	//启动的服务,这里是用的服务名称。服务名称是在对应的rc文件中注册并启动的
  start servicemanager

具体的服务信息是在servicemanger.rc命名并定义的

//\frameworks\native\cmds\servicemanager\servicemanager.rc
service servicemanager /system/bin/servicemanager
  class core animation
  user system //说明以用户system身份运行
  group system readproc
  //说明servicemanager是系统中的关键服务,
  //关键服务是不会退出的,如果退出了,系统就会重启,当系统重启时就会启动用onrestart关键字修饰的进程,
  //比如zygote、media、surfaceflinger等等。
  critical
  onrestart restart healthd
  onrestart restart zygote
  onrestart restart audioserver
  onrestart restart media
  onrestart restart surfaceflinger
  onrestart restart inputflinger
  onrestart restart drm
  onrestart restart cameraserver
  onrestart restart keystore
  onrestart restart gatekeeperd
  onrestart restart thermalservice
  ..

servicemanager的入口函数在service_manager.c中

//frameworks\native\libs\binder\ndk\service_manager.cpp
int main(int argc, char** argv)
{
	//binder_state结构体,用来存储binder的三个信息
  struct binder_state *bs;
	//打开binder驱动,并申请125k字节的内存空间
  bs = binder_open(driver, 128*1024);
  ...
	//将自己注册为Binder机制的管理者
  if (binder_become_context_manager(bs)) {
    ALOGE("cannot become context manager (%s)\n", strerror(errno));
    return -1;
  }
  ...
	//启动循环,等待并处理client端发来的请求
  binder_loop(bs, svcmgr_handler);

  return 0;
}

在main函数中主要做了3件事情。

  • 打开驱动,并申请了128k字节大小的内存空间
  • 将自己注册为Binder机制的管理者
  • 启动循环,等待并处理Client端发来的请求

binder_open

//frameworks\native\cmds\servicemanager\binder.c
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
  struct binder_state *bs;
  struct binder_version vers;
  //申请对应的内存空间
  bs = malloc(sizeof(*bs));
	//打开binder设备文件,这种属于设备驱动的操作方法
  bs->fd = open(driver, O_RDWR | O_CLOEXEC);
	//通过ioctl获取binder的版本号
  if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
    (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
    fprintf(stderr,
        "binder: kernel driver version (%d) differs from user space version (%d)\n",
        vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
    goto fail_open;
  }
  bs->mapsize = mapsize;
	//mmap进行内存映射,将Binder设备文件映射到进程的对应地址空间,地址空间大小为128k
	//映射之后,会将地址空间的起始地址和大小保存到结构体中,
  bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
  return bs;
}

binder_opende的主要功能是打开了Binder的驱动文件,并将文件进行了mmap映射,并将对应的地址空间保存到了结构体中。

binder_become_context_manager

//frameworks\native\cmds\servicemanager\binder.c
int binder_become_context_manager(struct binder_state *bs)
{
  return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}

ioctl会调用Binder驱动的binder_ioctl函数,去注册成为管理者。

binder_loop

将servicemanger注册为Binder的上下文管理者后,它就是Binder机制的“大总管”了,它会在系统运行期间处理Client端的请求,因为请求的时间不确定性,这里采用了无限循环来实现。也就是binder_loop

//frameworks\native\cmds\servicemanager\binder.c
void binder_loop(struct binder_state *bs, binder_handler func)
{
  int res;
  struct binder_write_read bwr;
  uint32_t readbuf[32];

  bwr.write_size = 0;
  bwr.write_consumed = 0;
  bwr.write_buffer = 0;
	//当前线程注册为Binder的指令
  readbuf[0] = BC_ENTER_LOOPER;
	//将BC_ENTER_LOOPER指令写入到Binder驱动,
	//将当前的ServiceManager线程注册为了一个Binder线程(注意ServiceManager本身也是一个Binder线程)。
	//注册为Binder线程之后,就可以处理进程间的请求了
  binder_write(bs, readbuf, sizeof(uint32_t));
	//不断的循环遍历
  for (;;) {
    bwr.read_size = sizeof(readbuf);
    bwr.read_consumed = 0;
    bwr.read_buffer = (uintptr_t) readbuf;
		//使用BINDER_WRITE_READ指令查询Binder驱动中是否有请求。
		//如果有请求,就走到下面的binder_parse部分处理,如果没有,当前的ServiceManager线程就会在Binder驱动中水命,等待新的进程间请求
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
		//走到这里说明有请求信息。将请求的信息用binder_parse来处理,处理方法是func
    res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
  }
}

servicemanager会先将自己注册为一个Binder线程。因为只有注册成为Binder服务之后才能接收进程间的请求。而注册为Binder服务的指令是BC_ENTER_LOOPER。然后通过**binder_write()**方法写入到binder驱动。

//frameworks\native\cmds\servicemanager\binder.c
int binder_write(struct binder_state *bs, void *data, size_t len)
{
  struct binder_write_read bwr;
  int res;

  bwr.write_size = len;
  bwr.write_consumed = 0;
  bwr.write_buffer = (uintptr_t) data;
  bwr.read_size = 0;
  bwr.read_consumed = 0;
  bwr.read_buffer = 0;
	//BINDER_WRITE_READ既可以读也可以写。关键在于read_size和write_size。
	//如果write_size>0。则是写。如果read_size>0则是读。
	//如果都大于0,则先写,再读
  res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
  if (res < 0) {
    fprintf(stderr,"binder_write: ioctl failed (%s)\n",
        strerror(errno));
  }
  return res;
}

系统服务注册

在Android中,每个进程获取系统提供的各种系统服务(AMS,PMS,WMS等)都是需要通过ServiceManager才可以。而这些系统服务进行Binder注册,也需要获取ServiceManager服务才可以。在刚才我们讲过,ServiceManager会将自己也注册成为一个Binder服务。

这里我们以SurfaceFling获取ServiceManager服务为例来看一下是如何获取的。

//frameworks\native\services\surfaceflinger\main_surfaceflinger.cpp
#include <binder/IServiceManager.h>
int main(int, char**) {
  ....
  //获取一个SM对象,相当于是new BpServiceManager(new BpBinder(0))
  sp<IServiceManager> sm(defaultServiceManager());
	//向ServiceManager注册SurfaceFling服务
  sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
          IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
	//在SurfaceFlinger调用init方法的时候,会初始化Display的相关信息
  startDisplayService(); // dependency on SF getting registered above
  ...
  return 0;
}

系统服务的注册过程主要有2点

  • 获取ServiceManager所对应的Binder对象。
  • 通过addService注册为系统服务。

ServiceManager的Binder对象获取

**defaultServiceManager()**方法就是用来获取ServiceManager服务的Binder对象。

defaultServiceManager

//frameworks\native\libs\binder\IServiceManager.cpp
sp<IServiceManager> defaultServiceManager()
{
  if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;

  {
    AutoMutex _l(gDefaultServiceManagerLock);
		/*
		 * 1. ProcessState::self()->getContextObject(NULL): 返回的是一个 BpBinder. ServiceManager 的 desc 默认为0.
		 * 2. interface_cast 就是将 BpBinder 封装为 IServiceManager,这样可以直接调用 IServiceManager 的接口.
		*/

		/*
		 * 这里,有一个设计思想.
		 * 1. defaultServiceManager 首先实例化 BpBinder.
		 * 2. interface_cast 就是 实例化 BpXXX,并将 BpBinder 交给其管理.
		 *
		 * Proxy 端的用户无法直接看到 BpBinder , BpBinder 由 BpXXX 持有.用户本身不关心 BpBinder 的能力,只关心 IXXX 定义的 接口.
		 * 所以这里很好的进行了封装.
		*/

    while (gDefaultServiceManager == nullptr) {//如果不为空,表示设置过了,直接返回
    	//尝试不断的获取ServiceManager对象,如果获取不到,就sleep(1),
    	//这里之所以会获取不到,是因为ServiceManager和一些通过init.rc启动的服务是同时启动的,不能保证ServiceManager能够优先启动完成。
    	//所以会存在获取ServiceManager的时候获取不到。
      gDefaultServiceManager = interface_cast<IServiceManager>(
        ProcessState::self()->getContextObject(nullptr));
      if (gDefaultServiceManager == nullptr)
        sleep(1);
    }
  }

  return gDefaultServiceManager;
}

这里会直接调用**ProcessState::self()->getContextObject(nullptr)**来获取对应的服务。

  • ProcessState::self()->getContextObject(NULL): 返回的是一个 BpHwBinder。ServiceManager 的 desc 默认为0。
  • interface_cast 就是将 BpBinder 封装为 IServiceManager

ProcessState::self()

//system\libhwbinder\ProcessState.cpp
//返回一个ProcessState
sp<ProcessState> ProcessState::self()
{
  Mutex::Autolock _l(gProcessMutex);
  if (gProcess != nullptr) {
    return gProcess;
  }
  gProcess = new ProcessState(kDefaultDriver);
  return gProcess;
}

这里会返回一个ProcessState对象。

getContextObject

//system\libhwbinder\ProcessState.cpp
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
  //传入的参数是handle。0,
  return getStrongProxyForHandle(0);
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
  handle_entry* e = lookupHandleLocked(handle);
  if (e != nullptr) {
    IBinder* b = e->binder;
    if (b == nullptr || !e->refs->attemptIncWeak(this)) {
			//如果b为空,那么创建一个BpHwBinder
      b = new BpHwBinder(handle);
      e->binder = b;
      if (b) e->refs = b->getWeakRefs();
      result = b;
    } else {
      result.force_set(b);
      e->refs->decWeak(this);
    }
  }

  return result;
}

当不存在的时候,这里会创建一个BpHwBinder对象。所以可以理解为最后我们返回的是一个BpBinder对象

这里,有一个设计思想:

  1. defaultServiceManager 首先实例化 BpBinder。
  2. interface_cast 就是 实例化 BpXXX,并将 BpBinder交给其管理。

Proxy 端的用户无法直接看到 BpBinder, BpBinder 由 BpXXX 持有.用户本身不关心 BpBinder的能力,只关心 IXXX 定义的 接口。所以这里很好的进行了封装。

回到前文的defaultServiceManger方法中,将返回值带入,可以得到

//注意,方法中传入的handle为0,所以BpBinder参数为0
gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));

interface_cast

//frameworks\native\include\binder\IInterface.h
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
  return INTERFACE::asInterface(obj);
}
//INTERFACE带入为IServiceManager之后,得到的代码为
inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)
{
  return IServiceManager::asInterface(obj);//静态方法所以直接调用
}

调用IServiceManager接口的成员函数asInterface,将一个句柄值为0的Binder代理对象封装为一个ServiceManger代理对象。将一个句柄值为0的Binder代理对象封装为一个ServiceManger代理对象。

这里 IServiceManager接口的成员函数asInterface是通过宏IMPLEMENT_META_INTERFACE实现,如下所示:

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)
  DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)
#endif

#define DO_NOT_DIRECTLY_USE_ME_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 = static_cast<I##INTERFACE*>(             \
        obj->queryLocalInterface(                \
            I##INTERFACE::descriptor).get());        \
      if (intr == nullptr) {                   \
        intr = new Bp##INTERFACE(obj);             \
      }                              \
    }                                \
    return intr;                          \
  }                                  \

带入IServiceManager之后的代码为:

android::sp<IServiceManager> IIServiceManager::asInterface(const android::sp<android::IBinder>& obj)
{
	android::sp<IServiceManager> intr;
	if (obj != NULL) {
		intr = static_cast<IIServiceManager*>(
          obj->queryLocalInterface(IServiceManager::descriptor).get());//返回NULL
		if (intr == NULL) {
			intr = new BpServiceManager(obj); //创建了ServiceManager代理对象
		}
	}
	return intr;
}

到这里为止,我们创建了一个BpIServiceManager对象,并将他的接口IServiceManager返回给了调用者。

整体的逻辑可以理解为:new BpServiceManager(new BpBinder())。当然了,这只是简化之后的代码,其内部复杂的逻辑现在可以暂不考虑。整体流程如下:

添加Service

客户端请求

当获取到ServiceManager服务之后,就可以使用addService方法来进行服务的注册了。在获取服务的时候,最终返回的是BpServiceManager对象,所以这里我们可以直接找到对应的添加服务方法

  virtual status_t addService(const String16& name, const sp<IBinder>& service,
                bool allowIsolated, int dumpsysPriority) {
    Parcel data, reply;
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeString16(name);
    data.writeStrongBinder(service);
    data.writeInt32(allowIsolated ? 1 : 0);
    data.writeInt32(dumpsysPriority);
    status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
    return err == NO_ERROR ? reply.readExceptionCode() : err;
  }

BpServiceManager的构造函数传入的了BpBinder对象,这里的remote()方法其实就是BpBinder对象。

status_t BpBinder::transact(
  uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
  //如果binder已经died,则不会返回数据
  if (mAlive) {
    ...
		//调用IPCThreadState的transact方法。
    status_t status = IPCThreadState::self()->transact(
      mHandle, code, data, reply, flags);
    if (status == DEAD_OBJECT) mAlive = 0;
    return status;
  }
  return DEAD_OBJECT;
}

这里调用了IPCThreadState的transact方法将对应的数据写入到了Binder驱动了。当Binder驱动接收到注册服务的信息的时候,就会将对应的服务注册到ServiceManager中。我们可以看下传递的参数:

  • mHandle:0,表示要处理该请求的进程号,ServiceManager在注册的时候,其对应的进程号是0。所以处理请求的也就是ServiceManager进程。
  • code:参数是ADD_SERVICE_TRANSACTION。
  • data:包含了要添加的进程相关信息:包括名称、是否单独运行等等相关信息

ServiceManager处理请求

当客户端发送请求之后,我们的ServiceManger就可以接收到消息,并且进行消息的处理了。在ServiceManager的启动中我们了解到,当ServiceManger启动之后,会调用binder_looper来不断的循环,检测是否接收到对应的数据信息。

这个功能是在binder_loop()方法的入参中的svcmgr_handler来实现的。

//frameworks\native\libs\binder\ndk\service_manager.cpp
int main(int argc, char** argv){
	...
	//启动循环,等待并处理client端发来的请求
  binder_loop(bs, svcmgr_handler);
  ...
}

svcmgr_handler就是我们具体的请求处理方法。

//frameworks\native\cmds\servicemanager\service_manager.c
int svcmgr_handler(struct binder_state *bs,
          struct binder_transaction_data_secctx *txn_secctx,
          struct binder_io *msg,
          struct binder_io *reply)
{
  ...
  struct binder_transaction_data *txn = &txn_secctx->transaction_data;
  ...
	//根据传输的不同类型来进行处理。
  switch(txn->code) {
    case SVC_MGR_ADD_SERVICE://添加服务
      //进行服务的添加
      do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
                txn->sender_pid, (const char*) txn_secctx->secctx)
      ...
}

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

  //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
  //    allow_isolated ? "allow_isolated" : "!allow_isolated", uid);
  //服务的名称长度不能超过127字节
  if (!handle || (len == 0) || (len > 127))
    return -1;
	//最终调用selinux_check_access方法,会进行权限的检测,检查服务是否有进行服务注册
  if (!svc_can_register(s, len, spid, sid, uid)) {
    ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
       str8(s, len), handle, uid);
    return -1;
  }
	//查询是否已经有包含了name的svcinfo
  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);
    }
		//更新服务的handle
    si->handle = handle;
  } else {
		//申请内存
    si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
    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->dumpsys_priority = dumpsys_priority;
		//将其注册到服务列表svclist中,这里使用的链表来保存数据
    si->next = svclist;
    svclist = si;
  }
	//以handle为目标,发送BC_ACQUIRE指令。
  binder_acquire(bs, handle);
	//以handle为目标,发送BC_REQUEST_DEATH_NOTIFICATION指令。
  binder_link_to_death(bs, handle, &si->death);
  return 0;
}

当拿到请求信息之后,ServiceManager会生成对应的svcinfo对象,将其保存到服务列表svclist中。

整体流程如下:

我们也可以从另一个维度去看看Binder的具体

系统服务获取

对于Servie服务的获取,其实也是答题思路也是相同的。显示获取ServiceManager的Binder对象,然后服务端发送获取某项服务的请求,ServiceManager来进行处理。

这里我们只看一下ServiceManager接收到服务获取的处理机制。也是在**svcmgr_handler()**中。

//frameworks\native\cmds\servicemanager\service_manager.c
int svcmgr_handler(struct binder_state *bs,
          struct binder_transaction_data_secctx *txn_secctx,
          struct binder_io *msg,
          struct binder_io *reply)
{
  ...
  struct binder_transaction_data *txn = &txn_secctx->transaction_data;
  ...
	//根据传输的不同类型来进行处理。
  switch(txn->code) {
    case SVC_MGR_GET_SERVICE://获取服务
    case SVC_MGR_CHECK_SERVICE:
      s = bio_get_string16(msg, &len);
      if (s == NULL) {
        return -1;
      }
      //根据pid,uid来获取服务对应的handle值
      handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid,
                   (const char*) txn_secctx->secctx);
      if (!handle)
        break;
      //返回服务对应的handle
      bio_put_ref(reply, handle);
      return 0;
}

这里主要做了2个操作:

  1. 从服务列表中获取到对应的服务的handle
  2. 将handle写入到要返回的reply数据中。

do_find_service

//frameworks\native\cmds\servicemanager\service_manager.c
//获取对应的服务
uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid)
{
	//获取对应的服务
  struct svcinfo *si = find_svc(s, len);

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

  if (!si->allow_isolated) {
    // If this service doesn't allow access from isolated processes,
    // then check the uid to see if it is isolated.
    uid_t appid = uid % AID_USER;
		//检查服务是否是允许孤立于进程而单独存在的
    if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
      return 0;
    }
  }
	//检测是否有selinx权限。
  if (!svc_can_find(s, len, spid, sid, uid)) {
    return 0;
  }
	//返回服务的handle
  return si->handle;
}

bio_put_ref

当获取到服务之后handle之后,会调用**bio_put_ref()**方法将服务对应的handle写入到返回的数据中。

//frameworks\native\cmds\servicemanager\service_manager.c
void bio_put_ref(struct binder_io *bio, uint32_t handle)
{
  struct flat_binder_object *obj;
	//申请对应的地址空间
  if (handle)
    obj = bio_alloc_obj(bio);
  else
    obj = bio_alloc(bio, sizeof(*obj));

  if (!obj)
    return;

  obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
	//类型是BINDER_TYPE_HANDLE
  obj->hdr.type = BINDER_TYPE_HANDLE;
	//记录handle
  obj->handle = handle;
  obj->cookie = 0;
}

对于服务的获取,肯定是需要将reply的数据写回到请求服务的进程的。这时候就需要回到我们在binder_loop()函数了。在该函数中,存在一个binder_parse(),在这个方法里面会处理请求信息,并将reply信息通过binder驱动发送给客户端。

binder_parse

//frameworks\native\cmds\servicemanager\binder.c
int binder_parse(struct binder_state *bs, struct binder_io *bio,
         uintptr_t ptr, size_t size, binder_handler func)
{
  ...
    case BR_TRANSACTION: {
      ...
				//调用func函数
        res = func(bs, txn, &msg, &reply);
        if (txn->flags & TF_ONE_WAY) {
          binder_free_buffer(bs, txn->data.ptr.buffer);
        } else {
        	//发送协议指令给Binder驱动,向Client端发送reply
          binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
        }
      ...
  return r;
}

当调用了func函数,有对应返回信息之后,会通过binder_send_reply()方法,将reply数据信息发送给client端。

void binder_send_reply(struct binder_state *bs,
            struct binder_io *reply,
            binder_uintptr_t buffer_to_free,
            int status)
{
  struct {
    uint32_t cmd_free;
    binder_uintptr_t buffer;
    uint32_t cmd_reply;
    struct binder_transaction_data txn;
  } __attribute__((packed)) data;

  data.cmd_free = BC_FREE_BUFFER;
  data.buffer = buffer_to_free;
	//返回指令
  data.cmd_reply = BC_REPLY;
  data.txn.target.ptr = 0;
  data.txn.cookie = 0;
  data.txn.code = 0;
  if (status) {
    data.txn.flags = TF_STATUS_CODE;
    data.txn.data_size = sizeof(int);
    data.txn.offsets_size = 0;
    data.txn.data.ptr.buffer = (uintptr_t)&status;
    data.txn.data.ptr.offsets = 0;
  } else {//svcmgr_handler执行成功,将reply数据组装到txn中
    data.txn.flags = 0;
    data.txn.data_size = reply->data - reply->data0;
    data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
    data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
    data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
  }
	//发送数据
  binder_write(bs, &data, sizeof(data));
}

总结

ServiceManager是一个守护进程,负责管理系统中的所有服务信息。通过一个链表来保存了所有注册过的信息。而且其本身也是一个服务,在通过Binder驱动将其注册为守护进程之后,会将自己也注册为一个服务,供其他服务调用。

以上就是Android ServiceManager的启动和工作原理的详细内容,更多关于Android ServiceManager的资料请关注我们其它相关文章!

时间: 2021-03-28

Android实现在ServiceManager中加入自定义服务的方法详解

本文实例讲述了Android实现在ServiceManager中加入自定义服务的方法.分享给大家供大家参考,具体如下: 当我们要使用android的系统服务时,一般都是使用Context.getSystemService方法.例如我们要获取AudioManager,我们可以: AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 获取的服务,其实是在ServiceManager中注册的Binder服务,

AngularJS基于factory创建自定义服务的方法详解

本文实例讲述了AngularJS基于factory创建自定义服务的方法.分享给大家供大家参考,具体如下: 为什么要创建自定义服务? 很简单,不想让控制器显得过于"臃肿",而且服务可复用.针对性强,每个服务对应不同的功能. 这里介绍如何使用factory创建自定义服务,并且使用他. 例子1: <!--HTML--> <div ng-controller="showTheName"> <h1 ng-bind="name"

Spring Data MongoDB中实现自定义级联的方法详解

前言 Spring Data MongoDB 项目提供与MongoDB文档数据库的集成,Spring与Hibernate集成时,Spring提供了org.springframework.orm.hibernate3.HibernateTemplate实现了对数据的CRUD操作, Spring Data MongoDB提供了org.springframework.data.mongodb.core.MongoTemplate对MongoDB的CRUD的操作,包括对集成的对象映射文件和POJO之间的

Android中用Bmob实现短信验证码功能的方法详解

这篇文章主要介绍发送验证码和校验验证码的功能,用到一个第三方平台Bmob,那Bmob是什么呢?Bmob可以开发一个云存储的移动应用软件,他提供了大量的标准的API接口,根据需要接入相关服务,开发者可以更加专注于应用的开发,让产品交付更快速,验证码功能就是其中一个. 一.跟其他第三方一样,我们开发之前要做一些准备工作. 1.首先,去官网注册一个帐号:http://www.bmob.cn/: 2.然后就可以创建应用了:具体怎么做Bmob说得很清楚了(官方操作介绍),如果你不想看,我简单说一下:点击右

Jsp自定义标签和方法详解

Jsp自定义标签和方法详解 首先是要有一个标签处理类,标签处理类可以直接实现Tag接口,也可以继承Java中已经实现了的TagSupport这个类,TagSupport也是继承自Tag接口的,它内部已经对Tag接口进行了实现,一般是继承TagSupport类,之后是重写父类的doStartTag和doEndTag方法, 对于开始标签来说返回值主要有EVAL_BODY_INCLUDE和SKIP_BODY,前者表示执行标签体,后者表示略过标签体: 对于结束标签的返回值主要有两种EVAL_PAGE和S

Struts中使用validate()输入校验方法详解

1.在ActionSupport中有一个validate()方法,这个方法是验证方法,它会在execute()方法执行之前执行,所以能够起到很好的验证的作用. @Override //重写Action中的validate()方法 public void validate() { if(null==this.username||this.username.length()<4||this.username.length()>6){ this.addActionError("userna

JavaScript 中有关数组对象的方法(详解)

JS 处理数组多种方法 js 中的数据类型分为两大类:原始类型和对象类型. 原始类型包括:数值.字符串.布尔值.null.undefined 对象类型包括:对象即是属性的集合,当然这里又两个特殊的对象----函数(js中的一等对象).数组(键值的有序集合). 数组元素的添加 arrayObj.push([item1 [item2 [. . . [itemN ]]]]); 将一个或多个新元素添加到数组结尾,并返回数组新长度 arrayObj.unshift([item1 [item2 [. . .

Mongodb中MapReduce实现数据聚合方法详解

Mongodb是针对大数据量环境下诞生的用于保存大数据量的非关系型数据库,针对大量的数据,如何进行统计操作至关重要,那么如何从Mongodb中统计一些数据呢? 在Mongodb中,给我们提供了三种用于数据聚合的方式: (1)简单的用户聚合函数: (2)使用aggregate进行统计: (3)使用mapReduce进行统计: 今天我们首先来讲讲mapReduce是如何统计,在后续的文章中,将另起文章进行相关说明. MapReduce是啥呢?以我的理解,其实就是对集合中的各个满足条件的文档进行预处理

Javascript中的迭代、归并方法详解

迭代方法 在Javascript中迭代方法个人觉得尤为重要,在很多时候都会有实际上的需求,javascript提供了5个迭代方法来供我们操作,它们分别为: every() 对数组中的每一个项运用给定的函数,如果每项都返回true,那么就会返回true filter() 对数组中的每一个项运用给定的函数,把返回true的项组成一个新数组并返回 forEach() 对数组中的每一项运用给定的函数,但是没有任何的返回值 map() 对数组中的每一个项运用给定的函数并返回每次函数调用的结果组成新的数组

js基础之DOM中元素对象的属性方法详解

在 HTML DOM (文档对象模型)中,每个部分都是节点. 节点是DOM结构中最基本的组成单元,每一个HTML标签都是DOM结构的节点. 文档是一个    文档节点 . 所有的HTML元素都是    元素节点 所有 HTML 属性都是    属性节点 文本插入到 HTML 元素是    文本节点 注释是    注释节点. 最基本的节点类型是Node类型,其他所有类型都继承自Node,DOM操作往往是js中开销最大的部分,因而NodeList导致的问题最多.要注意:NodeList是'动态的',