Merge "libsnapshot: Fix typo in nullptr check"
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index f0142bb..b2572f6 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -67,6 +67,9 @@
"libfs_mgr",
"liblp",
] + liblp_lib_deps,
+ header_libs: [
+ "libstorage_literals_headers",
+ ],
stl: "libc++_static",
srcs: [
"builder_test.cpp",
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index bd41f59..a67ffa7 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -17,11 +17,13 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <liblp/builder.h>
+#include <storage_literals/storage_literals.h>
#include "liblp_test.h"
#include "utility.h"
using namespace std;
+using namespace android::storage_literals;
using namespace android::fs_mgr;
using namespace android::fs_mgr::testing;
using ::testing::_;
@@ -591,13 +593,6 @@
ASSERT_NE(builder->Export(), nullptr);
}
-constexpr unsigned long long operator"" _GiB(unsigned long long x) { // NOLINT
- return x << 30;
-}
-constexpr unsigned long long operator"" _MiB(unsigned long long x) { // NOLINT
- return x << 20;
-}
-
TEST_F(BuilderTest, RemoveAndAddFirstPartition) {
auto builder = MetadataBuilder::New(10_GiB, 65536, 2);
ASSERT_NE(nullptr, builder);
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index f2b6141..f73b189 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -103,4 +103,7 @@
"libsparse",
"libz",
],
+ header_libs: [
+ "libstorage_literals_headers",
+ ],
}
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 876b8f8..e9835d0 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -32,8 +32,8 @@
#include <libfiemap/image_manager.h>
#include <liblp/builder.h>
#include <liblp/mock_property_fetcher.h>
+#include <storage_literals/storage_literals.h>
-#include "digital_storage.h"
#include "test_helpers.h"
#include "utility.h"
@@ -52,7 +52,7 @@
using android::fs_mgr::MetadataBuilder;
using namespace ::testing;
using namespace android::fs_mgr::testing;
-using namespace android::digital_storage;
+using namespace android::storage_literals;
using namespace std::chrono_literals;
using namespace std::string_literals;
@@ -62,7 +62,7 @@
TestDeviceInfo* test_device = nullptr;
std::string fake_super;
-static constexpr uint64_t kSuperSize = (16_MiB).bytes();
+static constexpr uint64_t kSuperSize = 16_MiB;
class SnapshotTest : public ::testing::Test {
public:
diff --git a/fs_mgr/libstorage_literals/Android.bp b/fs_mgr/libstorage_literals/Android.bp
new file mode 100644
index 0000000..11611dd
--- /dev/null
+++ b/fs_mgr/libstorage_literals/Android.bp
@@ -0,0 +1,6 @@
+
+cc_library_headers {
+ name: "libstorage_literals_headers",
+ host_supported: true,
+ export_include_dirs: ["."],
+}
diff --git a/fs_mgr/libsnapshot/digital_storage.h b/fs_mgr/libstorage_literals/storage_literals/storage_literals.h
similarity index 71%
rename from fs_mgr/libsnapshot/digital_storage.h
rename to fs_mgr/libstorage_literals/storage_literals/storage_literals.h
index 210298e..ac0dfbd 100644
--- a/fs_mgr/libsnapshot/digital_storage.h
+++ b/fs_mgr/libstorage_literals/storage_literals/storage_literals.h
@@ -18,25 +18,25 @@
#include <stdlib.h>
namespace android {
-namespace digital_storage {
+namespace storage_literals {
template <size_t Power>
struct Size {
static constexpr size_t power = Power;
- constexpr Size(uint64_t count) : value_(count) {}
+ explicit constexpr Size(uint64_t count) : value_(count) {}
- constexpr uint64_t bytes() const { return value_ << (Power * 10); }
+ constexpr uint64_t bytes() const { return value_ << power; }
constexpr uint64_t count() const { return value_; }
- operator uint64_t() const { return bytes(); }
+ constexpr operator uint64_t() const { return bytes(); }
private:
uint64_t value_;
};
using B = Size<0>;
-using KiB = Size<1>;
-using MiB = Size<2>;
-using GiB = Size<3>;
+using KiB = Size<10>;
+using MiB = Size<20>;
+using GiB = Size<30>;
constexpr B operator""_B(unsigned long long v) { // NOLINT
return B{v};
@@ -57,21 +57,21 @@
template <typename Dest, typename Src>
constexpr Dest size_cast(Src src) {
if (Src::power < Dest::power) {
- return Dest(src.count() >> ((Dest::power - Src::power) * 10));
+ return Dest(src.count() >> (Dest::power - Src::power));
}
if (Src::power > Dest::power) {
- return Dest(src.count() << ((Src::power - Dest::power) * 10));
+ return Dest(src.count() << (Src::power - Dest::power));
}
return Dest(src.count());
}
-static_assert((1_B).bytes() == 1);
-static_assert((1_KiB).bytes() == 1 << 10);
-static_assert((1_MiB).bytes() == 1 << 20);
-static_assert((1_GiB).bytes() == 1 << 30);
+static_assert(1_B == 1);
+static_assert(1_KiB == 1 << 10);
+static_assert(1_MiB == 1 << 20);
+static_assert(1_GiB == 1 << 30);
static_assert(size_cast<KiB>(1_B).count() == 0);
static_assert(size_cast<KiB>(1024_B).count() == 1);
static_assert(size_cast<KiB>(1_MiB).count() == 1024);
-} // namespace digital_storage
+} // namespace storage_literals
} // namespace android
diff --git a/init/Android.mk b/init/Android.mk
index d7258a7..54163fa 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -119,6 +119,7 @@
LOCAL_SANITIZE := signed-integer-overflow
# First stage init is weird: it may start without stdout/stderr, and no /proc.
LOCAL_NOSANITIZE := hwaddress
+LOCAL_INJECT_BSSL_HASH := true
include $(BUILD_EXECUTABLE)
endif
diff --git a/init/README.md b/init/README.md
index 2de76a9..423c6d1 100644
--- a/init/README.md
+++ b/init/README.md
@@ -263,6 +263,12 @@
> Scheduling priority of the service process. This value has to be in range
-20 to 19. Default priority is 0. Priority is set via setpriority().
+`reboot_on_failure <target>`
+> If this process cannot be started or if the process terminates with an exit code other than
+ CLD_EXITED or an status other than '0', reboot the system with the target specified in
+ _target_. _target_ takes the same format as the parameter to sys.powerctl. This is particularly
+ intended to be used with the `exec_start` builtin for any must-have checks during boot.
+
`restart_period <seconds>`
> If a non-oneshot service exits, it will be restarted at its start time plus
this period. It defaults to 5s to rate limit crashing services.
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 21db8dc..42211b2 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1104,20 +1104,6 @@
return {};
}
-static Result<void> do_exec_reboot_on_failure(const BuiltinArguments& args) {
- auto reboot_reason = args[1];
- auto reboot = [reboot_reason](const std::string& message) {
- property_set(LAST_REBOOT_REASON_PROPERTY, reboot_reason);
- sync();
- LOG(FATAL) << message << ": rebooting into bootloader, reason: " << reboot_reason;
- };
-
- std::vector<std::string> remaining_args(args.begin() + 1, args.end());
- remaining_args[0] = args[0];
-
- return ExecWithFunctionOnFailure(remaining_args, reboot);
-}
-
static Result<void> ExecVdcRebootOnFailure(const std::string& vdc_arg) {
auto reboot_reason = vdc_arg + "_failed";
@@ -1225,7 +1211,6 @@
{"enable", {1, 1, {false, do_enable}}},
{"exec", {1, kMax, {false, do_exec}}},
{"exec_background", {1, kMax, {false, do_exec_background}}},
- {"exec_reboot_on_failure", {2, kMax, {false, do_exec_reboot_on_failure}}},
{"exec_start", {1, 1, {false, do_exec_start}}},
{"export", {2, 2, {false, do_export}}},
{"hostname", {1, 1, {true, do_hostname}}},
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index f9a08a5..e3068b2 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -34,6 +34,11 @@
namespace android {
namespace init {
+// init.h
+inline void EnterShutdown(const std::string&) {
+ abort();
+}
+
// property_service.h
inline bool CanReadProperty(const std::string&, const std::string&) {
return true;
diff --git a/init/init.cpp b/init/init.cpp
index 4e9a14f..53b065f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -180,6 +180,16 @@
waiting_for_prop.reset();
}
+void EnterShutdown(const std::string& command) {
+ // We can't call HandlePowerctlMessage() directly in this function,
+ // because it modifies the contents of the action queue, which can cause the action queue
+ // to get into a bad state if this function is called from a command being executed by the
+ // action queue. Instead we set this flag and ensure that shutdown happens before the next
+ // command is run in the main init loop.
+ shutdown_command = command;
+ do_shutdown = true;
+}
+
void property_changed(const std::string& name, const std::string& value) {
// If the property is sys.powerctl, we bypass the event queue and immediately handle it.
// This is to ensure that init will always and immediately shutdown/reboot, regardless of
@@ -188,16 +198,7 @@
// In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
// commands to be executed.
if (name == "sys.powerctl") {
- // Despite the above comment, we can't call HandlePowerctlMessage() in this function,
- // because it modifies the contents of the action queue, which can cause the action queue
- // to get into a bad state if this function is called from a command being executed by the
- // action queue. Instead we set this flag and ensure that shutdown happens before the next
- // command is run in the main init loop.
- // TODO: once property service is removed from init, this will never happen from a builtin,
- // but rather from a callback from the property service socket, in which case this hack can
- // go away.
- shutdown_command = value;
- do_shutdown = true;
+ EnterShutdown(value);
}
if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
diff --git a/init/init.h b/init/init.h
index 8ac52e2..61fb110 100644
--- a/init/init.h
+++ b/init/init.h
@@ -31,6 +31,8 @@
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
Parser CreateServiceOnlyParser(ServiceList& service_list);
+void EnterShutdown(const std::string& command);
+
bool start_waiting_for_property(const char *name, const char *value);
void DumpState();
diff --git a/init/service.cpp b/init/service.cpp
index 7a20966..793a2b2 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -29,6 +29,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/sockets.h>
@@ -41,6 +42,7 @@
#if defined(__ANDROID__)
#include <ApexProperties.sysprop.h>
+#include "init.h"
#include "mount_namespace.h"
#include "property_service.h"
#else
@@ -50,6 +52,7 @@
using android::base::boot_clock;
using android::base::GetProperty;
using android::base::Join;
+using android::base::make_scope_guard;
using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
@@ -250,6 +253,11 @@
f(siginfo);
}
+ if ((siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) && on_failure_reboot_target_) {
+ LOG(ERROR) << "Service with 'reboot_on_failure' option failed, shutting down system.";
+ EnterShutdown(*on_failure_reboot_target_);
+ }
+
if (flags_ & SVC_EXEC) UnSetExec();
if (flags_ & SVC_TEMPORARY) return;
@@ -325,6 +333,12 @@
Result<void> Service::ExecStart() {
+ auto reboot_on_failure = make_scope_guard([this] {
+ if (on_failure_reboot_target_) {
+ EnterShutdown(*on_failure_reboot_target_);
+ }
+ });
+
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.
@@ -345,10 +359,17 @@
<< " gid " << proc_attr_.gid << "+" << proc_attr_.supp_gids.size() << " context "
<< (!seclabel_.empty() ? seclabel_ : "default") << ") started; waiting...";
+ reboot_on_failure.Disable();
return {};
}
Result<void> Service::Start() {
+ auto reboot_on_failure = make_scope_guard([this] {
+ if (on_failure_reboot_target_) {
+ EnterShutdown(*on_failure_reboot_target_);
+ }
+ });
+
if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
ServiceList::GetInstance().DelayService(*this);
return Error() << "Cannot start an updatable service '" << name_
@@ -371,6 +392,7 @@
flags_ |= SVC_RESTART;
}
// It is not an error to try to start a service that is already running.
+ reboot_on_failure.Disable();
return {};
}
@@ -532,6 +554,7 @@
}
NotifyStateChange("running");
+ reboot_on_failure.Disable();
return {};
}
diff --git a/init/service.h b/init/service.h
index ccefc8e..788f792 100644
--- a/init/service.h
+++ b/init/service.h
@@ -196,6 +196,8 @@
bool post_data_ = false;
bool running_at_post_data_reset_ = false;
+
+ std::optional<std::string> on_failure_reboot_target_;
};
} // namespace init
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 543be23..4322dc7 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -310,6 +310,18 @@
return {};
}
+Result<void> ServiceParser::ParseRebootOnFailure(std::vector<std::string>&& args) {
+ if (service_->on_failure_reboot_target_) {
+ return Error() << "Only one reboot_on_failure command may be specified";
+ }
+ if (!StartsWith(args[1], "shutdown") && !StartsWith(args[1], "reboot")) {
+ return Error()
+ << "reboot_on_failure commands must begin with either 'shutdown' or 'reboot'";
+ }
+ service_->on_failure_reboot_target_ = std::move(args[1]);
+ return {};
+}
+
Result<void> ServiceParser::ParseRestartPeriod(std::vector<std::string>&& args) {
int period;
if (!ParseInt(args[1], &period, 5)) {
@@ -471,49 +483,41 @@
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
// clang-format off
static const KeywordMap<ServiceParser::OptionParser> parser_map = {
- {"capabilities",
- {0, kMax, &ServiceParser::ParseCapabilities}},
- {"class", {1, kMax, &ServiceParser::ParseClass}},
- {"console", {0, 1, &ServiceParser::ParseConsole}},
- {"critical", {0, 0, &ServiceParser::ParseCritical}},
- {"disabled", {0, 0, &ServiceParser::ParseDisabled}},
- {"enter_namespace",
- {2, 2, &ServiceParser::ParseEnterNamespace}},
- {"file", {2, 2, &ServiceParser::ParseFile}},
- {"group", {1, NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}},
- {"interface", {2, 2, &ServiceParser::ParseInterface}},
- {"ioprio", {2, 2, &ServiceParser::ParseIoprio}},
- {"keycodes", {1, kMax, &ServiceParser::ParseKeycodes}},
- {"memcg.limit_in_bytes",
- {1, 1, &ServiceParser::ParseMemcgLimitInBytes}},
- {"memcg.limit_percent",
- {1, 1, &ServiceParser::ParseMemcgLimitPercent}},
- {"memcg.limit_property",
- {1, 1, &ServiceParser::ParseMemcgLimitProperty}},
+ {"capabilities", {0, kMax, &ServiceParser::ParseCapabilities}},
+ {"class", {1, kMax, &ServiceParser::ParseClass}},
+ {"console", {0, 1, &ServiceParser::ParseConsole}},
+ {"critical", {0, 0, &ServiceParser::ParseCritical}},
+ {"disabled", {0, 0, &ServiceParser::ParseDisabled}},
+ {"enter_namespace", {2, 2, &ServiceParser::ParseEnterNamespace}},
+ {"file", {2, 2, &ServiceParser::ParseFile}},
+ {"group", {1, NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}},
+ {"interface", {2, 2, &ServiceParser::ParseInterface}},
+ {"ioprio", {2, 2, &ServiceParser::ParseIoprio}},
+ {"keycodes", {1, kMax, &ServiceParser::ParseKeycodes}},
+ {"memcg.limit_in_bytes", {1, 1, &ServiceParser::ParseMemcgLimitInBytes}},
+ {"memcg.limit_percent", {1, 1, &ServiceParser::ParseMemcgLimitPercent}},
+ {"memcg.limit_property", {1, 1, &ServiceParser::ParseMemcgLimitProperty}},
{"memcg.soft_limit_in_bytes",
- {1, 1, &ServiceParser::ParseMemcgSoftLimitInBytes}},
- {"memcg.swappiness",
- {1, 1, &ServiceParser::ParseMemcgSwappiness}},
- {"namespace", {1, 2, &ServiceParser::ParseNamespace}},
- {"oneshot", {0, 0, &ServiceParser::ParseOneshot}},
- {"onrestart", {1, kMax, &ServiceParser::ParseOnrestart}},
- {"oom_score_adjust",
- {1, 1, &ServiceParser::ParseOomScoreAdjust}},
- {"override", {0, 0, &ServiceParser::ParseOverride}},
- {"priority", {1, 1, &ServiceParser::ParsePriority}},
- {"restart_period",
- {1, 1, &ServiceParser::ParseRestartPeriod}},
- {"rlimit", {3, 3, &ServiceParser::ParseProcessRlimit}},
- {"seclabel", {1, 1, &ServiceParser::ParseSeclabel}},
- {"setenv", {2, 2, &ServiceParser::ParseSetenv}},
- {"shutdown", {1, 1, &ServiceParser::ParseShutdown}},
- {"sigstop", {0, 0, &ServiceParser::ParseSigstop}},
- {"socket", {3, 6, &ServiceParser::ParseSocket}},
- {"timeout_period",
- {1, 1, &ServiceParser::ParseTimeoutPeriod}},
- {"updatable", {0, 0, &ServiceParser::ParseUpdatable}},
- {"user", {1, 1, &ServiceParser::ParseUser}},
- {"writepid", {1, kMax, &ServiceParser::ParseWritepid}},
+ {1, 1, &ServiceParser::ParseMemcgSoftLimitInBytes}},
+ {"memcg.swappiness", {1, 1, &ServiceParser::ParseMemcgSwappiness}},
+ {"namespace", {1, 2, &ServiceParser::ParseNamespace}},
+ {"oneshot", {0, 0, &ServiceParser::ParseOneshot}},
+ {"onrestart", {1, kMax, &ServiceParser::ParseOnrestart}},
+ {"oom_score_adjust", {1, 1, &ServiceParser::ParseOomScoreAdjust}},
+ {"override", {0, 0, &ServiceParser::ParseOverride}},
+ {"priority", {1, 1, &ServiceParser::ParsePriority}},
+ {"reboot_on_failure", {1, 1, &ServiceParser::ParseRebootOnFailure}},
+ {"restart_period", {1, 1, &ServiceParser::ParseRestartPeriod}},
+ {"rlimit", {3, 3, &ServiceParser::ParseProcessRlimit}},
+ {"seclabel", {1, 1, &ServiceParser::ParseSeclabel}},
+ {"setenv", {2, 2, &ServiceParser::ParseSetenv}},
+ {"shutdown", {1, 1, &ServiceParser::ParseShutdown}},
+ {"sigstop", {0, 0, &ServiceParser::ParseSigstop}},
+ {"socket", {3, 6, &ServiceParser::ParseSocket}},
+ {"timeout_period", {1, 1, &ServiceParser::ParseTimeoutPeriod}},
+ {"updatable", {0, 0, &ServiceParser::ParseUpdatable}},
+ {"user", {1, 1, &ServiceParser::ParseUser}},
+ {"writepid", {1, kMax, &ServiceParser::ParseWritepid}},
};
// clang-format on
return parser_map;
diff --git a/init/service_parser.h b/init/service_parser.h
index 4729874..ace4d70 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -68,6 +68,7 @@
Result<void> ParseMemcgSwappiness(std::vector<std::string>&& args);
Result<void> ParseNamespace(std::vector<std::string>&& args);
Result<void> ParseProcessRlimit(std::vector<std::string>&& args);
+ Result<void> ParseRebootOnFailure(std::vector<std::string>&& args);
Result<void> ParseRestartPeriod(std::vector<std::string>&& args);
Result<void> ParseSeclabel(std::vector<std::string>&& args);
Result<void> ParseSetenv(std::vector<std::string>&& args);
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b99c149..8808846 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -58,13 +58,29 @@
# Run boringssl self test for each ABI so that later processes can skip it. http://b/139348610
on early-init && property:ro.product.cpu.abilist32=*
- exec_reboot_on_failure boringssl-self-check-failed /system/bin/boringssl_self_test32
+ exec_start boringssl_self_test32
on early-init && property:ro.product.cpu.abilist64=*
- exec_reboot_on_failure boringssl-self-check-failed /system/bin/boringssl_self_test64
-on property:apexd.status=ready && property:ro.product.cpu.abilist64=*
- exec_reboot_on_failure boringssl-self-check-failed /apex/com.android.conscrypt/bin/boringssl_self_test64
+ exec_start boringssl_self_test64
on property:apexd.status=ready && property:ro.product.cpu.abilist32=*
- exec_reboot_on_failure boringssl-self-check-failed /apex/com.android.conscrypt/bin/boringssl_self_test32
+ exec_start boringssl_self_test_apex32
+on property:apexd.status=ready && property:ro.product.cpu.abilist64=*
+ exec_start boringssl_self_test_apex64
+
+service boringssl_self_test32 /system/bin/boringssl_self_test32
+ setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
+ reboot_on_failure reboot,bootloader,boringssl-self-check-failed
+
+service boringssl_self_test64 /system/bin/boringssl_self_test64
+ setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
+ reboot_on_failure reboot,bootloader,boringssl-self-check-failed
+
+service boringssl_self_test_apex32 /apex/com.android.conscrypt/bin/boringssl_self_test32
+ setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
+ reboot_on_failure reboot,bootloader,boringssl-self-check-failed
+
+service boringssl_self_test_apex64 /apex/com.android.conscrypt/bin/boringssl_self_test64
+ setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
+ reboot_on_failure reboot,bootloader,boringssl-self-check-failed
on init
sysclktz 0