Merge "[vts-core] Add VtsKernelBinderTest to vts-core suite."
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index db297a0..e048a19 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -7,6 +7,7 @@
cmds/idlcli/
include/input/
libs/binder/ndk/
+ libs/binderthreadstate/
libs/graphicsenv/
libs/gui/
libs/input/
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 4d98520..310b5ce 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -135,6 +135,11 @@
static char cmdline_buf[16384] = "(unknown)";
static const char *dump_traces_path = nullptr;
static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
+// Because telephony reports are significantly faster to collect (< 10 seconds vs. > 2 minutes),
+// it's often the case that they time out far too quickly for consent with such a hefty dialog for
+// the user to read. For telephony reports only, we increase the default timeout to 2 minutes to
+// roughly match full reports' durations.
+static const uint64_t TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS = 2 * 60 * 1000;
// TODO: variables and functions below should be part of dumpstate object
@@ -149,6 +154,7 @@
#define RECOVERY_DATA_DIR "/data/misc/recovery"
#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
#define LOGPERSIST_DATA_DIR "/data/misc/logd"
+#define PREREBOOT_DATA_DIR "/data/misc/prereboot"
#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
@@ -890,6 +896,14 @@
CommandOptions::WithTimeoutInMs(timeout_ms).Build());
}
+static void DoRadioLogcat() {
+ unsigned long timeout_ms = logcat_timeout({"radio"});
+ RunCommand(
+ "RADIO LOG",
+ {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
+}
+
static void DoLogcat() {
unsigned long timeout_ms;
// DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
@@ -908,11 +922,7 @@
"STATS LOG",
{"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
- timeout_ms = logcat_timeout({"radio"});
- RunCommand(
- "RADIO LOG",
- {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
- CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
+ DoRadioLogcat();
RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
@@ -1413,11 +1423,14 @@
RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
/* Binder state is expensive to look at as it uses a lot of memory. */
- DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
- DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
- DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
- DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
- DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
+ std::string binder_logs_dir = access("/dev/binderfs/binder_logs", R_OK) ?
+ "/sys/kernel/debug/binder" : "/dev/binderfs/binder_logs";
+
+ DumpFile("BINDER FAILED TRANSACTION LOG", binder_logs_dir + "/failed_transaction_log");
+ DumpFile("BINDER TRANSACTION LOG", binder_logs_dir + "/transaction_log");
+ DumpFile("BINDER TRANSACTIONS", binder_logs_dir + "/transactions");
+ DumpFile("BINDER STATS", binder_logs_dir + "/stats");
+ DumpFile("BINDER STATE", binder_logs_dir + "/state");
/* Add window and surface trace files. */
if (!PropertiesHelper::IsUserBuild()) {
@@ -1561,6 +1574,7 @@
ds.AddDir(PROFILE_DATA_DIR_CUR, true);
ds.AddDir(PROFILE_DATA_DIR_REF, true);
}
+ ds.AddDir(PREREBOOT_DATA_DIR, false);
add_mountinfo();
DumpIpTablesAsRoot();
DumpDynamicPartitionInfo();
@@ -1599,8 +1613,10 @@
return status;
}
-// This method collects common dumpsys for telephony and wifi
-static void DumpstateRadioCommon() {
+// This method collects common dumpsys for telephony and wifi. Typically, wifi
+// reports are fine to include all information, but telephony reports on user
+// builds need to strip some content (see DumpstateTelephonyOnly).
+static void DumpstateRadioCommon(bool include_sensitive_info = true) {
DumpIpTablesAsRoot();
ds.AddDir(LOGPERSIST_DATA_DIR, false);
@@ -1609,26 +1625,51 @@
return;
}
- do_dmesg();
- DoLogcat();
+ // We need to be picky about some stuff for telephony reports on user builds.
+ if (!include_sensitive_info) {
+ // Only dump the radio log buffer (other buffers and dumps contain too much unrelated info).
+ DoRadioLogcat();
+ } else {
+ // Contains various system properties and process startup info.
+ do_dmesg();
+ // Logs other than the radio buffer may contain package/component names and potential PII.
+ DoLogcat();
+ // Too broad for connectivity problems.
+ DoKmsg();
+ // Contains unrelated hardware info (camera, NFC, biometrics, ...).
+ DumpHals();
+ }
+
DumpPacketStats();
- DoKmsg();
DumpIpAddrAndRules();
dump_route_tables();
- DumpHals();
-
RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
CommandOptions::WithTimeout(10).Build());
}
-// This method collects dumpsys for telephony debugging only
+// We use "telephony" here for legacy reasons, though this now really means "connectivity" (cellular
+// + wifi + networking). This method collects dumpsys for connectivity debugging only. General rules
+// for what can be included on user builds: all reported information MUST directly relate to
+// connectivity debugging or customer support and MUST NOT contain unrelated personally identifiable
+// information. This information MUST NOT identify user-installed packages (UIDs are OK, package
+// names are not), and MUST NOT contain logs of user application traffic.
+// TODO(b/148168577) rename this and other related fields/methods to "connectivity" instead.
static void DumpstateTelephonyOnly() {
DurationReporter duration_reporter("DUMPSTATE");
+
const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
- DumpstateRadioCommon();
+ const bool include_sensitive_info = !PropertiesHelper::IsUserBuild();
- RunCommand("SYSTEM PROPERTIES", {"getprop"});
+ DumpstateRadioCommon(include_sensitive_info);
+
+ if (include_sensitive_info) {
+ // Contains too much unrelated PII, and given the unstructured nature of sysprops, we can't
+ // really cherrypick all of the connectivity-related ones. Apps generally have no business
+ // reading these anyway, and there should be APIs to supply the info in a more app-friendly
+ // way.
+ RunCommand("SYSTEM PROPERTIES", {"getprop"});
+ }
printf("========================================================\n");
printf("== Android Framework Services\n");
@@ -1636,15 +1677,28 @@
RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
- RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
- SEC_TO_MSEC(10));
- RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
+ // TODO(b/146521742) build out an argument to include bound services here for user builds
RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
- RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
+ RunDumpsys("DUMPSYS", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
+ RunDumpsys("DUMPSYS", {"network_management"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
+ if (include_sensitive_info) {
+ // Contains raw IP addresses, omit from reports on user builds.
+ RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
+ // Contains raw destination IP/MAC addresses, omit from reports on user builds.
+ RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
+ // Contains package/component names, omit from reports on user builds.
+ RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
+ // Contains package names, but should be relatively simple to remove them (also contains
+ // UIDs already), omit from reports on user builds.
+ RunDumpsys("BATTERYSTATS", {"deviceidle"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
+ }
printf("========================================================\n");
printf("== Running Application Services\n");
@@ -1652,18 +1706,24 @@
RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
- printf("========================================================\n");
- printf("== Running Application Services (non-platform)\n");
- printf("========================================================\n");
+ if (include_sensitive_info) {
+ printf("========================================================\n");
+ printf("== Running Application Services (non-platform)\n");
+ printf("========================================================\n");
- RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
- DUMPSYS_COMPONENTS_OPTIONS);
+ // Contains package/component names and potential PII, omit from reports on user builds.
+ // To get dumps of the active CarrierService(s) on user builds, we supply an argument to the
+ // carrier_config dumpsys instead.
+ RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
+ DUMPSYS_COMPONENTS_OPTIONS);
- printf("========================================================\n");
- printf("== Checkins\n");
- printf("========================================================\n");
+ printf("========================================================\n");
+ printf("== Checkins\n");
+ printf("========================================================\n");
- RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
+ // Contains package/component names, omit from reports on user builds.
+ RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
+ }
printf("========================================================\n");
printf("== dumpstate: done (id %d)\n", ds.id_);
@@ -2275,6 +2335,7 @@
break;
case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
options->telephony_only = true;
+ options->do_progress_updates = true;
options->do_fb = false;
options->do_broadcast = true;
break;
@@ -2825,8 +2886,13 @@
if (consent_result == UserConsentResult::UNAVAILABLE) {
// User has not responded yet.
uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
- if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
- uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
+ // Telephony is a fast report type, particularly on user builds where information may be
+ // more aggressively limited. To give the user time to read the consent dialog, increase the
+ // timeout.
+ uint64_t timeout_ms = options_->telephony_only ? TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS
+ : USER_CONSENT_TIMEOUT_MS;
+ if (elapsed_ms < timeout_ms) {
+ uint delay_seconds = (timeout_ms - elapsed_ms) / 1000;
MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
sleep(delay_seconds);
}
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index cff1d43..99d482f 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -372,12 +372,12 @@
EXPECT_TRUE(options_.do_broadcast);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.telephony_only);
+ EXPECT_TRUE(options_.do_progress_updates);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
EXPECT_FALSE(options_.use_control_socket);
EXPECT_FALSE(options_.show_header_only);
- EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.use_socket);
}
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 5597bcd..a427c8d 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -29,6 +29,7 @@
#include <utils/Log.h>
#include <utils/Vector.h>
+#include <iostream>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
@@ -231,14 +232,14 @@
const size_t N = services.size();
if (N > 1) {
// first print a list of the current services
- aout << "Currently running services:" << endl;
+ std::cout << "Currently running services:" << std::endl;
for (size_t i=0; i<N; i++) {
sp<IBinder> service = sm_->checkService(services[i]);
if (service != nullptr) {
bool skipped = IsSkipped(skippedServices, services[i]);
- aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
+ std::cout << " " << services[i] << (skipped ? " (skipped)" : "") << std::endl;
}
}
}
@@ -263,10 +264,10 @@
asProto, elapsedDuration, bytesWritten);
if (status == TIMED_OUT) {
- aout << endl
+ std::cout << std::endl
<< "*** SERVICE '" << serviceName << "' DUMP TIMEOUT (" << timeoutArgMs
- << "ms) EXPIRED ***" << endl
- << endl;
+ << "ms) EXPIRED ***" << std::endl
+ << std::endl;
}
if (addSeparator) {
@@ -332,14 +333,14 @@
const Vector<String16>& args) {
sp<IBinder> service = sm_->checkService(serviceName);
if (service == nullptr) {
- aerr << "Can't find service: " << serviceName << endl;
+ std::cerr << "Can't find service: " << serviceName << std::endl;
return NAME_NOT_FOUND;
}
int sfd[2];
if (pipe(sfd) != 0) {
- aerr << "Failed to create pipe to dump service info for " << serviceName << ": "
- << strerror(errno) << endl;
+ std::cerr << "Failed to create pipe to dump service info for " << serviceName << ": "
+ << strerror(errno) << std::endl;
return -errno;
}
@@ -359,13 +360,13 @@
err = dumpPidToFd(service, remote_end);
break;
default:
- aerr << "Unknown dump type" << static_cast<int>(type) << endl;
+ std::cerr << "Unknown dump type" << static_cast<int>(type) << std::endl;
return;
}
if (err != OK) {
- aerr << "Error dumping service info status_t: " << statusToString(err) << " "
- << serviceName << endl;
+ std::cerr << "Error dumping service info status_t: " << statusToString(err) << " "
+ << serviceName << std::endl;
}
});
return OK;
@@ -422,8 +423,8 @@
int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
if (rc < 0) {
- aerr << "Error in poll while dumping service " << serviceName << " : "
- << strerror(errno) << endl;
+ std::cerr << "Error in poll while dumping service " << serviceName << " : "
+ << strerror(errno) << std::endl;
status = -errno;
break;
} else if (rc == 0) {
@@ -434,8 +435,8 @@
char buf[4096];
rc = TEMP_FAILURE_RETRY(read(redirectFd_.get(), buf, sizeof(buf)));
if (rc < 0) {
- aerr << "Failed to read while dumping service " << serviceName << ": "
- << strerror(errno) << endl;
+ std::cerr << "Failed to read while dumping service " << serviceName << ": "
+ << strerror(errno) << std::endl;
status = -errno;
break;
} else if (rc == 0) {
@@ -444,8 +445,8 @@
}
if (!WriteFully(fd, buf, rc)) {
- aerr << "Failed to write while dumping service " << serviceName << ": "
- << strerror(errno) << endl;
+ std::cerr << "Failed to write while dumping service " << serviceName << ": "
+ << strerror(errno) << std::endl;
status = -errno;
break;
}
diff --git a/cmds/dumpsys/main.cpp b/cmds/dumpsys/main.cpp
index 8ba0eba..fa4cc97 100644
--- a/cmds/dumpsys/main.cpp
+++ b/cmds/dumpsys/main.cpp
@@ -21,10 +21,9 @@
#include "dumpsys.h"
#include <binder/IServiceManager.h>
-#include <binder/TextOutput.h>
+#include <iostream>
#include <signal.h>
-#include <stdio.h>
using namespace android;
@@ -34,7 +33,7 @@
fflush(stdout);
if (sm == nullptr) {
ALOGE("Unable to get default service manager!");
- aerr << "dumpsys: Unable to get default service manager!" << endl;
+ std::cerr << "dumpsys: Unable to get default service manager!" << std::endl;
return 20;
}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index f95e445..70bbc33 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -299,9 +299,10 @@
// Namespace for Android Runtime flags applied during boot time.
static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
// Feature flag name for running the JIT in Zygote experiment, b/119800099.
-static const char* ENABLE_APEX_IMAGE = "enable_apex_image";
-// Location of the apex image.
-static const char* kApexImage = "/system/framework/apex.art";
+static const char* ENABLE_JITZYGOTE_IMAGE = "enable_apex_image";
+// Location of the JIT Zygote image.
+static const char* kJitZygoteImage =
+ "boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
// Phenotype property name for enabling profiling the boot class path.
static const char* PROFILE_BOOT_CLASS_PATH = "profilebootclasspath";
@@ -405,9 +406,9 @@
GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
std::string boot_image;
- std::string use_apex_image =
+ std::string use_jitzygote_image =
server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
- ENABLE_APEX_IMAGE,
+ ENABLE_JITZYGOTE_IMAGE,
/*default_value=*/ "");
std::string profile_boot_class_path = GetProperty("dalvik.vm.profilebootclasspath", "");
@@ -417,10 +418,10 @@
PROFILE_BOOT_CLASS_PATH,
/*default_value=*/ profile_boot_class_path);
- if (use_apex_image == "true" || profile_boot_class_path == "true") {
- boot_image = StringPrintf("-Ximage:%s", kApexImage);
+ if (use_jitzygote_image == "true" || profile_boot_class_path == "true") {
+ boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
} else {
- boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+ boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
}
// clang FORTIFY doesn't let us use strlen in constant array bounds, so we
@@ -513,7 +514,8 @@
AddArg(instruction_set_variant_arg);
AddArg(instruction_set_features_arg);
- AddRuntimeArg(boot_image);
+ AddArg(boot_image);
+
AddRuntimeArg(bootclasspath);
AddRuntimeArg(dex2oat_Xms_arg);
AddRuntimeArg(dex2oat_Xmx_arg);
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 3ff9d11..7c989f6 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -73,7 +73,7 @@
for (const apex::ApexFile& apex_file : active_packages) {
const std::string& package_path = apex_file.GetPath();
base::Result<void> status = apex::deactivatePackage(package_path);
- if (!status) {
+ if (!status.ok()) {
LOG(ERROR) << "Failed to deactivate " << package_path << ": "
<< status.error();
}
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 1ee3853..bc541f4 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -138,7 +138,6 @@
"liblog",
"libcutils",
"libutils",
- "libbinderthreadstate",
],
header_libs: [
@@ -171,7 +170,6 @@
name: "libbinder_aidl_test_stub",
local_include_dir: "aidl",
srcs: [":libbinder_aidl"],
- visibility: [":__subpackages__"],
vendor_available: true,
backend: {
java: {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 4981d7a..9e89c57 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "IPCThreadState"
#include <binder/IPCThreadState.h>
-#include <binderthreadstate/IPCThreadStateBase.h>
#include <binder/Binder.h>
#include <binder/BpBinder.h>
@@ -803,6 +802,7 @@
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
+ mServingStackPointer(nullptr),
mWorkSource(kUnsetWorkSource),
mPropagateWorkSource(false),
mStrictModePolicy(0),
@@ -813,7 +813,6 @@
clearCaller();
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
- mIPCThreadStateBase = IPCThreadStateBase::self();
}
IPCThreadState::~IPCThreadState()
@@ -1163,9 +1162,6 @@
"Not enough command data for brTRANSACTION");
if (result != NO_ERROR) break;
- //Record the fact that we're in a binder call.
- mIPCThreadStateBase->pushCurrentState(
- IPCThreadStateBase::CallState::BINDER);
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
@@ -1173,6 +1169,9 @@
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
+ const void* origServingStackPointer = mServingStackPointer;
+ mServingStackPointer = &origServingStackPointer; // anything on the stack
+
const pid_t origPid = mCallingPid;
const char* origSid = mCallingSid;
const uid_t origUid = mCallingUid;
@@ -1223,7 +1222,6 @@
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
- mIPCThreadStateBase->popCurrentState();
//ALOGI("<<<< TRANSACT from pid %d restore pid %d sid %s uid %d\n",
// mCallingPid, origPid, (origSid ? origSid : "<N/A>"), origUid);
@@ -1232,9 +1230,15 @@
if (error < NO_ERROR) reply.setError(error);
sendReply(reply, 0);
} else {
+ if (error != OK || reply.dataSize() != 0) {
+ alog << "oneway function results will be dropped but finished with status "
+ << statusToString(error)
+ << " and parcel size " << reply.dataSize() << endl;
+ }
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
}
+ mServingStackPointer = origServingStackPointer;
mCallingPid = origPid;
mCallingSid = origSid;
mCallingUid = origUid;
@@ -1290,8 +1294,8 @@
return result;
}
-bool IPCThreadState::isServingCall() const {
- return mIPCThreadStateBase->getCurrentBinderCallState() == IPCThreadStateBase::CallState::BINDER;
+const void* IPCThreadState::getServingStackPointer() const {
+ return mServingStackPointer;
}
void IPCThreadState::threadDestructor(void *st)
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 328653a..9888b59 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -85,31 +85,36 @@
sp<AidlServiceManager> mTheRealServiceManager;
};
-static Mutex gDefaultServiceManagerLock;
+static std::once_flag gSmOnce;
static sp<IServiceManager> gDefaultServiceManager;
sp<IServiceManager> defaultServiceManager()
{
-
- if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;
-
- {
- AutoMutex _l(gDefaultServiceManagerLock);
- while (gDefaultServiceManager == nullptr) {
- gDefaultServiceManager = new ServiceManagerShim(
- interface_cast<AidlServiceManager>(
- ProcessState::self()->getContextObject(nullptr)));
- if (gDefaultServiceManager == nullptr)
+ std::call_once(gSmOnce, []() {
+ sp<AidlServiceManager> sm = nullptr;
+ while (sm == nullptr) {
+ sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
+ if (sm == nullptr) {
sleep(1);
+ }
}
- }
+
+ gDefaultServiceManager = new ServiceManagerShim(sm);
+ });
return gDefaultServiceManager;
}
void setDefaultServiceManager(const sp<IServiceManager>& sm) {
- AutoMutex _l(gDefaultServiceManagerLock);
- gDefaultServiceManager = sm;
+ bool called = false;
+ std::call_once(gSmOnce, [&]() {
+ gDefaultServiceManager = sm;
+ called = true;
+ });
+
+ if (!called) {
+ LOG_ALWAYS_FATAL("setDefaultServiceManager() called after defaultServiceManager().");
+ }
}
#if !defined(__ANDROID_VNDK__) && defined(__ANDROID__)
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 9f71f3e..822247f 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2543,11 +2543,13 @@
if (objectsSize == 0) {
free(mObjects);
mObjects = nullptr;
+ mObjectsCapacity = 0;
} else {
binder_size_t* objects =
(binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t));
if (objects) {
mObjects = objects;
+ mObjectsCapacity = objectsSize;
}
}
mObjectsSize = objectsSize;
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 7489afa..9aa7651 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -26,6 +26,9 @@
},
{
"name": "aidl_lazy_test"
+ },
+ {
+ "name": "libbinderthreadstateutils_test"
}
]
}
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index ff9244e..4818889 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -29,8 +29,6 @@
// ---------------------------------------------------------------------------
namespace android {
-class IPCThreadStateBase;
-
class IPCThreadState
{
public:
@@ -113,31 +111,12 @@
// Service manager registration
void setTheContextObject(sp<BBinder> obj);
- // Is this thread currently serving a binder call. This method
- // returns true if while traversing backwards from the function call
- // stack for this thread, we encounter a function serving a binder
- // call before encountering a hwbinder call / hitting the end of the
- // call stack.
- // Eg: If thread T1 went through the following call pattern
- // 1) T1 receives and executes hwbinder call H1.
- // 2) While handling H1, T1 makes binder call B1.
- // 3) The handler of B1, calls into T1 with a callback B2.
- // If isServingCall() is called during H1 before 3), this method
- // will return false, else true.
+ // WARNING: DO NOT USE THIS API
//
- // ----
- // | B2 | ---> While callback B2 is being handled, during 3).
- // ----
- // | H1 | ---> While H1 is being handled.
- // ----
- // Fig: Thread Call stack while handling B2
- //
- // This is since after 3), while traversing the thread call stack,
- // we hit a binder call before a hwbinder call / end of stack. This
- // method may be typically used to determine whether to use
- // hardware::IPCThreadState methods or IPCThreadState methods to
- // infer information about thread state.
- bool isServingCall() const;
+ // Returns a pointer to the stack from the last time a transaction
+ // was initiated by the kernel. Used to compare when making nested
+ // calls between multiple different transports.
+ const void* getServingStackPointer() const;
// The work source represents the UID of the process we should attribute the transaction
// to. We use -1 to specify that the work source was not set using #setWorkSource.
@@ -181,6 +160,7 @@
Parcel mIn;
Parcel mOut;
status_t mLastError;
+ const void* mServingStackPointer;
pid_t mCallingPid;
const char* mCallingSid;
uid_t mCallingUid;
@@ -191,7 +171,6 @@
bool mPropagateWorkSource;
int32_t mStrictModePolicy;
int32_t mLastTransactionBinderFlags;
- IPCThreadStateBase *mIPCThreadStateBase;
ProcessState::CallRestriction mCallRestriction;
};
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 31f022d..1d520c1 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -102,6 +102,9 @@
/**
* Directly set the default service manager. Only used for testing.
+ * Note that the caller is responsible for caling this method
+ * *before* any call to defaultServiceManager(); if the latter is
+ * called first, setDefaultServiceManager() will abort.
*/
void setDefaultServiceManager(const sp<IServiceManager>& sm);
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index e752c45..75dcdc8 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -24,10 +24,13 @@
#include <android-base/logging.h>
#include <binder/IPCThreadState.h>
+#include <binder/IResultReceiver.h>
+#include <private/android_filesystem_config.h>
using DeathRecipient = ::android::IBinder::DeathRecipient;
using ::android::IBinder;
+using ::android::IResultReceiver;
using ::android::Parcel;
using ::android::sp;
using ::android::status_t;
@@ -158,6 +161,45 @@
binder_status_t status = getClass()->onTransact(this, code, &in, &out);
return PruneStatusT(status);
+ } else if (code == SHELL_COMMAND_TRANSACTION) {
+ int in = data.readFileDescriptor();
+ int out = data.readFileDescriptor();
+ int err = data.readFileDescriptor();
+
+ int argc = data.readInt32();
+ std::vector<String8> utf8Args; // owns memory of utf8s
+ std::vector<const char*> utf8Pointers; // what can be passed over NDK API
+ for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+ utf8Args.push_back(String8(data.readString16()));
+ utf8Pointers.push_back(utf8Args[i].c_str());
+ }
+
+ data.readStrongBinder(); // skip over the IShellCallback
+ sp<IResultReceiver> resultReceiver = IResultReceiver::asInterface(data.readStrongBinder());
+
+ // Shell commands should only be callable by ADB.
+ uid_t uid = AIBinder_getCallingUid();
+ if (uid != AID_ROOT && uid != AID_SHELL) {
+ if (resultReceiver != nullptr) {
+ resultReceiver->send(-1);
+ }
+ return STATUS_PERMISSION_DENIED;
+ }
+
+ // Check that the file descriptors are valid.
+ if (in == STATUS_BAD_TYPE || out == STATUS_BAD_TYPE || err == STATUS_BAD_TYPE) {
+ if (resultReceiver != nullptr) {
+ resultReceiver->send(-1);
+ }
+ return STATUS_BAD_VALUE;
+ }
+
+ binder_status_t status = getClass()->handleShellCommand(
+ this, in, out, err, utf8Pointers.data(), utf8Pointers.size());
+ if (resultReceiver != nullptr) {
+ resultReceiver->send(status);
+ }
+ return status;
} else {
return BBinder::onTransact(code, data, reply, flags);
}
@@ -266,6 +308,13 @@
clazz->onDump = onDump;
}
+void AIBinder_Class_setHandleShellCommand(AIBinder_Class* clazz,
+ AIBinder_handleShellCommand handleShellCommand) {
+ CHECK(clazz != nullptr) << "setHandleShellCommand requires non-null clazz";
+
+ clazz->handleShellCommand = handleShellCommand;
+}
+
void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
CHECK(who == mWho);
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 5cb68c2..5779427 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -17,6 +17,7 @@
#pragma once
#include <android/binder_ibinder.h>
+#include <android/binder_shell.h>
#include "ibinder_internal.h"
#include <atomic>
@@ -115,6 +116,7 @@
// optional methods for a class
AIBinder_onDump onDump;
+ AIBinder_handleShellCommand handleShellCommand;
private:
// This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
index 83a1048..7331ba2 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -30,6 +30,11 @@
#include <android/binder_auto_utils.h>
#include <android/binder_ibinder.h>
+#if __has_include(<android/binder_shell.h>)
+#include <android/binder_shell.h>
+#define HAS_BINDER_SHELL_COMMAND
+#endif //_has_include
+
#include <assert.h>
#include <memory>
@@ -108,7 +113,15 @@
/**
* Dumps information about the interface. By default, dumps nothing.
*/
- virtual inline binder_status_t dump(int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
+ virtual inline binder_status_t dump(int fd, const char** args, uint32_t numArgs);
+
+#ifdef HAS_BINDER_SHELL_COMMAND
+ /**
+ * Process shell commands. By default, does nothing.
+ */
+ virtual inline binder_status_t handleShellCommand(int in, int out, int err, const char** argv,
+ uint32_t argc);
+#endif
/**
* Interprets this binder as this underlying interface if this has stored an ICInterface in the
@@ -136,6 +149,11 @@
static inline void onDestroy(void* userData);
static inline binder_status_t onDump(AIBinder* binder, int fd, const char** args,
uint32_t numArgs);
+
+#ifdef HAS_BINDER_SHELL_COMMAND
+ static inline binder_status_t handleShellCommand(AIBinder* binder, int in, int out, int err,
+ const char** argv, uint32_t argc);
+#endif
};
};
@@ -191,6 +209,13 @@
return STATUS_OK;
}
+#ifdef HAS_BINDER_SHELL_COMMAND
+binder_status_t ICInterface::handleShellCommand(int /*in*/, int /*out*/, int /*err*/,
+ const char** /*argv*/, uint32_t /*argc*/) {
+ return STATUS_OK;
+}
+#endif
+
std::shared_ptr<ICInterface> ICInterface::asInterface(AIBinder* binder) {
return ICInterfaceData::getInterface(binder);
}
@@ -203,9 +228,12 @@
return nullptr;
}
- // We can't know if this method is overriden by a subclass interface, so we must register
- // ourselves. The default (nothing to dump) is harmless.
+ // We can't know if these methods are overridden by a subclass interface, so we must register
+ // ourselves. The defaults are harmless.
AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump);
+#ifdef HAS_BINDER_SHELL_COMMAND
+ AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
+#endif
return clazz;
}
@@ -234,6 +262,15 @@
return interface->dump(fd, args, numArgs);
}
+#ifdef HAS_BINDER_SHELL_COMMAND
+binder_status_t ICInterface::ICInterfaceData::handleShellCommand(AIBinder* binder, int in, int out,
+ int err, const char** argv,
+ uint32_t argc) {
+ std::shared_ptr<ICInterface> interface = getInterface(binder);
+ return interface->handleShellCommand(in, out, err, argv, argc);
+}
+#endif
+
template <typename INTERFACE>
SpAIBinder BnCInterface<INTERFACE>::asBinder() {
std::lock_guard<std::mutex> l(mMutex);
diff --git a/libs/binder/ndk/include_platform/android/binder_shell.h b/libs/binder/ndk/include_platform/android/binder_shell.h
new file mode 100644
index 0000000..17b38b0
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_shell.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 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 <android/binder_ibinder.h>
+
+__BEGIN_DECLS
+
+/**
+ * Function to execute a shell command.
+ *
+ * Available since API level 30.
+ *
+ * \param binder the binder executing the command
+ * \param in input file descriptor, should be flushed, ownership is not passed
+ * \param out output file descriptor, should be flushed, ownership is not passed
+ * \param err error file descriptor, should be flushed, ownership is not passed
+ * \param argv array of null-terminated strings for command (may be null if argc
+ * is 0)
+ * \param argc length of argv array
+ *
+ * \return binder_status_t result of transaction
+ */
+typedef binder_status_t (*AIBinder_handleShellCommand)(AIBinder* binder, int in, int out, int err,
+ const char** argv, uint32_t argc);
+
+/**
+ * This sets the implementation of handleShellCommand for a class.
+ *
+ * If this isn't set, nothing will be executed when handleShellCommand is called.
+ *
+ * Available since API level 30.
+ *
+ * \param handleShellCommand function to call when a shell transaction is
+ * received
+ */
+void AIBinder_Class_setHandleShellCommand(AIBinder_Class* clazz,
+ AIBinder_handleShellCommand handleShellCommand)
+ __INTRODUCED_IN(30);
+
+__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index f3158d7..7e72f22 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -110,6 +110,7 @@
AIBinder_markSystemStability; # apex
AIBinder_markVendorStability; # llndk
AIBinder_markVintfStability; # apex llndk
+ AIBinder_Class_setHandleShellCommand; # apex llndk
local:
*;
};
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 513d8c2..cb4b20f 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -60,6 +60,7 @@
defaults: ["test_libbinder_ndk_test_defaults"],
srcs: ["libbinder_ndk_unit_test.cpp"],
static_libs: [
+ "IBinderNdkUnitTest-cpp",
"IBinderNdkUnitTest-ndk_platform",
],
test_suites: ["general-tests"],
diff --git a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
index 51dd169..fd30d87 100644
--- a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <IBinderNdkUnitTest.h>
#include <aidl/BnBinderNdkUnitTest.h>
#include <aidl/BnEmpty.h>
#include <android-base/logging.h>
@@ -26,13 +27,16 @@
// warning: this is assuming that libbinder_ndk is using the same copy
// of libbinder that we are.
#include <binder/IPCThreadState.h>
+#include <binder/IResultReceiver.h>
+#include <binder/IServiceManager.h>
+#include <binder/IShellCallback.h>
#include <sys/prctl.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
-using ::android::sp;
+using namespace android;
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
@@ -48,6 +52,14 @@
android::IPCThreadState::self()->flushCommands();
return ndk::ScopedAStatus::ok();
}
+ binder_status_t handleShellCommand(int /*in*/, int out, int /*err*/, const char** args,
+ uint32_t numArgs) override {
+ for (uint32_t i = 0; i < numArgs; i++) {
+ dprintf(out, "%s", args[i]);
+ }
+ fsync(out);
+ return STATUS_OK;
+ }
};
int generatedService() {
@@ -296,6 +308,92 @@
EXPECT_TRUE(destroyed);
}
+class MyResultReceiver : public BnResultReceiver {
+ public:
+ Mutex mMutex;
+ Condition mCondition;
+ bool mHaveResult = false;
+ int32_t mResult = 0;
+
+ virtual void send(int32_t resultCode) {
+ AutoMutex _l(mMutex);
+ mResult = resultCode;
+ mHaveResult = true;
+ mCondition.signal();
+ }
+
+ int32_t waitForResult() {
+ AutoMutex _l(mMutex);
+ while (!mHaveResult) {
+ mCondition.wait(mMutex);
+ }
+ return mResult;
+ }
+};
+
+class MyShellCallback : public BnShellCallback {
+ public:
+ virtual int openFile(const String16& /*path*/, const String16& /*seLinuxContext*/,
+ const String16& /*mode*/) {
+ // Empty implementation.
+ return 0;
+ }
+};
+
+bool ReadFdToString(int fd, std::string* content) {
+ char buf[64];
+ ssize_t n;
+ while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
+ content->append(buf, n);
+ }
+ return (n == 0) ? true : false;
+}
+
+std::string shellCmdToString(sp<IBinder> unitTestService, const std::vector<const char*>& args) {
+ int inFd[2] = {-1, -1};
+ int outFd[2] = {-1, -1};
+ int errFd[2] = {-1, -1};
+
+ EXPECT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, inFd));
+ EXPECT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, outFd));
+ EXPECT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, errFd));
+
+ sp<MyShellCallback> cb = new MyShellCallback();
+ sp<MyResultReceiver> resultReceiver = new MyResultReceiver();
+
+ Vector<String16> argsVec;
+ for (int i = 0; i < args.size(); i++) {
+ argsVec.add(String16(args[i]));
+ }
+ status_t error = IBinder::shellCommand(unitTestService, inFd[0], outFd[0], errFd[0], argsVec,
+ cb, resultReceiver);
+ EXPECT_EQ(error, android::OK);
+
+ status_t res = resultReceiver->waitForResult();
+ EXPECT_EQ(res, android::OK);
+
+ close(inFd[0]);
+ close(inFd[1]);
+ close(outFd[0]);
+ close(errFd[0]);
+ close(errFd[1]);
+
+ std::string ret;
+ EXPECT_TRUE(ReadFdToString(outFd[1], &ret));
+ close(outFd[1]);
+ return ret;
+}
+
+TEST(NdkBinder, UseHandleShellCommand) {
+ static const sp<android::IServiceManager> sm(android::defaultServiceManager());
+ sp<IBinder> testService = sm->getService(String16(kBinderNdkUnitTestService));
+
+ EXPECT_EQ("", shellCmdToString(testService, {}));
+ EXPECT_EQ("", shellCmdToString(testService, {"", ""}));
+ EXPECT_EQ("Hello world!", shellCmdToString(testService, {"Hello ", "world!"}));
+ EXPECT_EQ("CMD", shellCmdToString(testService, {"C", "M", "D"}));
+}
+
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/libs/binderthreadstate/1.0/Android.bp b/libs/binderthreadstate/1.0/Android.bp
new file mode 100644
index 0000000..ebdc932
--- /dev/null
+++ b/libs/binderthreadstate/1.0/Android.bp
@@ -0,0 +1,14 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "binderthreadstateutilstest@1.0",
+ root: "binderthreadstateutilstest",
+ system_ext_specific: true,
+ srcs: [
+ "IHidlStuff.hal",
+ ],
+ interfaces: [
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/libs/binderthreadstate/1.0/IHidlStuff.hal b/libs/binderthreadstate/1.0/IHidlStuff.hal
new file mode 100644
index 0000000..ffb6499
--- /dev/null
+++ b/libs/binderthreadstate/1.0/IHidlStuff.hal
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package binderthreadstateutilstest@1.0;
+
+interface IHidlStuff {
+ callLocal();
+ call(int32_t idx);
+};
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index ee1a6a4..4655e1d 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -12,6 +12,59 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// DO NOT ADD NEW USAGES OF THIS
+// See comments in header file.
+cc_library_static {
+ name: "libbinderthreadstateutils",
+ double_loadable: true,
+ vendor_available: true,
+ host_supported: true,
+
+ shared_libs: [
+ "libbinder",
+ "libhidlbase", // libhwbinder is in here
+ ],
+
+ export_include_dirs: ["include"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+hidl_package_root {
+ name: "binderthreadstateutilstest",
+}
+
+aidl_interface {
+ name: "binderthreadstateutilstest.aidl",
+ srcs: ["IAidlStuff.aidl"],
+}
+
+cc_test {
+ name: "libbinderthreadstateutils_test",
+ srcs: ["test.cpp"],
+ static_libs: [
+ "binderthreadstateutilstest@1.0",
+ "binderthreadstateutilstest.aidl-cpp",
+ "libbinderthreadstateutils",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libhidlbase",
+ "libutils",
+ "liblog",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+ require_root: true,
+}
+
+// TODO(b/148692216): remove empty lib
cc_library {
name: "libbinderthreadstate",
recovery_available: true,
@@ -21,28 +74,4 @@
support_system_process: true,
},
host_supported: true,
-
- srcs: [
- "IPCThreadStateBase.cpp",
- ],
-
- header_libs: [
- "libbase_headers",
- "libutils_headers",
- ],
-
- shared_libs: [
- "liblog",
- ],
-
- export_include_dirs: ["include"],
-
- sanitize: {
- misc_undefined: ["integer"],
- },
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
}
diff --git a/libs/binderthreadstate/IAidlStuff.aidl b/libs/binderthreadstate/IAidlStuff.aidl
new file mode 100644
index 0000000..0c81c42
--- /dev/null
+++ b/libs/binderthreadstate/IAidlStuff.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+
+interface IAidlStuff {
+ void callLocal();
+ void call(int idx);
+}
diff --git a/libs/binderthreadstate/IPCThreadStateBase.cpp b/libs/binderthreadstate/IPCThreadStateBase.cpp
deleted file mode 100644
index fede151..0000000
--- a/libs/binderthreadstate/IPCThreadStateBase.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "IPCThreadStateBase"
-
-#include <binderthreadstate/IPCThreadStateBase.h>
-#include <android-base/macros.h>
-
-#include <utils/Log.h>
-
-#include <errno.h>
-#include <inttypes.h>
-#include <pthread.h>
-
-namespace android {
-
-static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
-static bool gHaveTLS = false;
-static pthread_key_t gTLS = 0;
-
-IPCThreadStateBase::IPCThreadStateBase() {
- pthread_setspecific(gTLS, this);
-}
-
-IPCThreadStateBase* IPCThreadStateBase::self()
-{
- if (gHaveTLS) {
-restart:
- const pthread_key_t k = gTLS;
- IPCThreadStateBase* st = (IPCThreadStateBase*)pthread_getspecific(k);
- if (st) return st;
- return new IPCThreadStateBase;
- }
-
- pthread_mutex_lock(&gTLSMutex);
- if (!gHaveTLS) {
- int key_create_value = pthread_key_create(&gTLS, threadDestructor);
- if (key_create_value != 0) {
- pthread_mutex_unlock(&gTLSMutex);
- ALOGW("IPCThreadStateBase::self() unable to create TLS key, expect a crash: %s\n",
- strerror(key_create_value));
- return nullptr;
- }
- gHaveTLS = true;
- }
- pthread_mutex_unlock(&gTLSMutex);
- goto restart;
-}
-
-void IPCThreadStateBase::pushCurrentState(CallState callState) {
- mCallStateStack.emplace(callState);
-}
-
-IPCThreadStateBase::CallState IPCThreadStateBase::popCurrentState() {
- ALOG_ASSERT(mCallStateStack.size > 0);
- CallState val = mCallStateStack.top();
- mCallStateStack.pop();
- return val;
-}
-
-IPCThreadStateBase::CallState IPCThreadStateBase::getCurrentBinderCallState() {
- if (mCallStateStack.size() > 0) {
- return mCallStateStack.top();
- }
- return CallState::NONE;
-}
-
-void IPCThreadStateBase::threadDestructor(void *st)
-{
- IPCThreadStateBase* const self = static_cast<IPCThreadStateBase*>(st);
- if (self) {
- delete self;
- }
-}
-
-}; // namespace android
diff --git a/libs/binderthreadstate/TEST_MAPPING b/libs/binderthreadstate/TEST_MAPPING
new file mode 100644
index 0000000..2bd0463
--- /dev/null
+++ b/libs/binderthreadstate/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libbinderthreadstateutils_test"
+ }
+ ]
+}
diff --git a/libs/binderthreadstate/include/binderthreadstate/CallerUtils.h b/libs/binderthreadstate/include/binderthreadstate/CallerUtils.h
new file mode 100644
index 0000000..a3e5026
--- /dev/null
+++ b/libs/binderthreadstate/include/binderthreadstate/CallerUtils.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 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
+
+// WARNING: DO NOT USE THIS
+// You should:
+// - have code know how it is handling things. Pass in caller information rather
+// than assuming that code is running in a specific global context
+// - use AIDL exclusively in your stack (HIDL is no longer required anywhere)
+
+#include <binder/IPCThreadState.h>
+#include <hwbinder/IPCThreadState.h>
+
+namespace android {
+
+enum class BinderCallType {
+ NONE,
+ BINDER,
+ HWBINDER,
+};
+
+// Based on where we are in recursion of nested binder/hwbinder calls, determine
+// which one we are closer to.
+inline static BinderCallType getCurrentServingCall() {
+ const void* hwbinderSp = android::hardware::IPCThreadState::self()->getServingStackPointer();
+ const void* binderSp = android::IPCThreadState::self()->getServingStackPointer();
+
+ if (hwbinderSp == nullptr && binderSp == nullptr) return BinderCallType::NONE;
+ if (hwbinderSp == nullptr) return BinderCallType::BINDER;
+ if (binderSp == nullptr) return BinderCallType::HWBINDER;
+
+ if (hwbinderSp < binderSp) return BinderCallType::HWBINDER;
+ return BinderCallType::BINDER;
+}
+
+} // namespace android
diff --git a/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h b/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
deleted file mode 100644
index 6fdcc84..0000000
--- a/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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 BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
-#define BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
-
-#include <stack>
-namespace android {
-
-class IPCThreadStateBase {
-public:
- enum CallState {
- HWBINDER,
- BINDER,
- NONE,
- };
- static IPCThreadStateBase* self();
- void pushCurrentState(CallState callState);
- CallState popCurrentState();
- CallState getCurrentBinderCallState();
-
-private:
- IPCThreadStateBase();
- static void threadDestructor(void *st);
-
- std::stack<CallState> mCallStateStack;
-};
-
-}; // namespace android
-
-#endif // BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
diff --git a/libs/binderthreadstate/test.cpp b/libs/binderthreadstate/test.cpp
new file mode 100644
index 0000000..68cc225
--- /dev/null
+++ b/libs/binderthreadstate/test.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2020 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 <BnAidlStuff.h>
+#include <android-base/logging.h>
+#include <binder/IServiceManager.h>
+#include <binderthreadstate/CallerUtils.h>
+#include <binderthreadstateutilstest/1.0/IHidlStuff.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlTransportSupport.h>
+#include <linux/prctl.h>
+#include <sys/prctl.h>
+
+using android::BinderCallType;
+using android::defaultServiceManager;
+using android::getCurrentServingCall;
+using android::getService;
+using android::OK;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+using android::hardware::Return;
+using binderthreadstateutilstest::V1_0::IHidlStuff;
+
+constexpr size_t kP1Id = 1;
+constexpr size_t kP2Id = 2;
+
+// AIDL and HIDL are in separate namespaces so using same service names
+std::string id2name(size_t id) {
+ return "libbinderthreadstateutils-" + std::to_string(id);
+}
+
+// There are two servers calling each other recursively like this.
+//
+// P1 P2
+// | --HIDL--> |
+// | <--HIDL-- |
+// | --AIDL--> |
+// | <--AIDL-- |
+// | --HIDL--> |
+// | <--HIDL-- |
+// | --AIDL--> |
+// | <--AIDL-- |
+// ..........
+//
+// Calls always come in pairs (AIDL returns AIDL, HIDL returns HIDL) because
+// this means that P1 always has a 'waitForResponse' call which can service the
+// returning call and continue the recursion. Of course, with more threads, more
+// complicated calls are possible, but this should do here.
+
+static void callHidl(size_t id, int32_t idx) {
+ auto stuff = IHidlStuff::getService(id2name(id));
+ CHECK(stuff->call(idx).isOk());
+}
+
+static void callAidl(size_t id, int32_t idx) {
+ sp<IAidlStuff> stuff;
+ CHECK(OK == android::getService<IAidlStuff>(String16(id2name(id).c_str()), &stuff));
+ CHECK(stuff->call(idx).isOk());
+}
+
+class HidlServer : public IHidlStuff {
+public:
+ HidlServer(size_t thisId, size_t otherId) : thisId(thisId), otherId(otherId) {}
+ size_t thisId;
+ size_t otherId;
+
+ Return<void> callLocal() {
+ CHECK(BinderCallType::NONE == getCurrentServingCall());
+ return android::hardware::Status::ok();
+ }
+ Return<void> call(int32_t idx) {
+ LOG(INFO) << "HidlServer CALL " << thisId << " to " << otherId << " at idx: " << idx
+ << " with tid: " << gettid();
+ CHECK(BinderCallType::HWBINDER == getCurrentServingCall());
+ if (idx > 0) {
+ if (thisId == kP1Id && idx % 4 < 2) {
+ callHidl(otherId, idx - 1);
+ } else {
+ callAidl(otherId, idx - 1);
+ }
+ }
+ CHECK(BinderCallType::HWBINDER == getCurrentServingCall());
+ return android::hardware::Status::ok();
+ }
+};
+class AidlServer : public BnAidlStuff {
+public:
+ AidlServer(size_t thisId, size_t otherId) : thisId(thisId), otherId(otherId) {}
+ size_t thisId;
+ size_t otherId;
+
+ Status callLocal() {
+ CHECK(BinderCallType::NONE == getCurrentServingCall());
+ return Status::ok();
+ }
+ Status call(int32_t idx) {
+ LOG(INFO) << "AidlServer CALL " << thisId << " to " << otherId << " at idx: " << idx
+ << " with tid: " << gettid();
+ CHECK(BinderCallType::BINDER == getCurrentServingCall());
+ if (idx > 0) {
+ if (thisId == kP2Id && idx % 4 < 2) {
+ callHidl(otherId, idx - 1);
+ } else {
+ callAidl(otherId, idx - 1);
+ }
+ }
+ CHECK(BinderCallType::BINDER == getCurrentServingCall());
+ return Status::ok();
+ }
+};
+
+TEST(BinderThreadState, LocalHidlCall) {
+ sp<IHidlStuff> server = new HidlServer(0, 0);
+ EXPECT_TRUE(server->callLocal().isOk());
+}
+
+TEST(BinderThreadState, LocalAidlCall) {
+ sp<IAidlStuff> server = new AidlServer(0, 0);
+ EXPECT_TRUE(server->callLocal().isOk());
+}
+
+TEST(BindThreadState, RemoteHidlCall) {
+ auto stuff = IHidlStuff::getService(id2name(kP1Id));
+ ASSERT_NE(nullptr, stuff);
+ ASSERT_TRUE(stuff->call(0).isOk());
+}
+TEST(BindThreadState, RemoteAidlCall) {
+ sp<IAidlStuff> stuff;
+ ASSERT_EQ(OK, android::getService<IAidlStuff>(String16(id2name(kP1Id).c_str()), &stuff));
+ ASSERT_NE(nullptr, stuff);
+ ASSERT_TRUE(stuff->call(0).isOk());
+}
+
+TEST(BindThreadState, RemoteNestedStartHidlCall) {
+ auto stuff = IHidlStuff::getService(id2name(kP1Id));
+ ASSERT_NE(nullptr, stuff);
+ ASSERT_TRUE(stuff->call(100).isOk());
+}
+TEST(BindThreadState, RemoteNestedStartAidlCall) {
+ sp<IAidlStuff> stuff;
+ ASSERT_EQ(OK, android::getService<IAidlStuff>(String16(id2name(kP1Id).c_str()), &stuff));
+ ASSERT_NE(nullptr, stuff);
+ EXPECT_TRUE(stuff->call(100).isOk());
+}
+
+int server(size_t thisId, size_t otherId) {
+ // AIDL
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ sp<AidlServer> aidlServer = new AidlServer(thisId, otherId);
+ CHECK(OK == defaultServiceManager()->addService(String16(id2name(thisId).c_str()), aidlServer));
+ android::ProcessState::self()->startThreadPool();
+
+ // HIDL
+ setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+ android::hardware::configureRpcThreadpool(1, true /*callerWillJoin*/);
+ sp<IHidlStuff> hidlServer = new HidlServer(thisId, otherId);
+ CHECK(OK == hidlServer->registerAsService(id2name(thisId).c_str()));
+ android::hardware::joinRpcThreadpool();
+
+ return EXIT_FAILURE;
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return server(kP1Id, kP2Id);
+ }
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return server(kP2Id, kP1Id);
+ }
+
+ android::waitForService<IAidlStuff>(String16(id2name(kP1Id).c_str()));
+ android::hardware::details::waitForHwService(IHidlStuff::descriptor, id2name(kP1Id).c_str());
+ android::waitForService<IAidlStuff>(String16(id2name(kP2Id).c_str()));
+ android::hardware::details::waitForHwService(IHidlStuff::descriptor, id2name(kP2Id).c_str());
+
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 166775b..ba3195a 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -186,6 +186,10 @@
"libvndksupport",
],
+ static_libs: [
+ "libbinderthreadstateutils",
+ ],
+
header_libs: [
"libgui_headers",
"libnativebase_headers",
diff --git a/libs/gui/BufferQueueThreadState.cpp b/libs/gui/BufferQueueThreadState.cpp
index 3b531ec..c13030b 100644
--- a/libs/gui/BufferQueueThreadState.cpp
+++ b/libs/gui/BufferQueueThreadState.cpp
@@ -15,6 +15,7 @@
*/
#include <binder/IPCThreadState.h>
+#include <binderthreadstate/CallerUtils.h>
#include <hwbinder/IPCThreadState.h>
#include <private/gui/BufferQueueThreadState.h>
#include <unistd.h>
@@ -22,14 +23,14 @@
namespace android {
uid_t BufferQueueThreadState::getCallingUid() {
- if (hardware::IPCThreadState::self()->isServingCall()) {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingUid();
}
return IPCThreadState::self()->getCallingUid();
}
pid_t BufferQueueThreadState::getCallingPid() {
- if (hardware::IPCThreadState::self()->isServingCall()) {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingPid();
}
return IPCThreadState::self()->getCallingPid();
diff --git a/services/stats/Android.bp b/services/stats/Android.bp
new file mode 100644
index 0000000..1ce0524
--- /dev/null
+++ b/services/stats/Android.bp
@@ -0,0 +1,22 @@
+cc_library_shared {
+ name: "libstatshidl",
+ srcs: [
+ "StatsHal.cpp",
+ ],
+ cflags: ["-Wall", "-Werror"],
+ shared_libs: [
+ "android.frameworks.stats@1.0",
+ "libhidlbase",
+ "liblog",
+ "libstatslog",
+ "libstatssocket",
+ "libutils",
+ ],
+ export_include_dirs: [
+ "include/",
+ ],
+ local_include_dirs: [
+ "include/stats",
+ ],
+ vintf_fragments: ["android.frameworks.stats@1.0-service.xml"]
+}
diff --git a/services/stats/OWNERS b/services/stats/OWNERS
new file mode 100644
index 0000000..a61babf
--- /dev/null
+++ b/services/stats/OWNERS
@@ -0,0 +1,9 @@
+jeffreyhuang@google.com
+joeo@google.com
+jtnguyen@google.com
+muhammadq@google.com
+ruchirr@google.com
+singhtejinder@google.com
+tsaichristine@google.com
+yaochen@google.com
+yro@google.com
diff --git a/services/stats/StatsHal.cpp b/services/stats/StatsHal.cpp
new file mode 100644
index 0000000..b775431
--- /dev/null
+++ b/services/stats/StatsHal.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#define LOG_TAG "StatsHal"
+
+#include <log/log.h>
+#include <statslog.h>
+
+#include "StatsHal.h"
+
+namespace android {
+namespace frameworks {
+namespace stats {
+namespace V1_0 {
+namespace implementation {
+
+StatsHal::StatsHal() {}
+
+hardware::Return<void> StatsHal::reportSpeakerImpedance(
+ const SpeakerImpedance& speakerImpedance) {
+ android::util::stats_write(android::util::SPEAKER_IMPEDANCE_REPORTED,
+ speakerImpedance.speakerLocation, speakerImpedance.milliOhms);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportHardwareFailed(const HardwareFailed& hardwareFailed) {
+ android::util::stats_write(android::util::HARDWARE_FAILED, int32_t(hardwareFailed.hardwareType),
+ hardwareFailed.hardwareLocation, int32_t(hardwareFailed.errorCode));
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportPhysicalDropDetected(
+ const PhysicalDropDetected& physicalDropDetected) {
+ android::util::stats_write(android::util::PHYSICAL_DROP_DETECTED,
+ int32_t(physicalDropDetected.confidencePctg), physicalDropDetected.accelPeak,
+ physicalDropDetected.freefallDuration);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportChargeCycles(const ChargeCycles& chargeCycles) {
+ std::vector<int32_t> buckets = chargeCycles.cycleBucket;
+ int initialSize = buckets.size();
+ for (int i = 0; i < 10 - initialSize; i++) {
+ buckets.push_back(-1); // Push -1 for buckets that do not exist.
+ }
+ android::util::stats_write(android::util::CHARGE_CYCLES_REPORTED, buckets[0], buckets[1],
+ buckets[2], buckets[3], buckets[4], buckets[5], buckets[6], buckets[7], buckets[8],
+ buckets[9]);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportBatteryHealthSnapshot(
+ const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) {
+ android::util::stats_write(android::util::BATTERY_HEALTH_SNAPSHOT,
+ int32_t(batteryHealthSnapshotArgs.type), batteryHealthSnapshotArgs.temperatureDeciC,
+ batteryHealthSnapshotArgs.voltageMicroV, batteryHealthSnapshotArgs.currentMicroA,
+ batteryHealthSnapshotArgs.openCircuitVoltageMicroV,
+ batteryHealthSnapshotArgs.resistanceMicroOhm, batteryHealthSnapshotArgs.levelPercent);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportSlowIo(const SlowIo& slowIo) {
+ android::util::stats_write(android::util::SLOW_IO, int32_t(slowIo.operation), slowIo.count);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportBatteryCausedShutdown(
+ const BatteryCausedShutdown& batteryCausedShutdown) {
+ android::util::stats_write(android::util::BATTERY_CAUSED_SHUTDOWN,
+ batteryCausedShutdown.voltageMicroV);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportUsbPortOverheatEvent(
+ const UsbPortOverheatEvent& usbPortOverheatEvent) {
+ android::util::stats_write(android::util::USB_PORT_OVERHEAT_EVENT_REPORTED,
+ usbPortOverheatEvent.plugTemperatureDeciC, usbPortOverheatEvent.maxTemperatureDeciC,
+ usbPortOverheatEvent.timeToOverheat, usbPortOverheatEvent.timeToHysteresis,
+ usbPortOverheatEvent.timeToInactive);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportSpeechDspStat(
+ const SpeechDspStat& speechDspStat) {
+ android::util::stats_write(android::util::SPEECH_DSP_STAT_REPORTED,
+ speechDspStat.totalUptimeMillis, speechDspStat.totalDowntimeMillis,
+ speechDspStat.totalCrashCount, speechDspStat.totalRecoverCount);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
+ ALOGW("reportVendorAtom unsupported");
+ std::string reverDomainName = vendorAtom.reverseDomainName;
+ return hardware::Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace stats
+} // namespace frameworks
+} // namespace android
diff --git a/services/stats/android.frameworks.stats@1.0-service.xml b/services/stats/android.frameworks.stats@1.0-service.xml
new file mode 100644
index 0000000..bb02f66
--- /dev/null
+++ b/services/stats/android.frameworks.stats@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+ <hal>
+ <name>android.frameworks.stats</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IStats</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/services/stats/include/stats/StatsHal.h b/services/stats/include/stats/StatsHal.h
new file mode 100644
index 0000000..ad14263
--- /dev/null
+++ b/services/stats/include/stats/StatsHal.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 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/frameworks/stats/1.0/IStats.h>
+#include <android/frameworks/stats/1.0/types.h>
+
+using namespace android::frameworks::stats::V1_0;
+
+namespace android {
+namespace frameworks {
+namespace stats {
+namespace V1_0 {
+namespace implementation {
+
+using android::hardware::Return;
+
+/**
+* Implements the Stats HAL
+*/
+class StatsHal : public IStats {
+public:
+ StatsHal();
+
+ /**
+ * Binder call to get SpeakerImpedance atom.
+ */
+ virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override;
+
+ /**
+ * Binder call to get HardwareFailed atom.
+ */
+ virtual Return<void> reportHardwareFailed(const HardwareFailed& hardwareFailed) override;
+
+ /**
+ * Binder call to get PhysicalDropDetected atom.
+ */
+ virtual Return<void> reportPhysicalDropDetected(
+ const PhysicalDropDetected& physicalDropDetected) override;
+
+ /**
+ * Binder call to get ChargeCyclesReported atom.
+ */
+ virtual Return<void> reportChargeCycles(const ChargeCycles& chargeCycles) override;
+
+ /**
+ * Binder call to get BatteryHealthSnapshot atom.
+ */
+ virtual Return<void> reportBatteryHealthSnapshot(
+ const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) override;
+
+ /**
+ * Binder call to get SlowIo atom.
+ */
+ virtual Return<void> reportSlowIo(const SlowIo& slowIo) override;
+
+ /**
+ * Binder call to get BatteryCausedShutdown atom.
+ */
+ virtual Return<void> reportBatteryCausedShutdown(
+ const BatteryCausedShutdown& batteryCausedShutdown) override;
+
+ /**
+ * Binder call to get UsbPortOverheatEvent atom.
+ */
+ virtual Return<void> reportUsbPortOverheatEvent(
+ const UsbPortOverheatEvent& usbPortOverheatEvent) override;
+
+ /**
+ * Binder call to get Speech DSP state atom.
+ */
+ virtual Return<void> reportSpeechDspStat(
+ const SpeechDspStat& speechDspStat) override;
+
+ /**
+ * Binder call to get vendor atom.
+ */
+ virtual Return<void> reportVendorAtom(const VendorAtom& vendorAtom) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace stats
+} // namespace frameworks
+} // namespace android