Merge "init: fix subcontext tests running as non-root."
diff --git a/base/Android.bp b/base/Android.bp
index 25ae535..aeb8864 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -58,6 +58,7 @@
"file.cpp",
"logging.cpp",
"mapped_file.cpp",
+ "parsebool.cpp",
"parsenetaddress.cpp",
"process.cpp",
"properties.cpp",
@@ -149,6 +150,7 @@
"macros_test.cpp",
"mapped_file_test.cpp",
"parsedouble_test.cpp",
+ "parsebool_test.cpp",
"parseint_test.cpp",
"parsenetaddress_test.cpp",
"process_test.cpp",
diff --git a/base/include/android-base/parsebool.h b/base/include/android-base/parsebool.h
new file mode 100644
index 0000000..b2bd021
--- /dev/null
+++ b/base/include/android-base/parsebool.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string_view>
+
+namespace android {
+namespace base {
+
+// Parse the given string as yes or no inactivation of some sort. Return one of the
+// ParseBoolResult enumeration values.
+//
+// The following values parse as true:
+//
+// 1
+// on
+// true
+// y
+// yes
+//
+//
+// The following values parse as false:
+//
+// 0
+// false
+// n
+// no
+// off
+//
+// Anything else is a parse error.
+//
+// The purpose of this function is to have a single canonical parser for yes-or-no indications
+// throughout the system.
+
+enum class ParseBoolResult {
+ kError,
+ kFalse,
+ kTrue,
+};
+
+ParseBoolResult ParseBool(std::string_view s);
+
+} // namespace base
+} // namespace android
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index b1c22c9..14d534a 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -85,5 +85,10 @@
return true;
}
+// Replaces `from` with `to` in `s`, once if `all == false`, or as many times as
+// there are matches if `all == true`.
+[[nodiscard]] std::string StringReplace(std::string_view s, std::string_view from,
+ std::string_view to, bool all);
+
} // namespace base
} // namespace android
diff --git a/base/parsebool.cpp b/base/parsebool.cpp
new file mode 100644
index 0000000..ff96fe9
--- /dev/null
+++ b/base/parsebool.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/parsebool.h"
+#include <errno.h>
+
+namespace android {
+namespace base {
+
+ParseBoolResult ParseBool(std::string_view s) {
+ if (s == "1" || s == "y" || s == "yes" || s == "on" || s == "true") {
+ return ParseBoolResult::kTrue;
+ }
+ if (s == "0" || s == "n" || s == "no" || s == "off" || s == "false") {
+ return ParseBoolResult::kFalse;
+ }
+ return ParseBoolResult::kError;
+}
+
+} // namespace base
+} // namespace android
diff --git a/base/parsebool_test.cpp b/base/parsebool_test.cpp
new file mode 100644
index 0000000..a081994
--- /dev/null
+++ b/base/parsebool_test.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/parsebool.h"
+
+#include <errno.h>
+
+#include <gtest/gtest.h>
+#include <string_view>
+
+using android::base::ParseBool;
+using android::base::ParseBoolResult;
+
+TEST(parsebool, true_) {
+ static const char* yes[] = {
+ "1", "on", "true", "y", "yes",
+ };
+ for (const char* s : yes) {
+ ASSERT_EQ(ParseBoolResult::kTrue, ParseBool(s));
+ }
+}
+
+TEST(parsebool, false_) {
+ static const char* no[] = {
+ "0", "false", "n", "no", "off",
+ };
+ for (const char* s : no) {
+ ASSERT_EQ(ParseBoolResult::kFalse, ParseBool(s));
+ }
+}
+
+TEST(parsebool, invalid) {
+ ASSERT_EQ(ParseBoolResult::kError, ParseBool("blarg"));
+ ASSERT_EQ(ParseBoolResult::kError, ParseBool(""));
+}
diff --git a/base/properties.cpp b/base/properties.cpp
index d5a5918..4731bf2 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -28,19 +28,22 @@
#include <map>
#include <string>
+#include <android-base/parsebool.h>
#include <android-base/parseint.h>
namespace android {
namespace base {
bool GetBoolProperty(const std::string& key, bool default_value) {
- std::string value = GetProperty(key, "");
- if (value == "1" || value == "y" || value == "yes" || value == "on" || value == "true") {
- return true;
- } else if (value == "0" || value == "n" || value == "no" || value == "off" || value == "false") {
- return false;
+ switch (ParseBool(GetProperty(key, ""))) {
+ case ParseBoolResult::kError:
+ return default_value;
+ case ParseBoolResult::kFalse:
+ return false;
+ case ParseBoolResult::kTrue:
+ return true;
}
- return default_value;
+ __builtin_unreachable();
}
template <typename T>
diff --git a/base/strings.cpp b/base/strings.cpp
index bb3167e..40b2bf2 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -116,5 +116,24 @@
return lhs.size() == rhs.size() && strncasecmp(lhs.data(), rhs.data(), lhs.size()) == 0;
}
+std::string StringReplace(std::string_view s, std::string_view from, std::string_view to,
+ bool all) {
+ if (from.empty()) return std::string(s);
+
+ std::string result;
+ std::string_view::size_type start_pos = 0;
+ do {
+ std::string_view::size_type pos = s.find(from, start_pos);
+ if (pos == std::string_view::npos) break;
+
+ result.append(s.data() + start_pos, pos - start_pos);
+ result.append(to.data(), to.size());
+
+ start_pos = pos + from.size();
+ } while (all);
+ result.append(s.data() + start_pos, s.size() - start_pos);
+ return result;
+}
+
} // namespace base
} // namespace android
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index ca3c0b8..5ae3094 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -311,3 +311,46 @@
ASSERT_TRUE(android::base::ConsumeSuffix(&s, ".bar"));
ASSERT_EQ("foo", s);
}
+
+TEST(strings, StringReplace_false) {
+ // No change.
+ ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "z", "Z", false));
+ ASSERT_EQ("", android::base::StringReplace("", "z", "Z", false));
+ ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "", "Z", false));
+
+ // Equal lengths.
+ ASSERT_EQ("Abcabc", android::base::StringReplace("abcabc", "a", "A", false));
+ ASSERT_EQ("aBcabc", android::base::StringReplace("abcabc", "b", "B", false));
+ ASSERT_EQ("abCabc", android::base::StringReplace("abcabc", "c", "C", false));
+
+ // Longer replacement.
+ ASSERT_EQ("foobcabc", android::base::StringReplace("abcabc", "a", "foo", false));
+ ASSERT_EQ("afoocabc", android::base::StringReplace("abcabc", "b", "foo", false));
+ ASSERT_EQ("abfooabc", android::base::StringReplace("abcabc", "c", "foo", false));
+
+ // Shorter replacement.
+ ASSERT_EQ("xxyz", android::base::StringReplace("abcxyz", "abc", "x", false));
+ ASSERT_EQ("axyz", android::base::StringReplace("abcxyz", "bcx", "x", false));
+ ASSERT_EQ("abcx", android::base::StringReplace("abcxyz", "xyz", "x", false));
+}
+
+TEST(strings, StringReplace_true) {
+ // No change.
+ ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "z", "Z", true));
+ ASSERT_EQ("", android::base::StringReplace("", "z", "Z", true));
+ ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "", "Z", true));
+
+ // Equal lengths.
+ ASSERT_EQ("AbcAbc", android::base::StringReplace("abcabc", "a", "A", true));
+ ASSERT_EQ("aBcaBc", android::base::StringReplace("abcabc", "b", "B", true));
+ ASSERT_EQ("abCabC", android::base::StringReplace("abcabc", "c", "C", true));
+
+ // Longer replacement.
+ ASSERT_EQ("foobcfoobc", android::base::StringReplace("abcabc", "a", "foo", true));
+ ASSERT_EQ("afoocafooc", android::base::StringReplace("abcabc", "b", "foo", true));
+ ASSERT_EQ("abfooabfoo", android::base::StringReplace("abcabc", "c", "foo", true));
+
+ // Shorter replacement.
+ ASSERT_EQ("xxyzx", android::base::StringReplace("abcxyzabc", "abc", "x", true));
+ ASSERT_EQ("<xx>", android::base::StringReplace("<abcabc>", "abc", "x", true));
+}
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index f189c45..75bac87 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -20,6 +20,7 @@
#include <inttypes.h>
#include <signal.h>
+#include <stdarg.h>
#include <stdbool.h>
#include <sys/types.h>
@@ -71,6 +72,7 @@
// Log information onto the tombstone.
void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
+void _VLOG(log_t* log, logtype ltype, const char* fmt, va_list ap);
namespace unwindstack {
class Unwinder;
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 1993840..236fcf7 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -428,7 +428,7 @@
std::vector<std::pair<std::string, uint64_t>> special_row;
#if defined(__arm__) || defined(__aarch64__)
- static constexpr const char* special_registers[] = {"ip", "lr", "sp", "pc"};
+ static constexpr const char* special_registers[] = {"ip", "lr", "sp", "pc", "pst"};
#elif defined(__i386__)
static constexpr const char* special_registers[] = {"ebp", "esp", "eip"};
#elif defined(__x86_64__)
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 9b2779a..5ce26fc 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -67,6 +67,14 @@
__attribute__((__weak__, visibility("default")))
void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ _VLOG(log, ltype, fmt, ap);
+ va_end(ap);
+}
+
+__attribute__((__weak__, visibility("default")))
+void _VLOG(log_t* log, enum logtype ltype, const char* fmt, va_list ap) {
bool write_to_tombstone = (log->tfd != -1);
bool write_to_logcat = is_allowed_in_logcat(ltype)
&& log->crashed_tid != -1
@@ -75,10 +83,7 @@
static bool write_to_kmsg = should_write_to_kmsg();
std::string msg;
- va_list ap;
- va_start(ap, fmt);
android::base::StringAppendV(&msg, fmt, ap);
- va_end(ap);
if (msg.empty()) return;
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 02a887e..a757d56 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -137,12 +137,14 @@
"libhidlbase",
"liblog",
"liblp",
+ "libprotobuf-cpp-lite",
"libsparse",
"libutils",
],
static_libs: [
"libhealthhalutils",
+ "libsnapshot_nobinder",
],
header_libs: [
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index a2c95d6..1a745ab 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -19,6 +19,8 @@
#include <sys/socket.h>
#include <sys/un.h>
+#include <unordered_set>
+
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
@@ -33,6 +35,7 @@
#include <libgsi/libgsi.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
+#include <libsnapshot/snapshot.h>
#include <uuid/uuid.h>
#include "constants.h"
@@ -48,6 +51,7 @@
using ::android::hardware::boot::V1_1::MergeStatus;
using ::android::hardware::fastboot::V1_0::Result;
using ::android::hardware::fastboot::V1_0::Status;
+using android::snapshot::SnapshotManager;
using IBootControl1_1 = ::android::hardware::boot::V1_1::IBootControl;
struct VariableHandlers {
@@ -57,6 +61,24 @@
std::function<std::vector<std::vector<std::string>>(FastbootDevice*)> get_all_args;
};
+static bool IsSnapshotUpdateInProgress(FastbootDevice* device) {
+ auto hal = device->boot1_1();
+ if (!hal) {
+ return false;
+ }
+ auto merge_status = hal->getSnapshotMergeStatus();
+ return merge_status == MergeStatus::SNAPSHOTTED || merge_status == MergeStatus::MERGING;
+}
+
+static bool IsProtectedPartitionDuringMerge(FastbootDevice* device, const std::string& name) {
+ static const std::unordered_set<std::string> ProtectedPartitionsDuringMerge = {
+ "userdata", "metadata", "misc"};
+ if (ProtectedPartitionsDuringMerge.count(name) == 0) {
+ return false;
+ }
+ return IsSnapshotUpdateInProgress(device);
+}
+
static void GetAllVars(FastbootDevice* device, const std::string& name,
const VariableHandlers& handlers) {
if (!handlers.get_all_args) {
@@ -143,8 +165,14 @@
return device->WriteStatus(FastbootResult::FAIL, "Erase is not allowed on locked devices");
}
+ const auto& partition_name = args[1];
+ if (IsProtectedPartitionDuringMerge(device, partition_name)) {
+ auto message = "Cannot erase " + partition_name + " while a snapshot update is in progress";
+ return device->WriteFail(message);
+ }
+
PartitionHandle handle;
- if (!OpenPartition(device, args[1], &handle)) {
+ if (!OpenPartition(device, partition_name, &handle)) {
return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
}
if (wipe_block_device(handle.fd(), get_block_device_size(handle.fd())) == 0) {
@@ -209,9 +237,9 @@
"set_active command is not allowed on locked devices");
}
- // Slot suffix needs to be between 'a' and 'z'.
Slot slot;
if (!GetSlotNumber(args[1], &slot)) {
+ // Slot suffix needs to be between 'a' and 'z'.
return device->WriteStatus(FastbootResult::FAIL, "Bad slot suffix");
}
@@ -224,6 +252,32 @@
if (slot >= boot_control_hal->getNumberSlots()) {
return device->WriteStatus(FastbootResult::FAIL, "Slot out of range");
}
+
+ // If the slot is not changing, do nothing.
+ if (slot == boot_control_hal->getCurrentSlot()) {
+ return device->WriteOkay("");
+ }
+
+ // Check how to handle the current snapshot state.
+ if (auto hal11 = device->boot1_1()) {
+ auto merge_status = hal11->getSnapshotMergeStatus();
+ if (merge_status == MergeStatus::MERGING) {
+ return device->WriteFail("Cannot change slots while a snapshot update is in progress");
+ }
+ // Note: we allow the slot change if the state is SNAPSHOTTED. First-
+ // stage init does not have access to the HAL, and uses the slot number
+ // and /metadata OTA state to determine whether a slot change occurred.
+ // Booting into the old slot would erase the OTA, and switching A->B->A
+ // would simply resume it if no boots occur in between. Re-flashing
+ // partitions implicitly cancels the OTA, so leaving the state as-is is
+ // safe.
+ if (merge_status == MergeStatus::SNAPSHOTTED) {
+ device->WriteInfo(
+ "Changing the active slot with a snapshot applied may cancel the"
+ " update.");
+ }
+ }
+
CommandResult ret;
auto cb = [&ret](CommandResult result) { ret = result; };
auto result = boot_control_hal->setActiveBootSlot(slot, cb);
@@ -467,6 +521,11 @@
}
const auto& partition_name = args[1];
+ if (IsProtectedPartitionDuringMerge(device, partition_name)) {
+ auto message = "Cannot flash " + partition_name + " while a snapshot update is in progress";
+ return device->WriteFail(message);
+ }
+
if (LogicalPartitionExists(device, partition_name)) {
CancelPartitionSnapshot(device, partition_name);
}
@@ -556,12 +615,9 @@
bool SnapshotUpdateHandler(FastbootDevice* device, const std::vector<std::string>& args) {
// Note that we use the HAL rather than mounting /metadata, since we want
// our results to match the bootloader.
- auto hal = device->boot_control_hal();
+ auto hal = device->boot1_1();
if (!hal) return device->WriteFail("Not supported");
- android::sp<IBootControl1_1> hal11 = IBootControl1_1::castFrom(hal);
- if (!hal11) return device->WriteFail("Not supported");
-
// If no arguments, return the same thing as a getvar. Note that we get the
// HAL first so we can return "not supported" before we return the less
// specific error message below.
@@ -574,18 +630,34 @@
return device->WriteOkay("");
}
- if (args.size() != 2 || args[1] != "cancel") {
+ MergeStatus status = hal->getSnapshotMergeStatus();
+
+ if (args.size() != 2) {
return device->WriteFail("Invalid arguments");
}
+ if (args[1] == "cancel") {
+ switch (status) {
+ case MergeStatus::SNAPSHOTTED:
+ case MergeStatus::MERGING:
+ hal->setSnapshotMergeStatus(MergeStatus::CANCELLED);
+ break;
+ default:
+ break;
+ }
+ } else if (args[1] == "merge") {
+ if (status != MergeStatus::MERGING) {
+ return device->WriteFail("No snapshot merge is in progress");
+ }
- MergeStatus status = hal11->getSnapshotMergeStatus();
- switch (status) {
- case MergeStatus::SNAPSHOTTED:
- case MergeStatus::MERGING:
- hal11->setSnapshotMergeStatus(MergeStatus::CANCELLED);
- break;
- default:
- break;
+ auto sm = SnapshotManager::NewForFirstStageMount();
+ if (!sm) {
+ return device->WriteFail("Unable to create SnapshotManager");
+ }
+ if (!sm->HandleImminentDataWipe()) {
+ return device->WriteFail("Unable to finish snapshot merge");
+ }
+ } else {
+ return device->WriteFail("Invalid parameter to snapshot-update");
}
return device->WriteStatus(FastbootResult::OKAY, "Success");
}
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index d3c2bda..31fc359 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -60,7 +60,11 @@
boot_control_hal_(IBootControl::getService()),
health_hal_(get_health_service()),
fastboot_hal_(IFastboot::getService()),
- active_slot_("") {}
+ active_slot_("") {
+ if (boot_control_hal_) {
+ boot1_1_ = android::hardware::boot::V1_1::IBootControl::castFrom(boot_control_hal_);
+ }
+}
FastbootDevice::~FastbootDevice() {
CloseDevice();
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
index 091aadf..bbe8172 100644
--- a/fastboot/device/fastboot_device.h
+++ b/fastboot/device/fastboot_device.h
@@ -23,6 +23,7 @@
#include <vector>
#include <android/hardware/boot/1.0/IBootControl.h>
+#include <android/hardware/boot/1.1/IBootControl.h>
#include <android/hardware/fastboot/1.0/IFastboot.h>
#include <android/hardware/health/2.0/IHealth.h>
@@ -51,6 +52,7 @@
android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal() {
return boot_control_hal_;
}
+ android::sp<android::hardware::boot::V1_1::IBootControl> boot1_1() { return boot1_1_; }
android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal() {
return fastboot_hal_;
}
@@ -63,6 +65,7 @@
std::unique_ptr<Transport> transport_;
android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal_;
+ android::sp<android::hardware::boot::V1_1::IBootControl> boot1_1_;
android::sp<android::hardware::health::V2_0::IHealth> health_hal_;
android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal_;
std::vector<char> download_data_;
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index 717db06..10eac01 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -432,19 +432,13 @@
std::string* message) {
// Note that we use the HAL rather than mounting /metadata, since we want
// our results to match the bootloader.
- auto hal = device->boot_control_hal();
+ auto hal = device->boot1_1();
if (!hal) {
*message = "not supported";
return false;
}
- android::sp<IBootControl1_1> hal11 = IBootControl1_1::castFrom(hal);
- if (!hal11) {
- *message = "not supported";
- return false;
- }
-
- MergeStatus status = hal11->getSnapshotMergeStatus();
+ MergeStatus status = hal->getSnapshotMergeStatus();
switch (status) {
case MergeStatus::SNAPSHOTTED:
*message = "snapshotted";
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 7ce7c7c..cbd42b1 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -399,6 +399,9 @@
" snapshot-update cancel On devices that support snapshot-based updates, cancel\n"
" an in-progress update. This may make the device\n"
" unbootable until it is reflashed.\n"
+ " snapshot-update merge On devices that support snapshot-based updates, finish\n"
+ " an in-progress update if it is in the \"merging\"\n"
+ " phase.\n"
"\n"
"boot image:\n"
" boot KERNEL [RAMDISK [SECOND]]\n"
@@ -2089,8 +2092,8 @@
if (!args.empty()) {
arg = next_arg(&args);
}
- if (!arg.empty() && arg != "cancel") {
- syntax_error("expected: snapshot-update [cancel]");
+ if (!arg.empty() && (arg != "cancel" && arg != "merge")) {
+ syntax_error("expected: snapshot-update [cancel|merge]");
}
fb->SnapshotUpdateCommand(arg);
} else {
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index 6a5ad20..8d534ea 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -124,8 +124,11 @@
RetCode FastBootDriver::SnapshotUpdateCommand(const std::string& command, std::string* response,
std::vector<std::string>* info) {
+ prolog_(StringPrintf("Snapshot %s", command.c_str()));
std::string raw = FB_CMD_SNAPSHOT_UPDATE ":" + command;
- return RawCommand(raw, response, info);
+ auto result = RawCommand(raw, response, info);
+ epilog_(result);
+ return result;
}
RetCode FastBootDriver::FlashPartition(const std::string& partition,
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 8f24709..7411e5a 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -224,7 +224,8 @@
bool CreateLogicalAndSnapshotPartitions(const std::string& super_device);
// This method should be called preceding any wipe or flash of metadata or
- // userdata. It is only valid in recovery.
+ // userdata. It is only valid in recovery or fastbootd, and it ensures that
+ // a merge has been completed.
//
// When userdata will be wiped or flashed, it is necessary to clean up any
// snapshot state. If a merge is in progress, the merge must be finished.
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 1de7008..008ece7 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -2185,6 +2185,15 @@
return true;
}
+ // Check this early, so we don't accidentally start trying to populate
+ // the state file in recovery. Note we don't call GetUpdateState since
+ // we want errors in acquiring the lock to be propagated, instead of
+ // returning UpdateState::None.
+ auto state_file = GetStateFilePath();
+ if (access(state_file.c_str(), F_OK) != 0 && errno == ENOENT) {
+ return true;
+ }
+
auto slot_number = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
auto super_path = device_->GetSuperDevice(slot_number);
if (!CreateLogicalAndSnapshotPartitions(super_path)) {
diff --git a/init/Android.bp b/init/Android.bp
index c7021c3..9529617 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -152,6 +152,7 @@
whole_static_libs: [
"libcap",
"com.android.sysprop.apex",
+ "com.android.sysprop.init",
],
header_libs: ["bootimg_headers"],
proto: {
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 8f58145..485806b 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -45,6 +45,7 @@
#include <memory>
#include <ApexProperties.sysprop.h>
+#include <InitProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -1222,7 +1223,9 @@
boot_clock::time_point now = boot_clock::now();
property_set("sys.init.userspace_reboot.last_finished",
std::to_string(now.time_since_epoch().count()));
- property_set(kUserspaceRebootInProgress, "0");
+ if (!android::sysprop::InitProperties::userspace_reboot_in_progress(false)) {
+ return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
+ }
return {};
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 7167672..13cebcc 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -38,6 +38,7 @@
#include <thread>
#include <vector>
+#include <InitProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -743,8 +744,8 @@
// actions. We should make sure, that all of them are propagated before
// proceeding with userspace reboot. Synchronously setting kUserspaceRebootInProgress property
// is not perfect, but it should do the trick.
- if (property_set(kUserspaceRebootInProgress, "1") != 0) {
- return Error() << "Failed to set property " << kUserspaceRebootInProgress;
+ if (!android::sysprop::InitProperties::userspace_reboot_in_progress(true)) {
+ return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
}
EnterShutdown();
std::vector<Service*> stop_first;
diff --git a/init/reboot.h b/init/reboot.h
index cdfa024..81c3edc 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -22,8 +22,6 @@
namespace android {
namespace init {
-static const constexpr char* kUserspaceRebootInProgress = "sys.init.userspace_reboot.in_progress";
-
// Parses and handles a setprop sys.powerctl message.
void HandlePowerctlMessage(const std::string& command);
diff --git a/init/sysprop/Android.bp b/init/sysprop/Android.bp
new file mode 100644
index 0000000..7582875
--- /dev/null
+++ b/init/sysprop/Android.bp
@@ -0,0 +1,7 @@
+sysprop_library {
+ name: "com.android.sysprop.init",
+ srcs: ["InitProperties.sysprop"],
+ property_owner: "Platform",
+ api_packages: ["android.sysprop"],
+ recovery_available: true,
+}
diff --git a/init/sysprop/InitProperties.sysprop b/init/sysprop/InitProperties.sysprop
new file mode 100644
index 0000000..d6a1ab6
--- /dev/null
+++ b/init/sysprop/InitProperties.sysprop
@@ -0,0 +1,27 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+owner: Platform
+module: "android.sysprop.InitProperties"
+
+# Serves as a signal to all processes that userspace reboot is happening.
+prop {
+ api_name: "userspace_reboot_in_progress"
+ type: Boolean
+ scope: Public
+ access: ReadWrite
+ prop_name: "sys.init.userspace_reboot.in_progress"
+ integer_as_bool: true
+}
+
diff --git a/init/sysprop/api/com.android.sysprop.init-current.txt b/init/sysprop/api/com.android.sysprop.init-current.txt
new file mode 100644
index 0000000..8da50e0
--- /dev/null
+++ b/init/sysprop/api/com.android.sysprop.init-current.txt
@@ -0,0 +1,9 @@
+props {
+ module: "android.sysprop.InitProperties"
+ prop {
+ api_name: "userspace_reboot_in_progress"
+ access: ReadWrite
+ prop_name: "sys.init.userspace_reboot.in_progress"
+ integer_as_bool: true
+ }
+}
diff --git a/init/sysprop/api/com.android.sysprop.init-latest.txt b/init/sysprop/api/com.android.sysprop.init-latest.txt
new file mode 100644
index 0000000..c835b95
--- /dev/null
+++ b/init/sysprop/api/com.android.sysprop.init-latest.txt
@@ -0,0 +1,9 @@
+props {
+ module: "android.sysprop.InitProperties"
+ prop {
+ api_name: "userspace_reboot_in_progress"
+ scope: Public
+ prop_name: "sys.init.userspace_reboot.in_progress"
+ integer_as_bool: true
+ }
+}
diff --git a/liblog/logd_reader.cpp b/liblog/logd_reader.cpp
index 4e2dc66..96e7a61 100644
--- a/liblog/logd_reader.cpp
+++ b/liblog/logd_reader.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "logd_reader.h"
+
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -35,39 +37,8 @@
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
-#include "log_portability.h"
-#include "logd_reader.h"
#include "logger.h"
-static int LogdAvailable(log_id_t LogId);
-static int LogdRead(struct logger_list* logger_list, struct android_log_transport_context* transp,
- struct log_msg* log_msg);
-static void LogdClose(struct logger_list* logger_list,
- struct android_log_transport_context* transp);
-
-struct android_log_transport_read logdLoggerRead = {
- .name = "logd",
- .available = LogdAvailable,
- .close = LogdClose,
- .read = LogdRead,
-};
-
-static int LogdAvailable(log_id_t logId) {
- if (logId >= LOG_ID_MAX) {
- return -EINVAL;
- }
- if (logId == LOG_ID_SECURITY) {
- uid_t uid = __android_log_uid();
- if (uid != AID_SYSTEM) {
- return -EPERM;
- }
- }
- if (access("/dev/socket/logdw", W_OK) == 0) {
- return 0;
- }
- return -EBADF;
-}
-
// Connects to /dev/socket/<name> and returns the associated fd or returns -1 on error.
// O_CLOEXEC is always set.
static int socket_local_client(const std::string& name, int type) {
@@ -296,15 +267,11 @@
return check_log_success(buf, SendLogdControlMessage(buf, len));
}
-static int logdOpen(struct logger_list* logger_list, struct android_log_transport_context* transp) {
+static int logdOpen(struct logger_list* logger_list) {
char buffer[256], *cp, c;
int ret, remaining, sock;
- if (!logger_list) {
- return -EINVAL;
- }
-
- sock = atomic_load(&transp->context.sock);
+ sock = atomic_load(&logger_list->fd);
if (sock > 0) {
return sock;
}
@@ -377,7 +344,7 @@
return ret;
}
- ret = atomic_exchange(&transp->context.sock, sock);
+ ret = atomic_exchange(&logger_list->fd, sock);
if ((ret > 0) && (ret != sock)) {
close(ret);
}
@@ -385,15 +352,12 @@
}
/* Read from the selected logs */
-static int LogdRead(struct logger_list* logger_list, struct android_log_transport_context* transp,
- struct log_msg* log_msg) {
- int ret = logdOpen(logger_list, transp);
+int LogdRead(struct logger_list* logger_list, struct log_msg* log_msg) {
+ int ret = logdOpen(logger_list);
if (ret < 0) {
return ret;
}
- memset(log_msg, 0, sizeof(*log_msg));
-
/* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
ret = TEMP_FAILURE_RETRY(recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0));
if ((logger_list->mode & ANDROID_LOG_NONBLOCK) && ret == 0) {
@@ -407,8 +371,8 @@
}
/* Close all the logs */
-static void LogdClose(struct logger_list*, struct android_log_transport_context* transp) {
- int sock = atomic_exchange(&transp->context.sock, -1);
+void LogdClose(struct logger_list* logger_list) {
+ int sock = atomic_exchange(&logger_list->fd, -1);
if (sock > 0) {
close(sock);
}
diff --git a/liblog/logd_reader.h b/liblog/logd_reader.h
index 09f8627..2d032fa 100644
--- a/liblog/logd_reader.h
+++ b/liblog/logd_reader.h
@@ -18,10 +18,14 @@
#include <unistd.h>
+#include "log/log_read.h"
#include "log_portability.h"
__BEGIN_DECLS
+int LogdRead(struct logger_list* logger_list, struct log_msg* log_msg);
+void LogdClose(struct logger_list* logger_list);
+
ssize_t SendLogdControlMessage(char* buf, size_t buf_size);
__END_DECLS
diff --git a/liblog/logger.h b/liblog/logger.h
index d2251e5..9d74d29 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -46,32 +46,8 @@
size_t nr);
};
-struct android_log_transport_context;
-
-struct android_log_transport_read {
- const char* name; /* human name to describe the transport */
-
- /* Does not cause resources to be taken */
- int (*available)(log_id_t logId);
- /* Release resources taken by the following interfaces */
- void (*close)(struct logger_list* logger_list, struct android_log_transport_context* transp);
- /*
- * Expect all to instantiate open automagically on any call,
- * so we do not have an explicit open call.
- */
- int (*read)(struct logger_list* logger_list, struct android_log_transport_context* transp,
- struct log_msg* log_msg);
-};
-
-struct android_log_transport_context {
- union android_log_context_union context; /* zero init per-transport context */
-
- struct android_log_transport_read* transport;
-};
-
struct logger_list {
- android_log_transport_context transport_context;
- bool transport_initialized;
+ atomic_int fd;
int mode;
unsigned int tail;
log_time start;
@@ -85,9 +61,9 @@
// bits 0-2: the decimal value of the log buffer.
// Other bits are unused.
-#define LOGGER_LOGD (1 << 31)
-#define LOGGER_PMSG (1 << 30)
-#define LOGGER_LOG_ID_MASK ((1 << 3) - 1)
+#define LOGGER_LOGD (1U << 31)
+#define LOGGER_PMSG (1U << 30)
+#define LOGGER_LOG_ID_MASK ((1U << 3) - 1)
inline bool android_logger_is_logd(struct logger* logger) {
return reinterpret_cast<uintptr_t>(logger) & LOGGER_LOGD;
diff --git a/liblog/logger_read.cpp b/liblog/logger_read.cpp
index 0ce7a46..c65501c 100644
--- a/liblog/logger_read.cpp
+++ b/liblog/logger_read.cpp
@@ -31,7 +31,9 @@
#include <private/android_filesystem_config.h>
#include "log_portability.h"
+#include "logd_reader.h"
#include "logger.h"
+#include "pmsg_reader.h"
/* method for getting the associated sublog id */
log_id_t android_logger_get_id(struct logger* logger) {
@@ -50,14 +52,6 @@
logger_list->tail = tail;
logger_list->pid = pid;
-#if (FAKE_LOG_DEVICE == 0)
- extern struct android_log_transport_read logdLoggerRead;
- extern struct android_log_transport_read pmsgLoggerRead;
-
- logger_list->transport_context.transport =
- (mode & ANDROID_LOG_PSTORE) ? &pmsgLoggerRead : &logdLoggerRead;
-#endif
-
return logger_list;
}
@@ -100,14 +94,19 @@
}
int android_logger_list_read(struct logger_list* logger_list, struct log_msg* log_msg) {
- if (logger_list == nullptr || logger_list->transport_context.transport == nullptr ||
- logger_list->log_mask == 0) {
+ if (logger_list == nullptr || logger_list->log_mask == 0) {
return -EINVAL;
}
- android_log_transport_context* transp = &logger_list->transport_context;
+ int ret = 0;
- int ret = (*transp->transport->read)(logger_list, transp, log_msg);
+#if (FAKE_LOG_DEVICE == 0)
+ if (logger_list->mode & ANDROID_LOG_PSTORE) {
+ ret = PmsgRead(logger_list, log_msg);
+ } else {
+ ret = LogdRead(logger_list, log_msg);
+ }
+#endif
if (ret <= 0) {
return ret;
@@ -138,11 +137,13 @@
return;
}
- android_log_transport_context* transport_context = &logger_list->transport_context;
-
- if (transport_context->transport && transport_context->transport->close) {
- (*transport_context->transport->close)(logger_list, transport_context);
+#if (FAKE_LOG_DEVICE == 0)
+ if (logger_list->mode & ANDROID_LOG_PSTORE) {
+ PmsgClose(logger_list);
+ } else {
+ LogdClose(logger_list);
}
+#endif
free(logger_list);
}
diff --git a/liblog/pmsg_reader.cpp b/liblog/pmsg_reader.cpp
index 9f603e9..9390fec 100644
--- a/liblog/pmsg_reader.cpp
+++ b/liblog/pmsg_reader.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "pmsg_reader.h"
+
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -26,31 +28,7 @@
#include "logger.h"
-static int PmsgAvailable(log_id_t logId);
-static int PmsgRead(struct logger_list* logger_list, struct android_log_transport_context* transp,
- struct log_msg* log_msg);
-static void PmsgClose(struct logger_list* logger_list,
- struct android_log_transport_context* transp);
-
-struct android_log_transport_read pmsgLoggerRead = {
- .name = "pmsg",
- .available = PmsgAvailable,
- .close = PmsgClose,
- .read = PmsgRead,
-};
-
-static int PmsgAvailable(log_id_t logId) {
- if (logId > LOG_ID_SECURITY) {
- return -EINVAL;
- }
- if (access("/dev/pmsg0", W_OK) == 0) {
- return 0;
- }
- return -EBADF;
-}
-
-static int PmsgRead(struct logger_list* logger_list, struct android_log_transport_context* transp,
- struct log_msg* log_msg) {
+int PmsgRead(struct logger_list* logger_list, struct log_msg* log_msg) {
ssize_t ret;
off_t current, next;
struct __attribute__((__packed__)) {
@@ -62,7 +40,7 @@
memset(log_msg, 0, sizeof(*log_msg));
- if (atomic_load(&transp->context.fd) <= 0) {
+ if (atomic_load(&logger_list->fd) <= 0) {
int i, fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
if (fd < 0) {
@@ -75,7 +53,7 @@
return -errno;
}
}
- i = atomic_exchange(&transp->context.fd, fd);
+ i = atomic_exchange(&logger_list->fd, fd);
if ((i > 0) && (i != fd)) {
close(i);
}
@@ -86,7 +64,7 @@
int fd;
if (preread_count < sizeof(buf)) {
- fd = atomic_load(&transp->context.fd);
+ fd = atomic_load(&logger_list->fd);
if (fd <= 0) {
return -EBADF;
}
@@ -120,7 +98,7 @@
(!logger_list->pid || (logger_list->pid == buf.p.pid))) {
char* msg = log_msg->entry.msg;
*msg = buf.prio;
- fd = atomic_load(&transp->context.fd);
+ fd = atomic_load(&logger_list->fd);
if (fd <= 0) {
return -EBADF;
}
@@ -144,7 +122,7 @@
return ret + sizeof(buf.prio) + log_msg->entry.hdr_size;
}
- fd = atomic_load(&transp->context.fd);
+ fd = atomic_load(&logger_list->fd);
if (fd <= 0) {
return -EBADF;
}
@@ -152,7 +130,7 @@
if (current < 0) {
return -errno;
}
- fd = atomic_load(&transp->context.fd);
+ fd = atomic_load(&logger_list->fd);
if (fd <= 0) {
return -EBADF;
}
@@ -166,8 +144,8 @@
}
}
-static void PmsgClose(struct logger_list*, struct android_log_transport_context* transp) {
- int fd = atomic_exchange(&transp->context.fd, 0);
+void PmsgClose(struct logger_list* logger_list) {
+ int fd = atomic_exchange(&logger_list->fd, 0);
if (fd > 0) {
close(fd);
}
@@ -185,7 +163,6 @@
__android_log_pmsg_file_read_fn fn, void* arg) {
ssize_t ret;
struct logger_list logger_list;
- struct android_log_transport_context transp;
struct content {
struct listnode node;
struct logger_entry entry;
@@ -207,7 +184,6 @@
/* Add just enough clues in logger_list and transp to make API function */
memset(&logger_list, 0, sizeof(logger_list));
- memset(&transp, 0, sizeof(transp));
logger_list.mode = ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK | ANDROID_LOG_RDONLY;
logger_list.log_mask = (unsigned)-1;
@@ -241,7 +217,7 @@
/* Read the file content */
log_msg log_msg;
- while (PmsgRead(&logger_list, &transp, &log_msg) > 0) {
+ while (PmsgRead(&logger_list, &log_msg) > 0) {
const char* cp;
size_t hdr_size = log_msg.entry.hdr_size;
@@ -399,7 +375,7 @@
}
list_add_head(node, &content->node);
}
- PmsgClose(&logger_list, &transp);
+ PmsgClose(&logger_list);
/* Progress through all the collected files */
list_for_each_safe(node, n, &name_list) {
diff --git a/liblog/pmsg_reader.h b/liblog/pmsg_reader.h
new file mode 100644
index 0000000..53746d8
--- /dev/null
+++ b/liblog/pmsg_reader.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <unistd.h>
+
+#include "log/log_read.h"
+#include "log_portability.h"
+
+__BEGIN_DECLS
+
+int PmsgRead(struct logger_list* logger_list, struct log_msg* log_msg);
+void PmsgClose(struct logger_list* logger_list);
+
+__END_DECLS
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
index e9787aa..2e8af20 100644
--- a/libunwindstack/RegsArm64.cpp
+++ b/libunwindstack/RegsArm64.cpp
@@ -103,6 +103,7 @@
fn("sp", regs_[ARM64_REG_SP]);
fn("lr", regs_[ARM64_REG_LR]);
fn("pc", regs_[ARM64_REG_PC]);
+ fn("pst", regs_[ARM64_REG_PSTATE]);
}
Regs* RegsArm64::Read(void* remote_data) {
@@ -113,6 +114,7 @@
uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
reg_data[ARM64_REG_PC] = user->pc;
reg_data[ARM64_REG_SP] = user->sp;
+ reg_data[ARM64_REG_PSTATE] = user->pstate;
return regs;
}
diff --git a/libunwindstack/include/unwindstack/MachineArm64.h b/libunwindstack/include/unwindstack/MachineArm64.h
index e8b778b..e953335 100644
--- a/libunwindstack/include/unwindstack/MachineArm64.h
+++ b/libunwindstack/include/unwindstack/MachineArm64.h
@@ -55,6 +55,7 @@
ARM64_REG_R30,
ARM64_REG_R31,
ARM64_REG_PC,
+ ARM64_REG_PSTATE,
ARM64_REG_LAST,
ARM64_REG_SP = ARM64_REG_R31,
diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp
index 7e36953..bc95851 100644
--- a/libunwindstack/tests/RegsIterateTest.cpp
+++ b/libunwindstack/tests/RegsIterateTest.cpp
@@ -114,6 +114,7 @@
result.push_back({"sp", ARM64_REG_SP});
result.push_back({"lr", ARM64_REG_LR});
result.push_back({"pc", ARM64_REG_PC});
+ result.push_back({"pst", ARM64_REG_PSTATE});
return result;
}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 98921be..efa4c41 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -125,6 +125,7 @@
native_bridge_supported: true,
srcs: [
+ "Errors.cpp",
"FileMap.cpp",
"JenkinsHash.cpp",
"NativeHandle.cpp",
diff --git a/libutils/Errors.cpp b/libutils/Errors.cpp
new file mode 100644
index 0000000..2dfd138
--- /dev/null
+++ b/libutils/Errors.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <utils/Errors.h>
+
+namespace android {
+
+std::string statusToString(status_t s) {
+#define STATUS_CASE(STATUS) \
+ case STATUS: \
+ return #STATUS
+
+ switch (s) {
+ STATUS_CASE(OK);
+ STATUS_CASE(UNKNOWN_ERROR);
+ STATUS_CASE(NO_MEMORY);
+ STATUS_CASE(INVALID_OPERATION);
+ STATUS_CASE(BAD_VALUE);
+ STATUS_CASE(BAD_TYPE);
+ STATUS_CASE(NAME_NOT_FOUND);
+ STATUS_CASE(PERMISSION_DENIED);
+ STATUS_CASE(NO_INIT);
+ STATUS_CASE(ALREADY_EXISTS);
+ STATUS_CASE(DEAD_OBJECT);
+ STATUS_CASE(FAILED_TRANSACTION);
+ STATUS_CASE(BAD_INDEX);
+ STATUS_CASE(NOT_ENOUGH_DATA);
+ STATUS_CASE(WOULD_BLOCK);
+ STATUS_CASE(TIMED_OUT);
+ STATUS_CASE(UNKNOWN_TRANSACTION);
+ STATUS_CASE(FDS_NOT_ALLOWED);
+ STATUS_CASE(UNEXPECTED_NULL);
+#undef STATUS_CASE
+ }
+
+ return std::to_string(s) + ' ' + strerror(-s);
+}
+
+} // namespace android
diff --git a/libutils/include/utils/Errors.h b/libutils/include/utils/Errors.h
index 1e03677..d14d223 100644
--- a/libutils/include/utils/Errors.h
+++ b/libutils/include/utils/Errors.h
@@ -19,6 +19,7 @@
#include <errno.h>
#include <stdint.h>
#include <sys/types.h>
+#include <string>
namespace android {
@@ -72,6 +73,9 @@
UNEXPECTED_NULL = (UNKNOWN_ERROR + 8),
};
+// Human readable name of error
+std::string statusToString(status_t status);
+
// Restore define; enumeration is in "android" namespace, so the value defined
// there won't work for Win32 code in a different namespace.
#ifdef _WIN32
diff --git a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
index 33da1f1..f4a846f 100644
--- a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
+++ b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
@@ -375,9 +375,11 @@
{"audio_hal.period_size", "u:object_r:default_prop:s0"},
{"bluetooth.enable_timeout_ms", "u:object_r:bluetooth_prop:s0"},
{"dalvik.vm.appimageformat", "u:object_r:dalvik_prop:s0"},
+ {"dalvik.vm.boot-dex2oat-cpu-set", "u:object_r:dalvik_prop:s0"},
{"dalvik.vm.boot-dex2oat-threads", "u:object_r:dalvik_prop:s0"},
{"dalvik.vm.dex2oat-Xms", "u:object_r:dalvik_prop:s0"},
{"dalvik.vm.dex2oat-Xmx", "u:object_r:dalvik_prop:s0"},
+ {"dalvik.vm.dex2oat-cpu-set", "u:object_r:dalvik_prop:s0"},
{"dalvik.vm.dex2oat-threads", "u:object_r:dalvik_prop:s0"},
{"dalvik.vm.dexopt.secondary", "u:object_r:dalvik_prop:s0"},
{"dalvik.vm.heapgrowthlimit", "u:object_r:dalvik_prop:s0"},
@@ -388,6 +390,7 @@
{"dalvik.vm.heaptargetutilization", "u:object_r:dalvik_prop:s0"},
{"dalvik.vm.image-dex2oat-Xms", "u:object_r:dalvik_prop:s0"},
{"dalvik.vm.image-dex2oat-Xmx", "u:object_r:dalvik_prop:s0"},
+ {"dalvik.vm.image-dex2oat-cpu-set", "u:object_r:dalvik_prop:s0"},
{"dalvik.vm.image-dex2oat-threads", "u:object_r:dalvik_prop:s0"},
{"dalvik.vm.isa.arm.features", "u:object_r:dalvik_prop:s0"},
{"dalvik.vm.isa.arm.variant", "u:object_r:dalvik_prop:s0"},