Merge changes Ifed3b97a,I09aacb94,I9afedd7b
* changes:
adb: fix NonblockingFdConnection's behavior with large writes.
adb: fix zero-initialization in Block.
adb: make benchmarks build on the host.
diff --git a/init/README.md b/init/README.md
index 4b21e32..5c07ac1 100644
--- a/init/README.md
+++ b/init/README.md
@@ -332,6 +332,13 @@
This is particularly useful for creating a periodic service combined with the restart_period
option described above.
+`updatable`
+> Mark that the service can be overridden (via the 'override' option) later in
+ the boot sequence by APEXes. When a service with updatable option is started
+ before APEXes are all activated, the execution is delayed until the activation
+ is finished. A service that is not marked as updatable cannot be overridden by
+ APEXes.
+
`user <username>`
> Change to 'username' before exec'ing this service.
Currently defaults to root. (??? probably should default to nobody)
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 8660d2a..5676f92 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1079,6 +1079,7 @@
}
success &= parser.ParseConfigFile(c);
}
+ ServiceList::GetInstance().MarkServicesUpdate();
if (success) {
return Success();
} else {
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index a8b7862..1e434d2 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -560,7 +560,7 @@
std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
if (!links.empty()) {
auto [it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
- if (!inserted) {
+ if (!inserted && (links[0] != it->second)) {
LOG(ERROR) << "Partition '" << uevent.partition_name
<< "' already existed in the by-name symlink map with a value of '"
<< it->second << "', new value '" << links[0] << "' will be ignored.";
diff --git a/init/service.cpp b/init/service.cpp
index 1bda7ec..5aa3764 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -765,6 +765,11 @@
return Success();
}
+Result<Success> Service::ParseUpdatable(std::vector<std::string>&& args) {
+ updatable_ = true;
+ return Success();
+}
+
class Service::OptionParserMap : public KeywordMap<OptionParser> {
public:
OptionParserMap() {}
@@ -817,6 +822,7 @@
{"socket", {3, 6, &Service::ParseSocket}},
{"timeout_period",
{1, 1, &Service::ParseTimeoutPeriod}},
+ {"updatable", {0, 0, &Service::ParseUpdatable}},
{"user", {1, 1, &Service::ParseUser}},
{"writepid", {1, kMax, &Service::ParseWritepid}},
};
@@ -834,6 +840,13 @@
}
Result<Success> Service::ExecStart() {
+ if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
+ // Don't delay the service for ExecStart() as the semantic is that
+ // the caller might depend on the side effect of the execution.
+ return Error() << "Cannot start an updatable service '" << name_
+ << "' before configs from APEXes are all loaded";
+ }
+
flags_ |= SVC_ONESHOT;
if (auto result = Start(); !result) {
@@ -851,6 +864,13 @@
}
Result<Success> Service::Start() {
+ if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
+ ServiceList::GetInstance().DelayService(*this);
+ return Error() << "Cannot start an updatable service '" << name_
+ << "' before configs from APEXes are all loaded. "
+ << "Queued for execution.";
+ }
+
bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
@@ -1280,6 +1300,32 @@
}
}
+void ServiceList::MarkServicesUpdate() {
+ services_update_finished_ = true;
+
+ // start the delayed services
+ for (const auto& name : delayed_service_names_) {
+ Service* service = FindService(name);
+ if (service == nullptr) {
+ LOG(ERROR) << "delayed service '" << name << "' could not be found.";
+ continue;
+ }
+ if (auto result = service->Start(); !result) {
+ LOG(ERROR) << result.error_string();
+ }
+ }
+ delayed_service_names_.clear();
+}
+
+void ServiceList::DelayService(const Service& service) {
+ if (services_update_finished_) {
+ 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());
+}
+
Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) {
if (args.size() < 3) {
@@ -1291,6 +1337,8 @@
return Error() << "invalid service name '" << name << "'";
}
+ filename_ = filename;
+
Subcontext* restart_action_subcontext = nullptr;
if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
@@ -1326,6 +1374,11 @@
<< "'";
}
+ if (StartsWith(filename_, "/apex/") && !old_service->is_updatable()) {
+ return Error() << "cannot update a non-updatable service '" << service_->name()
+ << "' with a config in APEX";
+ }
+
service_list_->RemoveService(*old_service);
old_service = nullptr;
}
diff --git a/init/service.h b/init/service.h
index 49b09ce..56e75b0 100644
--- a/init/service.h
+++ b/init/service.h
@@ -123,6 +123,7 @@
std::chrono::seconds restart_period() const { return restart_period_; }
std::optional<std::chrono::seconds> timeout_period() const { return timeout_period_; }
const std::vector<std::string>& args() const { return args_; }
+ bool is_updatable() const { return updatable_; }
private:
using OptionParser = Result<Success> (Service::*)(std::vector<std::string>&& args);
@@ -170,6 +171,7 @@
Result<Success> ParseFile(std::vector<std::string>&& args);
Result<Success> ParseUser(std::vector<std::string>&& args);
Result<Success> ParseWritepid(std::vector<std::string>&& args);
+ Result<Success> ParseUpdatable(std::vector<std::string>&& args);
template <typename T>
Result<Success> AddDescriptor(std::vector<std::string>&& args);
@@ -235,6 +237,8 @@
std::chrono::seconds restart_period_ = 5s;
std::optional<std::chrono::seconds> timeout_period_;
+ bool updatable_ = false;
+
std::vector<std::string> args_;
std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
@@ -279,8 +283,15 @@
const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
const std::vector<Service*> services_in_shutdown_order() const;
+ void MarkServicesUpdate();
+ bool IsServicesUpdated() const { return services_update_finished_; }
+ void DelayService(const Service& service);
+
private:
std::vector<std::unique_ptr<Service>> services_;
+
+ bool services_update_finished_ = false;
+ std::vector<std::string> delayed_service_names_;
};
class ServiceParser : public SectionParser {
@@ -291,6 +302,7 @@
int line) override;
Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
Result<Success> EndSection() override;
+ void EndFile() override { filename_ = ""; }
private:
bool IsValidName(const std::string& name) const;
@@ -298,6 +310,7 @@
ServiceList* service_list_;
std::vector<Subcontext>* subcontexts_;
std::unique_ptr<Service> service_;
+ std::string filename_;
};
} // namespace init
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 1715501..208d67f 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -204,6 +204,10 @@
goto skip;
}
+ if (me->mRelease) {
+ goto stop;
+ }
+
if (!me->mTail) {
goto ok;
}