Skip to content

Service对象

解释 init Service 对象如何保存配置、运行状态、资源描述和恢复动作,以及这些字段在解析、启动、停止和回收阶段由谁消费。

基于android-17.0.0_r1
AndroidinitServiceServiceListlifecycle

Service对象 ​

本文面向已经读过 Service解析 和 Zygote服务 的读者。前文追踪了 service 段如何提交到 ServiceList;本文把问题收窄到提交之后仍然存在的对象:一个 Service 到底拥有哪些状态,配置字段何时生效,ServiceList 如何持有它,init.svc.* 由谁发布,以及 temporary exec 服务为什么不应和普通 rc 服务混为一谈。

本文不展开 Service::Start() 的完整 fork/exec 调用链,那是下一篇的主题;这里只引用启动前后必须理解的状态转换和资源交接。读完后,读者应能从一个 Service 的 name、args、flags、进程属性、socket/file 描述和 onrestart Action,定位其所有者、消费者、生效时机、停止清理路径,并用源码测试区分“字段初始化正确”和“设备进程真的启动成功”。

1. 对象边界 ​

1.1 配置所有者 ​

ServiceParser 在 section 开始时创建临时对象,option parser 直接写入其私有字段,EndSection() 成功后才把 unique_ptr<Service> 移交给 ServiceList。因此 Service 是“解析结果 + 运行时状态”的合体,不是 rc 文本的只读镜像。

相关源码:

  • system/core/init/service_parser.cpp
  • ParseSection
  • EndSection
cpp
Result<void> ServiceParser::ParseSection(std::vector<std::string>&& args,
                                         const std::string& filename, int line) {
    if (args.size() < 3) {
        return Error() << "services must have a name and a program";
    }

    const std::string& name = args[1];
    if (!IsValidName(name)) {
        return Error() << "invalid service name '" << name << "'";
    }

    filename_ = filename;
    Subcontext* restart_action_subcontext = nullptr;
    if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
        restart_action_subcontext = subcontext_;
    }

    std::vector<std::string> str_args(args.begin() + 2, args.end());
    service_ = std::make_unique<Service>(name, restart_action_subcontext, filename, str_args);
    return {};
}

这里的 str_args[0] 是待执行程序,后续元素是 argv;filename 同时成为诊断位置和 subcontext 路径判断输入。创建成功仍只表示“有一个临时 Service”,还没有进入全局列表。

1.2 提交边界 ​

源码文件:system/core/init/service_parser.cpp

相关函数/类型:EndSection

cpp
Result<void> ServiceParser::EndSection() {
    if (!service_) return {};

    if (service_->proc_attr_.parsed_uid == std::nullopt) {
        if (kAlwaysErrorUserRoot ||
            android::base::GetIntProperty("ro.vendor.api_level", 0) > 202404) {
            return Error() << "No user specified for service '" << service_->name()
                           << "', so it would have been root.";
        }
        // ... older vendor levels log a warning and retain the root default ...
    }

    if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) {
        if ((service_->flags() & SVC_CRITICAL) != 0 &&
            (service_->flags() & SVC_ONESHOT) != 0) {
            return Error() << "service '" << service_->name()
                           << "' can't be both critical and oneshot";
        }
    }

    Service* old_service = service_list_->FindService(service_->name());
    if (old_service) {
        if (!service_->is_override()) {
            return Error() << "ignored duplicate definition of service '"
                           << service_->name() << "'";
        }
        // ... reject non-updatable APEX replacement and cross-Treble override ...
        service_list_->RemoveService(*old_service);
    }

    service_list_->AddService(std::move(service_));
    return {};
}

完整 Android 17 代码还包含 APEX updatable 和 Treble subcontext 边界检查。这里保留的关键关系是:缺少 user、critical 与 oneshot 冲突、重复定义等错误都发生在移交前;ServiceList::AddService() 本身不负责查重,查重和替换策略属于 parser 的提交阶段。

2. 初始状态 ​

2.1 构造默认值 ​

源码文件:system/core/init/service.cpp

相关函数/类型:Service::Service

cpp
Service::Service(const std::string& name, unsigned flags, std::optional<uid_t> uid, gid_t gid,
                 const std::vector<gid_t>& supp_gids, int namespace_flags,
                 const std::string& seclabel, Subcontext* subcontext_for_restart_commands,
                 const std::string& filename, const std::vector<std::string>& args)
    : name_(name),
      classnames_({"default"}),
      flags_(flags),
      pid_(0),
      crash_count_(0),
      proc_attr_{.ioprio_class = IoSchedClass_NONE,
                 .ioprio_pri = 0,
                 .parsed_uid = uid,
                 .gid = gid,
                 .supp_gids = supp_gids,
                 .priority = 0},
      namespaces_{.flags = namespace_flags},
      seclabel_(seclabel),
      subcontext_(subcontext_for_restart_commands),
      onrestart_(false, subcontext_for_restart_commands,
                 "<Service '" + name + "' onrestart>", 0, "onrestart", {}),
      oom_score_adjust_(DEFAULT_OOM_SCORE_ADJUST),
      start_order_(0),
      args_(args),
      filename_(filename) {}

默认 class 是 default,不是“未设置”;flags 和 pid 都从零开始,restart_period_ 在类成员初始化中已有默认值。parsed_uid 用 optional 区分“没有写 user”和“明确写了 root”,这正是 EndSection() 能实施 Android 17 user 检查的原因。

2.2 字段分组 ​

相关源码:

  • system/core/init/service.h
  • Service
cpp
const std::string name_;
std::set<std::string> classnames_;
unsigned flags_;
pid_t pid_;
boot_clock::time_point time_started_;
int crash_count_;
bool was_last_exit_ok_ = true;

std::optional<CapSet> capabilities_;
ProcessAttributes proc_attr_;
NamespaceInfo namespaces_;
std::string seclabel_;

std::vector<SocketDescriptor> sockets_;
std::vector<FileDescriptor> files_;
std::vector<std::pair<std::string, std::string>> environment_vars_;
std::vector<std::pair<std::string, std::string>> once_environment_vars_;

const Subcontext* const subcontext_;
Action onrestart_;
std::vector<std::string> writepid_files_;
std::vector<std::string> task_profiles_;
std::set<std::string> interfaces_;
std::vector<int> keycodes_;

这些字段不是同一类状态:name_、args_ 和 filename_ 描述定义;flags_、pid_、crash_count_ 和 start_order_ 描述运行过程;socket、file、environment 和 task profile 是启动时要交给子进程或 cgroup 配置器的资源描述;onrestart_ 是重启时由 Service 自己消费的 Action。

图中的实心组合表示这些值随 Service 对象生存;ServiceList 的空心聚合强调真正的对象所有权在 unique_ptr 容器。Parser 只在提交前拥有临时对象,提交后对同名对象的查询、延迟启动和清理都经 ServiceList 完成。

3. 标志状态 ​

3.1 flags定义 ​

源码文件:system/core/init/service.h

相关函数/类型:SVC_*

cpp
#define SVC_DISABLED 0x001
#define SVC_ONESHOT 0x002
#define SVC_RUNNING 0x004
#define SVC_RESTARTING 0x008
#define SVC_CONSOLE 0x010
#define SVC_CRITICAL 0x020
#define SVC_RESET 0x040
#define SVC_RC_DISABLED 0x080
#define SVC_RESTART 0x100
#define SVC_DISABLED_START 0x200
#define SVC_EXEC 0x400
#define SVC_SHUTDOWN_CRITICAL 0x800
#define SVC_TEMPORARY 0x1000
#define SVC_GENTLE_KILL 0x2000

SVC_DISABLED 是当前是否禁止 class 自动启动,SVC_RC_DISABLED 保存 rc 是否曾写过 disabled,两者不能合并理解;SVC_EXEC 表示 init 正在等待一个 exec/exec_start 服务,SVC_TEMPORARY 表示该对象来自临时 exec 且不应进入普通 init.svc.* 状态发布路径。

3.2 启停标志 ​

相关源码:

  • system/core/init/service.cpp
  • ResetFlagsForStart
  • StartIfNotDisabled
  • Enable
cpp
void Service::ResetFlagsForStart() {
    flags_ &= ~(SVC_DISABLED | SVC_RESTARTING | SVC_RESET |
                SVC_RESTART | SVC_DISABLED_START);
}

Result<void> Service::StartIfNotDisabled() {
    if (!(flags_ & SVC_DISABLED)) {
        return Start();
    }
    flags_ |= SVC_DISABLED_START;
    return {};
}

Result<void> Service::Enable() {
    flags_ &= ~(SVC_DISABLED | SVC_RC_DISABLED);
    if (flags_ & SVC_DISABLED_START) {
        return Start();
    }
    return {};
}

start 请求遇到 disabled 并不一定返回错误;它记录 SVC_DISABLED_START,之后 enable 才可能补发 Start。这是“请求被拒绝执行”和“请求被保存等待启用”的区别,也是现场只看 init.svc.name=stopped 容易误判的原因。

4. 资源描述 ​

4.1 进程属性 ​

源码文件:system/core/init/service_utils.h

相关函数/类型:ProcessAttributes

cpp
struct ProcessAttributes {
    std::string console;
    IoSchedClass ioprio_class;
    int ioprio_pri;
    std::vector<std::pair<int, rlimit>> rlimits;
    std::optional<uid_t> parsed_uid;
    gid_t gid;
    std::vector<gid_t> supp_gids;
    int priority;
    bool stdio_to_kmsg;

    uid_t uid() const { return parsed_uid.value_or(0); }
};

parsed_uid 是配置输入,uid() 是启动时的默认化视图:没有 user 时仍能得到 root uid,但 parser 在 Android 17 新设备上会在提交阶段拒绝这种隐式 root。不要用运行时 uid() 反推 rc 是否明确写了 user。

4.2 socket与file ​

相关源码:

  • system/core/init/service_utils.h
  • SocketDescriptor
  • FileDescriptor
cpp
struct SocketDescriptor {
    std::string name;
    int type = 0;
    uid_t uid = 0;
    gid_t gid = 0;
    int perm = 0;
    std::string context;
    bool passcred = false;
    bool listen = false;
    bool persist = false;

    Result<Descriptor> Create(const std::string& global_context) const;
};

struct FileDescriptor {
    std::string name;
    std::string type;

    Result<Descriptor> Create() const;
};

Service 只保存描述,不在 parser 阶段创建 /dev/socket 或打开 file。启动阶段才由 Create() 生成 Descriptor,随后通过环境变量发布给 exec 子进程;因此 rc 中有 socket 行不等于设备上 socket 已经存在。

4.3 环境生命周期 ​

environment_vars_ 每次运行都会应用,once_environment_vars_ 只服务下一次运行,后者会在启动准备阶段清空。两者都属于 Service 对象而不是全局 property;修改 property 不会自动重写已保存的环境变量。

5. 运行消费者 ​

5.1 状态属性 ​

源码文件:system/core/init/service.cpp

相关函数/类型:NotifyStateChange

cpp
void Service::NotifyStateChange(const std::string& new_state) const {
    if ((flags_ & SVC_TEMPORARY) != 0) {
        // Services created by 'exec' are temporary and don't have properties tracking their state.
        return;
    }

    std::string prop_name = "init.svc." + name_;
    SetProperty(prop_name, new_state);

    if (new_state == "running") {
        uint64_t start_ns = time_started_.time_since_epoch().count();
        std::string boottime_property = "ro.boottime." + name_;
        if (GetProperty(boottime_property, "").empty()) {
            SetProperty(boottime_property, std::to_string(start_ns));
        }
    }
}

init.svc.<name> 的消费者可以观察 running/stopped/restarting,但它只反映 init 的 Service 状态通知,不等于业务协议 ready。temporary exec 服务跳过这组属性,所以不能用 init.svc.exec 1 之类的假设追踪它。

5.2 服务集合 ​

相关源码:

  • system/core/init/service_list.cpp
  • AddService
  • DelayService
  • StartDelayedServices
cpp
void ServiceList::AddService(std::unique_ptr<Service> service) {
    services_.emplace_back(std::move(service));
}

void ServiceList::DelayService(const Service& service) {
    if (IsDefaultMountNamespaceReady()) {
        LOG(ERROR) << "Cannot delay the start of service '" << service.name()
                   << "' because all services are already updated. Ignoring.";
        return;
    }
    delayed_service_names_.emplace_back(service.name());
}

void ServiceList::StartDelayedServices() {
    for (const auto& name : delayed_service_names_) {
        Service* service = FindService(name);
        if (service == nullptr) continue;
        if (auto result = service->Start(); !result.ok()) {
            LOG(ERROR) << result.error().message();
        }
    }
    delayed_service_names_.clear();
}

ServiceList 是所有普通 Service 的 owner;延迟启动只保存服务名,真正 mount namespace ready 后再查回对象并调用 Start。列表持有对象不代表对象正在运行,延迟列表消费失败也不会自动删除 Service。

6. 恢复路径 ​

6.1 重启动作 ​

相关源码:

  • system/core/init/service.cpp
  • Restart
  • StopOrReset
cpp
void Service::Restart() {
    if (flags_ & SVC_RUNNING) {
        StopOrReset(SVC_RESTART);
    } else if (!(flags_ & SVC_RESTARTING)) {
        if (auto result = Start(); !result.ok()) {
            LOG(ERROR) << "Could not restart '" << name_ << "': " << result.error();
        }
    }
}

void Service::StopOrReset(int how) {
    flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START);
    if (how == SVC_RESET) {
        flags_ |= (flags_ & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET;
    } else {
        flags_ |= how;
    }
    if (how == SVC_RESTART) {
        flags_ &= ~(SVC_DISABLED | SVC_RESET);
    } else {
        flags_ &= ~SVC_RESTART;
    }
    if (pid_) {
        KillProcessGroup(SIGKILL);
        NotifyStateChange("stopping");
    } else {
        NotifyStateChange("stopped");
    }
}

restart 的所有权仍在 Service:它先设置状态 flags,杀掉进程组,等待回收路径把旧 pid 清理,再由后续逻辑重新 Start。onrestart_ 的命令执行发生在更完整的 Reap()/restart 路径中,不能把 Restart() 简化为“立刻 fork 第二个进程”。

6.2 临时服务 ​

源码文件:system/core/init/service.cpp

相关函数/类型:MakeTemporaryOneshotService

cpp
// ... locate "--", validate command position, and build name/str_args ...
unsigned flags = SVC_ONESHOT | SVC_TEMPORARY;
std::string seclabel = "";
if (command_arg > 2 && args[1] != "-") {
    seclabel = args[1];
}

Result<uid_t> uid = 0;
if (command_arg > 3) {
    uid = DecodeUid(args[2]);
    if (!uid.ok()) {
        return Error() << "Unable to decode UID for '" << args[2] << "': " << uid.error();
    }
}

Result<gid_t> gid = 0;
std::vector<gid_t> supp_gids;
// ... decode the optional primary and supplementary groups ...

return std::make_unique<Service>(name, flags, *uid, *gid, supp_gids, 0, seclabel,
                                 nullptr, "", str_args);

exec 创建的 Service 使用 SVC_ONESHOT | SVC_TEMPORARY,没有普通 rc 文件来源,也没有 subcontext restart Action;它完成回收后从 ServiceList 消失。测试覆盖了空参数、-- 分隔、seclabel、uid/gid 和 supplementary gids 的组合,但不证明设备上的命令权限或执行成功。

7. Service测试 ​

7.1 初始化断言 ​

源码文件:system/core/init/service_test.cpp

相关函数/类型:pod_initialized

cpp
TEST(service, pod_initialized) {
    std::vector<std::string> dummy_args{"/bin/test"};
    Service* service_in_old_memory =
            new (old_memory) Service("test_old_memory", nullptr, "", dummy_args);

    EXPECT_EQ(0U, service_in_old_memory->flags());
    EXPECT_EQ(0, service_in_old_memory->pid());
    EXPECT_EQ(0, service_in_old_memory->crash_count());
    EXPECT_EQ(0U, service_in_old_memory->uid());
    EXPECT_EQ(0, service_in_old_memory->namespace_flags());
    EXPECT_EQ(IoSchedClass_NONE, service_in_old_memory->ioprio_class());
    EXPECT_EQ(DEFAULT_OOM_SCORE_ADJUST, service_in_old_memory->oom_score_adjust());
}

测试先用 0xFF 填充旧内存,再 placement-new 构造 Service,证明构造函数显式初始化了关键状态;它不证明 Parser option、SELinux context、fork/exec 或状态属性写入。

7.2 临时参数 ​

make_temporary_oneshot_service_* 系列测试对 exec [SECLABEL [UID [GID]*] --] COMMAND ARGS... 逐种组合断言 Service 字段和 argv,另有 supplementary gid 上限测试。测试证明参数解析结果,不证明 Service::Start() 能够在真实设备上通过 SELinux、文件路径和 cgroup 配置。

7.3 Parser边界 ​

init_test.cpp 的 IgnoreDuplicateService 和 OverrideService 证明 ServiceParser 在提交阶段处理重复定义;RejectsNoUserStartingInV 与 RejectsCriticalAndOneshotService 证明版本条件下的提交拒绝。它们都没有证明 Service 已经运行,更没有证明业务 ready。

8. 对象验证 ​

以“服务已经写进 rc,但没有启动”为实验问题:

  1. 从 parser 日志确认首行和 option 是否进入 service_,再确认 EndSection() 没有报 user、duplicate、critical/oneshot 或 Treble 错误;
  2. 用 init 的 parser/processing 日志确认定义已提交且后续命令能按服务名找到对象;公开 Android 接口没有一个可移植命令能直接枚举完整 ServiceList,不要把 rc 文件存在等同于已经注册;
  3. 对照 disabled、SVC_DISABLED_START 和 class_start 的调用者,判断请求是未启动、延迟启动还是被保存等待 enable;
  4. 查看 init.svc.<name> 与 init.svc_debug_pid.<name>,把 init 状态和进程业务状态分开;
  5. 若服务被停止或重启,沿 flags、进程组、onrestart 和回收日志确认清理顺序;
  6. 若是 exec,不要期待普通 init.svc.* 属性,也不要把 temporary Service 当作可长期 start 的列表成员。

本文证明了 Android 17 Service 对象的构造默认值、解析提交边界、flags 语义、资源描述 owner、ServiceList 延迟消费、状态属性发布、重启/停止清理和 temporary exec 差异;没有证明具体设备上的 fork/exec 成功、SELinux allow、cgroup 生效、socket 服务协议、HAL 注册或业务 readiness。