Binder Framework: ServiceManager Initialization Process

ServiceManager Initialization Flow

When the system boots, the init process parses init.rc to launch the servicemanager. The startup sequence invokes the main() functon in main.cpp, which performs four critical operations:

  1. Open the /dev/binder device node
  2. Map the binder device's memory space into the ServiceManager process address space
  3. Register ServiceManager as the context manager
  4. Enter the event loop to process incoming binder transactions
int main(int argc, char** argv) {
    if (argc > 2) {
        LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
    }
    const char* driver = argc == 2 ? argv[1] : "/dev/binder";

    // Step 1: Open /dev/binder and map device memory into SM process
    sp<ProcessState> ps = ProcessState::initWithDriver(driver);
    ps->setThreadPoolMaxThreadCount(0);
    ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);

    // Step 2: Create ServiceManager and register it
    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";
    }

    // Step 3: Set ServiceManager as context manager
    IPCThreadState::self()->setTheContextObject(manager);
    ps->becomeContextManager();

    // Step 4: Enter polling loop to handle transactions
    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
    BinderCallback::setupTo(looper);
    ClientCallbackCallback::setupTo(looper, manager);
    while(true) {
        looper->pollAll(-1);
    }
    return EXIT_FAILURE;
}

Opening the Binder Device

The ProcessState constructor handles device opening and memory mapping:

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    , mDriverFD(open_driver(driver))
    , mCallRestriction(CallRestriction::NONE) {
    if (mDriverFD >= 0) {
        mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
            mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            ALOGE("Using %s failed: unable to mmap transaction memory.\n",
                mDriverName.c_str());
            close(mDriverFD);
            mDriverFD = -1;
        }
    }
}

The open_driver() function opens the binder device node and queries driver capabilities via ioctl():

static int open_driver(const char *driver) {
    int fd = open(driver, O_RDWR | O_CLOEXEC);
    if (fd >= 0) {
        int vers = 0;
        status_t result = ioctl(fd, BINDER_VERSION, &vers);
        if (result != 0) {
            close(fd);
            return -1;
        }

        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
        if (result != 0) {
            ALOGE("Binder driver does not support BINDER_SET_MAX_THREADS\n");
        }

        uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
        result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
    } else {
        ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
    }
    return fd;
}

Memory Mapping from Kernel to User Space

The kernel-side binder_mmap() function handles the memory mapping request:

static int binder_mmap(struct file *filp, struct vm_area_struct *vma) {
    int ret;
    struct binder_proc *proc = filp->private_data;

    if (proc->tsk != current->group_leader)
        return -EINVAL;

    // Enforce 4MB size limit
    if ((vma->vm_end - vma->vm_start) > SZ_4M)
        vma->vm_end = vma->vm_start + SZ_4M;

    // Validate memory flags
    if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {
        ret = -EPERM;
        goto err_bad_arg;
    }

    vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP;
    vma->vm_flags &= ~VM_MAYWRITE;

    vma->vm_ops = &binder_vm_ops;
    vma->vm_private_data = proc;

    ret = binder_alloc_mmap_handler(&proc->alloc, vma);
    if (ret)
        return ret;

    return 0;
}

Registerring as Context Manager

ServiceManager registers itself with the binder driver as the context manager:

sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
if (!manager->addService("manager", manager, false, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
    LOG(ERROR) << "Could not self register servicemanager";
}

The ServiceManager stores registered services in an internal map:

Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder) {
    mNameToService[name] = Service {
        .binder = binder,
        .allowIsolated = allowIsolated,
        .dumpPriority = dumpPriority,
        .debugPid = ctx.debugPid,
    };
    return Status::ok();
}

The becomeContextManager() function uses ioctl() with BINDER_SET_CONTEXT_MGR:

bool ProcessState::becomeContextManager() {
    AutoMutex _l(mLock);

    flat_binder_object obj {
        .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
    };

    int unused = 0;
    result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &unused);

    return result == 0;
}

Event Loop

ServiceManager enters a polling loop to process incoming transactions:

int main(int argc, char** argv) {
    // ... initialization code ...

    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
    BinderCallback::setupTo(looper);
    ClientCallbackCallback::setupTo(looper, manager);

    while(true) {
        looper->pollAll(-1);
    }

    return EXIT_FAILURE;
}

Tags: Android Binder ServiceManager IPC AOSP

Posted on Thu, 07 May 2026 01:51:06 +0000 by Monkee Of Evil