0

Boot sequence in Android is defined via system/core/rootdir/init.rc and other *.rc files. Such approach allows to bind any action to any boot stage (early-init, init, etc). Also in system/core/init/init.cpp is defined the following sequence of the boot:
- ...;
- early-init;
- wait_for_coldboot_done;
- ...;
- init;
- ....

It means that some action inside imported *.rc file binded to the early-init stage can be started before coldboot (and SELinux initialization) will be finished by the ueventd.

So my question: does a native service work correctly if it will be started before coldboot done (obviously it means that such service does not require any device which should be created by the ueventd)?

Gluttton
  • 5,739
  • 3
  • 31
  • 58

1 Answers1

0

So my question: does a native service work correctly if it will be started before coldboot done?

Sometimes it may work correct but in general case it may fail. If native service doesn't interact with any device it doesn't require the /dev/ file system. But binderized services communicate via Binder IPC which is require opening the binder driver (for interact between kernel and userspace layers):

frameworks/native/include/binder/BinderService.h:

template<typename SERVICE>
class BinderService
{
public:
    ...
    static void instantiate() { publish(); }
    ...
    static status_t publish(bool allowIsolated = false) {
        sp<IServiceManager> sm(defaultServiceManager());
        return sm->addService(
                String16(SERVICE::getServiceName()),
                new SERVICE(), allowIsolated);
    }

frameworks/native/libs/binder/IServiceManager.cpp:

sp<IServiceManager> defaultServiceManager()
{
                ...
                ProcessState::self()->getContextObject(NULL));

frameworks/native/libs/binder/ProcessState.cpp:

sp<ProcessState> ProcessState::self()
{
    ...
    gProcess = new ProcessState("/dev/binder");
    return gProcess;
}

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    , mDriverFD(open_driver(driver))
    ...
    {
        if (mDriverFD >= 0) {
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ...
            ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
}

static int open_driver(const char *driver)
{
    int fd = open(driver, O_RDWR | O_CLOEXEC);
    if (fd >= 0) {
    ...
    } else {
        ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
    }
    return fd;
}

But the Binder driver /der/binder (as well as /dev/hwbinder and /dev/vndbinder) is created at the coldboot stage by the ueventd according to ueventd.rc.

system/core/rootdir/ueventd.rc:

...
/dev/binder               0666   root       root
/dev/hwbinder             0666   root       root
/dev/vndbinder            0666   root       root
...

So if a native service was be started before coldboot done it wouldn't open the /dev/binder!

Also at before coldboot done the cgrops and SELinux (not sure) are not initialized:
system/core/rootdir/init.rc:

on init
    ...
    # Mount cgroup mount point for cpu accounting
    mount cgroup none /acct cpuacct
    mkdir /acct/uid

P.S. But if a service communicates in passthrough mode?

Gluttton
  • 5,739
  • 3
  • 31
  • 58