Merge "lmkd: Detect the highest level of vmpressure when event is detected"
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index d126f52..6a80bcd 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1944,7 +1944,8 @@
for (int i = argc - 1; i >= 0; i--) {
const char* file = argv[i];
- if (android::base::EndsWithIgnoreCase(file, ".apk")) {
+ if (android::base::EndsWithIgnoreCase(file, ".apk") ||
+ android::base::EndsWithIgnoreCase(file, ".dm")) {
struct stat sb;
if (stat(file, &sb) != -1) total_size += sb.st_size;
first_apk = i;
@@ -2005,9 +2006,8 @@
}
std::string cmd = android::base::StringPrintf(
- "%s install-write -S %" PRIu64 " %d %d_%s -",
- install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i,
- android::base::Basename(file).c_str());
+ "%s install-write -S %" PRIu64 " %d %s -", install_cmd.c_str(),
+ static_cast<uint64_t>(sb.st_size), session_id, android::base::Basename(file).c_str());
int localFd = adb_open(file, O_RDONLY);
if (localFd < 0) {
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 9127c60..7792eaf 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -50,6 +50,7 @@
android.hardware.health@2.0 \
android.hardware.health@2.0-impl \
android.hardware.health@1.0 \
+ android.hardware.health@1.0-convert \
libhealthstoragedefault \
libminui \
libpng \
@@ -96,6 +97,7 @@
android.hardware.health@2.0-impl \
android.hardware.health@2.0 \
android.hardware.health@1.0 \
+ android.hardware.health@1.0-convert \
libhidltransport \
libhidlbase \
libhwbinder \
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 676ee41..561948c 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -86,6 +86,10 @@
initBatteryProperties(&props);
}
+struct BatteryProperties getBatteryProperties(BatteryMonitor* batteryMonitor) {
+ return batteryMonitor->props;
+}
+
int BatteryMonitor::getBatteryStatus(const char* status) {
int ret;
struct sysfsStringEnumMap batteryStatusMap[] = {
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index f9067cc..b6a1b66 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -42,6 +42,7 @@
int getChargeStatus();
status_t getProperty(int id, struct BatteryProperty *val);
void dumpState(int fd);
+ friend struct BatteryProperties getBatteryProperties(BatteryMonitor* batteryMonitor);
private:
struct healthd_config *mHealthdConfig;
diff --git a/init/Android.bp b/init/Android.bp
index 2fea359..0db7824 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -75,6 +75,7 @@
"persistent_properties.cpp",
"persistent_properties.proto",
"property_service.cpp",
+ "property_type.cpp",
"security.cpp",
"selinux.cpp",
"service.cpp",
@@ -178,6 +179,7 @@
"init_test.cpp",
"persistent_properties_test.cpp",
"property_service_test.cpp",
+ "property_type_test.cpp",
"result_test.cpp",
"rlimit_parser_test.cpp",
"service_test.cpp",
diff --git a/init/action.cpp b/init/action.cpp
index 16ecdcd..ba03e66 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -21,6 +21,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
+#include "stable_properties.h"
#include "util.h"
using android::base::Join;
@@ -134,6 +135,25 @@
}
}
+static bool IsActionableProperty(Subcontext* subcontext, const std::string& prop_name) {
+ static bool enabled =
+ android::base::GetBoolProperty("ro.actionable_compatible_property.enabled", false);
+
+ if (subcontext == nullptr || !enabled) {
+ return true;
+ }
+
+ if (kExportedActionableProperties.count(prop_name) == 1) {
+ return true;
+ }
+ for (const auto& prefix : kPartnerPrefixes) {
+ if (android::base::StartsWith(prop_name, prefix)) {
+ return true;
+ }
+ }
+ return false;
+}
+
Result<Success> Action::ParsePropertyTrigger(const std::string& trigger) {
const static std::string prop_str("property:");
std::string prop_name(trigger.substr(prop_str.length()));
@@ -145,6 +165,10 @@
std::string prop_value(prop_name.substr(equal_pos + 1));
prop_name.erase(equal_pos);
+ if (!IsActionableProperty(subcontext_, prop_name)) {
+ return Error() << "unexported property tigger found: " << prop_name;
+ }
+
if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) {
return Error() << "multiple property triggers found for same property";
}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 7aa94b0..79f7f25 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -58,6 +58,7 @@
#include "init.h"
#include "persistent_properties.h"
+#include "property_type.h"
#include "util.h"
using android::base::ReadFileToString;
@@ -95,14 +96,9 @@
LOG(FATAL) << "Failed to load serialized property info file";
}
}
-static bool check_mac_perms(const std::string& name, char* sctx, struct ucred* cr) {
- if (!sctx) {
- return false;
- }
-
- const char* target_context = nullptr;
- property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
- if (target_context == nullptr) {
+static bool CheckMacPerms(const std::string& name, const char* target_context,
+ const char* source_context, struct ucred* cr) {
+ if (!target_context || !source_context) {
return false;
}
@@ -111,29 +107,12 @@
audit_data.name = name.c_str();
audit_data.cr = cr;
- bool has_access =
- (selinux_check_access(sctx, target_context, "property_service", "set", &audit_data) == 0);
+ bool has_access = (selinux_check_access(source_context, target_context, "property_service",
+ "set", &audit_data) == 0);
return has_access;
}
-static int check_control_mac_perms(const char *name, char *sctx, struct ucred *cr)
-{
- /*
- * Create a name prefix out of ctl.<service name>
- * The new prefix allows the use of the existing
- * property service backend labeling while avoiding
- * mislabels based on true property prefixes.
- */
- char ctl_name[PROP_VALUE_MAX+4];
- int ret = snprintf(ctl_name, sizeof(ctl_name), "ctl.%s", name);
-
- if (ret < 0 || (size_t) ret >= sizeof(ctl_name))
- return 0;
-
- return check_mac_perms(ctl_name, sctx, cr);
-}
-
bool is_legal_property_name(const std::string& name) {
size_t namelen = name.size();
@@ -422,52 +401,70 @@
struct ucred cr = socket.cred();
char* source_ctx = nullptr;
getpeercon(socket.socket(), &source_ctx);
+ std::string source_context = source_ctx;
+ freecon(source_ctx);
if (StartsWith(name, "ctl.")) {
- if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
+ // ctl. properties have their name ctl.<action> and their value is the name of the service to
+ // apply that action to. Permissions for these actions are based on the service, so we must
+ // create a fake name of ctl.<service> to check permissions.
+ auto control_string = "ctl." + value;
+ const char* target_context = nullptr;
+ const char* type = nullptr;
+ property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
+ if (!CheckMacPerms(control_string, target_context, source_context.c_str(), &cr)) {
+ LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
+ << " service ctl [" << value << "]"
+ << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
+ if (!legacy_protocol) {
+ socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
+ }
+ return;
+ }
+
handle_control_message(name.c_str() + 4, value.c_str());
if (!legacy_protocol) {
- socket.SendUint32(PROP_SUCCESS);
+ socket.SendUint32(PROP_SUCCESS);
}
- } else {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
- << " service ctl [" << value << "]"
- << " uid:" << cr.uid
- << " gid:" << cr.gid
- << " pid:" << cr.pid;
- if (!legacy_protocol) {
- socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
- }
- }
} else {
- if (check_mac_perms(name, source_ctx, &cr)) {
+ const char* target_context = nullptr;
+ const char* type = nullptr;
+ property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
+ if (!CheckMacPerms(name, target_context, source_context.c_str(), &cr)) {
+ LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid
+ << " name:" << name;
+ if (!legacy_protocol) {
+ socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
+ }
+ return;
+ }
+ if (type == nullptr || !CheckType(type, value)) {
+ LOG(ERROR) << "sys_prop(" << cmd_name << "): type check failed, type: '"
+ << (type ?: "(null)") << "' value: '" << value << "'";
+ if (!legacy_protocol) {
+ socket.SendUint32(PROP_ERROR_INVALID_VALUE);
+ }
+ return;
+ }
// sys.powerctl is a special property that is used to make the device reboot. We want to log
// any process that sets this property to be able to accurately blame the cause of a shutdown.
if (name == "sys.powerctl") {
- std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
- std::string process_cmdline;
- std::string process_log_string;
- if (ReadFileToString(cmdline_path, &process_cmdline)) {
- // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path.
- process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
- }
- LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
- << process_log_string;
+ std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
+ std::string process_cmdline;
+ std::string process_log_string;
+ if (ReadFileToString(cmdline_path, &process_cmdline)) {
+ // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path.
+ process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
+ }
+ LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
+ << process_log_string;
}
uint32_t result = property_set(name, value);
if (!legacy_protocol) {
- socket.SendUint32(result);
+ socket.SendUint32(result);
}
- } else {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name;
- if (!legacy_protocol) {
- socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
- }
- }
}
-
- freecon(source_ctx);
}
static void handle_property_set_fd() {
@@ -764,9 +761,10 @@
}
LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
}
+
auto serialized_contexts = std::string();
auto error = std::string();
- if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "\\s*", &serialized_contexts,
+ if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
&error)) {
LOG(ERROR) << "Unable to serialize property contexts: " << error;
return;
diff --git a/init/property_type.cpp b/init/property_type.cpp
new file mode 100644
index 0000000..249b12b
--- /dev/null
+++ b/init/property_type.cpp
@@ -0,0 +1,81 @@
+//
+// Copyright (C) 2017 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 "property_type.h"
+
+#include <android-base/parsedouble.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+using android::base::ParseDouble;
+using android::base::ParseInt;
+using android::base::ParseUint;
+using android::base::Split;
+
+namespace android {
+namespace init {
+
+bool CheckType(const std::string& type_string, const std::string& value) {
+ auto type_strings = Split(type_string, " ");
+ if (type_strings.empty()) {
+ return false;
+ }
+ auto type = type_strings[0];
+
+ if (type == "string") {
+ return true;
+ }
+ if (type == "bool") {
+ return value == "true" || value == "false" || value == "1" || value == "0";
+ }
+ if (type == "int") {
+ int64_t parsed;
+ return ParseInt(value, &parsed);
+ }
+ if (type == "uint") {
+ uint64_t parsed;
+ if (value.empty() || value.front() == '-') {
+ return false;
+ }
+ return ParseUint(value, &parsed);
+ }
+ if (type == "double") {
+ double parsed;
+ return ParseDouble(value.c_str(), &parsed);
+ }
+ if (type == "size") {
+ auto it = value.begin();
+ while (it != value.end() && isdigit(*it)) {
+ it++;
+ }
+ if (it == value.begin() || it == value.end() || (*it != 'g' && *it != 'k' && *it != 'm')) {
+ return false;
+ }
+ it++;
+ return it == value.end();
+ }
+ if (type == "enum") {
+ for (auto it = std::next(type_strings.begin()); it != type_strings.end(); ++it) {
+ if (*it == value) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/property_type.h b/init/property_type.h
new file mode 100644
index 0000000..c889e16
--- /dev/null
+++ b/init/property_type.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef _INIT_PROPERTY_TYPE_H
+#define _INIT_PROPERTY_TYPE_H
+
+#include <string>
+
+namespace android {
+namespace init {
+
+bool CheckType(const std::string& type_string, const std::string& value);
+
+} // namespace init
+} // namespace android
+
+#endif
diff --git a/init/property_type_test.cpp b/init/property_type_test.cpp
new file mode 100644
index 0000000..068bccc
--- /dev/null
+++ b/init/property_type_test.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 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 "property_type.h"
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace init {
+
+TEST(property_type, CheckType_string) {
+ EXPECT_TRUE(CheckType("string", ""));
+ EXPECT_TRUE(CheckType("string", "-234"));
+ EXPECT_TRUE(CheckType("string", "234"));
+ EXPECT_TRUE(CheckType("string", "true"));
+ EXPECT_TRUE(CheckType("string", "false"));
+ EXPECT_TRUE(CheckType("string", "45645634563456345634563456"));
+ EXPECT_TRUE(CheckType("string", "some other string"));
+}
+
+TEST(property_type, CheckType_int) {
+ EXPECT_FALSE(CheckType("int", ""));
+ EXPECT_FALSE(CheckType("int", "abc"));
+ EXPECT_FALSE(CheckType("int", "-abc"));
+ EXPECT_TRUE(CheckType("int", "0"));
+ EXPECT_TRUE(CheckType("int", std::to_string(std::numeric_limits<int64_t>::min())));
+ EXPECT_TRUE(CheckType("int", std::to_string(std::numeric_limits<int64_t>::max())));
+ EXPECT_TRUE(CheckType("int", "123"));
+ EXPECT_TRUE(CheckType("int", "-123"));
+}
+
+TEST(property_type, CheckType_uint) {
+ EXPECT_FALSE(CheckType("uint", ""));
+ EXPECT_FALSE(CheckType("uint", "abc"));
+ EXPECT_FALSE(CheckType("uint", "-abc"));
+ EXPECT_TRUE(CheckType("uint", "0"));
+ EXPECT_TRUE(CheckType("uint", std::to_string(std::numeric_limits<uint64_t>::max())));
+ EXPECT_TRUE(CheckType("uint", "123"));
+ EXPECT_FALSE(CheckType("uint", "-123"));
+}
+
+TEST(property_type, CheckType_double) {
+ EXPECT_FALSE(CheckType("double", ""));
+ EXPECT_FALSE(CheckType("double", "abc"));
+ EXPECT_FALSE(CheckType("double", "-abc"));
+ EXPECT_TRUE(CheckType("double", "0.0"));
+ EXPECT_TRUE(CheckType("double", std::to_string(std::numeric_limits<double>::min())));
+ EXPECT_TRUE(CheckType("double", std::to_string(std::numeric_limits<double>::max())));
+ EXPECT_TRUE(CheckType("double", "123.1"));
+ EXPECT_TRUE(CheckType("double", "-123.1"));
+}
+
+TEST(property_type, CheckType_size) {
+ EXPECT_FALSE(CheckType("size", ""));
+ EXPECT_FALSE(CheckType("size", "ab"));
+ EXPECT_FALSE(CheckType("size", "abcd"));
+ EXPECT_FALSE(CheckType("size", "0"));
+
+ EXPECT_TRUE(CheckType("size", "512g"));
+ EXPECT_TRUE(CheckType("size", "512k"));
+ EXPECT_TRUE(CheckType("size", "512m"));
+
+ EXPECT_FALSE(CheckType("size", "512gggg"));
+ EXPECT_FALSE(CheckType("size", "512mgk"));
+ EXPECT_FALSE(CheckType("size", "g"));
+ EXPECT_FALSE(CheckType("size", "m"));
+}
+
+TEST(property_type, CheckType_enum) {
+ EXPECT_FALSE(CheckType("enum abc", ""));
+ EXPECT_FALSE(CheckType("enum abc", "ab"));
+ EXPECT_FALSE(CheckType("enum abc", "abcd"));
+ EXPECT_FALSE(CheckType("enum 123 456 789", "0"));
+
+ EXPECT_TRUE(CheckType("enum abc", "abc"));
+ EXPECT_TRUE(CheckType("enum 123 456 789", "123"));
+ EXPECT_TRUE(CheckType("enum 123 456 789", "456"));
+ EXPECT_TRUE(CheckType("enum 123 456 789", "789"));
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/stable_properties.h b/init/stable_properties.h
new file mode 100644
index 0000000..8219838
--- /dev/null
+++ b/init/stable_properties.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef _INIT_STABLE_PROPERTIES_H
+#define _INIT_STABLE_PROPERTIES_H
+
+#include <set>
+#include <string>
+
+namespace android {
+namespace init {
+
+static constexpr const char* kPartnerPrefixes[] = {
+ "init.svc.vendor.", "ro.vendor.", "persist.vendor.", "vendor.",
+ "init.svc.odm.", "ro.odm.", "persist.odm.", "odm.",
+};
+
+static const std::set<std::string> kExportedActionableProperties = {
+ "init.svc.zygote", "persist.bluetooth.btsnoopenable",
+ "persist.sys.crash_rcu", "persist.sys.zram_enabled",
+ "ro.boot.revision", "ro.bootmode",
+ "ro.build.type", "sys.boot_completed",
+ "sys.retaildemo.enabled", "sys.shutdown.requested",
+ "sys.usb.config", "sys.usb.configfs",
+ "sys.usb.ffs.mtp.ready", "sys.usb.ffs.ready",
+ "sys.user.0.ce_available", "sys.vdso",
+ "vts.native_server.on",
+};
+
+} // namespace init
+} // namespace android
+
+#endif
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index b0345a1..b62ee16 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -70,6 +70,7 @@
back_frame->rel_pc = frame->rel_pc;
back_frame->pc = frame->pc;
back_frame->sp = frame->sp;
+ back_frame->dex_pc = frame->dex_pc;
back_frame->func_name = demangle(frame->function_name.c_str());
back_frame->func_offset = frame->function_offset;
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 5922664..f34fb2d 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -81,6 +81,7 @@
uintptr_t rel_pc; // The relative pc.
uintptr_t sp; // The top of the stack.
size_t stack_size; // The size of the stack, zero indicate an unknown stack size.
+ uint64_t dex_pc; // If non-zero, the Dex PC for the ART interpreter.
backtrace_map_t map; // The map associated with the given pc.
std::string func_name; // The function name associated with this pc, NULL if not found.
uintptr_t func_offset; // pc relative to the start of the function, only valid if func_name is not NULL.
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 0954187..91d855b 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -34,6 +34,8 @@
namespace unwindstack {
+constexpr uint64_t DEX_PC_REG = 0x20444558;
+
DwarfSection::DwarfSection(Memory* memory) : memory_(memory), last_error_(DWARF_ERROR_NONE) {}
const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
@@ -98,6 +100,84 @@
}
template <typename AddressType>
+struct EvalInfo {
+ const dwarf_loc_regs_t* loc_regs;
+ const DwarfCie* cie;
+ RegsImpl<AddressType>* cur_regs;
+ Memory* regular_memory;
+ AddressType cfa;
+ bool return_address_undefined = false;
+ uint64_t reg_map = 0;
+ AddressType reg_values[64];
+};
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint32_t reg,
+ AddressType* reg_ptr, void* info) {
+ EvalInfo<AddressType>* eval_info = reinterpret_cast<EvalInfo<AddressType>*>(info);
+ Memory* regular_memory = eval_info->regular_memory;
+ switch (loc->type) {
+ case DWARF_LOCATION_OFFSET:
+ if (!regular_memory->ReadFully(eval_info->cfa + loc->values[0], reg_ptr, sizeof(AddressType))) {
+ last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ return false;
+ }
+ break;
+ case DWARF_LOCATION_VAL_OFFSET:
+ *reg_ptr = eval_info->cfa + loc->values[0];
+ break;
+ case DWARF_LOCATION_REGISTER: {
+ uint32_t cur_reg = loc->values[0];
+ if (cur_reg >= eval_info->cur_regs->total_regs()) {
+ last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+ AddressType* cur_reg_ptr = &(*eval_info->cur_regs)[cur_reg];
+ const auto& entry = eval_info->loc_regs->find(cur_reg);
+ if (entry != eval_info->loc_regs->end()) {
+ if (!(eval_info->reg_map & (1 << cur_reg))) {
+ eval_info->reg_map |= 1 << cur_reg;
+ eval_info->reg_values[cur_reg] = *cur_reg_ptr;
+ if (!EvalRegister(&entry->second, cur_reg, cur_reg_ptr, eval_info)) {
+ return false;
+ }
+ }
+
+ // Use the register value from before any evaluations.
+ *reg_ptr = eval_info->reg_values[cur_reg] + loc->values[1];
+ } else {
+ *reg_ptr = *cur_reg_ptr + loc->values[1];
+ }
+ break;
+ }
+ case DWARF_LOCATION_EXPRESSION:
+ case DWARF_LOCATION_VAL_EXPRESSION: {
+ AddressType value;
+ if (!EvalExpression(*loc, eval_info->cie->version, regular_memory, &value)) {
+ return false;
+ }
+ if (loc->type == DWARF_LOCATION_EXPRESSION) {
+ if (!regular_memory->ReadFully(value, reg_ptr, sizeof(AddressType))) {
+ last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ return false;
+ }
+ } else {
+ *reg_ptr = value;
+ }
+ break;
+ }
+ case DWARF_LOCATION_UNDEFINED:
+ if (reg == eval_info->cie->return_address_register) {
+ eval_info->return_address_undefined = true;
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
+
+template <typename AddressType>
bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_memory,
const dwarf_loc_regs_t& loc_regs, Regs* regs,
bool* finished) {
@@ -114,9 +194,13 @@
return false;
}
+ // Always set the dex pc to zero when evaluating.
+ cur_regs->set_dex_pc(0);
+
AddressType prev_cfa = regs->sp();
- AddressType cfa;
+ EvalInfo<AddressType> eval_info{
+ .loc_regs = &loc_regs, .cie = cie, .regular_memory = regular_memory, .cur_regs = cur_regs};
const DwarfLocation* loc = &cfa_entry->second;
// Only a few location types are valid for the cfa.
switch (loc->type) {
@@ -129,11 +213,11 @@
// pointer register does not have any associated location
// information, use the current cfa value.
if (regs->sp_reg() == loc->values[0] && loc_regs.count(regs->sp_reg()) == 0) {
- cfa = prev_cfa;
+ eval_info.cfa = prev_cfa;
} else {
- cfa = (*cur_regs)[loc->values[0]];
+ eval_info.cfa = (*cur_regs)[loc->values[0]];
}
- cfa += loc->values[1];
+ eval_info.cfa += loc->values[1];
break;
case DWARF_LOCATION_EXPRESSION:
case DWARF_LOCATION_VAL_EXPRESSION: {
@@ -142,12 +226,12 @@
return false;
}
if (loc->type == DWARF_LOCATION_EXPRESSION) {
- if (!regular_memory->ReadFully(value, &cfa, sizeof(AddressType))) {
+ if (!regular_memory->ReadFully(value, &eval_info.cfa, sizeof(AddressType))) {
last_error_ = DWARF_ERROR_MEMORY_INVALID;
return false;
}
} else {
- cfa = value;
+ eval_info.cfa = value;
}
break;
}
@@ -156,81 +240,38 @@
return false;
}
- // This code is not guaranteed to work in cases where a register location
- // is a double indirection to the actual value. For example, if r3 is set
- // to r5 + 4, and r5 is set to CFA + 4, then this won't necessarily work
- // because it does not guarantee that r5 is evaluated before r3.
- // Check that this case does not exist, and error if it does.
- bool return_address_undefined = false;
for (const auto& entry : loc_regs) {
- uint16_t reg = entry.first;
+ uint32_t reg = entry.first;
// Already handled the CFA register.
if (reg == CFA_REG) continue;
- if (reg >= cur_regs->total_regs()) {
- // Skip this unknown register.
+ AddressType* reg_ptr;
+ AddressType dex_pc = 0;
+ if (reg == DEX_PC_REG) {
+ // Special register that indicates this is a dex pc.
+ dex_pc = 0;
+ reg_ptr = &dex_pc;
+ } else if (reg >= cur_regs->total_regs() || eval_info.reg_map & (1 << reg)) {
+ // Skip this unknown register, or a register that has already been
+ // processed.
continue;
+ } else {
+ reg_ptr = &(*cur_regs)[reg];
+ eval_info.reg_map |= 1 << reg;
+ eval_info.reg_values[reg] = *reg_ptr;
}
- const DwarfLocation* loc = &entry.second;
- switch (loc->type) {
- case DWARF_LOCATION_OFFSET:
- if (!regular_memory->ReadFully(cfa + loc->values[0], &(*cur_regs)[reg],
- sizeof(AddressType))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
- return false;
- }
- break;
- case DWARF_LOCATION_VAL_OFFSET:
- (*cur_regs)[reg] = cfa + loc->values[0];
- break;
- case DWARF_LOCATION_REGISTER: {
- uint16_t cur_reg = loc->values[0];
- if (cur_reg >= cur_regs->total_regs()) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- if (loc_regs.find(cur_reg) != loc_regs.end()) {
- // This is a double indirection, a register definition references
- // another register which is also defined as something other
- // than a register.
- log(0,
- "Invalid indirection: register %d references register %d which is "
- "not a plain register.\n",
- reg, cur_reg);
- last_error_ = DWARF_ERROR_ILLEGAL_STATE;
- return false;
- }
- (*cur_regs)[reg] = (*cur_regs)[cur_reg] + loc->values[1];
- break;
- }
- case DWARF_LOCATION_EXPRESSION:
- case DWARF_LOCATION_VAL_EXPRESSION: {
- AddressType value;
- if (!EvalExpression(*loc, cie->version, regular_memory, &value)) {
- return false;
- }
- if (loc->type == DWARF_LOCATION_EXPRESSION) {
- if (!regular_memory->ReadFully(value, &(*cur_regs)[reg], sizeof(AddressType))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
- return false;
- }
- } else {
- (*cur_regs)[reg] = value;
- }
- break;
- }
- case DWARF_LOCATION_UNDEFINED:
- if (reg == cie->return_address_register) {
- return_address_undefined = true;
- }
- default:
- break;
+ if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
+ return false;
+ }
+
+ if (reg == DEX_PC_REG) {
+ cur_regs->set_dex_pc(dex_pc);
}
}
// Find the return address location.
- if (return_address_undefined) {
+ if (eval_info.return_address_undefined) {
cur_regs->set_pc(0);
} else {
cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
@@ -239,7 +280,7 @@
// If the pc was set to zero, consider this the final frame.
*finished = (cur_regs->pc() == 0) ? true : false;
- cur_regs->set_sp(cfa);
+ cur_regs->set_sp(eval_info.cfa);
return true;
}
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index b0a1c0c..d711772 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -40,6 +40,7 @@
frame->num = frame_num;
frame->sp = regs_->sp();
frame->rel_pc = adjusted_rel_pc;
+ frame->dex_pc = regs_->dex_pc();
if (map_info == nullptr) {
frame->pc = regs_->pc();
diff --git a/libunwindstack/include/unwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h
index 3467e6a..0881182 100644
--- a/libunwindstack/include/unwindstack/DwarfLocation.h
+++ b/libunwindstack/include/unwindstack/DwarfLocation.h
@@ -38,7 +38,7 @@
uint64_t values[2];
};
-typedef std::unordered_map<uint16_t, DwarfLocation> dwarf_loc_regs_t;
+typedef std::unordered_map<uint32_t, DwarfLocation> dwarf_loc_regs_t;
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index 10be6b4..e0004aa 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -132,6 +132,8 @@
const DwarfFde* GetFdeFromIndex(size_t index) override;
+ bool EvalRegister(const DwarfLocation* loc, uint32_t reg, AddressType* reg_ptr, void* info);
+
bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs,
Regs* regs, bool* finished) override;
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 1904d4d..a5ba7a0 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -57,6 +57,9 @@
virtual uint64_t pc() = 0;
virtual uint64_t sp() = 0;
+ uint64_t dex_pc() { return dex_pc_; }
+ void set_dex_pc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
+
virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0;
virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0;
@@ -79,6 +82,7 @@
uint16_t total_regs_;
uint16_t sp_reg_;
Location return_loc_;
+ uint64_t dex_pc_ = 0;
};
template <typename AddressType>
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 5adec4f..32858ae 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -41,6 +41,7 @@
uint64_t rel_pc;
uint64_t pc;
uint64_t sp;
+ uint64_t dex_pc;
std::string function_name;
uint64_t function_offset;
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index d54b0bf..dfd2ce0 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -266,13 +266,67 @@
regs.set_pc(0x100);
regs.set_sp(0x2000);
+ regs[1] = 0x100;
+ regs[3] = 0x300;
regs[8] = 0x10;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 0}};
- loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 0}};
+ loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 1}};
+ loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 2}};
bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error());
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_EQ(0x301U, regs[1]);
+ EXPECT_EQ(0x300U, regs[3]);
+ EXPECT_EQ(0x10U, regs[8]);
+ EXPECT_EQ(0x102U, regs[9]);
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, Eval_register_reference_chain) {
+ DwarfCie cie{.return_address_register = 5};
+ RegsImplFake<TypeParam> regs(10, 9);
+ dwarf_loc_regs_t loc_regs;
+
+ regs.set_pc(0x100);
+ regs.set_sp(0x2000);
+ regs[0] = 0x10;
+ regs[1] = 0x20;
+ regs[2] = 0x30;
+ regs[3] = 0x40;
+ regs[4] = 0x50;
+ regs[5] = 0x60;
+ regs[8] = 0x20;
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+ loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 1}};
+ loc_regs[2] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 2}};
+ loc_regs[3] = DwarfLocation{DWARF_LOCATION_REGISTER, {2, 3}};
+ loc_regs[4] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 4}};
+ loc_regs[5] = DwarfLocation{DWARF_LOCATION_REGISTER, {4, 5}};
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_EQ(0x10U, regs[0]);
+ EXPECT_EQ(0x11U, regs[1]);
+ EXPECT_EQ(0x22U, regs[2]);
+ EXPECT_EQ(0x33U, regs[3]);
+ EXPECT_EQ(0x44U, regs[4]);
+ EXPECT_EQ(0x55U, regs[5]);
+ EXPECT_EQ(0x20U, regs[8]);
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, Eval_dex_pc) {
+ DwarfCie cie{.return_address_register = 5};
+ RegsImplFake<TypeParam> regs(10, 9);
+ dwarf_loc_regs_t loc_regs;
+
+ regs.set_pc(0x100);
+ regs.set_sp(0x2000);
+ regs[0] = 0x10;
+ regs[8] = 0x20;
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+ loc_regs[0x20444558] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 1}};
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_EQ(0x10U, regs[0]);
+ EXPECT_EQ(0x20U, regs[8]);
+ EXPECT_EQ(0x11U, regs.dex_pc());
}
TYPED_TEST_P(DwarfSectionImplTest, Eval_invalid_register) {
@@ -840,11 +894,11 @@
DwarfSectionImplTest, Eval_cfa_expr_eval_fail, Eval_cfa_expr_no_stack,
Eval_cfa_expr_is_register, Eval_cfa_expr, Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa,
Eval_cfa_bad, Eval_cfa_register_prev, Eval_cfa_register_from_value, Eval_double_indirection,
- Eval_invalid_register, Eval_different_reg_locations, Eval_return_address_undefined,
- Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
- GetCie_fail_should_not_cache, GetCie_32_version_check, GetCie_negative_data_alignment_factor,
- GetCie_64_no_augment, GetCie_augment, GetCie_version_3, GetCie_version_4,
- GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
+ Eval_register_reference_chain, Eval_dex_pc, Eval_invalid_register, Eval_different_reg_locations,
+ Eval_return_address_undefined, Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc,
+ Eval_reg_expr, Eval_reg_val_expr, GetCie_fail_should_not_cache, GetCie_32_version_check,
+ GetCie_negative_data_alignment_factor, GetCie_64_no_augment, GetCie_augment, GetCie_version_3,
+ GetCie_version_4, GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
GetFdeFromOffset_32_no_augment_non_zero_segment_size, GetFdeFromOffset_32_augment,
GetFdeFromOffset_64_no_augment, GetFdeFromOffset_cached, GetCfaLocationInfo_cie_not_cached,
GetCfaLocationInfo_cie_cached, Log);
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 07e48af..33e5527 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -96,8 +96,13 @@
unwinder.Unwind();
// Print the frames.
+ const std::vector<unwindstack::FrameData>& frames = unwinder.frames();
for (size_t i = 0; i < unwinder.NumFrames(); i++) {
printf("%s\n", unwinder.FormatFrame(i).c_str());
+ const unwindstack::FrameData* frame = &frames[i];
+ if (frame->dex_pc != 0) {
+ printf(" dex pc %" PRIx64 "\n", frame->dex_pc);
+ }
}
}
diff --git a/property_service/libpropertyinfoserializer/property_info_file.cpp b/property_service/libpropertyinfoserializer/property_info_file.cpp
index bf96d88..2cdc62d 100644
--- a/property_service/libpropertyinfoserializer/property_info_file.cpp
+++ b/property_service/libpropertyinfoserializer/property_info_file.cpp
@@ -1,9 +1,26 @@
+//
+// Copyright (C) 2017 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 <property_info_serializer/property_info_serializer.h>
#include <android-base/strings.h>
#include "space_tokenizer.h"
+using android::base::Join;
using android::base::Split;
using android::base::StartsWith;
using android::base::Trim;
@@ -11,6 +28,34 @@
namespace android {
namespace properties {
+namespace {
+
+bool IsTypeValid(const std::vector<std::string>& type_strings) {
+ if (type_strings.empty()) {
+ return false;
+ }
+
+ // There must be at least one string following 'enum'
+ if (type_strings[0] == "enum") {
+ return type_strings.size() > 1;
+ }
+
+ // There should not be any string following any other types.
+ if (type_strings.size() != 1) {
+ return false;
+ }
+
+ // Check that the type matches one of remaining valid types.
+ static const char* const no_parameter_types[] = {"string", "bool", "int",
+ "uint", "double", "size"};
+ for (const auto& type : no_parameter_types) {
+ if (type_strings[0] == type) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool ParsePropertyInfoLine(const std::string& line, PropertyInfoEntry* out, std::string* error) {
auto tokenizer = SpaceTokenizer(line);
@@ -26,14 +71,28 @@
return false;
}
- // It is not an error to not find these, as older files will not contain them.
+ // It is not an error to not find exact_match or a type, as older files will not contain them.
auto exact_match = tokenizer.GetNext();
- auto type = tokenizer.GetRemaining();
+ // We reformat type to be space deliminated regardless of the input whitespace for easier storage
+ // and subsequent parsing.
+ auto type_strings = std::vector<std::string>{};
+ auto type = tokenizer.GetNext();
+ while (!type.empty()) {
+ type_strings.emplace_back(type);
+ type = tokenizer.GetNext();
+ }
- *out = {property, context, type, exact_match == "exact"};
+ if (!type_strings.empty() && !IsTypeValid(type_strings)) {
+ *error = "Type '" + Join(type_strings, " ") + "' is not valid";
+ return false;
+ }
+
+ *out = {property, context, Join(type_strings, " "), exact_match == "exact"};
return true;
}
+} // namespace
+
void ParsePropertyInfoFile(const std::string& file_contents,
std::vector<PropertyInfoEntry>* property_infos,
std::vector<std::string>* errors) {
diff --git a/storaged/binder/android/os/IStoraged.aidl b/storaged/binder/android/os/IStoraged.aidl
index f81e904..0bcc70c 100644
--- a/storaged/binder/android/os/IStoraged.aidl
+++ b/storaged/binder/android/os/IStoraged.aidl
@@ -20,4 +20,5 @@
interface IStoraged {
void onUserStarted(int userId);
void onUserStopped(int userId);
+ int getRecentPerf();
}
\ No newline at end of file
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index c5cac27..7b27988 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -119,6 +119,8 @@
return storage_info->get_perf_history();
}
+ uint32_t get_recent_perf(void) { return storage_info->get_recent_perf(); }
+
map<uint64_t, struct uid_records> get_uid_records(
double hours, uint64_t threshold, bool force_report) {
return mUidm.dump(hours, threshold, force_report);
diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h
index 3a6a0d4..88a53de 100644
--- a/storaged/include/storaged_info.h
+++ b/storaged/include/storaged_info.h
@@ -78,6 +78,7 @@
void update_perf_history(uint32_t bw,
const time_point<system_clock>& tp);
vector<int> get_perf_history();
+ uint32_t get_recent_perf();
};
class emmc_info_t : public storage_info_t {
diff --git a/storaged/include/storaged_service.h b/storaged/include/storaged_service.h
index 05c3b94..7ec6864 100644
--- a/storaged/include/storaged_service.h
+++ b/storaged/include/storaged_service.h
@@ -39,6 +39,7 @@
binder::Status onUserStarted(int32_t userId);
binder::Status onUserStopped(int32_t userId);
+ binder::Status getRecentPerf(int32_t* _aidl_return);
};
class StoragedPrivateService : public BinderService<StoragedPrivateService>, public BnStoragedPrivate {
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index b6dd164..055f375 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -219,6 +219,13 @@
return ret;
}
+uint32_t storage_info_t::get_recent_perf() {
+ Mutex::Autolock _l(si_mutex);
+ if (recent_perf.size() == 0) return 0;
+ return accumulate(recent_perf.begin(), recent_perf.end(), recent_perf.size() / 2) /
+ recent_perf.size();
+}
+
void emmc_info_t::report()
{
if (!report_sysfs() && !report_debugfs())
diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp
index 3c790e6..17ea25b 100644
--- a/storaged/storaged_service.cpp
+++ b/storaged/storaged_service.cpp
@@ -174,6 +174,16 @@
return binder::Status::ok();
}
+binder::Status StoragedService::getRecentPerf(int32_t* _aidl_return) {
+ uint32_t recent_perf = storaged_sp->get_recent_perf();
+ if (recent_perf > INT32_MAX) {
+ *_aidl_return = INT32_MAX;
+ } else {
+ *_aidl_return = static_cast<int32_t>(recent_perf);
+ }
+ return binder::Status::ok();
+}
+
status_t StoragedPrivateService::start() {
return BinderService<StoragedPrivateService>::publish();
}