installd守护进程分析

installd进程

pms分析前置守护进程启动,基于android Q源码解析

  • installd进程
    • bp配置文件
    • rc文件解析
    • installd启动
      • 全局初始化
      • 用户初始化
      • InstalldNativeService初始化

bp配置文件

platform/frameworks/native/cmds/installd/Android.bp

...
cc_binary {
    ...
    srcs: ["installd.cpp"],
    ...
    init_rc: ["installd.rc"],
    ...
}
...

Android.bp文件中指定这个模块装载时候解析的init.rc文件为installd.rc,对外部提供的加载文件为installd.cpp

rc文件解析

platform/frameworks/native/cmds/installd/installd.rc

service installd /system/bin/installd
    class main
....

启动时,以service形式启动

installd启动

platform/frameworks/native/cmds/installd/installd.cpp

int main(const int argc, char *argv[]) {
    return android::installd::installd_main(argc, argv);
}

可以看到调用的是installd这个命名空间的isstalld_main做初始化

static int installd_main(const int argc ATTRIBUTE_UNUSED, char *argv[]) {
    int ret;
    ...

    //初始化 /data 、/system目录
    if (!initialize_globals()) {
        ...
    }

    //初始化 /data/misc/user
    if (initialize_directories() < 0) {
        ...
    }
    //selinux校验
    if (selinux_enabled && selinux_status_open(true) < 0) {
        ...
    }
    ...

    //注册binder服务 InstalldNativeService
    if ((ret = InstalldNativeService::start()) != android::OK) {
        ...
    }

    IPCThreadState::self()->joinThreadPool();
    ...
    return 0;
}

这里首先调initialize_globals用初始化解析/data、/system下各种必要目录,然后通过initialize_directories去初始化/data/misc/user下用户组信息,这里会根据不同用户设置不同的id,默认只有一个用户则是0,之后会经过一个selinux的校验,最后会向binder注册一个InstalldNativeService类型的服务

全局初始化

platform/frameworks/native/cmds/installd/installd.cpp

static bool initialize_globals() {
    return init_globals_from_data_and_root();
}

init_globals_from_data_and_root定义在platform/frameworks/native/cmds/installd/globals.cpp下

bool init_globals_from_data_and_root() {
    //env查看,ANDROID_DATA->/data
    const char* data_path = getenv("ANDROID_DATA");
    ...
    //ANDROID_ROOT->/system
    const char* root_path = getenv("ANDROID_ROOT");
    ...
    return init_globals_from_data_and_root(data_path, root_path);
}

这里去拿环境变量ANDROID_DATA、ANDROID_ROOT目录,可以在adb shell环境下

env |grep ANDROID_

ANDROID_DATA=/data
ANDROID_ROOT=/system

对应的其实就是/data、/system,这里其实就是找到/data、/system然后通过调用init_globals_from_data_and_root去初始化各级目录,并复制给各个全局变量

namespace android{
namespace installd{
...
std::string android_app_dir;
std::string android_app_ephemeral_dir;
std::string android_app_lib_dir;
std::string android_app_private_dir;
std::string android_asec_dir;
std::string android_data_dir;
std::string android_media_dir;
std::string android_mnt_expand_dir;
std::string android_profiles_dir;
std::string android_root_dir;
std::string android_staging_dir;
std::vector android_system_dirs;
...
bool init_globals_from_data_and_root(const char* data, const char* root) {
    // android_data_dir->/data/
    android_data_dir = ensure_trailing_slash(data);

    // android_root_dir->/system/
    android_root_dir = ensure_trailing_slash(root);

    // android_app_dir-> /data/app
    android_app_dir = android_data_dir + APP_SUBDIR;

    // android_app_private_dir-> /data/app-private
    android_app_private_dir = android_data_dir + PRIVATE_APP_SUBDIR;

    // android_app_ephemeral_dir-> /data/app-private/
    android_app_ephemeral_dir = android_data_dir + EPHEMERAL_APP_SUBDIR;

    // android_app_lib_dir->/data/app-lib/
    android_app_lib_dir = android_data_dir + APP_LIB_SUBDIR;

    // ASEC_MOUNTPOINT=/mnt/asec
    android_asec_dir = ensure_trailing_slash(getenv(ASEC_MOUNTPOINT_ENV_NAME));

    // android_media_dir->/data/media/
    android_media_dir = android_data_dir + MEDIA_SUBDIR;

    // Get the android external app directory.
    android_mnt_expand_dir = "/mnt/expand/";

    // android_profiles_dir->/data/misc/profiles
    android_profiles_dir = android_data_dir + PROFILES_SUBDIR;

    // android_staging_dir->/data/app-staging/
    android_staging_dir = android_data_dir + STAGING_SUBDIR;

    // Take note of the system and vendor directories.
    android_system_dirs.clear();
    android_system_dirs.push_back(android_root_dir + APP_SUBDIR);
    android_system_dirs.push_back(android_root_dir + PRIV_APP_SUBDIR);
    android_system_dirs.push_back("/vendor/app/");
    android_system_dirs.push_back("/oem/app/");

    return true;
}
...
}
}

ensure_trailing_slash这个函数只是对/data下添加了一个/
android_system_dirs存储的是一个dir数组

static std::string ensure_trailing_slash(const std::string& path) {
    if (path.rfind('/') != path.size() - 1) {
        return path + '/';
    } else {
        return path;
    }
}

执行完init_globals_from_data_and_root,android::installd::xxx下的变量就已经复制完毕,接下来我们看用户目录初始化

用户初始化

platform/frameworks/native/cmds/installd/installd.cpp

static int initialize_directories() {
    ...
    char version_path[PATH_MAX];
    //version_path => /data/.layout_version
    snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.c_str());
    int oldVersion;
    //读.layout_version存储的值
    if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
        oldVersion = 0;
    }
    int version = oldVersion;
    if (version < 2) {
        ...
        version = 2;
    }
    // /data/misc/user/0
    if (ensure_config_user_dirs(0) == -1) {
        ...
        goto fail;
    }
    ...
    // /data/misc/user/0
    if (ensure_config_user_dirs(0) == -1) {
        ...
        goto fail;
    }
    if (version == 2) {
        ...
        char misc_dir[PATH_MAX];
        //misc_dir => /data/misc
        snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.c_str());

        char keychain_added_dir[PATH_MAX];
        // keychain_added_dir => /data/msic/keychain/cacerts-added
        snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir);

        char keychain_removed_dir[PATH_MAX];
        // keychain_added_dir => /data/msic/keychain/cacerts-removed
        snprintf(keychain_removed_dir, PATH_MAX, "%s/keychain/cacerts-removed", misc_dir);
        ...
        DIR *dir;
        struct dirent *dirent;
        dir = opendir("/data/user");
        if (dir != nullptr) {
            while ((dirent = readdir(dir))) {
                const char *name = dirent->d_name;
                ...
                uint32_t user_id = std::stoi(name);

                // /data/misc/user/
                if (ensure_config_user_dirs(user_id) == -1) {
                    goto fail;
                }
                char misc_added_dir[PATH_MAX];
                // misc_added_dir => /data/msic/user/0/cacerts-added
                snprintf(misc_added_dir, PATH_MAX, 
                    "%s/user/%s/cacerts-added", misc_dir, name);

                char misc_removed_dir[PATH_MAX];
                // misc_removed_dir => /data/msic/user/0/cacerts-removed
                snprintf(misc_removed_dir, PATH_MAX, 
                    "%s/user/%s/cacerts-removed", misc_dir, name);
                //获取uid
                uid_t uid = multiuser_get_uid(user_id, AID_SYSTEM);
                gid_t gid = uid;
                //文件目录copy
                if (access(keychain_added_dir, F_OK) == 0) {
                    if (copy_dir_files(keychain_added_dir, 
                        misc_added_dir, uid, gid) != 0) {
                        ...
                    }
                }
                //文件目录copy
                if (access(keychain_removed_dir, F_OK) == 0) {
                    if (copy_dir_files(keychain_removed_dir, 
                     misc_removed_dir, uid, gid) != 0) {
                        ...
                    }
                }
            }
            //关闭dir
            closedir(dir);
            //删除临时文件
            if (access(keychain_added_dir, F_OK) == 0) {
                delete_dir_contents(keychain_added_dir, 1, nullptr);
            }
            if (access(keychain_removed_dir, F_OK) == 0) {
                delete_dir_contents(keychain_removed_dir, 1, nullptr);
            }
        }
        version = 3;
    }

    if (version != oldVersion) {
        if (fs_write_atomic_int(version_path, version) == -1) {
            ...
            goto fail;
        }
    }
}

-initialize_directories首先将/data/.layout_version复制给version_path,这里其实.layout_version就是简单的存储了个version值,其实是为了防止多次初始化
-之后读该文件的value,如果读取失败返回-1,否则返回0
-之后version==2时候,则会/data/misc/user/0,并将/data/misc/keychain/cacerts-added、/data/misc/keychain/cacerts-removed下的dir拷贝到/data/misc/user/uid/cacerts-added、/data/misc/user/uid/cacerts-removed下
-最后会校验版本,如果不一致则,回想.layout_version文件写入3,那么已经完成installd初始化的.layout_version一定是记录为3
adb shell验证如下:

download.png

InstalldNativeService初始化

最后我们来分析service的注册,InstalldNativeService#start定义如下
platform/frameworks/native/cmds/installd/InstalldNativeService.cpp

status_t InstalldNativeService::start() {
    IPCThreadState::self()->disableBackgroundScheduling(true);
    status_t ret = BinderService::publish();
    if (ret != android::OK) {
        return ret;
    }
    sp ps(ProcessState::self());
    ps->startThreadPool();
    ps->giveThreadPoolName();
    return android::OK;
}

这里很常规的进程初始化+binder服务注册,BinderService::publish()这个是个模板函数,定义在/frameworks/native/libs/binder/include/binder/BinderService.h展开后伪代码如下:

static status_t publish(bool allowIsolated = false,
                            int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
     sp sm(defaultServiceManager());
     return sm->addService(String16(InstalldNativeService::getServiceName())
      , new InstalldNativeService(), allowIsolated,dumpFlags);
}

这里实际上就是通过servce_manager去注册一个binder服务,详情可以参考我的另一篇binder解析

你可能感兴趣的:(installd守护进程分析)