Android系统启动流程(三)——属性服务(基于Android13)

1 属性服务

属性服务的启动在init进程中,init进程初始化的第二阶段初始化中启动了属性服务。
system/core/init/init.cpp

int SecondStageMain(int argc, char** argv) {
   
	...
	PropertyInit();
	...
	StartPropertyService(&property_fd);
	...

2 启动属性服务

system/core/init/property_service.cpp

void PropertyInit() {
   
    selinux_callback cb;
    cb.func_audit = PropertyAuditCallback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);

    mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
    CreateSerializedPropertyInfo();
    if (__system_property_area_init()) {
   
        LOG(FATAL) << "Failed to initialize property area";
    }
    if (!property_info_area.LoadDefaultPath()) {
   
        LOG(FATAL) << "Failed to load serialized property info file";
    }

    // If arguments are passed both on the command line and in DT,
    // properties set in DT always have priority over the command-line ones.
    ProcessKernelDt();
    ProcessKernelCmdline();
    ProcessBootconfig();

    // Propagate the kernel variables to internal variables
    // used by init as well as the current required properties.
    ExportKernelBootProps();

    PropertyLoadBootDefaults();
}

接下来分析一下这个函数

mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);

首先创建属性服务的存储目录,位于/dev/properties,权限为711,即rwx–x–x

2.1 写入序列化属性上下文信息

system/core/init/property_service.cpp

void CreateSerializedPropertyInfo() {
   
    //创建一个vector用于存储selinux中属性相关
    auto property_infos = std::vector<PropertyInfoEntry>();
    if (access("/system/etc/selinux/plat_property_contexts", R_OK) != -1) {
   
        if (!LoadPropertyInfoFromFile("/system/etc/selinux/plat_property_contexts",   //这个函数的具体作用就是从文件中解析属性相关的,写到vector中
                                      &property_infos)) {
   
            return;
        }
        // Don't check for failure here, since we don't always have all of these partitions.
        // E.g. In case of recovery, the vendor partition will not have mounted and we
        // still need the system / platform properties to function.
        if (access("/dev/selinux/apex_property_contexts", R_OK) != -1) {
   
            LoadPropertyInfoFromFile("/dev/selinux/apex_property_contexts", &property_infos);
        }
        if (access("/system_ext/etc/selinux/system_ext_property_contexts", R_OK) != -1) {
   
            LoadPropertyInfoFromFile("/system_ext/etc/selinux/system_ext_property_contexts",
                                     &property_infos);
        }
        if (access("/vendor/etc/selinux/vendor_property_contexts", R_OK) != -1) {
   
            LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_property_contexts",
                                     &property_infos);
        }
        if (access("/product/etc/selinux/product_property_contexts", R_OK) != -1) {
   
            LoadPropertyInfoFromFile("/product/etc/selinux/product_property_contexts",
                                     &property_infos);
        }
        if (access("/odm/etc/selinux/odm_property_contexts", R_OK) != -1) {
   
            LoadPropertyInfoFromFile("/odm/etc/selinux/odm_property_contexts", &property_infos);
        }
    } else {
   
        if (!LoadPropertyInfoFromFile("/plat_property_contexts", &property_infos)) {
   
            return;
        }
        LoadPropertyInfoFromFile("/system_ext_property_contexts", &property_infos);
        LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos);
        LoadPropertyInfoFromFile("/product_property_contexts", &property_infos);
        LoadPropertyInfoFromFile("/odm_property_contexts", &property_infos);
        LoadPropertyInfoFromFile("/dev/selinux/apex_property_contexts", &property_infos);
    }

    auto serialized_contexts = std::string();
    auto error = std::string();
    if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
                   &error)) {
   
        LOG(ERROR) << "Unable to serialize property contexts: " << error;
        return;
    }

    //上面解析的数据都写到了property_info中
    constexpr static const char kPropertyInfosPath[] = "/dev/__properties__/property_info";
    if (!WriteStringToFile(serialized_contexts, kPropertyInfosPath, 0444, 0, 0, false)) {
   
        PLOG(ERROR) << "Unable to write serialized property infos to file";
    }
    selinux_android_restorecon(kPropertyInfosPath, 0);
}

创建一个存储属性服务的vector——property_infos,存储的是PropertyInfoEntry,是一个结构体

struct PropertyInfoEntry {
   
  PropertyInfoEntry() {
   }
  template <typename T, typename U, typename V>
  PropertyInfoEntry(T&& name, U&& context, V&& type, bool exact_match)
      : name(std::forward<T>(name)),
        context(std::forward<U>(context)),
        type(std::forward<V>(type)),
        exact_match(exact_match) {
   }
  std::string name;
  std::string context;
  std::string type;
  bool exact_match;
};

包含一些函数和一些字段。

if (!LoadPropertyInfoFromFile("/system/etc/selinux/plat_property_contexts", &property_infos)) {
   
    return;
}

然后就是调用LoadPropertyInfoFromFile加载各个镜像中能够的属性上下文到property_infos这个结构体中。

bool LoadPropertyInfoFromFile(const std::string& filename,
                              std::vector<PropertyInfoEntry>* property_infos) {
   
    auto file_contents = std::string();
    if (!ReadFileToString(filename, &file_contents)) {
   
        PLOG(ERROR) << "Could not read properties from '" << filename << "'";
        return false;
    }

    auto errors = std::vector<std::string>{
   };
    bool require_prefix_or_exact = SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__;
    ParsePropertyInfoFile(file_contents, require_prefix_or_exact, property_infos, &errors);
    // Individual parsing errors are reported but do not cause a failed boot, which is what
    // returning false would do here.
    for (const auto& error : errors) {
   
        LOG(ERROR) << "Could not read line from '" << filename << "': " << error;
    }

    return true;
}

读取文件中的属性上下文,并生成string字符串file_contents。require_prefix_or_exact用于判断属性是不是分离存放在各个镜像中,如果版本大于R,安卓11,则为true。
system/core/property_service/libpropertyinfoserializer/property_info_file.cpp

void ParsePropertyInfoFile(const std::string& file_contents, bool require_prefix_or_exact,
                           std::vector<PropertyInfoEntry>* property_infos,
                           std::vector<std::string>* errors) {
   
  // Do not clear property_infos to allow this function to be called on multiple files, with
  // their results concatenated.
  errors->clear();

  for (const auto& line : Split(file_contents, "\n")) {
   
    auto trimmed_line = Trim(line);
    if (trimmed_line.empty() || StartsWith(trimmed_line, "#")) {
   
      continue;
    }

    auto property_info_entry = PropertyInfoEntry{
   };
    auto parse_error = std::string{
   };
    if (!ParsePropertyInfoLine(trimmed_line, require_prefix_or_exact, &property_info_entry,
                               &parse_error)) {
   
      errors->emplace_back(parse_error);
      continue;
    }

    property_infos->emplace_back(property_info_entry);
  }
}

然后解析文件中的属性,以行\n为分割,然后在ParsePropertyInfoLine中解析。

bool ParsePropertyInfoLine(const std::string& line, bool require_prefix_or_exact,
                           PropertyInfoEntry* out, std::string* error)<
### 如何在 Android Studio 中正确配置并启动一个新项目 #### 配置环境 为了成功启动一个新的 Android 项目,在开始之前需要确保已安装最新版本的 Android Studio 并完成必要的 SDK 和工具链设置。如果尚未安装所需的组件,可以通过 `Tools` -> `SDK Manager` 来下载和更新所需的内容[^1]。 #### 创建新的原生 Android 项目 当创建一个标准的 Android 应用时,可以按照以下方式操作: 打开 Android Studio 后进入欢迎界面,点击 “Start a New Android Studio Project”,随后会弹出向导窗口来引导用户逐步定义项目的属性,比如应用名称、包名以及保存路径等基本信息。接着选择目标设备类型和支持的语言(Kotlin 或 Java)。最后确认所有选项无误之后按 Finish 完成初始化过程。 对于更复杂的场景如JNI开发,则需额外注意C/C++支持部分的选择,并通过 CMakeLists.txt 文件指定本地库编译规则: ```cmake # Sets the minimum version of CMake required to build your native library. cmake_minimum_required(VERSION 3.4.1) add_library( hello-jni SHARED src/main/cpp/hello-jni.cpp ) find_library(android-lib android REQUIRED ) target_link_libraries(hello-jni ${android-lib}) ``` #### 创建新的 Flutter 项目 如果是打算构建基于 Dart 的跨平台移动应用程序即 Flutter App ,那么应该遵循另一套流程。具体而言,在首次运行后的初始页面上找到“Start a new Flutter project”的按钮或者经由菜单栏中的“File”->“New”->“New Flutter Project”发起新建请求即可[^2]。 一旦上述任意一种类型的工程被建立起来以后,就可以利用内置模拟器测试成果了——只需从顶部工具条里挑选合适的 AVD (Android Virtual Device),再按下绿色角形图标代表执行命令让其加载出来供预览效果之用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值