installd进程
pms分析前置守护进程启动,基于android Q源码解析
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<std::string> 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/<user_id>
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验证如下:
InstalldNativeService初始化
最后我们来分析service的注册,InstalldNativeService#start定义如下
platform/frameworks/native/cmds/installd/InstalldNativeService.cpp
status_t InstalldNativeService::start() {
IPCThreadState::self()->disableBackgroundScheduling(true);
status_t ret = BinderService<InstalldNativeService>::publish();
if (ret != android::OK) {
return ret;
}
sp<ProcessState> 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<IServiceManager> sm(defaultServiceManager());
return sm->addService(String16(InstalldNativeService::getServiceName())
, new InstalldNativeService(), allowIsolated,dumpFlags);
}
这里实际上就是通过servce_manager去注册一个binder服务,详情可以参考我的另一篇binder解析