Merge "libbinder should not be included in APEX"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 443f885..eaa84f5 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -170,6 +170,7 @@
{ OPT, "events/clk/clk_disable/enable" },
{ OPT, "events/clk/clk_enable/enable" },
{ OPT, "events/power/cpu_frequency_limits/enable" },
+ { OPT, "events/power/suspend_resume/enable" },
} },
{ "membus", "Memory Bus Utilization", 0, {
{ REQ, "events/memory_bus/enable" },
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index f1426b6..6e460a0 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -49,6 +49,8 @@
chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable
chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/power/suspend_resume/enable
+ chmod 0666 /sys/kernel/tracing/events/power/suspend_resume/enable
chmod 0666 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
chmod 0666 /sys/kernel/tracing/events/cpufreq_interactive/enable
chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 8d383f5..93bbe90 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -93,7 +93,6 @@
"libutils",
],
srcs: [
- "DumpstateSectionReporter.cpp",
"DumpstateService.cpp",
],
static_libs: [
diff --git a/cmds/dumpstate/DumpstateSectionReporter.cpp b/cmds/dumpstate/DumpstateSectionReporter.cpp
deleted file mode 100644
index f814bde..0000000
--- a/cmds/dumpstate/DumpstateSectionReporter.cpp
+++ /dev/null
@@ -1,42 +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 "dumpstate"
-
-#include "DumpstateSectionReporter.h"
-
-namespace android {
-namespace os {
-namespace dumpstate {
-
-DumpstateSectionReporter::DumpstateSectionReporter(const std::string& title,
- sp<android::os::IDumpstateListener> listener,
- bool sendReport)
- : title_(title), listener_(listener), sendReport_(sendReport), status_(OK), size_(-1) {
- started_ = std::chrono::steady_clock::now();
-}
-
-DumpstateSectionReporter::~DumpstateSectionReporter() {
- if ((listener_ != nullptr) && (sendReport_)) {
- auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now() - started_);
- listener_->onSectionComplete(title_, status_, size_, (int32_t)elapsed.count());
- }
-}
-
-} // namespace dumpstate
-} // namespace os
-} // namespace android
diff --git a/cmds/dumpstate/DumpstateSectionReporter.h b/cmds/dumpstate/DumpstateSectionReporter.h
deleted file mode 100644
index e971de8..0000000
--- a/cmds/dumpstate/DumpstateSectionReporter.h
+++ /dev/null
@@ -1,65 +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 ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
-#define ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
-
-#include <android/os/IDumpstateListener.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-namespace os {
-namespace dumpstate {
-
-
-/*
- * Helper class used to report per section details to a listener.
- *
- * Typical usage:
- *
- * DumpstateSectionReporter sectionReporter(title, listener, sendReport);
- * sectionReporter.setSize(5000);
- *
- */
-class DumpstateSectionReporter {
- public:
- DumpstateSectionReporter(const std::string& title, sp<android::os::IDumpstateListener> listener,
- bool sendReport);
-
- ~DumpstateSectionReporter();
-
- void setStatus(status_t status) {
- status_ = status;
- }
-
- void setSize(int size) {
- size_ = size;
- }
-
- private:
- std::string title_;
- android::sp<android::os::IDumpstateListener> listener_;
- bool sendReport_;
- status_t status_;
- int size_;
- std::chrono::time_point<std::chrono::steady_clock> started_;
-};
-
-} // namespace dumpstate
-} // namespace os
-} // namespace android
-
-#endif // ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 37ba4f9..f98df99 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -200,8 +200,7 @@
dprintf(fd, "id: %d\n", ds_->id_);
dprintf(fd, "pid: %d\n", ds_->pid_);
dprintf(fd, "update_progress: %s\n", ds_->options_->do_progress_updates ? "true" : "false");
- dprintf(fd, "update_progress_threshold: %d\n", ds_->update_progress_threshold_);
- dprintf(fd, "last_updated_progress: %d\n", ds_->last_updated_progress_);
+ dprintf(fd, "last_percent_progress: %d\n", ds_->last_reported_percent_progress_);
dprintf(fd, "progress:\n");
ds_->progress_->Dump(fd, " ");
dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index ea1e467..e486460 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -61,21 +61,4 @@
* Called when taking bugreport finishes successfully.
*/
void onFinished();
-
- // TODO(b/111441001): Remove old methods when not used anymore.
- void onProgressUpdated(int progress);
- void onMaxProgressUpdated(int maxProgress);
-
- /**
- * Called after every section is complete.
- *
- * @param name section name
- * @param status values from status_t
- * {@code OK} section completed successfully
- * {@code TIMEOUT} dump timed out
- * {@code != OK} error
- * @param size size in bytes, may be invalid if status != OK
- * @param durationMs duration in ms
- */
- void onSectionComplete(@utf8InCpp String name, int status, int size, int durationMs);
}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index bdb1363..e296eaa 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -43,10 +43,12 @@
#include <unistd.h>
#include <chrono>
+#include <cmath>
#include <fstream>
#include <functional>
#include <future>
#include <memory>
+#include <numeric>
#include <regex>
#include <set>
#include <string>
@@ -77,7 +79,6 @@
#include <serviceutils/PriorityDumper.h>
#include <utils/StrongPointer.h>
#include "DumpstateInternal.h"
-#include "DumpstateSectionReporter.h"
#include "DumpstateService.h"
#include "dumpstate.h"
@@ -102,7 +103,6 @@
using android::os::IDumpstateListener;
using android::os::dumpstate::CommandOptions;
using android::os::dumpstate::DumpFileToFd;
-using android::os::dumpstate::DumpstateSectionReporter;
using android::os::dumpstate::PropertiesHelper;
// Keep in sync with
@@ -115,8 +115,9 @@
// TODO: temporary variables and functions used during C++ refactoring
static Dumpstate& ds = Dumpstate::GetInstance();
static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
- const CommandOptions& options = CommandOptions::DEFAULT) {
- return ds.RunCommand(title, full_command, options);
+ const CommandOptions& options = CommandOptions::DEFAULT,
+ bool verbose_duration = false) {
+ return ds.RunCommand(title, full_command, options, verbose_duration);
}
// Reasonable value for max stats.
@@ -867,17 +868,17 @@
RunCommand(
"EVENT LOG",
{"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
- CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
timeout_ms = logcat_timeout({"stats"});
RunCommand(
"STATS LOG",
{"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
- CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+ 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());
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
@@ -1016,7 +1017,6 @@
RETURN_IF_USER_DENIED_CONSENT();
std::string path(title);
path.append(" - ").append(String8(service).c_str());
- DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
size_t bytes_written = 0;
status_t status = dumpsys.startDumpThread(service, args);
if (status == OK) {
@@ -1024,12 +1024,10 @@
std::chrono::duration<double> elapsed_seconds;
status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
/* as_proto = */ false, elapsed_seconds, bytes_written);
- section_reporter.setSize(bytes_written);
dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
bool dump_complete = (status == OK);
dumpsys.stopDumpThread(dump_complete);
}
- section_reporter.setStatus(status);
auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start);
@@ -1092,7 +1090,6 @@
path.append("_HIGH");
}
path.append(kProtoExt);
- DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
status_t status = dumpsys.startDumpThread(service, args);
if (status == OK) {
status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
@@ -1101,8 +1098,6 @@
}
ZipWriter::FileEntry file_entry;
ds.zip_writer_->GetLastEntry(&file_entry);
- section_reporter.setSize(file_entry.compressed_size);
- section_reporter.setStatus(status);
auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start);
@@ -1209,6 +1204,45 @@
}
}
+static void DumpExternalFragmentationInfo() {
+ struct stat st;
+ if (stat("/proc/buddyinfo", &st) != 0) {
+ MYLOGE("Unable to dump external fragmentation info\n");
+ return;
+ }
+
+ printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
+ std::ifstream ifs("/proc/buddyinfo");
+ auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
+ for (std::string line; std::getline(ifs, line);) {
+ std::smatch match_results;
+ if (std::regex_match(line, match_results, unusable_index_regex)) {
+ std::stringstream free_pages(std::string{match_results[3]});
+ std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
+ std::istream_iterator<int>());
+
+ int total_free_pages = 0;
+ for (size_t i = 0; i < free_pages_per_order.size(); i++) {
+ total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
+ }
+
+ printf("Node %s, zone %8s", match_results[1].str().c_str(),
+ match_results[2].str().c_str());
+
+ int usable_free_pages = total_free_pages;
+ for (size_t i = 0; i < free_pages_per_order.size(); i++) {
+ auto unusable_index = (total_free_pages - usable_free_pages) /
+ static_cast<double>(total_free_pages);
+ printf(" %5.3f", unusable_index);
+ usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
+ }
+
+ printf("\n");
+ }
+ }
+ printf("\n");
+}
+
// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
// via the consent they are shown. Ignores other errors that occur while running various
// commands. The consent checking is currently done around long running tasks, which happen to
@@ -1222,7 +1256,6 @@
dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
RunCommand("UPTIME", {"uptime"});
DumpBlockStatFiles();
- dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
DumpFile("MEMORY INFO", "/proc/meminfo");
RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
"pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
@@ -1235,11 +1268,10 @@
DumpFile("ZONEINFO", "/proc/zoneinfo");
DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
DumpFile("BUDDYINFO", "/proc/buddyinfo");
- DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
+ DumpExternalFragmentationInfo();
DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
- DumpFile("KERNEL SYNC", "/d/sync");
RunCommand("PROCESSES AND THREADS",
{"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
@@ -1477,6 +1509,8 @@
static void DumpstateRadioCommon() {
DumpIpTablesAsRoot();
+ ds.AddDir(LOGPERSIST_DATA_DIR, false);
+
if (!DropRootUser()) {
return;
}
@@ -1487,6 +1521,7 @@
DoKmsg();
DumpIpAddrAndRules();
dump_route_tables();
+ DumpHals();
RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
CommandOptions::WithTimeout(10).Build());
@@ -1556,8 +1591,6 @@
RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
- DumpHals();
-
printf("========================================================\n");
printf("== dumpstate: done (id %d)\n", ds.id_);
printf("========================================================\n");
@@ -2772,6 +2805,7 @@
Dumpstate::Dumpstate(const std::string& version)
: pid_(getpid()),
options_(new Dumpstate::DumpOptions()),
+ last_reported_percent_progress_(0),
version_(version),
now_(time(nullptr)) {
}
@@ -2781,8 +2815,8 @@
return singleton_;
}
-DurationReporter::DurationReporter(const std::string& title, bool logcat_only)
- : title_(title), logcat_only_(logcat_only) {
+DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
+ : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
if (!title_.empty()) {
started_ = Nanotime();
}
@@ -2791,7 +2825,7 @@
DurationReporter::~DurationReporter() {
if (!title_.empty()) {
float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
- if (elapsed < .5f) {
+ if (elapsed < .5f && !verbose_) {
return;
}
MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
@@ -3384,8 +3418,8 @@
}
int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
- const CommandOptions& options) {
- DurationReporter duration_reporter(title);
+ const CommandOptions& options, bool verbose_duration) {
+ DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
@@ -3534,31 +3568,25 @@
}
// Always update progess so stats can be tuned...
- bool max_changed = progress_->Inc(delta_sec);
+ progress_->Inc(delta_sec);
// ...but only notifiy listeners when necessary.
if (!options_->do_progress_updates) return;
int progress = progress_->Get();
int max = progress_->GetMax();
+ int percent = 100 * progress / max;
- // adjusts max on the fly
- if (max_changed && listener_ != nullptr) {
- listener_->onMaxProgressUpdated(max);
- }
-
- int32_t last_update_delta = progress - last_updated_progress_;
- if (last_updated_progress_ > 0 && last_update_delta < update_progress_threshold_) {
+ if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
return;
}
- last_updated_progress_ = progress;
+ last_reported_percent_progress_ = percent;
if (control_socket_fd_ >= 0) {
dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
fsync(control_socket_fd_);
}
- int percent = 100 * progress / max;
if (listener_ != nullptr) {
if (percent % 5 == 0) {
// We don't want to spam logcat, so only log multiples of 5.
@@ -3570,8 +3598,6 @@
fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
progress, max, percent);
}
- // TODO(b/111441001): Remove in favor of onProgress
- listener_->onProgressUpdated(progress);
listener_->onProgress(percent);
}
@@ -3604,110 +3630,3 @@
}
return info.st_mtime;
}
-
-void dump_emmc_ecsd(const char *ext_csd_path) {
- // List of interesting offsets
- struct hex {
- char str[2];
- };
- static const size_t EXT_CSD_REV = 192 * sizeof(hex);
- static const size_t EXT_PRE_EOL_INFO = 267 * sizeof(hex);
- static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_A = 268 * sizeof(hex);
- static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_B = 269 * sizeof(hex);
-
- std::string buffer;
- if (!android::base::ReadFileToString(ext_csd_path, &buffer)) {
- return;
- }
-
- printf("------ %s Extended CSD ------\n", ext_csd_path);
-
- if (buffer.length() < (EXT_CSD_REV + sizeof(hex))) {
- printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
- return;
- }
-
- int ext_csd_rev = 0;
- std::string sub = buffer.substr(EXT_CSD_REV, sizeof(hex));
- if (sscanf(sub.c_str(), "%2x", &ext_csd_rev) != 1) {
- printf("*** %s: EXT_CSD_REV parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
- return;
- }
-
- static const char *ver_str[] = {
- "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
- };
- printf("rev 1.%d (MMC %s)\n", ext_csd_rev,
- (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ? ver_str[ext_csd_rev]
- : "Unknown");
- if (ext_csd_rev < 7) {
- printf("\n");
- return;
- }
-
- if (buffer.length() < (EXT_PRE_EOL_INFO + sizeof(hex))) {
- printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length());
- return;
- }
-
- int ext_pre_eol_info = 0;
- sub = buffer.substr(EXT_PRE_EOL_INFO, sizeof(hex));
- if (sscanf(sub.c_str(), "%2x", &ext_pre_eol_info) != 1) {
- printf("*** %s: PRE_EOL_INFO parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
- return;
- }
-
- static const char *eol_str[] = {
- "Undefined",
- "Normal",
- "Warning (consumed 80% of reserve)",
- "Urgent (consumed 90% of reserve)"
- };
- printf(
- "PRE_EOL_INFO %d (MMC %s)\n", ext_pre_eol_info,
- eol_str[(ext_pre_eol_info < (int)(sizeof(eol_str) / sizeof(eol_str[0]))) ? ext_pre_eol_info
- : 0]);
-
- for (size_t lifetime = EXT_DEVICE_LIFE_TIME_EST_TYP_A;
- lifetime <= EXT_DEVICE_LIFE_TIME_EST_TYP_B;
- lifetime += sizeof(hex)) {
- int ext_device_life_time_est;
- static const char *est_str[] = {
- "Undefined",
- "0-10% of device lifetime used",
- "10-20% of device lifetime used",
- "20-30% of device lifetime used",
- "30-40% of device lifetime used",
- "40-50% of device lifetime used",
- "50-60% of device lifetime used",
- "60-70% of device lifetime used",
- "70-80% of device lifetime used",
- "80-90% of device lifetime used",
- "90-100% of device lifetime used",
- "Exceeded the maximum estimated device lifetime",
- };
-
- if (buffer.length() < (lifetime + sizeof(hex))) {
- printf("*** %s: truncated content %zu\n", ext_csd_path, buffer.length());
- break;
- }
-
- ext_device_life_time_est = 0;
- sub = buffer.substr(lifetime, sizeof(hex));
- if (sscanf(sub.c_str(), "%2x", &ext_device_life_time_est) != 1) {
- printf("*** %s: DEVICE_LIFE_TIME_EST_TYP_%c parse error \"%s\"\n", ext_csd_path,
- (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
- sub.c_str());
- continue;
- }
- printf("DEVICE_LIFE_TIME_EST_TYP_%c %d (MMC %s)\n",
- (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
- ext_device_life_time_est,
- est_str[(ext_device_life_time_est < (int)(sizeof(est_str) / sizeof(est_str[0])))
- ? ext_device_life_time_est
- : 0]);
- }
-
- printf("\n");
-}
-
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index ae6a721..82bf821 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -73,13 +73,15 @@
*/
class DurationReporter {
public:
- explicit DurationReporter(const std::string& title, bool logcat_only = false);
+ explicit DurationReporter(const std::string& title, bool logcat_only = false,
+ bool verbose = false);
~DurationReporter();
private:
std::string title_;
bool logcat_only_;
+ bool verbose_;
uint64_t started_;
DISALLOW_COPY_AND_ASSIGN(DurationReporter);
@@ -224,7 +226,8 @@
*/
int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
const android::os::dumpstate::CommandOptions& options =
- android::os::dumpstate::CommandOptions::DEFAULT);
+ android::os::dumpstate::CommandOptions::DEFAULT,
+ bool verbose_duration = false);
/*
* Runs `dumpsys` with the given arguments, automatically setting its timeout
@@ -400,12 +403,8 @@
// Runtime options.
std::unique_ptr<DumpOptions> options_;
- // How frequently the progess should be updated;the listener will only be notificated when the
- // delta from the previous update is more than the threshold.
- int32_t update_progress_threshold_ = 100;
-
- // Last progress that triggered a listener updated
- int32_t last_updated_progress_;
+ // Last progress that was sent to the listener [0-100].
+ int last_reported_percent_progress_ = 0;
// Whether it should take an screenshot earlier in the process.
bool do_early_screenshot_ = false;
@@ -585,9 +584,6 @@
/** Gets the last modification time of a file, or default time if file is not found. */
time_t get_mtime(int fd, time_t default_mtime);
-/* Dumps eMMC Extended CSD data. */
-void dump_emmc_ecsd(const char *ext_csd_path);
-
/** Gets command-line arguments. */
void format_args(int argc, const char *argv[], std::string *args);
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index f7acaf1..181046a 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -167,26 +167,6 @@
return binder::Status::ok();
}
- binder::Status onProgressUpdated(int32_t progress) override {
- dprintf(out_fd_, "\rIn progress %d/%d", progress, max_progress_);
- return binder::Status::ok();
- }
-
- binder::Status onMaxProgressUpdated(int32_t max_progress) override {
- std::lock_guard<std::mutex> lock(lock_);
- max_progress_ = max_progress;
- return binder::Status::ok();
- }
-
- binder::Status onSectionComplete(const ::std::string& name, int32_t, int32_t size_bytes,
- int32_t) override {
- std::lock_guard<std::mutex> lock(lock_);
- if (sections_.get() != nullptr) {
- sections_->push_back({name, size_bytes});
- }
- return binder::Status::ok();
- }
-
bool getIsFinished() {
std::lock_guard<std::mutex> lock(lock_);
return is_finished_;
@@ -199,7 +179,6 @@
private:
int out_fd_;
- int max_progress_ = 5000;
int error_code_ = -1;
bool is_finished_ = false;
std::shared_ptr<std::vector<SectionInfo>> sections_;
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 4e6b084..cff1d43 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -62,10 +62,6 @@
MOCK_METHOD1(onProgress, binder::Status(int32_t progress));
MOCK_METHOD1(onError, binder::Status(int32_t error_code));
MOCK_METHOD0(onFinished, binder::Status());
- MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
- MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
- MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status,
- int32_t size, int32_t durationMs));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
@@ -590,7 +586,6 @@
SetDryRun(false);
SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
ds.progress_.reset(new Progress());
- ds.update_progress_threshold_ = 0;
ds.options_.reset(new Dumpstate::DumpOptions());
}
@@ -615,10 +610,9 @@
return status;
}
- void SetProgress(long progress, long initial_max, long threshold = 0) {
+ void SetProgress(long progress, long initial_max) {
+ ds.last_reported_percent_progress_ = 0;
ds.options_->do_progress_updates = true;
- ds.update_progress_threshold_ = threshold;
- ds.last_updated_progress_ = 0;
ds.progress_.reset(new Progress(initial_max, progress, 1.2));
}
@@ -796,73 +790,36 @@
ds.listener_name_ = "FoxMulder";
SetProgress(0, 30);
- EXPECT_CALL(*listener, onProgressUpdated(20));
EXPECT_CALL(*listener, onProgress(66)); // 20/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
- EXPECT_CALL(*listener, onProgressUpdated(30));
- EXPECT_CALL(*listener, onProgress(100)); // 35/35 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
- EXPECT_THAT(out, StrEq("stdout\n"));
- EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
-
- // Run a command that will increase maximum timeout.
- EXPECT_CALL(*listener, onProgressUpdated(31));
- EXPECT_CALL(*listener, onMaxProgressUpdated(37));
- EXPECT_CALL(*listener, onProgress(83)); // 31/37 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30); // 20% increase
+ EXPECT_CALL(*listener, onProgress(80)); // 24/30 %
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
+ progress_message = GetProgressMessage(ds.listener_name_, 24, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
// Make sure command ran while in dry_run is counted.
SetDryRun(true);
- EXPECT_CALL(*listener, onProgressUpdated(35));
- EXPECT_CALL(*listener, onProgress(94)); // 35/37 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
+ EXPECT_CALL(*listener, onProgress(90)); // 27/30 %
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
+ progress_message = GetProgressMessage(ds.listener_name_, 27, 30);
EXPECT_THAT(out, IsEmpty());
EXPECT_THAT(err, StrEq(progress_message));
- ds.listener_.clear();
-}
-
-TEST_F(DumpstateTest, RunCommandProgressIgnoreThreshold) {
- sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
- ds.listener_ = listener;
- ds.listener_name_ = "FoxMulder";
- SetProgress(0, 8, 5); // 8 max, 5 threshold
-
- // First update should always be sent.
- EXPECT_CALL(*listener, onProgressUpdated(1));
- EXPECT_CALL(*listener, onProgress(12)); // 1/12 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
- std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8);
+ SetDryRun(false);
+ EXPECT_CALL(*listener, onProgress(96)); // 29/30 %
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(2).Build()));
+ progress_message = GetProgressMessage(ds.listener_name_, 29, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
- // Fourth update should be ignored because it's between the threshold (5 -1 = 4 < 5).
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
- EXPECT_THAT(out, StrEq("stdout\n"));
- EXPECT_THAT(err, StrEq("stderr\n"));
-
- // Third update should be sent because it reaches threshold (6 - 1 = 5).
- EXPECT_CALL(*listener, onProgressUpdated(6));
- EXPECT_CALL(*listener, onProgress(75)); // 6/8 %
+ EXPECT_CALL(*listener, onProgress(100)); // 30/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 6, 8);
- EXPECT_THAT(out, StrEq("stdout\n"));
- EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
-
- // Fourth update should be ignored because it's between the threshold (9 - 6 = 3 < 5).
- // But max update should be sent.
- EXPECT_CALL(*listener, onMaxProgressUpdated(10)); // 9 * 120% = 10.8 = 10
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 9, 10, 8, false);
+ progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
@@ -1090,7 +1047,6 @@
ds.listener_name_ = "FoxMulder";
SetProgress(0, 30);
- EXPECT_CALL(*listener, onProgressUpdated(5));
EXPECT_CALL(*listener, onProgress(16)); // 5/30 %
EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 73780ec..0212bc5 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -275,7 +275,7 @@
writer.StartEntry("primary.prof", ZipWriter::kCompress);
writer.FinishEntry();
writer.Finish();
- close(fd);
+ fclose(file);
}
// Create the app user data.
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 4760818..c4aed95 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -71,6 +71,7 @@
"ProcessInfoService.cpp",
"ProcessState.cpp",
"Static.cpp",
+ "Stability.cpp",
"Status.cpp",
"TextOutput.cpp",
"IpPrefix.cpp",
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 1729d6a..221c002 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -81,6 +81,24 @@
return target->transact(SHELL_COMMAND_TRANSACTION, send, &reply);
}
+status_t IBinder::getExtension(sp<IBinder>* out) {
+ BBinder* local = this->localBinder();
+ if (local != nullptr) {
+ *out = local->getExtension();
+ return OK;
+ }
+
+ BpBinder* proxy = this->remoteBinder();
+ LOG_ALWAYS_FATAL_IF(proxy == nullptr);
+
+ Parcel data;
+ Parcel reply;
+ status_t status = transact(EXTENSION_TRANSACTION, data, &reply);
+ if (status != OK) return status;
+
+ return reply.readNullableStrongBinder(out);
+}
+
// ---------------------------------------------------------------------------
class BBinder::Extras
@@ -88,6 +106,7 @@
public:
// unlocked objects
bool mRequestingSid = false;
+ sp<IBinder> mExtension;
// for below objects
Mutex mLock;
@@ -130,11 +149,15 @@
case PING_TRANSACTION:
err = pingBinder();
break;
+ case EXTENSION_TRANSACTION:
+ err = reply->writeStrongBinder(getExtension());
+ break;
default:
err = onTransact(code, data, reply, flags);
break;
}
+ // In case this is being transacted on in the same process.
if (reply != nullptr) {
reply->setDataPosition(0);
}
@@ -221,6 +244,17 @@
e->mRequestingSid = true;
}
+sp<IBinder> BBinder::getExtension() {
+ Extras* e = mExtras.load(std::memory_order_acquire);
+ if (e == nullptr) return nullptr;
+ return e->mExtension;
+}
+
+void BBinder::setExtension(const sp<IBinder>& extension) {
+ Extras* e = getOrCreateExtras();
+ e->mExtension = extension;
+}
+
BBinder::~BBinder()
{
Extras* e = mExtras.load(std::memory_order_relaxed);
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 5ceb218..425ece3 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -21,6 +21,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
+#include <binder/Stability.h>
#include <cutils/compiler.h>
#include <utils/Log.h>
@@ -213,9 +214,22 @@
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
+ // user transactions require a given stability level
+ // Cannot add requirement w/o SM update
+ // if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
+ // using android::internal::Stability;
+
+ // auto stability = Stability::get(this);
+
+ // if (CC_UNLIKELY(!Stability::check(stability, Stability::kLocalStability))) {
+ // return BAD_TYPE;
+ // }
+ // }
+
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
+
return status;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index aa9d188..485869e 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -35,6 +35,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
+#include <binder/Stability.h>
#include <binder/Status.h>
#include <binder/TextOutput.h>
@@ -164,14 +165,34 @@
ALOGE("Invalid object type 0x%08x", obj.hdr.type);
}
-inline static status_t finish_flatten_binder(
- const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
+status_t Parcel::finishFlattenBinder(
+ const sp<IBinder>& /*binder*/, const flat_binder_object& flat)
{
- return out->writeObject(flat, false);
+ status_t status = writeObject(flat, false);
+ if (status != OK) return status;
+
+ // internal::Stability::tryMarkCompilationUnit(binder.get());
+ // Cannot change wire protocol w/o SM update
+ // return writeInt32(internal::Stability::get(binder.get()));
+ return OK;
}
-static status_t flatten_binder(const sp<ProcessState>& /*proc*/,
- const sp<IBinder>& binder, Parcel* out)
+status_t Parcel::finishUnflattenBinder(
+ const sp<IBinder>& binder, sp<IBinder>* out) const
+{
+ // int32_t stability;
+ // Cannot change wire protocol w/o SM update
+ // status_t status = readInt32(&stability);
+ // if (status != OK) return status;
+
+ // status = internal::Stability::set(binder.get(), stability, true /*log*/);
+ // if (status != OK) return status;
+
+ *out = binder;
+ return OK;
+}
+
+status_t Parcel::flattenBinder(const sp<IBinder>& binder)
{
flat_binder_object obj;
@@ -209,30 +230,24 @@
obj.cookie = 0;
}
- return finish_flatten_binder(binder, obj, out);
+ return finishFlattenBinder(binder, obj);
}
-inline static status_t finish_unflatten_binder(
- BpBinder* /*proxy*/, const flat_binder_object& /*flat*/,
- const Parcel& /*in*/)
+status_t Parcel::unflattenBinder(sp<IBinder>* out) const
{
- return NO_ERROR;
-}
-
-static status_t unflatten_binder(const sp<ProcessState>& proc,
- const Parcel& in, sp<IBinder>* out)
-{
- const flat_binder_object* flat = in.readObject(false);
+ const flat_binder_object* flat = readObject(false);
if (flat) {
switch (flat->hdr.type) {
- case BINDER_TYPE_BINDER:
- *out = reinterpret_cast<IBinder*>(flat->cookie);
- return finish_unflatten_binder(nullptr, *flat, in);
- case BINDER_TYPE_HANDLE:
- *out = proc->getStrongProxyForHandle(flat->handle);
- return finish_unflatten_binder(
- static_cast<BpBinder*>(out->get()), *flat, in);
+ case BINDER_TYPE_BINDER: {
+ sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie);
+ return finishUnflattenBinder(binder, out);
+ }
+ case BINDER_TYPE_HANDLE: {
+ sp<IBinder> binder =
+ ProcessState::self()->getStrongProxyForHandle(flat->handle);
+ return finishUnflattenBinder(binder, out);
+ }
}
}
return BAD_TYPE;
@@ -965,7 +980,7 @@
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
- return flatten_binder(ProcessState::self(), val, this);
+ return flattenBinder(val);
}
status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
@@ -1782,8 +1797,8 @@
const char* Parcel::readCString() const
{
- const size_t avail = mDataSize-mDataPos;
- if (avail > 0) {
+ if (mDataPos < mDataSize) {
+ const size_t avail = mDataSize-mDataPos;
const char* str = reinterpret_cast<const char*>(mData+mDataPos);
// is the string's trailing NUL within the parcel's valid bounds?
const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));
@@ -1903,7 +1918,7 @@
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
- return unflatten_binder(ProcessState::self(), *this, val);
+ return unflattenBinder(val);
}
sp<IBinder> Parcel::readStrongBinder() const
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 1e1bc3a..07db50f 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -21,6 +21,7 @@
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/Stability.h>
#include <cutils/atomic.h>
#include <utils/Log.h>
#include <utils/String8.h>
@@ -109,7 +110,13 @@
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
- return getStrongProxyForHandle(0);
+ sp<IBinder> context = getStrongProxyForHandle(0);
+
+ // The root object is special since we get it directly from the driver, it is never
+ // written by Parcell::writeStrongBinder.
+ internal::Stability::tryMarkCompilationUnit(context.get());
+
+ return context;
}
void ProcessState::startThreadPool()
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
new file mode 100644
index 0000000..b6f10c8
--- /dev/null
+++ b/libs/binder/Stability.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <binder/Stability.h>
+
+namespace android {
+namespace internal {
+
+void Stability::markCompilationUnit(IBinder* binder) {
+ status_t result = set(binder, kLocalStability, true /*log*/);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::markVintf(IBinder* binder) {
+ status_t result = set(binder, Level::VINTF, true /*log*/);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::debugLogStability(const std::string& tag, const sp<IBinder>& binder) {
+ ALOGE("%s: stability is %s", tag.c_str(), stabilityString(get(binder.get())).c_str());
+}
+
+void Stability::markVndk(IBinder* binder) {
+ status_t result = set(binder, Level::VENDOR, true /*log*/);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::tryMarkCompilationUnit(IBinder* binder) {
+ (void) set(binder, kLocalStability, false /*log*/);
+}
+
+status_t Stability::set(IBinder* binder, int32_t stability, bool log) {
+ Level currentStability = get(binder);
+
+ // null binder is always written w/ 'UNDECLARED' stability
+ if (binder == nullptr) {
+ if (stability == UNDECLARED) {
+ return OK;
+ } else {
+ if (log) {
+ ALOGE("Null binder written with stability %s.",
+ stabilityString(stability).c_str());
+ }
+ return BAD_TYPE;
+ }
+ }
+
+ if (!isDeclaredStability(stability)) {
+ if (log) {
+ ALOGE("Can only set known stability, not %d.", stability);
+ }
+ return BAD_TYPE;
+ }
+
+ if (currentStability != Level::UNDECLARED && currentStability != stability) {
+ if (log) {
+ ALOGE("Interface being set with %s but it is already marked as %s.",
+ stabilityString(stability).c_str(), stabilityString(currentStability).c_str());
+ }
+ return BAD_TYPE;
+ }
+
+ if (currentStability == stability) return OK;
+
+ binder->attachObject(
+ reinterpret_cast<void*>(&Stability::get),
+ reinterpret_cast<void*>(stability),
+ nullptr /*cleanupCookie*/,
+ nullptr /*cleanup function*/);
+
+ return OK;
+}
+
+Stability::Level Stability::get(IBinder* binder) {
+ if (binder == nullptr) return UNDECLARED;
+
+ return static_cast<Level>(reinterpret_cast<intptr_t>(
+ binder->findObject(reinterpret_cast<void*>(&Stability::get))));
+}
+
+bool Stability::check(int32_t provided, Level required) {
+ bool stable = (provided & required) == required;
+
+ if (!isDeclaredStability(provided) && provided != UNDECLARED) {
+ ALOGE("Unknown stability when checking interface stability %d.", provided);
+
+ stable = false;
+ }
+
+ if (!stable) {
+ ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
+ stabilityString(provided).c_str(),
+ stabilityString(required).c_str());
+ }
+
+ return stable;
+}
+
+bool Stability::isDeclaredStability(int32_t stability) {
+ return stability == VENDOR || stability == SYSTEM || stability == VINTF;
+}
+
+std::string Stability::stabilityString(int32_t stability) {
+ switch (stability) {
+ case Level::UNDECLARED: return "undeclared stability";
+ case Level::VENDOR: return "vendor stability";
+ case Level::SYSTEM: return "system stability";
+ case Level::VINTF: return "vintf stability";
+ }
+ return "unknown stability " + std::to_string(stability);
+}
+
+} // namespace internal
+} // namespace stability
\ No newline at end of file
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index 8b33a56..0ad99ce 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -102,13 +102,23 @@
// Skip over fat response headers. Not used (or propagated) in native code.
if (mException == EX_HAS_REPLY_HEADER) {
// Note that the header size includes the 4 byte size field.
- const int32_t header_start = parcel.dataPosition();
+ const size_t header_start = parcel.dataPosition();
+ // Get available size before reading more
+ const size_t header_avail = parcel.dataAvail();
+
int32_t header_size;
status = parcel.readInt32(&header_size);
if (status != OK) {
setFromStatusT(status);
return status;
}
+
+ if (header_size < 0 || static_cast<size_t>(header_size) > header_avail) {
+ android_errorWriteLog(0x534e4554, "132650049");
+ setFromStatusT(UNKNOWN_ERROR);
+ return UNKNOWN_ERROR;
+ }
+
parcel.setDataPosition(header_start + header_size);
// And fat response headers are currently only used when there are no
// exceptions, so act like there was no error.
@@ -135,19 +145,36 @@
setFromStatusT(status);
return status;
}
+ if (remote_stack_trace_header_size < 0 ||
+ static_cast<size_t>(remote_stack_trace_header_size) > parcel.dataAvail()) {
+
+ android_errorWriteLog(0x534e4554, "132650049");
+ setFromStatusT(UNKNOWN_ERROR);
+ return UNKNOWN_ERROR;
+ }
parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size);
if (mException == EX_SERVICE_SPECIFIC) {
status = parcel.readInt32(&mErrorCode);
} else if (mException == EX_PARCELABLE) {
// Skip over the blob of Parcelable data
- const int32_t header_start = parcel.dataPosition();
+ const size_t header_start = parcel.dataPosition();
+ // Get available size before reading more
+ const size_t header_avail = parcel.dataAvail();
+
int32_t header_size;
status = parcel.readInt32(&header_size);
if (status != OK) {
setFromStatusT(status);
return status;
}
+
+ if (header_size < 0 || static_cast<size_t>(header_size) > header_avail) {
+ android_errorWriteLog(0x534e4554, "132650049");
+ setFromStatusT(UNKNOWN_ERROR);
+ return UNKNOWN_ERROR;
+ }
+
parcel.setDataPosition(header_start + header_size);
}
if (status != OK) {
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 1537e69..1095c7f 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -38,7 +38,7 @@
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
- uint32_t flags = 0);
+ uint32_t flags = 0) final;
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
@@ -64,6 +64,10 @@
// This must be called before the object is sent to another process. Not thread safe.
void setRequestingSid(bool requestSid);
+ sp<IBinder> getExtension();
+ // This must be called before the object is sent to another process. Not thread safe.
+ void setExtension(const sp<IBinder>& extension);
+
protected:
virtual ~BBinder();
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index e71541b..28599f4 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -45,7 +45,7 @@
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
- uint32_t flags = 0);
+ uint32_t flags = 0) final;
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index aa44285..408037e 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -59,6 +59,7 @@
SHELL_COMMAND_TRANSACTION = B_PACK_CHARS('_','C','M','D'),
INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
SYSPROPS_TRANSACTION = B_PACK_CHARS('_', 'S', 'P', 'R'),
+ EXTENSION_TRANSACTION = B_PACK_CHARS('_', 'E', 'X', 'T'),
// Corresponds to TF_ONE_WAY -- an asynchronous call.
FLAG_ONEWAY = 0x00000001
@@ -86,6 +87,49 @@
Vector<String16>& args, const sp<IShellCallback>& callback,
const sp<IResultReceiver>& resultReceiver);
+ /**
+ * This allows someone to add their own additions to an interface without
+ * having to modify the original interface.
+ *
+ * For instance, imagine if we have this interface:
+ * interface IFoo { void doFoo(); }
+ *
+ * If an unrelated owner (perhaps in a downstream codebase) wants to make a
+ * change to the interface, they have two options:
+ *
+ * A). Historical option that has proven to be BAD! Only the original
+ * author of an interface should change an interface. If someone
+ * downstream wants additional functionality, they should not ever
+ * change the interface or use this method.
+ *
+ * BAD TO DO: interface IFoo { BAD TO DO
+ * BAD TO DO: void doFoo(); BAD TO DO
+ * BAD TO DO: + void doBar(); // adding a method BAD TO DO
+ * BAD TO DO: } BAD TO DO
+ *
+ * B). Option that this method enables!
+ * Leave the original interface unchanged (do not change IFoo!).
+ * Instead, create a new interface in a downstream package:
+ *
+ * package com.<name>; // new functionality in a new package
+ * interface IBar { void doBar(); }
+ *
+ * When registering the interface, add:
+ * sp<MyFoo> foo = new MyFoo; // class in AOSP codebase
+ * sp<MyBar> bar = new MyBar; // custom extension class
+ * foo->setExtension(bar); // use method in BBinder
+ *
+ * Then, clients of IFoo can get this extension:
+ * sp<IBinder> binder = ...;
+ * sp<IFoo> foo = interface_cast<IFoo>(binder); // handle if null
+ * sp<IBinder> barBinder;
+ * ... handle error ... = binder->getExtension(&barBinder);
+ * sp<IBar> bar = interface_cast<IBar>(barBinder);
+ * // if bar is null, then there is no extension or a different
+ * // type of extension
+ */
+ status_t getExtension(sp<IBinder>* out);
+
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t transact( uint32_t code,
const Parcel& data,
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 3c56fcb..c8f82a3 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -67,7 +67,7 @@
status_t setDataSize(size_t size);
void setDataPosition(size_t pos) const;
status_t setDataCapacity(size_t size);
-
+
status_t setData(const uint8_t* buffer, size_t len);
status_t appendFrom(const Parcel *parcel,
@@ -408,7 +408,13 @@
void initState();
void scanForFds() const;
status_t validateReadData(size_t len) const;
-
+
+ status_t finishFlattenBinder(const sp<IBinder>& binder,
+ const flat_binder_object& flat);
+ status_t finishUnflattenBinder(const sp<IBinder>& binder, sp<IBinder>* out) const;
+ status_t flattenBinder(const sp<IBinder>& binder);
+ status_t unflattenBinder(sp<IBinder>* out) const;
+
template<class T>
status_t readAligned(T *pArg) const;
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
new file mode 100644
index 0000000..f8240e4
--- /dev/null
+++ b/libs/binder/include/binder/Stability.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IBinder.h>
+#include <string>
+
+namespace android {
+
+class BpBinder;
+class ProcessState;
+
+namespace internal {
+
+// WARNING: These APIs are only ever expected to be called by auto-generated code.
+// Instead of calling them, you should set the stability of a .aidl interface
+class Stability final {
+public:
+ // WARNING: This is only ever expected to be called by auto-generated code. You likely want to
+ // change or modify the stability class of the interface you are using.
+ // This must be called as soon as the binder in question is constructed. No thread safety
+ // is provided.
+ // E.g. stability is according to libbinder compilation unit
+ static void markCompilationUnit(IBinder* binder);
+ // WARNING: This is only ever expected to be called by auto-generated code. You likely want to
+ // change or modify the stability class of the interface you are using.
+ // This must be called as soon as the binder in question is constructed. No thread safety
+ // is provided.
+ // E.g. stability is according to libbinder_ndk or Java SDK AND the interface
+ // expressed here is guaranteed to be stable for multiple years (Stable AIDL)
+ static void markVintf(IBinder* binder);
+
+ // WARNING: for debugging only
+ static void debugLogStability(const std::string& tag, const sp<IBinder>& binder);
+
+ // WARNING: This is only ever expected to be called by auto-generated code or tests.
+ // You likely want to change or modify the stability of the interface you are using.
+ // This must be called as soon as the binder in question is constructed. No thread safety
+ // is provided.
+ // E.g. stability is according to libbinder_ndk or Java SDK AND the interface
+ // expressed here is guaranteed to be stable for multiple years (Stable AIDL)
+ // If this is called when __ANDROID_VNDK__ is not defined, then it is UB and will likely
+ // break the device during GSI or other tests.
+ static void markVndk(IBinder* binder);
+
+private:
+ // Parcel needs to read/write stability level in an unstable format.
+ friend ::android::Parcel;
+
+ // only expose internal APIs inside of libbinder, for checking stability
+ friend ::android::BpBinder;
+
+ // so that it can mark the context object (only the root object doesn't go
+ // through Parcel)
+ friend ::android::ProcessState;
+
+ static void tryMarkCompilationUnit(IBinder* binder);
+
+ enum Level : int32_t {
+ UNDECLARED = 0,
+
+ VENDOR = 0b000011,
+ SYSTEM = 0b001100,
+ VINTF = 0b111111,
+ };
+
+#ifdef __ANDROID_VNDK__
+ static constexpr Level kLocalStability = Level::VENDOR;
+#else
+ static constexpr Level kLocalStability = Level::SYSTEM;
+#endif
+
+ // applies stability to binder if stability level is known
+ __attribute__((warn_unused_result))
+ static status_t set(IBinder* binder, int32_t stability, bool log);
+
+ static Level get(IBinder* binder);
+
+ static bool check(int32_t provided, Level required);
+
+ static bool isDeclaredStability(int32_t stability);
+ static std::string stabilityString(int32_t stability);
+
+ Stability();
+};
+
+} // namespace internal
+} // namespace android
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 6da3086..734a928 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-cc_library {
+cc_library_shared {
name: "libbinder_ndk",
export_include_dirs: [
"include_ndk",
- "include_apex",
+ "include_platform",
],
cflags: [
@@ -33,6 +33,7 @@
"ibinder_jni.cpp",
"parcel.cpp",
"process.cpp",
+ "stability.cpp",
"status.cpp",
"service_manager.cpp",
],
@@ -54,7 +55,7 @@
version_script: "libbinder_ndk.map.txt",
stubs: {
symbol_file: "libbinder_ndk.map.txt",
- versions: ["29"],
+ versions: ["29", "30"],
},
}
@@ -79,6 +80,6 @@
symbol_file: "libbinder_ndk.map.txt",
export_include_dirs: [
"include_ndk",
- "include_apex",
+ "include_platform",
],
}
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index bd6886d..b06ca86 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -589,3 +589,40 @@
recipient->decStrong(nullptr);
}
+
+binder_status_t AIBinder_getExtension(AIBinder* binder, AIBinder** outExt) {
+ if (binder == nullptr || outExt == nullptr) {
+ if (outExt != nullptr) {
+ *outExt = nullptr;
+ }
+ return STATUS_UNEXPECTED_NULL;
+ }
+
+ sp<IBinder> ext;
+ status_t res = binder->getBinder()->getExtension(&ext);
+
+ if (res != android::OK) {
+ *outExt = nullptr;
+ return PruneStatusT(res);
+ }
+
+ sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(ext);
+ if (ret != nullptr) ret->incStrong(binder);
+
+ *outExt = ret.get();
+ return STATUS_OK;
+}
+
+binder_status_t AIBinder_setExtension(AIBinder* binder, AIBinder* ext) {
+ if (binder == nullptr || ext == nullptr) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+
+ ABBinder* rawBinder = binder->asABBinder();
+ if (rawBinder == nullptr) {
+ return STATUS_INVALID_OPERATION;
+ }
+
+ rawBinder->setExtension(ext->getBinder());
+ return STATUS_OK;
+}
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 80d1254..160739b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -510,6 +510,76 @@
void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29);
#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+
+#if __ANDROID_API__ >= __ANDROID_API_R__
+
+/**
+ * Gets the extension registered with AIBinder_setExtension.
+ *
+ * See AIBinder_setExtension.
+ *
+ * \param binder the object to get the extension of.
+ * \param outExt the returned extension object. Will be null if there is no extension set or
+ * non-null with one strong ref count.
+ *
+ * \return error of getting the interface (may be a transaction error if this is
+ * remote binder). STATUS_UNEXPECTED_NULL if binder is null.
+ */
+binder_status_t AIBinder_getExtension(AIBinder* binder, AIBinder** outExt) __INTRODUCED_IN(30);
+
+/**
+ * Gets the extension of a binder interface. This allows a downstream developer to add
+ * an extension to an interface without modifying its interface file. This should be
+ * called immediately when the object is created before it is passed to another thread.
+ * No thread safety is required.
+ *
+ * For instance, imagine if we have this interface:
+ * interface IFoo { void doFoo(); }
+ *
+ * A). Historical option that has proven to be BAD! Only the original
+ * author of an interface should change an interface. If someone
+ * downstream wants additional functionality, they should not ever
+ * change the interface or use this method.
+ *
+ * BAD TO DO: interface IFoo { BAD TO DO
+ * BAD TO DO: void doFoo(); BAD TO DO
+ * BAD TO DO: + void doBar(); // adding a method BAD TO DO
+ * BAD TO DO: } BAD TO DO
+ *
+ * B). Option that this method enables.
+ * Leave the original interface unchanged (do not change IFoo!).
+ * Instead, create a new interface in a downstream package:
+ *
+ * package com.<name>; // new functionality in a new package
+ * interface IBar { void doBar(); }
+ *
+ * When registering the interface, add:
+ * std::shared_ptr<MyFoo> foo = new MyFoo; // class in AOSP codebase
+ * std::shared_ptr<MyBar> bar = new MyBar; // custom extension class
+ * ... = AIBinder_setExtension(foo->asBinder().get(), bar->asBinder().get());
+ * // handle error
+ *
+ * Then, clients of IFoo can get this extension:
+ * SpAIBinder binder = ...;
+ * std::shared_ptr<IFoo> foo = IFoo::fromBinder(binder); // handle if null
+ * SpAIBinder barBinder;
+ * ... = AIBinder_getExtension(barBinder.get());
+ * // handle error
+ * std::shared_ptr<IBar> bar = IBar::fromBinder(barBinder);
+ * // type is checked with AIBinder_associateClass
+ * // if bar is null, then there is no extension or a different
+ * // type of extension
+ *
+ * \param binder the object to get the extension on. Must be local.
+ * \param ext the extension to set (binder will hold a strong reference to this)
+ *
+ * \return OK on success, STATUS_INVALID_OPERATION if binder is not local, STATUS_UNEXPECTED_NULL
+ * if either binder is null.
+ */
+binder_status_t AIBinder_setExtension(AIBinder* binder, AIBinder* ext) __INTRODUCED_IN(30);
+
+#endif //__ANDROID_API__ >= __ANDROID_API_R__
+
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
similarity index 100%
rename from libs/binder/ndk/include_apex/android/binder_manager.h
rename to libs/binder/ndk/include_platform/android/binder_manager.h
diff --git a/libs/binder/ndk/include_apex/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
similarity index 100%
rename from libs/binder/ndk/include_apex/android/binder_process.h
rename to libs/binder/ndk/include_platform/android/binder_process.h
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
new file mode 100644
index 0000000..e6aeb04
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+
+__BEGIN_DECLS
+
+#ifdef __ANDROID_VNDK__
+
+/**
+ * This interface has the stability of the vendor image.
+ */
+void AIBinder_markVendorStability(AIBinder* binder);
+
+static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) {
+ AIBinder_markVendorStability(binder);
+}
+
+#else // ndef defined __ANDROID_VNDK__
+
+/**
+ * This interface has the stability of the system image.
+ */
+void AIBinder_markSystemStability(AIBinder* binder);
+
+static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) {
+ AIBinder_markSystemStability(binder);
+}
+
+#endif // ifdef __ANDROID_VNDK__
+
+/**
+ * This interface has system<->vendor stability
+ */
+void AIBinder_markVintfStability(AIBinder* binder);
+
+__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 4f685d1..d4d5387 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -98,3 +98,15 @@
local:
*;
};
+
+LIBBINDER_NDK30 { # introduced=30
+ global:
+ AIBinder_getExtension;
+ AIBinder_setExtension;
+
+ AIBinder_markSystemStability; # apex
+ AIBinder_markVendorStability; # vndk
+ AIBinder_markVintfStability; # apex vndk
+ local:
+ *;
+};
diff --git a/libs/binder/ndk/stability.cpp b/libs/binder/ndk/stability.cpp
new file mode 100644
index 0000000..a5b3ece
--- /dev/null
+++ b/libs/binder/ndk/stability.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_stability.h>
+
+#include <binder/Stability.h>
+#include "ibinder_internal.h"
+
+#include <log/log.h>
+
+using ::android::internal::Stability;
+
+#ifdef __ANDROID_VNDK__
+#error libbinder_ndk should only be built in a system context
+#endif
+
+#ifdef __ANDROID_NDK__
+#error libbinder_ndk should only be built in a system context
+#endif
+
+// explicit extern because symbol is only declared in header when __ANDROID_VNDK__
+extern "C" void AIBinder_markVendorStability(AIBinder* binder) {
+ Stability::markVndk(binder->getBinder().get());
+}
+
+void AIBinder_markSystemStability(AIBinder* binder) {
+ Stability::markCompilationUnit(binder->getBinder().get());
+}
+
+void AIBinder_markVintfStability(AIBinder* binder) {
+ Stability::markVintf(binder->getBinder().get());
+}
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 8cd4e03..bb1fe2f 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -44,10 +44,10 @@
"libandroid_runtime_lazy",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libutils",
],
static_libs: [
- "libbinder_ndk",
"test_libbinder_ndk_library",
],
}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 44a691d..bc457ce 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -137,3 +137,31 @@
],
test_suites: ["device-tests"],
}
+
+aidl_interface {
+ name: "binderStabilityTestIface",
+ srcs: [
+ "IBinderStabilityTest.aidl",
+ ],
+}
+
+cc_test {
+ name: "binderStabilityTest",
+ defaults: ["binder_test_defaults"],
+ srcs: [
+ "binderStabilityTest.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder_ndk",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "binderStabilityTestIface-cpp",
+ "binderStabilityTestIface-ndk_platform",
+ ],
+
+ test_suites: ["device-tests"],
+}
diff --git a/libs/binder/tests/IBinderStabilityTest.aidl b/libs/binder/tests/IBinderStabilityTest.aidl
new file mode 100644
index 0000000..36e1c2c
--- /dev/null
+++ b/libs/binder/tests/IBinderStabilityTest.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+// THIS IS ONLY FOR TESTING!
+interface IBinderStabilityTest {
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ void sendBinder(IBinder binder);
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ void sendAndCallBinder(IBinder binder);
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinder returnNoStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinder returnLocalStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinder returnVintfStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinder returnVendorStabilityBinder();
+}
+// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+// THIS IS ONLY FOR TESTING!
+// Construct and return a binder with a specific stability
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 4f0c969..5f8887b 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -766,6 +766,24 @@
EXPECT_TRUE(strong_from_weak == nullptr);
}
+TEST_F(BinderLibTest, LocalGetExtension) {
+ sp<BBinder> binder = new BBinder();
+ sp<IBinder> ext = new BBinder();
+ binder->setExtension(ext);
+ EXPECT_EQ(ext, binder->getExtension());
+}
+
+TEST_F(BinderLibTest, RemoteGetExtension) {
+ sp<IBinder> server = addServer();
+ ASSERT_TRUE(server != nullptr);
+
+ sp<IBinder> extension;
+ EXPECT_EQ(NO_ERROR, server->getExtension(&extension));
+ ASSERT_NE(nullptr, extension.get());
+
+ EXPECT_EQ(NO_ERROR, extension->pingBinder());
+}
+
TEST_F(BinderLibTest, CheckHandleZeroBinderHighBitsZeroCookie) {
status_t ret;
Parcel data, reply;
@@ -1170,6 +1188,13 @@
BinderLibTestService* testServicePtr;
{
sp<BinderLibTestService> testService = new BinderLibTestService(index);
+
+ /*
+ * Normally would also contain functionality as well, but we are only
+ * testing the extension mechanism.
+ */
+ testService->setExtension(new BBinder());
+
/*
* We need this below, but can't hold a sp<> because it prevents the
* node from being cleaned up automatically. It's safe in this case
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
new file mode 100644
index 0000000..0336b9e
--- /dev/null
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_manager.h>
+#include <android/binder_stability.h>
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Stability.h>
+#include <gtest/gtest.h>
+
+#include <sys/prctl.h>
+
+#include "aidl/BnBinderStabilityTest.h"
+#include "BnBinderStabilityTest.h"
+
+using namespace android;
+using namespace ndk;
+using android::binder::Status;
+using android::internal::Stability; // for testing only!
+
+const String16 kSystemStabilityServer = String16("binder_stability_test_service_system");
+
+// This is handwritten so that we can test different stability levels w/o having the AIDL
+// compiler assign them. Hand-writing binder interfaces is considered a bad practice
+// sanity reasons. YOU SHOULD DEFINE AN AIDL INTERFACE INSTEAD!
+class BadStableBinder : public BBinder {
+public:
+ static constexpr uint32_t USER_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION;
+ static String16 kDescriptor;
+
+ bool gotUserTransaction = false;
+
+ static status_t doUserTransaction(const sp<IBinder>& binder) {
+ Parcel data, reply;
+ data.writeInterfaceToken(kDescriptor);
+ return binder->transact(USER_TRANSACTION, data, &reply, 0/*flags*/);
+ }
+
+ status_t onTransact(uint32_t code,
+ const Parcel& data, Parcel* reply, uint32_t flags) override {
+ if (code == USER_TRANSACTION) {
+ // not interested in this kind of stability. Make sure
+ // we have a test failure
+ LOG_ALWAYS_FATAL_IF(!data.enforceInterface(kDescriptor));
+
+ gotUserTransaction = true;
+
+ ALOGE("binder stability: Got user transaction");
+ return OK;
+ }
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+
+ static sp<BadStableBinder> undef() {
+ sp<BadStableBinder> iface = new BadStableBinder();
+ return iface;
+ }
+
+ static sp<BadStableBinder> system() {
+ sp<BadStableBinder> iface = new BadStableBinder();
+ Stability::markCompilationUnit(iface.get()); // <- for test only
+ return iface;
+ }
+
+ static sp<BadStableBinder> vintf() {
+ sp<BadStableBinder> iface = new BadStableBinder();
+ Stability::markVintf(iface.get()); // <- for test only
+ return iface;
+ }
+
+ static sp<BadStableBinder> vendor() {
+ sp<BadStableBinder> iface = new BadStableBinder();
+ Stability::markVndk(iface.get()); // <- for test only
+ return iface;
+ }
+};
+String16 BadStableBinder::kDescriptor = String16("BadStableBinder.test");
+
+// NO! NO! NO! Do not even think of doing something like this!
+// This is for testing! If a class like this was actually used in production,
+// it would ruin everything!
+class MyBinderStabilityTest : public BnBinderStabilityTest {
+public:
+ Status sendBinder(const sp<IBinder>& /*binder*/) override {
+ return Status::ok();
+ }
+ Status sendAndCallBinder(const sp<IBinder>& binder) override {
+ Stability::debugLogStability("sendAndCallBinder got binder", binder);
+ return Status::fromExceptionCode(BadStableBinder::doUserTransaction(binder));
+ }
+ Status returnNoStabilityBinder(sp<IBinder>* _aidl_return) override {
+ *_aidl_return = BadStableBinder::undef();
+ return Status::ok();
+ }
+ Status returnLocalStabilityBinder(sp<IBinder>* _aidl_return) override {
+ *_aidl_return = BadStableBinder::system();
+ return Status::ok();
+ }
+ Status returnVintfStabilityBinder(sp<IBinder>* _aidl_return) override {
+ *_aidl_return = BadStableBinder::vintf();
+ return Status::ok();
+ }
+ Status returnVendorStabilityBinder(sp<IBinder>* _aidl_return) override {
+ *_aidl_return = BadStableBinder::vendor();
+ return Status::ok();
+ }
+};
+
+TEST(BinderStability, CantCallVendorBinderInSystemContext) {
+ sp<IBinder> serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer);
+ auto server = interface_cast<IBinderStabilityTest>(serverBinder);
+
+ ASSERT_NE(nullptr, server.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(server)->remoteBinder());
+
+ EXPECT_TRUE(server->sendBinder(BadStableBinder::undef()).isOk());
+ EXPECT_TRUE(server->sendBinder(BadStableBinder::system()).isOk());
+ EXPECT_TRUE(server->sendBinder(BadStableBinder::vintf()).isOk());
+ EXPECT_TRUE(server->sendBinder(BadStableBinder::vendor()).isOk());
+
+ {
+ sp<BadStableBinder> binder = BadStableBinder::undef();
+ EXPECT_TRUE(server->sendAndCallBinder(binder).isOk());
+ EXPECT_TRUE(binder->gotUserTransaction);
+ }
+ {
+ sp<BadStableBinder> binder = BadStableBinder::system();
+ EXPECT_TRUE(server->sendAndCallBinder(binder).isOk());
+ EXPECT_TRUE(binder->gotUserTransaction);
+ }
+ {
+ sp<BadStableBinder> binder = BadStableBinder::vintf();
+ EXPECT_TRUE(server->sendAndCallBinder(binder).isOk());
+ EXPECT_TRUE(binder->gotUserTransaction);
+ }
+ {
+ // !!! user-defined transaction may not be stable for remote server !!!
+ // !!! so, it does not work !!!
+ sp<BadStableBinder> binder = BadStableBinder::vendor();
+ EXPECT_EQ(BAD_TYPE, server->sendAndCallBinder(binder).exceptionCode());
+ EXPECT_FALSE(binder->gotUserTransaction);
+ }
+
+ sp<IBinder> out;
+ EXPECT_TRUE(server->returnNoStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, out->pingBinder());
+ EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out));
+
+ EXPECT_TRUE(server->returnLocalStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, out->pingBinder());
+ EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out));
+
+ EXPECT_TRUE(server->returnVintfStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, out->pingBinder());
+ EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out));
+
+ EXPECT_TRUE(server->returnVendorStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+
+ // !!! libbinder-defined transaction works !!!
+ EXPECT_EQ(OK, out->pingBinder());
+
+ // !!! user-defined transaction may not be stable !!!
+ // !!! so, it does not work !!!
+ EXPECT_EQ(BAD_TYPE, BadStableBinder::doUserTransaction(out));
+}
+
+// This is handwritten so that we can test different stability levels w/o having the AIDL
+// compiler assign them. Hand-writing binder interfaces is considered a bad practice
+// sanity reasons. YOU SHOULD DEFINE AN AIDL INTERFACE INSTEAD!
+
+struct NdkBinderStable_DataClass {
+ bool gotUserTransaction = false;
+};
+void* NdkBadStableBinder_Class_onCreate(void* args) {
+ LOG_ALWAYS_FATAL_IF(args != nullptr, "Takes no args");
+ return static_cast<void*>(new NdkBinderStable_DataClass);
+}
+void NdkBadStableBinder_Class_onDestroy(void* userData) {
+ delete static_cast<NdkBinderStable_DataClass*>(userData);
+}
+NdkBinderStable_DataClass* NdkBadStableBinder_getUserData(AIBinder* binder) {
+ LOG_ALWAYS_FATAL_IF(binder == nullptr);
+ void* userData = AIBinder_getUserData(binder);
+ LOG_ALWAYS_FATAL_IF(userData == nullptr, "null data - binder is remote?");
+
+ return static_cast<NdkBinderStable_DataClass*>(userData);
+}
+binder_status_t NdkBadStableBinder_Class_onTransact(
+ AIBinder* binder, transaction_code_t code, const AParcel* /*in*/, AParcel* /*out*/) {
+
+ if (code == BadStableBinder::USER_TRANSACTION) {
+ ALOGE("ndk binder stability: Got user transaction");
+ NdkBadStableBinder_getUserData(binder)->gotUserTransaction = true;
+ return STATUS_OK;
+ }
+
+ return STATUS_UNKNOWN_TRANSACTION;
+}
+
+static AIBinder_Class* kNdkBadStableBinder =
+ AIBinder_Class_define(String8(BadStableBinder::kDescriptor).c_str(),
+ NdkBadStableBinder_Class_onCreate,
+ NdkBadStableBinder_Class_onDestroy,
+ NdkBadStableBinder_Class_onTransact);
+
+// for testing only to get around __ANDROID_VNDK__ guard.
+extern "C" void AIBinder_markVendorStability(AIBinder* binder); // <- BAD DO NOT COPY
+
+TEST(BinderStability, NdkCantCallVendorBinderInSystemContext) {
+ SpAIBinder binder = SpAIBinder(AServiceManager_getService(
+ String8(kSystemStabilityServer).c_str()));
+
+ std::shared_ptr<aidl::IBinderStabilityTest> remoteServer =
+ aidl::IBinderStabilityTest::fromBinder(binder);
+
+ ASSERT_NE(nullptr, remoteServer.get());
+
+ SpAIBinder comp = SpAIBinder(AIBinder_new(kNdkBadStableBinder, nullptr /*args*/));
+ EXPECT_TRUE(remoteServer->sendBinder(comp).isOk());
+ EXPECT_TRUE(remoteServer->sendAndCallBinder(comp).isOk());
+ EXPECT_TRUE(NdkBadStableBinder_getUserData(comp.get())->gotUserTransaction);
+
+ SpAIBinder vendor = SpAIBinder(AIBinder_new(kNdkBadStableBinder, nullptr /*args*/));
+ AIBinder_markVendorStability(vendor.get());
+ EXPECT_TRUE(remoteServer->sendBinder(vendor).isOk());
+ EXPECT_FALSE(remoteServer->sendAndCallBinder(vendor).isOk());
+ EXPECT_FALSE(NdkBadStableBinder_getUserData(vendor.get())->gotUserTransaction);
+}
+
+class MarksStabilityInConstructor : public BBinder {
+public:
+ static bool gDestructed;
+
+ MarksStabilityInConstructor() {
+ Stability::markCompilationUnit(this);
+ }
+ ~MarksStabilityInConstructor() {
+ gDestructed = true;
+ }
+};
+bool MarksStabilityInConstructor::gDestructed = false;
+
+TEST(BinderStability, MarkingObjectNoDestructTest) {
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ // best practice is to put this directly in an sp, but for this test, we
+ // want to explicitly check what happens before that happens
+ MarksStabilityInConstructor* binder = new MarksStabilityInConstructor();
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ sp<MarksStabilityInConstructor> binderSp = binder;
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ binderSp = nullptr;
+ ASSERT_TRUE(MarksStabilityInConstructor::gDestructed);
+}
+
+TEST(BinderStability, RemarkDies) {
+ ASSERT_DEATH({
+ sp<IBinder> binder = new BBinder();
+ Stability::markCompilationUnit(binder.get()); // <-- only called for tests
+ Stability::markVndk(binder.get()); // <-- only called for tests
+ }, "Should only mark known object.");
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ if (fork() == 0) {
+ // child process
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+ sp<IBinder> server = new MyBinderStabilityTest;
+ android::defaultServiceManager()->addService(kSystemStabilityServer, server);
+
+ IPCThreadState::self()->joinThreadPool(true);
+ exit(1); // should not reach
+ }
+
+ // This is not racey. Just giving these services some time to register before we call
+ // getService which sleeps for much longer...
+ usleep(10000);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 3db8a39..bb5c151 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1306,7 +1306,7 @@
bool active = swapchain->surface.swapchain_handle == swapchain_handle;
ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr;
- if (swapchain->frame_timestamps_enabled) {
+ if (window && swapchain->frame_timestamps_enabled) {
native_window_enable_frame_timestamps(window, false);
}
for (uint32_t i = 0; i < swapchain->num_images; i++)