Merge "Convert gsid to use the dynamic AIDL service infrastructure"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index c84bd24..0a534a2 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -90,3 +90,4 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/debug_ramdisk/product_services)
$(call add-clean-step, find $(PRODUCT_OUT) -type l -name "charger" -print0 | xargs -0 rm -f)
$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/bin/adbd)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/snapshotctl.rc)
diff --git a/adb/Android.bp b/adb/Android.bp
index fea8c78..97bc4da 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -314,6 +314,7 @@
"libadb_protos",
"libadb_tls_connection",
"libandroidfw",
+ "libapp_processes_protos_full",
"libbase",
"libcutils",
"libcrypto_utils",
@@ -323,7 +324,7 @@
"liblog",
"liblz4",
"libmdnssd",
- "libprotobuf-cpp-lite",
+ "libprotobuf-cpp-full",
"libssl",
"libusb",
"libutils",
@@ -375,6 +376,7 @@
srcs: libadb_srcs + libadb_linux_srcs + libadb_posix_srcs + [
"daemon/auth.cpp",
"daemon/jdwp_service.cpp",
+ "daemon/logging.cpp",
"daemon/adb_wifi.cpp",
],
@@ -386,6 +388,7 @@
static_libs: [
"libadbconnection_server",
+ "libapp_processes_protos_lite",
"libdiagnose_usb",
],
@@ -402,6 +405,12 @@
"liblog",
],
+ proto: {
+ type: "lite",
+ static: true,
+ export_proto_headers: true,
+ },
+
target: {
android: {
whole_static_libs: [
@@ -418,6 +427,12 @@
srcs: [
"daemon/usb_dummy.cpp",
]
+ },
+ recovery: {
+ exclude_shared_libs: [
+ "libadb_pairing_auth",
+ "libadb_pairing_connection",
+ ],
}
},
}
@@ -443,7 +458,9 @@
static_libs: [
"libadbconnection_server",
"libadbd_core",
+ "libapp_processes_protos_lite",
"libdiagnose_usb",
+ "libprotobuf-cpp-lite",
],
shared_libs: [
@@ -477,6 +494,10 @@
exclude_srcs: [
"daemon/abb_service.cpp",
],
+ exclude_shared_libs: [
+ "libadb_pairing_auth",
+ "libadb_pairing_connection",
+ ],
},
},
}
@@ -496,6 +517,8 @@
whole_static_libs: [
"libadbconnection_server",
"libadbd_core",
+ "libapp_processes_protos_lite",
+ "libprotobuf-cpp-lite",
],
shared_libs: [
@@ -512,6 +535,15 @@
"libselinux",
],
+ target: {
+ recovery: {
+ exclude_shared_libs: [
+ "libadb_pairing_auth",
+ "libadb_pairing_connection",
+ ],
+ }
+ },
+
static_libs: [
"libadbd_services",
"libcutils_sockets",
@@ -544,9 +576,12 @@
},
static_libs: [
+ "libadb_crypto",
+ "libadb_tls_connection",
"libadbconnection_server",
"libadbd",
"libadbd_services",
+ "libapp_processes_protos_lite",
"libasyncio",
"libbase",
"libcap",
@@ -556,20 +591,28 @@
"liblog",
"libmdnssd",
"libminijail",
+ "libprotobuf-cpp-lite",
"libselinux",
"libssl",
],
shared_libs: [
- "libadb_crypto",
"libadb_pairing_connection",
"libadb_protos",
- "libadb_tls_connection",
"libadbd_auth",
"libadbd_fs",
"libcrypto",
],
+ target: {
+ recovery: {
+ exclude_shared_libs: [
+ "libadb_pairing_auth",
+ "libadb_pairing_connection",
+ ],
+ }
+ },
+
required: [
"libadbd_auth",
"libadbd_fs",
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 554a754..98db191 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -34,6 +34,7 @@
#include <condition_variable>
#include <mutex>
#include <string>
+#include <string_view>
#include <thread>
#include <vector>
@@ -61,6 +62,8 @@
#include <sys/mount.h>
#include <android-base/properties.h>
using namespace std::chrono_literals;
+
+#include "daemon/logging.h"
#endif
std::string adb_version() {
@@ -312,6 +315,9 @@
#if ADB_HOST
handle_online(t);
#else
+ ADB_LOG(Connection) << "received CNXN: version=" << p->msg.arg0 << ", maxdata = " << p->msg.arg1
+ << ", banner = '" << banner << "'";
+
if (t->use_tls) {
// We still handshake in TLS mode. If auth_required is disabled,
// we'll just not verify the client's certificate. This should be the
diff --git a/adb/adb.h b/adb/adb.h
index 86d205c..9f8d299 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -169,6 +169,7 @@
int init_jdwp(void);
asocket* create_jdwp_service_socket();
asocket* create_jdwp_tracker_service_socket();
+asocket* create_app_tracker_service_socket();
unique_fd create_jdwp_connection_fd(int jdwp_pid);
#endif
diff --git a/adb/apex/Android.bp b/adb/apex/Android.bp
index 0189455..4346f67 100644
--- a/adb/apex/Android.bp
+++ b/adb/apex/Android.bp
@@ -1,5 +1,6 @@
apex_defaults {
name: "com.android.adbd-defaults",
+ updatable: true,
binaries: ["adbd"],
compile_multilib: "both",
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 8738ce7..4b2fa04 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -145,12 +145,12 @@
std::lock_guard<std::mutex> lock(g_keys_mutex);
std::string fingerprint = hash_key(key.get());
- if (g_keys.find(fingerprint) != g_keys.end()) {
- LOG(INFO) << "ignoring already-loaded key: " << file;
- } else {
- LOG(INFO) << "Loaded fingerprint=[" << SHA256BitsToHexString(fingerprint) << "]";
+ bool already_loaded = (g_keys.find(fingerprint) != g_keys.end());
+ if (!already_loaded) {
g_keys[fingerprint] = std::move(key);
}
+ LOG(INFO) << (already_loaded ? "ignored already-loaded" : "loaded new") << " key from '" << file
+ << "' with fingerprint " << SHA256BitsToHexString(fingerprint);
return true;
}
@@ -159,23 +159,25 @@
struct stat st;
if (stat(path.c_str(), &st) != 0) {
- PLOG(ERROR) << "failed to stat '" << path << "'";
+ PLOG(ERROR) << "load_keys: failed to stat '" << path << "'";
return false;
}
if (S_ISREG(st.st_mode)) {
return load_key(path);
- } else if (S_ISDIR(st.st_mode)) {
+ }
+
+ if (S_ISDIR(st.st_mode)) {
if (!allow_dir) {
// inotify isn't recursive. It would break expectations to load keys in nested
// directories but not monitor them for new keys.
- LOG(WARNING) << "refusing to recurse into directory '" << path << "'";
+ LOG(WARNING) << "load_keys: refusing to recurse into directory '" << path << "'";
return false;
}
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
if (!dir) {
- PLOG(ERROR) << "failed to open directory '" << path << "'";
+ PLOG(ERROR) << "load_keys: failed to open directory '" << path << "'";
return false;
}
@@ -189,7 +191,7 @@
}
if (!android::base::EndsWith(name, ".adb_key")) {
- LOG(INFO) << "skipping non-adb_key '" << path << "/" << name << "'";
+ LOG(INFO) << "skipped non-adb_key '" << path << "/" << name << "'";
continue;
}
@@ -198,7 +200,7 @@
return result;
}
- LOG(ERROR) << "unexpected type for '" << path << "': 0x" << std::hex << st.st_mode;
+ LOG(ERROR) << "load_keys: unexpected type for '" << path << "': 0x" << std::hex << st.st_mode;
return false;
}
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 081bac4..1186060 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -50,6 +50,8 @@
#include <unistd.h>
#endif
+#include <google/protobuf/text_format.h>
+
#include "adb.h"
#include "adb_auth.h"
#include "adb_client.h"
@@ -57,6 +59,7 @@
#include "adb_io.h"
#include "adb_unique_fd.h"
#include "adb_utils.h"
+#include "app_processes.pb.h"
#include "bugreport.h"
#include "client/file_sync_client.h"
#include "commandline.h"
@@ -1354,17 +1357,49 @@
}
}
-static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
+static int adb_connect_command(const std::string& command, TransportId* transport,
+ StandardStreamsCallbackInterface* callback) {
std::string error;
unique_fd fd(adb_connect(transport, command, &error));
if (fd < 0) {
fprintf(stderr, "error: %s\n", error.c_str());
return 1;
}
- read_and_dump(fd);
+ read_and_dump(fd, false, callback);
return 0;
}
+static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
+ return adb_connect_command(command, transport, &DEFAULT_STANDARD_STREAMS_CALLBACK);
+}
+
+// A class that prints out human readable form of the protobuf message for "track-app" service
+// (received in binary format).
+class TrackAppStreamsCallback : public DefaultStandardStreamsCallback {
+ public:
+ TrackAppStreamsCallback() : DefaultStandardStreamsCallback(nullptr, nullptr) {}
+
+ // Assume the buffer contains at least 4 bytes of valid data.
+ void OnStdout(const char* buffer, int length) override {
+ if (length < 4) return; // Unexpected length received. Do nothing.
+
+ adb::proto::AppProcesses binary_proto;
+ // The first 4 bytes are the length of remaining content in hexadecimal format.
+ binary_proto.ParseFromString(std::string(buffer + 4, length - 4));
+ char summary[24]; // The following string includes digits and 16 fixed characters.
+ int written = snprintf(summary, sizeof(summary), "Process count: %d\n",
+ binary_proto.process_size());
+ OnStream(nullptr, stdout, summary, written);
+
+ std::string string_proto;
+ google::protobuf::TextFormat::PrintToString(binary_proto, &string_proto);
+ OnStream(nullptr, stdout, string_proto.data(), string_proto.length());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TrackAppStreamsCallback);
+};
+
static int adb_connect_command_bidirectional(const std::string& command) {
std::string error;
unique_fd fd(adb_connect(command, &error));
@@ -1925,6 +1960,18 @@
return adb_connect_command("jdwp");
} else if (!strcmp(argv[0], "track-jdwp")) {
return adb_connect_command("track-jdwp");
+ } else if (!strcmp(argv[0], "track-app")) {
+ FeatureSet features;
+ std::string error;
+ if (!adb_get_feature_set(&features, &error)) {
+ fprintf(stderr, "error: %s\n", error.c_str());
+ return 1;
+ }
+ if (!CanUseFeature(features, kFeatureTrackApp)) {
+ error_exit("track-app is not supported by the device");
+ }
+ TrackAppStreamsCallback callback;
+ return adb_connect_command("track-app", nullptr, &callback);
} else if (!strcmp(argv[0], "track-devices")) {
if (argc > 2 || (argc == 2 && strcmp(argv[1], "-l"))) {
error_exit("usage: adb track-devices [-l]");
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 922f2ba..cc38926 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -29,6 +29,7 @@
#include <utime.h>
#include <chrono>
+#include <deque>
#include <functional>
#include <memory>
#include <sstream>
@@ -203,7 +204,7 @@
class SyncConnection {
public:
- SyncConnection() : expect_done_(false) {
+ SyncConnection() {
max = SYNC_DATA_MAX; // TODO: decide at runtime.
std::string error;
@@ -239,16 +240,6 @@
bool IsValid() { return fd >= 0; }
- bool ReceivedError(const char* from, const char* to) {
- adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
- int rc = adb_poll(&pfd, 1, 0);
- if (rc < 0) {
- Error("failed to poll: %s", strerror(errno));
- return true;
- }
- return rc != 0;
- }
-
void NewTransfer() {
current_ledger_.Reset();
}
@@ -258,6 +249,11 @@
global_ledger_.bytes_transferred += bytes;
}
+ void RecordFileSent(std::string from, std::string to) {
+ RecordFilesTransferred(1);
+ deferred_acknowledgements_.emplace_back(std::move(from), std::move(to));
+ }
+
void RecordFilesTransferred(size_t files) {
current_ledger_.files_transferred += files;
global_ledger_.files_transferred += files;
@@ -283,39 +279,38 @@
}
}
- bool SendRequest(int id, const char* path_and_mode) {
- size_t path_length = strlen(path_and_mode);
- if (path_length > 1024) {
- Error("SendRequest failed: path too long: %zu", path_length);
+ bool SendRequest(int id, const std::string& path) {
+ if (path.length() > 1024) {
+ Error("SendRequest failed: path too long: %zu", path.length());
errno = ENAMETOOLONG;
return false;
}
// Sending header and payload in a single write makes a noticeable
// difference to "adb sync" performance.
- std::vector<char> buf(sizeof(SyncRequest) + path_length);
+ std::vector<char> buf(sizeof(SyncRequest) + path.length());
SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
req->id = id;
- req->path_length = path_length;
+ req->path_length = path.length();
char* data = reinterpret_cast<char*>(req + 1);
- memcpy(data, path_and_mode, path_length);
+ memcpy(data, path.data(), path.length());
- return WriteFdExactly(fd, &buf[0], buf.size());
+ return WriteFdExactly(fd, buf.data(), buf.size());
}
- bool SendStat(const char* path_and_mode) {
+ bool SendStat(const std::string& path) {
if (!have_stat_v2_) {
errno = ENOTSUP;
return false;
}
- return SendRequest(ID_STAT_V2, path_and_mode);
+ return SendRequest(ID_STAT_V2, path);
}
- bool SendLstat(const char* path_and_mode) {
+ bool SendLstat(const std::string& path) {
if (have_stat_v2_) {
- return SendRequest(ID_LSTAT_V2, path_and_mode);
+ return SendRequest(ID_LSTAT_V2, path);
} else {
- return SendRequest(ID_LSTAT_V1, path_and_mode);
+ return SendRequest(ID_LSTAT_V1, path);
}
}
@@ -374,7 +369,7 @@
return true;
}
- bool SendLs(const char* path) {
+ bool SendLs(const std::string& path) {
return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path);
}
@@ -415,28 +410,26 @@
// Sending header, payload, and footer in a single write makes a huge
// difference to "adb sync" performance.
- bool SendSmallFile(const char* path_and_mode,
- const char* lpath, const char* rpath,
- unsigned mtime,
- const char* data, size_t data_length) {
- size_t path_length = strlen(path_and_mode);
- if (path_length > 1024) {
- Error("SendSmallFile failed: path too long: %zu", path_length);
+ bool SendSmallFile(const std::string& path, mode_t mode, const std::string& lpath,
+ const std::string& rpath, unsigned mtime, const char* data,
+ size_t data_length) {
+ std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
+ if (path_and_mode.length() > 1024) {
+ Error("SendSmallFile failed: path too long: %zu", path_and_mode.length());
errno = ENAMETOOLONG;
return false;
}
- std::vector<char> buf(sizeof(SyncRequest) + path_length +
- sizeof(SyncRequest) + data_length +
- sizeof(SyncRequest));
+ std::vector<char> buf(sizeof(SyncRequest) + path_and_mode.length() + sizeof(SyncRequest) +
+ data_length + sizeof(SyncRequest));
char* p = &buf[0];
SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
req_send->id = ID_SEND;
- req_send->path_length = path_length;
+ req_send->path_length = path_and_mode.length();
p += sizeof(SyncRequest);
- memcpy(p, path_and_mode, path_length);
- p += path_length;
+ memcpy(p, path_and_mode.data(), path_and_mode.size());
+ p += path_and_mode.length();
SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
req_data->id = ID_DATA;
@@ -451,34 +444,34 @@
p += sizeof(SyncRequest);
WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
- expect_done_ = true;
- // RecordFilesTransferred gets called in CopyDone.
+ RecordFileSent(lpath, rpath);
RecordBytesTransferred(data_length);
ReportProgress(rpath, data_length, data_length);
return true;
}
- bool SendLargeFile(const char* path_and_mode,
- const char* lpath, const char* rpath,
- unsigned mtime) {
+ bool SendLargeFile(const std::string& path, mode_t mode, const std::string& lpath,
+ const std::string& rpath, unsigned mtime) {
+ std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
if (!SendRequest(ID_SEND, path_and_mode)) {
- Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
+ Error("failed to send ID_SEND message '%s': %s", path_and_mode.c_str(),
+ strerror(errno));
return false;
}
struct stat st;
- if (stat(lpath, &st) == -1) {
- Error("cannot stat '%s': %s", lpath, strerror(errno));
+ if (stat(lpath.c_str(), &st) == -1) {
+ Error("cannot stat '%s': %s", lpath.c_str(), strerror(errno));
return false;
}
uint64_t total_size = st.st_size;
uint64_t bytes_copied = 0;
- unique_fd lfd(adb_open(lpath, O_RDONLY));
+ unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY));
if (lfd < 0) {
- Error("opening '%s' locally failed: %s", lpath, strerror(errno));
+ Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno));
return false;
}
@@ -487,7 +480,7 @@
while (true) {
int bytes_read = adb_read(lfd, sbuf.data, max - sizeof(SyncRequest));
if (bytes_read == -1) {
- Error("reading '%s' locally failed: %s", lpath, strerror(errno));
+ Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno));
return false;
} else if (bytes_read == 0) {
break;
@@ -499,55 +492,53 @@
RecordBytesTransferred(bytes_read);
bytes_copied += bytes_read;
- // Check to see if we've received an error from the other side.
- if (ReceivedError(lpath, rpath)) {
- break;
- }
-
ReportProgress(rpath, bytes_copied, total_size);
}
syncmsg msg;
msg.data.id = ID_DONE;
msg.data.size = mtime;
- expect_done_ = true;
-
- // RecordFilesTransferred gets called in CopyDone.
+ RecordFileSent(lpath, rpath);
return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
}
- bool CopyDone(const char* from, const char* to) {
+ bool ReadAcknowledgments() {
+ bool result = true;
+ while (!deferred_acknowledgements_.empty()) {
+ auto [from, to] = std::move(deferred_acknowledgements_.front());
+ deferred_acknowledgements_.pop_front();
+ result &= CopyDone(from, to);
+ }
+ return result;
+ }
+
+ bool CopyDone(const std::string& from, const std::string& to) {
syncmsg msg;
if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
- Error("failed to copy '%s' to '%s': couldn't read from device", from, to);
+ Error("failed to copy '%s' to '%s': couldn't read from device", from.c_str(),
+ to.c_str());
return false;
}
if (msg.status.id == ID_OKAY) {
- if (expect_done_) {
- expect_done_ = false;
- RecordFilesTransferred(1);
- return true;
- } else {
- Error("failed to copy '%s' to '%s': received premature success", from, to);
- return true;
- }
+ return true;
}
if (msg.status.id != ID_FAIL) {
- Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
+ Error("failed to copy '%s' to '%s': unknown reason %d", from.c_str(), to.c_str(),
+ msg.status.id);
return false;
}
return ReportCopyFailure(from, to, msg);
}
- bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
+ bool ReportCopyFailure(const std::string& from, const std::string& to, const syncmsg& msg) {
std::vector<char> buf(msg.status.msglen + 1);
if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
- Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
- from, to, strerror(errno));
+ Error("failed to copy '%s' to '%s'; failed to read reason (!): %s", from.c_str(),
+ to.c_str(), strerror(errno));
return false;
}
buf[msg.status.msglen] = 0;
- Error("failed to copy '%s' to '%s': remote %s", from, to, &buf[0]);
+ Error("failed to copy '%s' to '%s': remote %s", from.c_str(), to.c_str(), &buf[0]);
return false;
}
@@ -616,7 +607,7 @@
size_t max;
private:
- bool expect_done_;
+ std::deque<std::pair<std::string, std::string>> deferred_acknowledgements_;
FeatureSet features_;
bool have_stat_v2_;
bool have_ls_v2_;
@@ -629,16 +620,19 @@
return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
}
- bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
+ bool WriteOrDie(const std::string& from, const std::string& to, const void* data,
+ size_t data_length) {
if (!WriteFdExactly(fd, data, data_length)) {
if (errno == ECONNRESET) {
// Assume adbd told us why it was closing the connection, and
// try to read failure reason from adbd.
syncmsg msg;
if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
- Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
+ Error("failed to copy '%s' to '%s': no response: %s", from.c_str(), to.c_str(),
+ strerror(errno));
} else if (msg.status.id != ID_FAIL) {
- Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
+ Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from.c_str(), to.c_str(),
+ msg.status.id);
} else {
ReportCopyFailure(from, to, msg);
}
@@ -651,20 +645,20 @@
}
};
-static bool sync_ls(SyncConnection& sc, const char* path,
+static bool sync_ls(SyncConnection& sc, const std::string& path,
const std::function<sync_ls_cb>& func) {
return sc.SendLs(path) && sc.FinishLs(func);
}
-static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_stat(SyncConnection& sc, const std::string& path, struct stat* st) {
return sc.SendStat(path) && sc.FinishStat(st);
}
-static bool sync_lstat(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_lstat(SyncConnection& sc, const std::string& path, struct stat* st) {
return sc.SendLstat(path) && sc.FinishStat(st);
}
-static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_stat_fallback(SyncConnection& sc, const std::string& path, struct stat* st) {
if (sync_stat(sc, path, st)) {
return true;
}
@@ -688,7 +682,7 @@
struct stat tmp_st;
st->st_mode &= ~S_IFMT;
- if (sync_lstat(sc, dir_path.c_str(), &tmp_st)) {
+ if (sync_lstat(sc, dir_path, &tmp_st)) {
st->st_mode |= S_IFDIR;
} else {
st->st_mode |= S_IFREG;
@@ -697,10 +691,8 @@
return true;
}
-static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, unsigned mtime,
- mode_t mode, bool sync) {
- std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
-
+static bool sync_send(SyncConnection& sc, const std::string& lpath, const std::string& rpath,
+ unsigned mtime, mode_t mode, bool sync) {
if (sync) {
struct stat st;
if (sync_lstat(sc, rpath, &st)) {
@@ -714,41 +706,40 @@
if (S_ISLNK(mode)) {
#if !defined(_WIN32)
char buf[PATH_MAX];
- ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
+ ssize_t data_length = readlink(lpath.c_str(), buf, PATH_MAX - 1);
if (data_length == -1) {
- sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
+ sc.Error("readlink '%s' failed: %s", lpath.c_str(), strerror(errno));
return false;
}
buf[data_length++] = '\0';
- if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
+ if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, buf, data_length)) {
return false;
}
- return sc.CopyDone(lpath, rpath);
+ return true;
#endif
}
struct stat st;
- if (stat(lpath, &st) == -1) {
- sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
+ if (stat(lpath.c_str(), &st) == -1) {
+ sc.Error("failed to stat local file '%s': %s", lpath.c_str(), strerror(errno));
return false;
}
if (st.st_size < SYNC_DATA_MAX) {
std::string data;
if (!android::base::ReadFileToString(lpath, &data, true)) {
- sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
+ sc.Error("failed to read all of '%s': %s", lpath.c_str(), strerror(errno));
return false;
}
- if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
- data.data(), data.size())) {
+ if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, data.data(), data.size())) {
return false;
}
} else {
- if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
+ if (!sc.SendLargeFile(rpath, mode, lpath, rpath, mtime)) {
return false;
}
}
- return sc.CopyDone(lpath, rpath);
+ return true;
}
static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
@@ -943,7 +934,7 @@
if (check_timestamps) {
for (const copyinfo& ci : file_list) {
- if (!sc.SendLstat(ci.rpath.c_str())) {
+ if (!sc.SendLstat(ci.rpath)) {
sc.Error("failed to send lstat");
return false;
}
@@ -965,7 +956,7 @@
if (list_only) {
sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
} else {
- if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode, false)) {
+ if (!sync_send(sc, ci.lpath, ci.rpath, ci.time, ci.mode, false)) {
return false;
}
}
@@ -1069,6 +1060,7 @@
sc.ReportTransferRate(src_path, TransferDirection::push);
}
+ success &= sc.ReadAcknowledgments();
sc.ReportOverallTransferRate(TransferDirection::push);
return success;
}
diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp
index b7f75ed..ce1de4a 100644
--- a/adb/crypto/Android.bp
+++ b/adb/crypto/Android.bp
@@ -45,8 +45,6 @@
host_supported: true,
recovery_available: true,
- stl: "libc++_static",
-
shared_libs: [
"libadb_protos",
"libbase",
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index b92a7de..c99aead 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -21,6 +21,7 @@
#include "sysdeps.h"
#include <errno.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -33,6 +34,7 @@
#include <thread>
#include <vector>
+#include <adbconnection/process_info.h>
#include <adbconnection/server.h>
#include <android-base/cmsg.h>
#include <android-base/unique_fd.h>
@@ -41,6 +43,7 @@
#include "adb_io.h"
#include "adb_unique_fd.h"
#include "adb_utils.h"
+#include "app_processes.pb.h"
using android::base::borrowed_fd;
using android::base::unique_fd;
@@ -132,18 +135,24 @@
** for each JDWP process, we record its pid and its connected socket
**/
+enum class TrackerKind {
+ kJdwp,
+ kApp,
+};
+
static void jdwp_process_event(int socket, unsigned events, void* _proc);
static void jdwp_process_list_updated(void);
+static void app_process_list_updated(void);
struct JdwpProcess;
static auto& _jdwp_list = *new std::list<std::unique_ptr<JdwpProcess>>();
struct JdwpProcess {
- JdwpProcess(unique_fd socket, pid_t pid) {
- CHECK(pid != 0);
+ JdwpProcess(unique_fd socket, ProcessInfo process) {
+ CHECK(process.pid != 0);
this->socket = socket;
- this->pid = pid;
+ this->process = process;
this->fde = fdevent_create(socket.release(), jdwp_process_event, this);
if (!this->fde) {
@@ -171,17 +180,19 @@
}
borrowed_fd socket = -1;
- int32_t pid = -1;
+ ProcessInfo process;
fdevent* fde = nullptr;
std::vector<unique_fd> out_fds;
};
+// Populate the list of processes for "track-jdwp" service.
static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
std::string temp;
for (auto& proc : _jdwp_list) {
- std::string next = std::to_string(proc->pid) + "\n";
+ if (!proc->process.debuggable) continue;
+ std::string next = std::to_string(proc->process.pid) + "\n";
if (temp.length() + next.length() > bufferlen) {
D("truncating JDWP process list (max len = %zu)", bufferlen);
break;
@@ -193,7 +204,44 @@
return temp.length();
}
-static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
+// Populate the list of processes for "track-app" service.
+// The list is a protobuf message in the binary format for efficiency.
+static size_t app_process_list(char* buffer, size_t bufferlen) {
+ adb::proto::AppProcesses output; // result that's guaranteed to fit in the given buffer
+ adb::proto::AppProcesses temp; // temporary result that may be longer than the given buffer
+ std::string serialized_message;
+
+ for (auto& proc : _jdwp_list) {
+ if (!proc->process.debuggable && !proc->process.profileable) continue;
+ auto* entry = temp.add_process();
+ entry->set_pid(proc->process.pid);
+ entry->set_debuggable(proc->process.debuggable);
+ entry->set_profileable(proc->process.profileable);
+ entry->set_architecture(proc->process.arch_name, proc->process.arch_name_length);
+ temp.SerializeToString(&serialized_message);
+ if (serialized_message.size() > bufferlen) {
+ D("truncating app process list (max len = %zu)", bufferlen);
+ break;
+ }
+ output = temp;
+ }
+ output.SerializeToString(&serialized_message);
+ memcpy(buffer, serialized_message.data(), serialized_message.length());
+ return serialized_message.length();
+}
+
+// Populate the list of processes for either "track-jdwp" or "track-app" services,
+// depending on the given kind.
+static size_t process_list(TrackerKind kind, char* buffer, size_t bufferlen) {
+ switch (kind) {
+ case TrackerKind::kJdwp:
+ return jdwp_process_list(buffer, bufferlen);
+ case TrackerKind::kApp:
+ return app_process_list(buffer, bufferlen);
+ }
+}
+
+static size_t process_list_msg(TrackerKind kind, char* buffer, size_t bufferlen) {
// Message is length-prefixed with 4 hex digits in ASCII.
static constexpr size_t header_len = 4;
if (bufferlen < header_len) {
@@ -201,7 +249,7 @@
}
char head[header_len + 1];
- size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len);
+ size_t len = process_list(kind, buffer + header_len, bufferlen - header_len);
snprintf(head, sizeof head, "%04zx", len);
memcpy(buffer, head, header_len);
return len + header_len;
@@ -213,7 +261,7 @@
if (events & FDE_READ) {
// We already have the PID, if we can read from the socket, we've probably hit EOF.
- D("terminating JDWP connection %d", proc->pid);
+ D("terminating JDWP connection %" PRId64, proc->process.pid);
goto CloseProcess;
}
@@ -223,11 +271,12 @@
int fd = proc->out_fds.back().get();
if (android::base::SendFileDescriptors(socket, "", 1, fd) != 1) {
- D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
+ D("sending new file descriptor to JDWP %" PRId64 " failed: %s", proc->process.pid,
+ strerror(errno));
goto CloseProcess;
}
- D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
+ D("sent file descriptor %d to JDWP process %" PRId64, fd, proc->process.pid);
proc->out_fds.pop_back();
if (proc->out_fds.empty()) {
@@ -238,15 +287,20 @@
return;
CloseProcess:
+ bool debuggable = proc->process.debuggable;
+ bool profileable = proc->process.profileable;
proc->RemoveFromList();
- jdwp_process_list_updated();
+ if (debuggable) jdwp_process_list_updated();
+ if (debuggable || profileable) app_process_list_updated();
}
unique_fd create_jdwp_connection_fd(int pid) {
D("looking for pid %d in JDWP process list", pid);
for (auto& proc : _jdwp_list) {
- if (proc->pid == pid) {
+ // Don't allow JDWP connection to a non-debuggable process.
+ if (!proc->process.debuggable) continue;
+ if (proc->process.pid == static_cast<uint64_t>(pid)) {
int fds[2];
if (adb_socketpair(fds) < 0) {
@@ -338,18 +392,22 @@
**/
struct JdwpTracker : public asocket {
+ TrackerKind kind;
bool need_initial;
+
+ explicit JdwpTracker(TrackerKind k, bool initial) : kind(k), need_initial(initial) {}
};
static auto& _jdwp_trackers = *new std::vector<std::unique_ptr<JdwpTracker>>();
-static void jdwp_process_list_updated(void) {
+static void process_list_updated(TrackerKind kind) {
std::string data;
- data.resize(1024);
- data.resize(jdwp_process_list_msg(&data[0], data.size()));
+ const int kMaxLength = kind == TrackerKind::kJdwp ? 1024 : 2048;
+ data.resize(kMaxLength);
+ data.resize(process_list_msg(kind, &data[0], data.size()));
for (auto& t : _jdwp_trackers) {
- if (t->peer) {
+ if (t->kind == kind && t->peer) {
// The tracker might not have been connected yet.
apacket::payload_type payload(data.begin(), data.end());
t->peer->enqueue(t->peer, std::move(payload));
@@ -357,6 +415,14 @@
}
}
+static void jdwp_process_list_updated(void) {
+ process_list_updated(TrackerKind::kJdwp);
+}
+
+static void app_process_list_updated(void) {
+ process_list_updated(TrackerKind::kApp);
+}
+
static void jdwp_tracker_close(asocket* s) {
D("LS(%d): destroying jdwp tracker service", s->id);
@@ -380,7 +446,7 @@
if (t->need_initial) {
apacket::payload_type data;
data.resize(s->get_max_payload());
- data.resize(jdwp_process_list_msg(&data[0], data.size()));
+ data.resize(process_list_msg(t->kind, &data[0], data.size()));
t->need_initial = false;
s->peer->enqueue(s->peer, std::move(data));
}
@@ -393,8 +459,8 @@
return -1;
}
-asocket* create_jdwp_tracker_service_socket(void) {
- auto t = std::make_unique<JdwpTracker>();
+asocket* create_process_tracker_service_socket(TrackerKind kind) {
+ auto t = std::make_unique<JdwpTracker>(kind, true);
if (!t) {
LOG(FATAL) << "failed to allocate JdwpTracker";
}
@@ -407,7 +473,6 @@
t->ready = jdwp_tracker_ready;
t->enqueue = jdwp_tracker_enqueue;
t->close = jdwp_tracker_close;
- t->need_initial = true;
asocket* result = t.get();
@@ -416,19 +481,28 @@
return result;
}
+asocket* create_jdwp_tracker_service_socket() {
+ return create_process_tracker_service_socket(TrackerKind::kJdwp);
+}
+
+asocket* create_app_tracker_service_socket() {
+ return create_process_tracker_service_socket(TrackerKind::kApp);
+}
+
int init_jdwp(void) {
std::thread([]() {
adb_thread_setname("jdwp control");
- adbconnection_listen([](int fd, pid_t pid) {
- LOG(INFO) << "jdwp connection from " << pid;
- fdevent_run_on_main_thread([fd, pid] {
+ adbconnection_listen([](int fd, ProcessInfo process) {
+ LOG(INFO) << "jdwp connection from " << process.pid;
+ fdevent_run_on_main_thread([fd, process] {
unique_fd ufd(fd);
- auto proc = std::make_unique<JdwpProcess>(std::move(ufd), pid);
+ auto proc = std::make_unique<JdwpProcess>(std::move(ufd), process);
if (!proc) {
LOG(FATAL) << "failed to allocate JdwpProcess";
}
_jdwp_list.emplace_back(std::move(proc));
- jdwp_process_list_updated();
+ if (process.debuggable) jdwp_process_list_updated();
+ if (process.debuggable || process.profileable) app_process_list_updated();
});
});
}).detach();
diff --git a/adb/daemon/logging.cpp b/adb/daemon/logging.cpp
new file mode 100644
index 0000000..203c6c7
--- /dev/null
+++ b/adb/daemon/logging.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 "daemon/logging.h"
+
+#include <mutex>
+#include <optional>
+#include <string_view>
+
+#include <android-base/no_destructor.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android-base/thread_annotations.h>
+
+#if defined(__ANDROID__)
+struct LogStatus {
+ bool enabled[static_cast<size_t>(adb::LogType::COUNT)];
+
+ bool& operator[](adb::LogType type) { return enabled[static_cast<size_t>(type)]; }
+};
+
+using android::base::CachedProperty;
+using android::base::NoDestructor;
+
+static NoDestructor<std::mutex> log_mutex;
+static NoDestructor<CachedProperty> log_property GUARDED_BY(log_mutex)("debug.adbd.logging");
+static std::optional<LogStatus> cached_log_status GUARDED_BY(log_mutex);
+
+static NoDestructor<CachedProperty> persist_log_property
+ GUARDED_BY(log_mutex)("persist.debug.adbd.logging");
+static std::optional<LogStatus> cached_persist_log_status GUARDED_BY(log_mutex);
+
+static LogStatus ParseLogStatus(std::string_view str) {
+ LogStatus result = {};
+ for (const auto& part : android::base::Split(std::string(str), ",")) {
+ if (part == "cnxn") {
+ result[adb::LogType::Connection] = true;
+ } else if (part == "service") {
+ result[adb::LogType::Service] = true;
+ } else if (part == "shell") {
+ result[adb::LogType::Shell] = true;
+ } else if (part == "all") {
+ result[adb::LogType::Connection] = true;
+ result[adb::LogType::Service] = true;
+ result[adb::LogType::Shell] = true;
+ }
+ }
+ return result;
+}
+
+static LogStatus GetLogStatus(android::base::CachedProperty* property,
+ std::optional<LogStatus>* cached_status) REQUIRES(log_mutex) {
+ bool changed;
+ const char* value = property->Get(&changed);
+ if (changed || !*cached_status) {
+ **cached_status = ParseLogStatus(value);
+ }
+ return **cached_status;
+}
+
+namespace adb {
+bool is_logging_enabled(LogType type) {
+ std::lock_guard<std::mutex> lock(*log_mutex);
+ return GetLogStatus(log_property.get(), &cached_log_status)[type] ||
+ GetLogStatus(persist_log_property.get(), &cached_persist_log_status)[type];
+}
+} // namespace adb
+
+#else
+
+namespace adb {
+bool is_logging_enabled(LogType type) {
+ return false;
+}
+} // namespace adb
+#endif
diff --git a/adb/daemon/logging.h b/adb/daemon/logging.h
new file mode 100644
index 0000000..3e28bef
--- /dev/null
+++ b/adb/daemon/logging.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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-base/logging.h>
+
+namespace adb {
+enum class LogType {
+ Connection,
+ Service,
+ Shell,
+ COUNT,
+};
+
+bool is_logging_enabled(LogType type);
+
+#define ADB_LOG(type) ::adb::is_logging_enabled(::adb::LogType::type) && LOG(INFO)
+
+} // namespace adb
diff --git a/adb/daemon/mdns.cpp b/adb/daemon/mdns.cpp
index fa692c0..c1e766e 100644
--- a/adb/daemon/mdns.cpp
+++ b/adb/daemon/mdns.cpp
@@ -150,11 +150,11 @@
for (size_t i = 0; i < len; ++i) {
uint8_t val = dist(mt);
if (val < 10) {
- ret += '0' + val;
+ ret += static_cast<char>('0' + val);
} else if (val < 36) {
- ret += 'A' + (val - 10);
+ ret += static_cast<char>('A' + (val - 10));
} else {
- ret += 'a' + (val - 36);
+ ret += static_cast<char>('a' + (val - 36));
}
}
return ret;
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 4ec90d2..a9d1fe8 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -54,10 +54,10 @@
#include "daemon/file_sync_service.h"
#include "daemon/framebuffer_service.h"
+#include "daemon/logging.h"
#include "daemon/restart_service.h"
#include "daemon/shell_service.h"
-
void reconnect_service(unique_fd fd, atransport* t) {
WriteFdExactly(fd.get(), "done");
kick_transport(t);
@@ -241,6 +241,8 @@
return create_jdwp_service_socket();
} else if (name == "track-jdwp") {
return create_jdwp_tracker_service_socket();
+ } else if (name == "track-app") {
+ return create_app_tracker_service_socket();
} else if (android::base::ConsumePrefix(&name, "sink:")) {
uint64_t byte_count = 0;
if (!ParseUint(&byte_count, name)) {
@@ -259,6 +261,8 @@
}
unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {
+ ADB_LOG(Service) << "transport " << transport->serial_name() << " opening service " << name;
+
#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
if (name.starts_with("abb:") || name.starts_with("abb_exec:")) {
return execute_abb_command(name);
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index f62032d..fbfae1e 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -107,6 +107,7 @@
#include "adb_trace.h"
#include "adb_unique_fd.h"
#include "adb_utils.h"
+#include "daemon/logging.h"
#include "security_log_tags.h"
#include "shell_protocol.h"
@@ -760,14 +761,14 @@
D("post waitpid (pid=%d) status=%04x", pid_, status);
if (WIFSIGNALED(status)) {
exit_code = 0x80 | WTERMSIG(status);
- D("subprocess killed by signal %d", WTERMSIG(status));
+ ADB_LOG(Shell) << "subprocess " << pid_ << " killed by signal " << WTERMSIG(status);
break;
} else if (!WIFEXITED(status)) {
D("subprocess didn't exit");
break;
} else if (WEXITSTATUS(status) >= 0) {
exit_code = WEXITSTATUS(status);
- D("subprocess exit code = %d", WEXITSTATUS(status));
+ ADB_LOG(Shell) << "subprocess " << pid_ << " exited with status " << exit_code;
break;
}
}
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 0928198..87937fb 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -282,6 +282,7 @@
monitor_thread_ = std::thread([this]() {
adb_thread_setname("UsbFfs-monitor");
+ LOG(INFO) << "UsbFfs-monitor thread spawned";
bool bound = false;
bool enabled = false;
@@ -427,6 +428,8 @@
worker_started_ = true;
worker_thread_ = std::thread([this]() {
adb_thread_setname("UsbFfs-worker");
+ LOG(INFO) << "UsbFfs-worker thread spawned";
+
for (size_t i = 0; i < kUsbReadQueueDepth; ++i) {
read_requests_[i] = CreateReadBlock(next_read_id_++);
if (!SubmitRead(&read_requests_[i])) {
@@ -525,14 +528,16 @@
}
if (id.direction == TransferDirection::READ) {
- HandleRead(id, event.res);
+ if (!HandleRead(id, event.res)) {
+ return;
+ }
} else {
HandleWrite(id);
}
}
}
- void HandleRead(TransferId id, int64_t size) {
+ bool HandleRead(TransferId id, int64_t size) {
uint64_t read_idx = id.id % kUsbReadQueueDepth;
IoReadBlock* block = &read_requests_[read_idx];
block->pending = false;
@@ -542,7 +547,7 @@
if (block->id().id != needed_read_id_) {
LOG(VERBOSE) << "read " << block->id().id << " completed while waiting for "
<< needed_read_id_;
- return;
+ return true;
}
for (uint64_t id = needed_read_id_;; ++id) {
@@ -551,15 +556,22 @@
if (current_block->pending) {
break;
}
- ProcessRead(current_block);
+ if (!ProcessRead(current_block)) {
+ return false;
+ }
++needed_read_id_;
}
+
+ return true;
}
- void ProcessRead(IoReadBlock* block) {
+ bool ProcessRead(IoReadBlock* block) {
if (!block->payload.empty()) {
if (!incoming_header_.has_value()) {
- CHECK_EQ(sizeof(amessage), block->payload.size());
+ if (block->payload.size() != sizeof(amessage)) {
+ HandleError("received packet of unexpected length while reading header");
+ return false;
+ }
amessage& msg = incoming_header_.emplace();
memcpy(&msg, block->payload.data(), sizeof(msg));
LOG(DEBUG) << "USB read:" << dump_header(&msg);
@@ -567,7 +579,10 @@
} else {
size_t bytes_left = incoming_header_->data_length - incoming_payload_.size();
Block payload = std::move(block->payload);
- CHECK_LE(payload.size(), bytes_left);
+ if (block->payload.size() > bytes_left) {
+ HandleError("received too many bytes while waiting for payload");
+ return false;
+ }
incoming_payload_.append(std::move(payload));
}
@@ -590,6 +605,7 @@
PrepareReadBlock(block, block->id().id + kUsbReadQueueDepth);
SubmitRead(block);
+ return true;
}
bool SubmitRead(IoReadBlock* block) {
diff --git a/adb/daemon/usb_ffs.cpp b/adb/daemon/usb_ffs.cpp
index b19fa5d..cb7e2fb 100644
--- a/adb/daemon/usb_ffs.cpp
+++ b/adb/daemon/usb_ffs.cpp
@@ -299,6 +299,7 @@
}
// Signal only when writing the descriptors to ffs
android::base::SetProperty("sys.usb.ffs.ready", "1");
+ *out_control = std::move(control);
}
bulk_out.reset(adb_open(USB_FFS_ADB_OUT, O_RDONLY));
@@ -313,7 +314,6 @@
return false;
}
- *out_control = std::move(control);
*out_bulk_in = std::move(bulk_in);
*out_bulk_out = std::move(bulk_out);
return true;
diff --git a/adb/libs/adbconnection/adbconnection_client.cpp b/adb/libs/adbconnection/adbconnection_client.cpp
index ee48abb..c132342 100644
--- a/adb/libs/adbconnection/adbconnection_client.cpp
+++ b/adb/libs/adbconnection/adbconnection_client.cpp
@@ -29,6 +29,8 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include "adbconnection/process_info.h"
+
using android::base::unique_fd;
static constexpr char kJdwpControlName[] = "\0jdwp-control";
@@ -60,6 +62,8 @@
std::optional<uint64_t> pid;
std::optional<bool> debuggable;
+ std::optional<bool> profileable;
+ std::optional<std::string> architecture;
for (size_t i = 0; i < info_count; ++i) {
auto info = info_elems[i];
@@ -77,7 +81,23 @@
LOG(ERROR) << "multiple debuggable entries in AdbConnectionClientInfo, ignoring";
continue;
}
- debuggable = info->data.pid;
+ debuggable = info->data.debuggable;
+ break;
+
+ case AdbConnectionClientInfoType::profileable:
+ if (profileable) {
+ LOG(ERROR) << "multiple profileable entries in AdbConnectionClientInfo, ignoring";
+ continue;
+ }
+ profileable = info->data.profileable;
+ break;
+
+ case AdbConnectionClientInfoType::architecture:
+ if (architecture) {
+ LOG(ERROR) << "multiple architecture entries in AdbConnectionClientInfo, ignoring";
+ continue;
+ }
+ architecture = std::string(info->data.architecture.name, info->data.architecture.size);
break;
}
}
@@ -92,6 +112,16 @@
return nullptr;
}
+ if (!profileable) {
+ LOG(ERROR) << "AdbConnectionClientInfo missing required field profileable";
+ return nullptr;
+ }
+
+ if (!architecture) {
+ LOG(ERROR) << "AdbConnectionClientInfo missing required field architecture";
+ return nullptr;
+ }
+
ctx->control_socket_.reset(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
if (ctx->control_socket_ < 0) {
PLOG(ERROR) << "failed to create Unix domain socket";
@@ -120,10 +150,10 @@
return nullptr;
}
- uint32_t pid_u32 = static_cast<uint32_t>(*pid);
- rc = TEMP_FAILURE_RETRY(write(ctx->control_socket_.get(), &pid_u32, sizeof(pid_u32)));
- if (rc != sizeof(pid_u32)) {
- PLOG(ERROR) << "failed to send JDWP process pid to adbd";
+ ProcessInfo process(*pid, *debuggable, *profileable, *architecture);
+ rc = TEMP_FAILURE_RETRY(write(ctx->control_socket_.get(), &process, sizeof(process)));
+ if (rc != sizeof(process)) {
+ PLOG(ERROR) << "failed to send JDWP process info to adbd";
}
return ctx.release();
diff --git a/adb/libs/adbconnection/adbconnection_server.cpp b/adb/libs/adbconnection/adbconnection_server.cpp
index 939da2f..aac9615 100644
--- a/adb/libs/adbconnection/adbconnection_server.cpp
+++ b/adb/libs/adbconnection/adbconnection_server.cpp
@@ -28,6 +28,8 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include "adbconnection/process_info.h"
+
using android::base::unique_fd;
#define JDWP_CONTROL_NAME "\0jdwp-control"
@@ -36,7 +38,7 @@
static_assert(JDWP_CONTROL_NAME_LEN <= sizeof(reinterpret_cast<sockaddr_un*>(0)->sun_path));
// Listen for incoming jdwp clients forever.
-void adbconnection_listen(void (*callback)(int fd, pid_t pid)) {
+void adbconnection_listen(void (*callback)(int fd, ProcessInfo process)) {
sockaddr_un addr = {};
socklen_t addrlen = JDWP_CONTROL_NAME_LEN + sizeof(addr.sun_family);
@@ -106,16 +108,13 @@
<< ") in pending connections";
}
- // Massively oversized buffer: we're expecting an int32_t from the other end.
- char buf[32];
- int rc = TEMP_FAILURE_RETRY(recv(it->get(), buf, sizeof(buf), MSG_DONTWAIT));
- if (rc != 4) {
+ ProcessInfo process;
+ int rc = TEMP_FAILURE_RETRY(recv(it->get(), &process, sizeof(process), MSG_DONTWAIT));
+ if (rc != sizeof(process)) {
LOG(ERROR) << "received data of incorrect size from JDWP client: read " << rc
- << ", expected 4";
+ << ", expected " << sizeof(process);
} else {
- int32_t pid;
- memcpy(&pid, buf, sizeof(pid));
- callback(it->release(), static_cast<pid_t>(pid));
+ callback(it->release(), process);
}
if (epoll_ctl(epfd.get(), EPOLL_CTL_DEL, event.data.fd, nullptr) != 0) {
diff --git a/adb/libs/adbconnection/include/adbconnection/client.h b/adb/libs/adbconnection/include/adbconnection/client.h
index 692fea0..a74cd36 100644
--- a/adb/libs/adbconnection/include/adbconnection/client.h
+++ b/adb/libs/adbconnection/include/adbconnection/client.h
@@ -28,6 +28,8 @@
enum AdbConnectionClientInfoType {
pid,
debuggable,
+ profileable,
+ architecture,
};
struct AdbConnectionClientInfo {
@@ -35,11 +37,17 @@
union {
uint64_t pid;
bool debuggable;
+ bool profileable;
+ struct {
+ const char* name;
+ size_t size;
+ } architecture;
} data;
};
// Construct a context and connect to adbd.
// Returns null if we fail to connect to adbd.
+// Note this is an apex interface as it's loaded by ART.
AdbConnectionClientContext* adbconnection_client_new(
const AdbConnectionClientInfo* const* info_elems, size_t info_count);
diff --git a/adb/libs/adbconnection/include/adbconnection/process_info.h b/adb/libs/adbconnection/include/adbconnection/process_info.h
new file mode 100644
index 0000000..86d3259
--- /dev/null
+++ b/adb/libs/adbconnection/include/adbconnection/process_info.h
@@ -0,0 +1,39 @@
+/*
+ * 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 <stdint.h>
+#include <string.h>
+#include <string>
+
+struct ProcessInfo {
+ const static size_t kMaxArchNameLength = 16;
+
+ uint64_t pid;
+ bool debuggable;
+ bool profileable;
+ int32_t arch_name_length; // length of architecture name in bytes
+ char arch_name[kMaxArchNameLength]; // ISA name, e.g., "arm64"
+
+ ProcessInfo() : pid(0), debuggable(false), profileable(false), arch_name_length(0) {}
+
+ ProcessInfo(uint64_t pid, bool dbg, bool prof, const std::string& arch)
+ : pid(pid), debuggable(dbg), profileable(prof) {
+ arch_name_length = std::min(arch.size(), kMaxArchNameLength);
+ memcpy(arch_name, arch.data(), arch_name_length);
+ }
+};
diff --git a/adb/libs/adbconnection/include/adbconnection/server.h b/adb/libs/adbconnection/include/adbconnection/server.h
index 57ca6cd..b1059ba 100644
--- a/adb/libs/adbconnection/include/adbconnection/server.h
+++ b/adb/libs/adbconnection/include/adbconnection/server.h
@@ -20,7 +20,7 @@
#include <android-base/unique_fd.h>
-extern "C" {
+#include "adbconnection/process_info.h"
-void adbconnection_listen(void (*callback)(int fd, pid_t pid));
-}
+// Note this is NOT an apex interface as it's linked only into adbd.
+void adbconnection_listen(void (*callback)(int fd, ProcessInfo process));
diff --git a/adb/pairing_auth/Android.bp b/adb/pairing_auth/Android.bp
index 0850047..a43f4d0 100644
--- a/adb/pairing_auth/Android.bp
+++ b/adb/pairing_auth/Android.bp
@@ -47,7 +47,7 @@
use_version_lib: false,
host_supported: true,
- recovery_available: true,
+ recovery_available: false,
stl: "libc++_static",
diff --git a/adb/pairing_connection/Android.bp b/adb/pairing_connection/Android.bp
index c053854..bcde7b1 100644
--- a/adb/pairing_connection/Android.bp
+++ b/adb/pairing_connection/Android.bp
@@ -52,7 +52,7 @@
stl: "libc++_static",
host_supported: true,
- recovery_available: true,
+ recovery_available: false,
static_libs: [
"libbase",
@@ -131,7 +131,7 @@
],
host_supported: true,
- recovery_available: true,
+ recovery_available: false,
stl: "libc++_static",
diff --git a/adb/pairing_connection/tests/pairing_connection_test.cpp b/adb/pairing_connection/tests/pairing_connection_test.cpp
index b6e09f1..86b66aa 100644
--- a/adb/pairing_connection/tests/pairing_connection_test.cpp
+++ b/adb/pairing_connection/tests/pairing_connection_test.cpp
@@ -440,7 +440,7 @@
EXPECT_FALSE(*(server_waiter.is_valid_));
}
-TEST_F(AdbPairingConnectionTest, MultipleClientsOnePass) {
+TEST_F(AdbPairingConnectionTest, DISABLED_MultipleClientsOnePass) {
// Send multiple clients with bad passwords, but send the last one with the
// correct password.
std::vector<uint8_t> pswd{0x01, 0x03, 0x05, 0x07};
diff --git a/adb/proto/Android.bp b/adb/proto/Android.bp
index a7e5d9c..fe828a0 100644
--- a/adb/proto/Android.bp
+++ b/adb/proto/Android.bp
@@ -68,3 +68,61 @@
"//apex_available:platform",
],
}
+
+cc_defaults {
+ name: "libapp_processes_protos_defaults",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wthread-safety",
+ "-Werror",
+ ],
+
+ compile_multilib: "both",
+
+ srcs: [
+ "app_processes.proto",
+ ],
+ target: {
+ windows: {
+ compile_multilib: "first",
+ enabled: true,
+ },
+ },
+
+ visibility: [
+ "//system/core/adb:__subpackages__",
+ ],
+
+ stl: "libc++_static",
+
+ apex_available: [
+ "com.android.adbd",
+ "test_com.android.adbd",
+ ],
+}
+
+cc_library {
+ name: "libapp_processes_protos_lite",
+ defaults: ["libapp_processes_protos_defaults"],
+
+ apex_available: ["//apex_available:platform"],
+
+ proto: {
+ export_proto_headers: true,
+ type: "lite",
+ },
+
+ host_supported: true,
+ recovery_available: true,
+}
+
+cc_library_host_static {
+ name: "libapp_processes_protos_full",
+ defaults: ["libapp_processes_protos_defaults"],
+
+ proto: {
+ export_proto_headers: true,
+ type: "full",
+ },
+}
diff --git a/adb/proto/app_processes.proto b/adb/proto/app_processes.proto
new file mode 100644
index 0000000..1183645
--- /dev/null
+++ b/adb/proto/app_processes.proto
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+option java_package = "com.android.server.adb.protos";
+option java_outer_classname = "AppProcessesProto";
+
+package adb.proto;
+
+message ProcessEntry {
+ int64 pid = 1;
+ bool debuggable = 2;
+ bool profileable = 3;
+ string architecture = 4;
+}
+
+message AppProcesses {
+ repeated ProcessEntry process = 1;
+}
diff --git a/adb/test_adb.py b/adb/test_adb.py
index 3d6de26..c872fb0 100755
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -33,6 +33,11 @@
import unittest
import warnings
+def find_open_port():
+ # Find an open port.
+ with socket.socket() as s:
+ s.bind(("localhost", 0))
+ return s.getsockname()[1]
@contextlib.contextmanager
def fake_adbd(protocol=socket.AF_INET, port=0):
@@ -126,10 +131,7 @@
This creates an ADB server and returns the port it's listening on.
"""
- port = 5038
- # Kill any existing server on this non-default port.
- subprocess.check_output(["adb", "-P", str(port), "kill-server"],
- stderr=subprocess.STDOUT)
+ port = find_open_port()
read_pipe, write_pipe = os.pipe()
if sys.platform == "win32":
@@ -224,10 +226,7 @@
# adb server, this also tests whether multiple instances of the adb
# server conflict on adb.log.
- port = 5038
- # Kill any existing server on this non-default port.
- subprocess.check_output(["adb", "-P", str(port), "kill-server"],
- stderr=subprocess.STDOUT)
+ port = find_open_port()
try:
# We get warnings for unclosed files for the subprocess's pipes,
@@ -289,12 +288,8 @@
"""
Tests that the server can start up on ::1 and that it's accessible
"""
- server_port = 5037
- # Kill any existing server on this non-default port.
- subprocess.check_output(
- ["adb", "-P", str(server_port), "kill-server"],
- stderr=subprocess.STDOUT,
- )
+
+ server_port = find_open_port()
try:
subprocess.check_output(
["adb", "-L", "tcp:[::1]:{}".format(server_port), "server"],
diff --git a/adb/tls/Android.bp b/adb/tls/Android.bp
index 49833ff..f2837e1 100644
--- a/adb/tls/Android.bp
+++ b/adb/tls/Android.bp
@@ -42,12 +42,8 @@
"//system/core/adb:__subpackages__",
],
- stl: "libc++_static",
-
- static_libs: [
- "libbase",
- ],
shared_libs: [
+ "libbase",
"libcrypto",
"liblog",
"libssl",
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 8b3461a..447a8fe 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -81,6 +81,7 @@
const char* const kFeatureFixedPushSymlinkTimestamp = "fixed_push_symlink_timestamp";
const char* const kFeatureAbbExec = "abb_exec";
const char* const kFeatureRemountShell = "remount_shell";
+const char* const kFeatureTrackApp = "track_app";
namespace {
@@ -1175,6 +1176,7 @@
kFeatureFixedPushSymlinkTimestamp,
kFeatureAbbExec,
kFeatureRemountShell,
+ kFeatureTrackApp,
// Increment ADB_SERVER_VERSION when adding a feature that adbd needs
// to know about. Otherwise, the client can be stuck running an old
// version of the server even after upgrading their copy of adb.
diff --git a/adb/transport.h b/adb/transport.h
index 8a0f62a..a62349e 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -82,6 +82,8 @@
// adbd properly updates symlink timestamps on push.
extern const char* const kFeatureFixedPushSymlinkTimestamp;
extern const char* const kFeatureRemountShell;
+// adbd supports `track-app` service reporting debuggable/profileable apps.
+extern const char* const kFeatureTrackApp;
TransportId NextTransportId();
diff --git a/base/Android.bp b/base/Android.bp
index 25c74f2..fc8dff1 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -47,6 +47,10 @@
enabled: true,
},
},
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
}
cc_defaults {
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 31823df..49f1f31 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -20,8 +20,11 @@
#include <chrono>
#include <limits>
+#include <optional>
#include <string>
+struct prop_info;
+
namespace android {
namespace base {
@@ -67,5 +70,32 @@
std::chrono::milliseconds::max());
#endif
+#if defined(__BIONIC__) && __cplusplus >= 201703L
+// Cached system property lookup. For code that needs to read the same property multiple times,
+// this class helps optimize those lookups.
+class CachedProperty {
+ public:
+ explicit CachedProperty(const char* property_name);
+
+ // Returns the current value of the underlying system property as cheaply as possible.
+ // The returned pointer is valid until the next call to Get. Because most callers are going
+ // to want to parse the string returned here and cached that as well, this function performs
+ // no locking, and is completely thread unsafe. It is the caller's responsibility to provide a
+ // lock for thread-safety.
+ //
+ // Note: *changed can be set to true even if the contents of the property remain the same.
+ const char* Get(bool* changed = nullptr);
+
+ private:
+ std::string property_name_;
+ const prop_info* prop_info_;
+ std::optional<uint32_t> cached_area_serial_;
+ std::optional<uint32_t> cached_property_serial_;
+ char cached_value_[92];
+ bool is_read_only_;
+ const char* read_only_property_;
+};
+#endif
+
} // namespace base
} // namespace android
diff --git a/base/logging.cpp b/base/logging.cpp
index f42b996..9360a56 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -447,7 +447,7 @@
// See the comment in SetLogger().
static std::atomic<AbortFunction*> abort_function(nullptr);
auto* old_abort_function = abort_function.exchange(new AbortFunction(aborter));
- __android_log_set_aborter([](const char* abort_message) {
+ liblog_functions->__android_log_set_aborter([](const char* abort_message) {
auto& function = *abort_function.load(std::memory_order_acquire);
function(abort_message);
});
@@ -578,7 +578,7 @@
if (liblog_functions) {
__android_logger_data logger_data = {
sizeof(__android_logger_data), LOG_ID_DEFAULT, priority, tag, file, line};
- __android_log_write_logger_data(&logger_data, message);
+ liblog_functions->__android_log_write_logger_data(&logger_data, message);
} else {
if (tag == nullptr) {
std::lock_guard<std::recursive_mutex> lock(TagLock());
diff --git a/base/properties.cpp b/base/properties.cpp
index 4731bf2..35e41a8 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -30,6 +30,7 @@
#include <android-base/parsebool.h>
#include <android-base/parseint.h>
+#include <android-base/strings.h>
namespace android {
namespace base {
@@ -195,6 +196,62 @@
return (WaitForPropertyCreation(key, relative_timeout, start_time) != nullptr);
}
+CachedProperty::CachedProperty(const char* property_name)
+ : property_name_(property_name),
+ prop_info_(nullptr),
+ cached_area_serial_(0),
+ cached_property_serial_(0),
+ is_read_only_(android::base::StartsWith(property_name, "ro.")),
+ read_only_property_(nullptr) {
+ static_assert(sizeof(cached_value_) == PROP_VALUE_MAX);
+}
+
+const char* CachedProperty::Get(bool* changed) {
+ std::optional<uint32_t> initial_property_serial_ = cached_property_serial_;
+
+ // Do we have a `struct prop_info` yet?
+ if (prop_info_ == nullptr) {
+ // `__system_property_find` is expensive, so only retry if a property
+ // has been created since last time we checked.
+ uint32_t property_area_serial = __system_property_area_serial();
+ if (property_area_serial != cached_area_serial_) {
+ prop_info_ = __system_property_find(property_name_.c_str());
+ cached_area_serial_ = property_area_serial;
+ }
+ }
+
+ if (prop_info_ != nullptr) {
+ // Only bother re-reading the property if it's actually changed since last time.
+ uint32_t property_serial = __system_property_serial(prop_info_);
+ if (property_serial != cached_property_serial_) {
+ __system_property_read_callback(
+ prop_info_,
+ [](void* data, const char*, const char* value, uint32_t serial) {
+ CachedProperty* instance = reinterpret_cast<CachedProperty*>(data);
+ instance->cached_property_serial_ = serial;
+ // Read only properties can be larger than PROP_VALUE_MAX, but also never change value
+ // or location, thus we return the pointer from the shared memory directly.
+ if (instance->is_read_only_) {
+ instance->read_only_property_ = value;
+ } else {
+ strlcpy(instance->cached_value_, value, PROP_VALUE_MAX);
+ }
+ },
+ this);
+ }
+ }
+
+ if (changed) {
+ *changed = cached_property_serial_ != initial_property_serial_;
+ }
+
+ if (is_read_only_) {
+ return read_only_property_;
+ } else {
+ return cached_value_;
+ }
+}
+
#endif
} // namespace base
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
index e7d4880..c30c41e 100644
--- a/base/properties_test.cpp
+++ b/base/properties_test.cpp
@@ -230,3 +230,28 @@
GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
#endif
}
+
+TEST(properties, CachedProperty) {
+#if defined(__BIONIC__)
+ android::base::CachedProperty cached_property("debug.libbase.CachedProperty_test");
+ bool changed;
+ cached_property.Get(&changed);
+
+ android::base::SetProperty("debug.libbase.CachedProperty_test", "foo");
+ ASSERT_STREQ("foo", cached_property.Get(&changed));
+ ASSERT_TRUE(changed);
+
+ ASSERT_STREQ("foo", cached_property.Get(&changed));
+ ASSERT_FALSE(changed);
+
+ android::base::SetProperty("debug.libbase.CachedProperty_test", "bar");
+ ASSERT_STREQ("bar", cached_property.Get(&changed));
+ ASSERT_TRUE(changed);
+
+ ASSERT_STREQ("bar", cached_property.Get(&changed));
+ ASSERT_FALSE(changed);
+
+#else
+ GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
+#endif
+}
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 3e99880..6a38145 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -254,9 +254,7 @@
}
static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo,
- std::unique_ptr<unwindstack::Regs>* regs, uintptr_t* abort_msg_address,
- uintptr_t* fdsan_table_address, uintptr_t* gwp_asan_state,
- uintptr_t* gwp_asan_metadata) {
+ std::unique_ptr<unwindstack::Regs>* regs, ProcessInfo* process_info) {
std::aligned_storage<sizeof(CrashInfo) + 1, alignof(CrashInfo)>::type buf;
CrashInfo* crash_info = reinterpret_cast<CrashInfo*>(&buf);
ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &buf, sizeof(buf)));
@@ -288,19 +286,16 @@
}
}
- *fdsan_table_address = 0;
- *gwp_asan_state = 0;
- *gwp_asan_metadata = 0;
switch (crash_info->header.version) {
case 3:
- *gwp_asan_state = crash_info->data.v3.gwp_asan_state;
- *gwp_asan_metadata = crash_info->data.v3.gwp_asan_metadata;
+ process_info->gwp_asan_state = crash_info->data.v3.gwp_asan_state;
+ process_info->gwp_asan_metadata = crash_info->data.v3.gwp_asan_metadata;
FALLTHROUGH_INTENDED;
case 2:
- *fdsan_table_address = crash_info->data.v2.fdsan_table_address;
+ process_info->fdsan_table_address = crash_info->data.v2.fdsan_table_address;
FALLTHROUGH_INTENDED;
case 1:
- *abort_msg_address = crash_info->data.v1.abort_msg_address;
+ process_info->abort_msg_address = crash_info->data.v1.abort_msg_address;
*siginfo = crash_info->data.v1.siginfo;
regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(),
&crash_info->data.v1.ucontext));
@@ -425,10 +420,7 @@
ATRACE_NAME("after reparent");
pid_t pseudothread_tid;
DebuggerdDumpType dump_type;
- uintptr_t abort_msg_address = 0;
- uintptr_t fdsan_table_address = 0;
- uintptr_t gwp_asan_state = 0;
- uintptr_t gwp_asan_metadata = 0;
+ ProcessInfo process_info;
Initialize(argv);
ParseArgs(argc, argv, &pseudothread_tid, &dump_type);
@@ -489,8 +481,7 @@
if (thread == g_target_thread) {
// Read the thread's registers along with the rest of the crash info out of the pipe.
- ReadCrashInfo(input_pipe, &siginfo, &info.registers, &abort_msg_address,
- &fdsan_table_address, &gwp_asan_state, &gwp_asan_metadata);
+ ReadCrashInfo(input_pipe, &siginfo, &info.registers, &process_info);
info.siginfo = &siginfo;
info.signo = info.siginfo->si_signo;
} else {
@@ -599,14 +590,14 @@
} else {
{
ATRACE_NAME("fdsan table dump");
- populate_fdsan_table(&open_files, unwinder.GetProcessMemory(), fdsan_table_address);
+ populate_fdsan_table(&open_files, unwinder.GetProcessMemory(),
+ process_info.fdsan_table_address);
}
{
ATRACE_NAME("engrave_tombstone");
- engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread,
- abort_msg_address, &open_files, &amfd_data, gwp_asan_state,
- gwp_asan_metadata);
+ engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread, process_info,
+ &open_files, &amfd_data);
}
}
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
index 4f24360..665d24a 100644
--- a/debuggerd/include/debuggerd/handler.h
+++ b/debuggerd/include/debuggerd/handler.h
@@ -19,7 +19,9 @@
#include <bionic/reserved_signals.h>
#include <signal.h>
#include <stdint.h>
+#include <string.h>
#include <sys/cdefs.h>
+#include <sys/system_properties.h>
#include <sys/types.h>
__BEGIN_DECLS
@@ -50,16 +52,21 @@
#define DEBUGGER_SIGNAL BIONIC_SIGNAL_DEBUGGER
static void __attribute__((__unused__)) debuggerd_register_handlers(struct sigaction* action) {
- sigaction(SIGABRT, action, nullptr);
- sigaction(SIGBUS, action, nullptr);
- sigaction(SIGFPE, action, nullptr);
- sigaction(SIGILL, action, nullptr);
- sigaction(SIGSEGV, action, nullptr);
-#if defined(SIGSTKFLT)
- sigaction(SIGSTKFLT, action, nullptr);
-#endif
- sigaction(SIGSYS, action, nullptr);
- sigaction(SIGTRAP, action, nullptr);
+ char value[PROP_VALUE_MAX] = "";
+ bool enabled =
+ !(__system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1") &&
+ __system_property_get("debug.debuggerd.disable", value) > 0 && !strcmp(value, "1"));
+ if (enabled) {
+ sigaction(SIGABRT, action, nullptr);
+ sigaction(SIGBUS, action, nullptr);
+ sigaction(SIGFPE, action, nullptr);
+ sigaction(SIGILL, action, nullptr);
+ sigaction(SIGSEGV, action, nullptr);
+ sigaction(SIGSTKFLT, action, nullptr);
+ sigaction(SIGSYS, action, nullptr);
+ sigaction(SIGTRAP, action, nullptr);
+ }
+
sigaction(BIONIC_SIGNAL_DEBUGGER, action, nullptr);
}
diff --git a/debuggerd/libdebuggerd/gwp_asan.cpp b/debuggerd/libdebuggerd/gwp_asan.cpp
index 53df783..fe3a173 100644
--- a/debuggerd/libdebuggerd/gwp_asan.cpp
+++ b/debuggerd/libdebuggerd/gwp_asan.cpp
@@ -63,12 +63,11 @@
}
GwpAsanCrashData::GwpAsanCrashData(unwindstack::Memory* process_memory,
- uintptr_t gwp_asan_state_ptr, uintptr_t gwp_asan_metadata_ptr,
- const ThreadInfo& thread_info) {
- if (!process_memory || !gwp_asan_metadata_ptr || !gwp_asan_state_ptr) return;
+ const ProcessInfo& process_info, const ThreadInfo& thread_info) {
+ if (!process_memory || !process_info.gwp_asan_metadata || !process_info.gwp_asan_state) return;
// Extract the GWP-ASan regions from the dead process.
- if (!retrieve_gwp_asan_state(process_memory, gwp_asan_state_ptr, &state_)) return;
- metadata_.reset(retrieve_gwp_asan_metadata(process_memory, state_, gwp_asan_metadata_ptr));
+ if (!retrieve_gwp_asan_state(process_memory, process_info.gwp_asan_state, &state_)) return;
+ metadata_.reset(retrieve_gwp_asan_metadata(process_memory, state_, process_info.gwp_asan_metadata));
if (!metadata_.get()) return;
// Get the external crash address from the thread info.
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h b/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
index aef4c62..6c88733 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
@@ -38,8 +38,8 @@
// still be responsible, as it terminates when it detects an internal error
// (double free, invalid free). In these cases, we will retrieve the fault
// address from the GWP-ASan allocator's state.
- GwpAsanCrashData(unwindstack::Memory* process_memory, uintptr_t gwp_asan_state_ptr,
- uintptr_t gwp_asan_metadata_ptr, const ThreadInfo& thread_info);
+ GwpAsanCrashData(unwindstack::Memory* process_memory, const ProcessInfo& process_info,
+ const ThreadInfo& thread_info);
// Is GWP-ASan responsible for this crash.
bool CrashIsMine() const;
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 291d994..3ff7d62 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -44,18 +44,13 @@
int open_tombstone(std::string* path);
/* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, unwindstack::Unwinder* unwinder,
- const OpenFilesList* open_files, pid_t pid, pid_t tid,
- const std::string& process_name, const std::map<pid_t, std::string>& threads,
- uint64_t abort_msg_address, std::string* amfd_data);
+void engrave_tombstone(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
+ const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
+ const ProcessInfo& process_info, OpenFilesList* open_files,
+ std::string* amfd_data);
void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo,
ucontext_t* ucontext);
-void engrave_tombstone(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
- const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
- uint64_t abort_msg_address, OpenFilesList* open_files,
- std::string* amfd_data, uintptr_t gwp_asan_state,
- uintptr_t gwp_asan_metadata);
#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index eb4b1b8..4f681c2 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -35,3 +35,10 @@
int signo = 0;
siginfo_t* siginfo = nullptr;
};
+
+struct ProcessInfo {
+ uintptr_t abort_msg_address = 0;
+ uintptr_t fdsan_table_address = 0;
+ uintptr_t gwp_asan_state = 0;
+ uintptr_t gwp_asan_metadata = 0;
+};
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index eed95bc..aec8c60 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -371,7 +371,7 @@
GwpAsanCrashDataTest(
gwp_asan::Error error,
const gwp_asan::AllocationMetadata *responsible_allocation) :
- GwpAsanCrashData(nullptr, 0u, 0u, ThreadInfo{}) {
+ GwpAsanCrashData(nullptr, ProcessInfo{}, ThreadInfo{}) {
is_gwp_asan_responsible_ = true;
error_ = error;
responsible_allocation_ = responsible_allocation;
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index fd52e81..b3f059c 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -376,8 +376,7 @@
}
static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info,
- uint64_t abort_msg_address, bool primary_thread,
- const GwpAsanCrashData& gwp_asan_crash_data) {
+ const ProcessInfo& process_info, bool primary_thread) {
log->current_tid = thread_info.tid;
if (!primary_thread) {
_LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
@@ -388,15 +387,21 @@
dump_signal_info(log, thread_info, unwinder->GetProcessMemory().get());
}
- if (primary_thread && gwp_asan_crash_data.CrashIsMine()) {
- gwp_asan_crash_data.DumpCause(log);
+ std::unique_ptr<GwpAsanCrashData> gwp_asan_crash_data;
+ if (primary_thread) {
+ gwp_asan_crash_data = std::make_unique<GwpAsanCrashData>(unwinder->GetProcessMemory().get(),
+ process_info, thread_info);
+ }
+
+ if (primary_thread && gwp_asan_crash_data->CrashIsMine()) {
+ gwp_asan_crash_data->DumpCause(log);
} else if (thread_info.siginfo) {
dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps(),
thread_info.registers.get());
}
if (primary_thread) {
- dump_abort_message(log, unwinder->GetProcessMemory().get(), abort_msg_address);
+ dump_abort_message(log, unwinder->GetProcessMemory().get(), process_info.abort_msg_address);
}
dump_registers(log, thread_info.registers.get());
@@ -413,12 +418,12 @@
}
if (primary_thread) {
- if (gwp_asan_crash_data.HasDeallocationTrace()) {
- gwp_asan_crash_data.DumpDeallocationTrace(log, unwinder);
+ if (gwp_asan_crash_data->HasDeallocationTrace()) {
+ gwp_asan_crash_data->DumpDeallocationTrace(log, unwinder);
}
- if (gwp_asan_crash_data.HasAllocationTrace()) {
- gwp_asan_crash_data.DumpAllocationTrace(log, unwinder);
+ if (gwp_asan_crash_data->HasAllocationTrace()) {
+ gwp_asan_crash_data->DumpAllocationTrace(log, unwinder);
}
unwindstack::Maps* maps = unwinder->GetMaps();
@@ -601,15 +606,16 @@
LOG(FATAL) << "Failed to init unwinder object.";
}
- engrave_tombstone(unique_fd(dup(tombstone_fd)), &unwinder, threads, tid, abort_msg_address,
- nullptr, nullptr, 0u, 0u);
+ ProcessInfo process_info;
+ process_info.abort_msg_address = abort_msg_address;
+ engrave_tombstone(unique_fd(dup(tombstone_fd)), &unwinder, threads, tid, process_info, nullptr,
+ nullptr);
}
void engrave_tombstone(unique_fd output_fd, unwindstack::Unwinder* unwinder,
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
- uint64_t abort_msg_address, OpenFilesList* open_files,
- std::string* amfd_data, uintptr_t gwp_asan_state_ptr,
- uintptr_t gwp_asan_metadata_ptr) {
+ const ProcessInfo& process_info, OpenFilesList* open_files,
+ std::string* amfd_data) {
// don't copy log messages to tombstone unless this is a dev device
bool want_logs = android::base::GetBoolProperty("ro.debuggable", false);
@@ -628,12 +634,7 @@
LOG(FATAL) << "failed to find target thread";
}
- GwpAsanCrashData gwp_asan_crash_data(unwinder->GetProcessMemory().get(),
- gwp_asan_state_ptr,
- gwp_asan_metadata_ptr, it->second);
-
- dump_thread(&log, unwinder, it->second, abort_msg_address, true,
- gwp_asan_crash_data);
+ dump_thread(&log, unwinder, it->second, process_info, true);
if (want_logs) {
dump_logs(&log, it->second.pid, 50);
@@ -644,7 +645,7 @@
continue;
}
- dump_thread(&log, unwinder, thread_info, 0, false, gwp_asan_crash_data);
+ dump_thread(&log, unwinder, thread_info, process_info, false);
}
if (open_files) {
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 2c9dec9..ca120c6 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -261,7 +261,7 @@
}
// If the slot is not changing, do nothing.
- if (slot == boot_control_hal->getCurrentSlot()) {
+ if (args[1] == device->GetCurrentSlot()) {
return device->WriteOkay("");
}
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
index 705d4e3..676f446 100644
--- a/fs_mgr/TEST_MAPPING
+++ b/fs_mgr/TEST_MAPPING
@@ -13,7 +13,7 @@
"name": "fiemap_writer_test"
},
{
- "name": "vts_libsnapshot_test_presubmit"
+ "name": "vts_libsnapshot_test"
}
]
}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 5223087..0089989 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -96,7 +96,9 @@
using android::base::Basename;
using android::base::GetBoolProperty;
+using android::base::Readlink;
using android::base::Realpath;
+using android::base::SetProperty;
using android::base::StartsWith;
using android::base::Timer;
using android::base::unique_fd;
@@ -178,6 +180,7 @@
return;
}
+ Timer t;
/* Check for the types of filesystems we know how to check */
if (is_extfs(fs_type)) {
/*
@@ -253,15 +256,19 @@
}
}
} else if (is_f2fs(fs_type)) {
- const char* f2fs_fsck_argv[] = {F2FS_FSCK_BIN, "-a", blk_device.c_str()};
- const char* f2fs_fsck_forced_argv[] = {F2FS_FSCK_BIN, "-f", blk_device.c_str()};
+ const char* f2fs_fsck_argv[] = {F2FS_FSCK_BIN, "-a", "-c", "10000", "--debug-cache",
+ blk_device.c_str()};
+ const char* f2fs_fsck_forced_argv[] = {
+ F2FS_FSCK_BIN, "-f", "-c", "10000", "--debug-cache", blk_device.c_str()};
if (should_force_check(*fs_stat)) {
- LINFO << "Running " << F2FS_FSCK_BIN << " -f " << realpath(blk_device);
+ LINFO << "Running " << F2FS_FSCK_BIN << " -f -c 10000 --debug-cache"
+ << realpath(blk_device);
ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_forced_argv), f2fs_fsck_forced_argv,
&status, false, LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
} else {
- LINFO << "Running " << F2FS_FSCK_BIN << " -a " << realpath(blk_device);
+ LINFO << "Running " << F2FS_FSCK_BIN << " -a -c 10000 --debug-cache"
+ << realpath(blk_device);
ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv, &status, false,
LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
}
@@ -270,7 +277,8 @@
LERROR << "Failed trying to run " << F2FS_FSCK_BIN;
}
}
-
+ android::base::SetProperty("ro.boottime.init.fsck." + Basename(target),
+ std::to_string(t.duration().count()));
return;
}
@@ -1580,6 +1588,79 @@
}
}
+static std::string ResolveBlockDevice(const std::string& block_device) {
+ if (!StartsWith(block_device, "/dev/block/")) {
+ LWARNING << block_device << " is not a block device";
+ return block_device;
+ }
+ std::string name = block_device.substr(5);
+ if (!StartsWith(name, "block/dm-")) {
+ // Not a dm-device, but might be a symlink. Optimistically try to readlink.
+ std::string result;
+ if (Readlink(block_device, &result)) {
+ return result;
+ } else if (errno == EINVAL) {
+ // After all, it wasn't a symlink.
+ return block_device;
+ } else {
+ LERROR << "Failed to readlink " << block_device;
+ return "";
+ }
+ }
+ // It's a dm-device, let's find what's inside!
+ std::string sys_dir = "/sys/" + name;
+ while (true) {
+ std::string slaves_dir = sys_dir + "/slaves";
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(slaves_dir.c_str()), closedir);
+ if (!dir) {
+ LERROR << "Failed to open " << slaves_dir;
+ return "";
+ }
+ std::string sub_device_name = "";
+ for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
+ if (entry->d_type != DT_LNK) continue;
+ if (!sub_device_name.empty()) {
+ LERROR << "Too many slaves in " << slaves_dir;
+ return "";
+ }
+ sub_device_name = entry->d_name;
+ }
+ if (sub_device_name.empty()) {
+ LERROR << "No slaves in " << slaves_dir;
+ return "";
+ }
+ if (!StartsWith(sub_device_name, "dm-")) {
+ // Not a dm-device! We can stop now.
+ return "/dev/block/" + sub_device_name;
+ }
+ // Still a dm-device, keep digging.
+ sys_dir = "/sys/block/" + sub_device_name;
+ }
+}
+
+FstabEntry* fs_mgr_get_mounted_entry_for_userdata(Fstab* fstab, const FstabEntry& mounted_entry) {
+ std::string resolved_block_device = ResolveBlockDevice(mounted_entry.blk_device);
+ if (resolved_block_device.empty()) {
+ return nullptr;
+ }
+ LINFO << "/data is mounted on " << resolved_block_device;
+ for (auto& entry : *fstab) {
+ if (entry.mount_point != "/data") {
+ continue;
+ }
+ std::string block_device;
+ if (!Readlink(entry.blk_device, &block_device)) {
+ LWARNING << "Failed to readlink " << entry.blk_device;
+ block_device = entry.blk_device;
+ }
+ if (block_device == resolved_block_device) {
+ return &entry;
+ }
+ }
+ LERROR << "Didn't find entry that was used to mount /data";
+ return nullptr;
+}
+
// TODO(b/143970043): return different error codes based on which step failed.
int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
Fstab proc_mounts;
@@ -1588,16 +1669,13 @@
return -1;
}
std::string block_device;
- if (auto entry = GetEntryForMountPoint(&proc_mounts, "/data"); entry != nullptr) {
- // Note: we don't care about a userdata wrapper here, since it's safe
- // to remount on top of the bow device instead, there will be no
- // conflicts.
- block_device = entry->blk_device;
- } else {
+ auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
+ if (mounted_entry == nullptr) {
LERROR << "/data is not mounted";
return -1;
}
- auto fstab_entry = GetMountedEntryForUserdata(fstab);
+ block_device = mounted_entry->blk_device;
+ auto fstab_entry = fs_mgr_get_mounted_entry_for_userdata(fstab, *mounted_entry);
if (fstab_entry == nullptr) {
LERROR << "Can't find /data in fstab";
return -1;
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 4ebe085..a836d3b 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -819,89 +819,6 @@
return entries;
}
-static std::string ResolveBlockDevice(const std::string& block_device) {
- if (!StartsWith(block_device, "/dev/block/")) {
- LWARNING << block_device << " is not a block device";
- return block_device;
- }
- std::string name = block_device.substr(5);
- if (!StartsWith(name, "block/dm-")) {
- // Not a dm-device, but might be a symlink. Optimistically try to readlink.
- std::string result;
- if (Readlink(block_device, &result)) {
- return result;
- } else if (errno == EINVAL) {
- // After all, it wasn't a symlink.
- return block_device;
- } else {
- LERROR << "Failed to readlink " << block_device;
- return "";
- }
- }
- // It's a dm-device, let's find what's inside!
- std::string sys_dir = "/sys/" + name;
- while (true) {
- std::string slaves_dir = sys_dir + "/slaves";
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(slaves_dir.c_str()), closedir);
- if (!dir) {
- LERROR << "Failed to open " << slaves_dir;
- return "";
- }
- std::string sub_device_name = "";
- for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
- if (entry->d_type != DT_LNK) continue;
- if (!sub_device_name.empty()) {
- LERROR << "Too many slaves in " << slaves_dir;
- return "";
- }
- sub_device_name = entry->d_name;
- }
- if (sub_device_name.empty()) {
- LERROR << "No slaves in " << slaves_dir;
- return "";
- }
- if (!StartsWith(sub_device_name, "dm-")) {
- // Not a dm-device! We can stop now.
- return "/dev/block/" + sub_device_name;
- }
- // Still a dm-device, keep digging.
- sys_dir = "/sys/block/" + sub_device_name;
- }
-}
-
-FstabEntry* GetMountedEntryForUserdata(Fstab* fstab) {
- Fstab mounts;
- if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
- LERROR << "Failed to read /proc/mounts";
- return nullptr;
- }
- auto mounted_entry = GetEntryForMountPoint(&mounts, "/data");
- if (mounted_entry == nullptr) {
- LWARNING << "/data is not mounted";
- return nullptr;
- }
- std::string resolved_block_device = ResolveBlockDevice(mounted_entry->blk_device);
- if (resolved_block_device.empty()) {
- return nullptr;
- }
- LINFO << "/data is mounted on " << resolved_block_device;
- for (auto& entry : *fstab) {
- if (entry.mount_point != "/data") {
- continue;
- }
- std::string block_device;
- if (!Readlink(entry.blk_device, &block_device)) {
- LWARNING << "Failed to readlink " << entry.blk_device;
- block_device = entry.blk_device;
- }
- if (block_device == resolved_block_device) {
- return &entry;
- }
- }
- LERROR << "Didn't find entry that was used to mount /data";
- return nullptr;
-}
-
std::set<std::string> GetBootDevices() {
// First check the kernel commandline, then try the device tree otherwise
std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 9bc38f9..3d556c9 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -107,6 +107,10 @@
// it destroys verity devices from device mapper after the device is unmounted.
int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab);
+// Finds a entry in |fstab| that was used to mount a /data |mounted_entry| from
+// /proc/mounts.
+android::fs_mgr::FstabEntry* fs_mgr_get_mounted_entry_for_userdata(
+ android::fs_mgr::Fstab* fstab, const android::fs_mgr::FstabEntry& mounted_entry);
int fs_mgr_remount_userdata_into_checkpointing(android::fs_mgr::Fstab* fstab);
// Finds the dm_bow device on which this block device is stacked, or returns
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 05e18fa..79d9402 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -104,7 +104,6 @@
FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
// The Fstab can contain multiple entries for the same mount point with different configurations.
std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path);
-FstabEntry* GetMountedEntryForUserdata(Fstab* fstab);
// This method builds DSU fstab entries and transfer the fstab.
//
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 1c3427f..c2c2cc4 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -84,17 +84,21 @@
}
cc_fuzz {
- name: "dm_linear_table_fuzzer",
- defaults: ["fs_mgr_defaults"],
- srcs: [
- "dm_linear_fuzzer.cpp",
- "test_util.cpp",
- ],
- static_libs: [
+ name: "dm_linear_table_fuzzer",
+ defaults: ["fs_mgr_defaults"],
+ srcs: [
+ "dm_linear_fuzzer.cpp",
+ "test_util.cpp",
+ ],
+ static_libs: [
"libdm",
"libbase",
"libext2_uuid",
"libfs_mgr",
"liblog",
- ],
+ ],
+}
+
+vts_config {
+ name: "VtsKernelLibdmTest",
}
diff --git a/fs_mgr/libdm/Android.mk b/fs_mgr/libdm/Android.mk
deleted file mode 100644
index 6aedc25..0000000
--- a/fs_mgr/libdm/Android.mk
+++ /dev/null
@@ -1,22 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := VtsKernelLibdmTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 254fbed..673e145 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -120,7 +120,7 @@
return false;
}
if (!WaitForFileDeleted(unique_path, timeout_ms)) {
- LOG(ERROR) << "Timeout out waiting for " << unique_path << " to be deleted";
+ LOG(ERROR) << "Failed waiting for " << unique_path << " to be deleted";
return false;
}
return true;
@@ -161,7 +161,7 @@
return true;
}
if (!WaitForFile(unique_path, timeout_ms)) {
- LOG(ERROR) << "Timed out waiting for device path: " << unique_path;
+ LOG(ERROR) << "Failed waiting for device path: " << unique_path;
DeleteDevice(name);
return false;
}
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 6461788..29b1032 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -243,12 +243,10 @@
return android::base::Join(argv, " ");
}
-const std::string DmTargetDefaultKey::name_ = "default-key";
-
bool DmTargetDefaultKey::IsLegacy(bool* result) {
DeviceMapper& dm = DeviceMapper::Instance();
DmTargetTypeInfo info;
- if (!dm.GetTargetByName(name_, &info)) return false;
+ if (!dm.GetTargetByName(kName, &info)) return false;
// dm-default-key was modified to be like dm-crypt with version 2
*result = !info.IsAtLeast(2, 0, 0);
return true;
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index d2e50d3..050d0b6 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -287,7 +287,7 @@
blockdev_(blockdev),
start_sector_(start_sector) {}
- std::string name() const override { return name_; }
+ std::string name() const override { return kName; }
bool Valid() const override;
std::string GetParameterString() const override;
static bool IsLegacy(bool* result);
@@ -296,7 +296,8 @@
void SetWrappedKeyV0() { is_hw_wrapped_ = true; }
private:
- static const std::string name_;
+ inline static const std::string kName = "default-key";
+
std::string cipher_;
std::string key_;
std::string blockdev_;
diff --git a/fs_mgr/libdm/utility.cpp b/fs_mgr/libdm/utility.cpp
index f252565..0eb59ab 100644
--- a/fs_mgr/libdm/utility.cpp
+++ b/fs_mgr/libdm/utility.cpp
@@ -19,6 +19,8 @@
#include <thread>
+#include <android-base/logging.h>
+
using namespace std::literals;
namespace android {
@@ -45,7 +47,11 @@
// If the file exists but returns EPERM or something, we consider the
// condition met.
if (access(path.c_str(), F_OK) != 0) {
- if (errno == ENOENT) return WaitResult::Wait;
+ if (errno == ENOENT) {
+ return WaitResult::Wait;
+ }
+ PLOG(ERROR) << "access failed: " << path;
+ return WaitResult::Fail;
}
return WaitResult::Done;
};
@@ -54,9 +60,13 @@
bool WaitForFileDeleted(const std::string& path, const std::chrono::milliseconds& timeout_ms) {
auto condition = [&]() -> WaitResult {
- if (access(path.c_str(), F_OK) == 0 || errno != ENOENT) {
+ if (access(path.c_str(), F_OK) == 0) {
return WaitResult::Wait;
}
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "access failed: " << path;
+ return WaitResult::Fail;
+ }
return WaitResult::Done;
};
return WaitForCondition(condition, timeout_ms);
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index ea0fca8..ad19f38 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -108,3 +108,6 @@
defaults: ["liblp_test_defaults"],
}
+vts_config {
+ name: "VtsKernelLiblpTest",
+}
diff --git a/fs_mgr/liblp/Android.mk b/fs_mgr/liblp/Android.mk
deleted file mode 100644
index 7f7f891..0000000
--- a/fs_mgr/liblp/Android.mk
+++ /dev/null
@@ -1,22 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := VtsKernelLiblpTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index e4d92ca..0b1e522 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -124,7 +124,7 @@
}
bool WriteToImageFile(const std::string& file, const LpMetadata& input) {
- unique_fd fd(open(file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
+ unique_fd fd(open(file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_BINARY, 0644));
if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
return false;
@@ -184,7 +184,7 @@
}
bool ImageBuilder::Export(const std::string& file) {
- unique_fd fd(open(file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
+ unique_fd fd(open(file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_BINARY, 0644));
if (fd < 0) {
PERROR << "open failed: " << file;
return false;
@@ -208,7 +208,7 @@
std::string file_name = "super_" + name + ".img";
std::string file_path = output_dir + "/" + file_name;
- static const int kOpenFlags = O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_NOFOLLOW;
+ static const int kOpenFlags = O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
unique_fd fd(open(file_path.c_str(), kOpenFlags, 0644));
if (fd < 0) {
PERROR << "open failed: " << file_path;
@@ -443,7 +443,7 @@
}
int ImageBuilder::OpenImageFile(const std::string& file) {
- android::base::unique_fd source_fd = GetControlFileOrOpen(file.c_str(), O_RDONLY | O_CLOEXEC);
+ unique_fd source_fd = GetControlFileOrOpen(file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY);
if (source_fd < 0) {
PERROR << "open image file failed: " << file;
return -1;
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index d274ba4..0a0a21d 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -208,21 +208,12 @@
defaults: ["libsnapshot_test_defaults"],
}
-cc_test {
- name: "vts_libsnapshot_test_presubmit",
- defaults: ["libsnapshot_test_defaults"],
- cppflags: [
- "-DSKIP_TEST_IN_PRESUBMIT",
- ],
-}
-
cc_binary {
name: "snapshotctl",
srcs: [
"snapshotctl.cpp",
],
static_libs: [
- "libdm",
"libfstab",
"libsnapshot",
],
@@ -238,12 +229,10 @@
"liblog",
"liblp",
"libprotobuf-cpp-lite",
+ "libstatslog",
"libutils",
// TODO(b/148818798): remove when parent bug is fixed.
"libutilscallstack",
],
- init_rc: [
- "snapshotctl.rc",
- ],
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/return.h b/fs_mgr/libsnapshot/include/libsnapshot/return.h
index 1f132fa..dedc445 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/return.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/return.h
@@ -30,7 +30,6 @@
enum class ErrorCode : int32_t {
SUCCESS = static_cast<int32_t>(FiemapStatus::ErrorCode::SUCCESS),
ERROR = static_cast<int32_t>(FiemapStatus::ErrorCode::ERROR),
- NEEDS_REBOOT = ERROR + 1,
NO_SPACE = static_cast<int32_t>(FiemapStatus::ErrorCode::NO_SPACE),
};
ErrorCode error_code() const { return error_code_; }
@@ -43,7 +42,6 @@
static Return Ok() { return Return(ErrorCode::SUCCESS); }
static Return Error() { return Return(ErrorCode::ERROR); }
static Return NoSpace(uint64_t size) { return Return(ErrorCode::NO_SPACE, size); }
- static Return NeedsReboot() { return Return(ErrorCode::NEEDS_REBOOT); }
// Does not set required_size_ properly even when status.error_code() == NO_SPACE.
explicit Return(const FiemapStatus& status)
: error_code_(FromFiemapStatusErrorCode(status.error_code())), required_size_(0) {}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index b440c71..81f616c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -125,6 +125,9 @@
// might be needed to perform first-stage mounts.
static bool IsSnapshotManagerNeeded();
+ // Helper function for second stage init to restorecon on the rollback indicator.
+ static std::string GetGlobalRollbackIndicatorPath();
+
// Begin an update. This must be called before creating any snapshots. It
// will fail if GetUpdateState() != None.
bool BeginUpdate();
@@ -140,7 +143,6 @@
// Before calling this function, all snapshots must be mapped.
bool FinishedSnapshotWrites();
- private:
// Initiate a merge on all snapshot devices. This should only be used after an
// update has been marked successful after booting.
bool InitiateMerge();
@@ -149,7 +151,11 @@
// /data is mounted.
//
// If a merge is in progress, this function will block until the merge is
- // completed. If a merge or update was cancelled, this will clean up any
+ // completed.
+ // - Callback is called periodically during the merge. If callback()
+ // returns false during the merge, ProcessUpdateState() will pause
+ // and returns Merging.
+ // If a merge or update was cancelled, this will clean up any
// update artifacts and return.
//
// Note that after calling this, GetUpdateState() may still return that a
@@ -169,9 +175,9 @@
//
// The optional callback allows the caller to periodically check the
// progress with GetUpdateState().
- UpdateState ProcessUpdateState(const std::function<void()>& callback = {});
+ UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
+ const std::function<bool()>& before_cancel = {});
- public:
// Initiate the merge if necessary, then wait for the merge to finish.
// See InitiateMerge() and ProcessUpdateState() for details.
// Returns:
@@ -179,16 +185,8 @@
// - Unverified if called on the source slot
// - MergeCompleted if merge is completed
// - other states indicating an error has occurred
- UpdateState InitiateMergeAndWait(SnapshotMergeReport* report = nullptr);
-
- // Wait for the merge if rebooted into the new slot. Does NOT initiate a
- // merge. If the merge has not been initiated (but should be), wait.
- // Returns:
- // - Return::Ok(): there is no merge or merge finishes
- // - Return::NeedsReboot(): merge finishes but need a reboot before
- // applying the next update.
- // - Return::Error(): other irrecoverable errors
- Return WaitForMerge();
+ UpdateState InitiateMergeAndWait(SnapshotMergeReport* report = nullptr,
+ const std::function<bool()>& before_cancel = {});
// Find the status of the current update, if any.
//
@@ -375,14 +373,23 @@
// Check for a cancelled or rolled back merge, returning true if such a
// condition was detected and handled.
- bool HandleCancelledUpdate(LockedFile* lock);
+ bool HandleCancelledUpdate(LockedFile* lock, const std::function<bool()>& before_cancel);
// Helper for HandleCancelledUpdate. Assumes booting from new slot.
bool AreAllSnapshotsCancelled(LockedFile* lock);
+ // Determine whether partition names in |snapshots| have been flashed and
+ // store result to |out|.
+ // Return true if values are successfully retrieved and false on error
+ // (e.g. super partition metadata cannot be read). When it returns true,
+ // |out| stores true for partitions that have been flashed and false for
+ // partitions that have not been flashed.
+ bool GetSnapshotFlashingStatus(LockedFile* lock, const std::vector<std::string>& snapshots,
+ std::map<std::string, bool>* out);
+
// Remove artifacts created by the update process, such as snapshots, and
// set the update state to None.
- bool RemoveAllUpdateState(LockedFile* lock);
+ bool RemoveAllUpdateState(LockedFile* lock, const std::function<bool()>& prolog = {});
// Interact with /metadata/ota.
std::unique_ptr<LockedFile> OpenLock(int lock_flags);
@@ -437,8 +444,8 @@
// UpdateState::MergeCompleted
// UpdateState::MergeFailed
// UpdateState::MergeNeedsReboot
- UpdateState CheckMergeState();
- UpdateState CheckMergeState(LockedFile* lock);
+ UpdateState CheckMergeState(const std::function<bool()>& before_cancel);
+ UpdateState CheckMergeState(LockedFile* lock, const std::function<bool()>& before_cancel);
UpdateState CheckTargetMergeState(LockedFile* lock, const std::string& name);
// Interact with status files under /metadata/ota/snapshots.
@@ -513,6 +520,11 @@
std::string ReadUpdateSourceSlotSuffix();
+ // Helper for RemoveAllSnapshots.
+ // Check whether |name| should be deleted as a snapshot name.
+ bool ShouldDeleteSnapshot(LockedFile* lock, const std::map<std::string, bool>& flashing_status,
+ Slot current_slot, const std::string& name);
+
std::string gsid_dir_;
std::string metadata_dir_;
std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
new file mode 100644
index 0000000..91dd34f
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
@@ -0,0 +1,59 @@
+// 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 <chrono>
+#include <memory>
+
+#include <android/snapshot/snapshot.pb.h>
+#include <libsnapshot/snapshot.h>
+
+namespace android {
+namespace snapshot {
+
+class SnapshotMergeStats {
+ public:
+ // Not thread safe.
+ static SnapshotMergeStats* GetInstance(SnapshotManager& manager);
+
+ // Called when merge starts or resumes.
+ bool Start();
+ void set_state(android::snapshot::UpdateState state);
+
+ // Called when merge ends. Properly clean up permanent storage.
+ class Result {
+ public:
+ virtual ~Result() {}
+ virtual const SnapshotMergeReport& report() const = 0;
+ // Time between successful Start() / Resume() to Finish().
+ virtual std::chrono::steady_clock::duration merge_time() const = 0;
+ };
+ std::unique_ptr<Result> Finish();
+
+ private:
+ bool ReadState();
+ bool WriteState();
+ bool DeleteState();
+ SnapshotMergeStats(const std::string& path);
+
+ std::string path_;
+ SnapshotMergeReport report_;
+ // Time of the last successful Start() / Resume() call.
+ std::chrono::time_point<std::chrono::steady_clock> start_time_;
+ bool running_{false};
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/return.cpp b/fs_mgr/libsnapshot/return.cpp
index 6559c12..cc64af5 100644
--- a/fs_mgr/libsnapshot/return.cpp
+++ b/fs_mgr/libsnapshot/return.cpp
@@ -24,8 +24,6 @@
switch (error_code()) {
case ErrorCode::ERROR:
return "Error";
- case ErrorCode::NEEDS_REBOOT:
- return "Retry after reboot";
case ErrorCode::SUCCESS:
[[fallthrough]];
case ErrorCode::NO_SPACE:
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 187f24c..0573c59 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -43,10 +43,10 @@
#endif
#include <android/snapshot/snapshot.pb.h>
+#include <libsnapshot/snapshot_stats.h>
#include "device_info.h"
#include "partition_cow_creator.h"
#include "snapshot_metadata_updater.h"
-#include "snapshot_stats.h"
#include "utility.h"
namespace android {
@@ -81,6 +81,7 @@
using namespace std::string_literals;
static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot";
+static constexpr char kRollbackIndicatorPath[] = "/metadata/ota/rollback-indicator";
static constexpr auto kUpdateStateCheckInterval = 2s;
// Note: IImageManager is an incomplete type in the header, so the default
@@ -219,7 +220,12 @@
return true;
}
-bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock) {
+bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock, const std::function<bool()>& prolog) {
+ if (prolog && !prolog()) {
+ LOG(WARNING) << "Can't RemoveAllUpdateState: prolog failed.";
+ return false;
+ }
+
LOG(INFO) << "Removing all update state.";
#ifdef LIBSNAPSHOT_USE_CALLSTACK
@@ -789,9 +795,10 @@
// Note that when a merge fails, we will *always* try again to complete the
// merge each time the device boots. There is no harm in doing so, and if
// the problem was transient, we might manage to get a new outcome.
-UpdateState SnapshotManager::ProcessUpdateState(const std::function<void()>& callback) {
+UpdateState SnapshotManager::ProcessUpdateState(const std::function<bool()>& callback,
+ const std::function<bool()>& before_cancel) {
while (true) {
- UpdateState state = CheckMergeState();
+ UpdateState state = CheckMergeState(before_cancel);
if (state == UpdateState::MergeFailed) {
AcknowledgeMergeFailure();
}
@@ -801,8 +808,8 @@
return state;
}
- if (callback) {
- callback();
+ if (callback && !callback()) {
+ return state;
}
// This wait is not super time sensitive, so we have a relatively
@@ -811,24 +818,27 @@
}
}
-UpdateState SnapshotManager::CheckMergeState() {
+UpdateState SnapshotManager::CheckMergeState(const std::function<bool()>& before_cancel) {
auto lock = LockExclusive();
if (!lock) {
return UpdateState::MergeFailed;
}
- UpdateState state = CheckMergeState(lock.get());
+ UpdateState state = CheckMergeState(lock.get(), before_cancel);
if (state == UpdateState::MergeCompleted) {
// Do this inside the same lock. Failures get acknowledged without the
// lock, because flock() might have failed.
AcknowledgeMergeSuccess(lock.get());
} else if (state == UpdateState::Cancelled) {
- RemoveAllUpdateState(lock.get());
+ if (!RemoveAllUpdateState(lock.get(), before_cancel)) {
+ return ReadSnapshotUpdateStatus(lock.get()).state();
+ }
}
return state;
}
-UpdateState SnapshotManager::CheckMergeState(LockedFile* lock) {
+UpdateState SnapshotManager::CheckMergeState(LockedFile* lock,
+ const std::function<bool()>& before_cancel) {
UpdateState state = ReadUpdateState(lock);
switch (state) {
case UpdateState::None:
@@ -849,7 +859,7 @@
// This is an edge case. Normally cancelled updates are detected
// via the merge poll below, but if we never started a merge, we
// need to also check here.
- if (HandleCancelledUpdate(lock)) {
+ if (HandleCancelledUpdate(lock, before_cancel)) {
return UpdateState::Cancelled;
}
return state;
@@ -1003,7 +1013,7 @@
}
std::string SnapshotManager::GetRollbackIndicatorPath() {
- return metadata_dir_ + "/rollback-indicator";
+ return metadata_dir_ + "/" + android::base::Basename(kRollbackIndicatorPath);
}
void SnapshotManager::AcknowledgeMergeSuccess(LockedFile* lock) {
@@ -1169,7 +1179,8 @@
return true;
}
-bool SnapshotManager::HandleCancelledUpdate(LockedFile* lock) {
+bool SnapshotManager::HandleCancelledUpdate(LockedFile* lock,
+ const std::function<bool()>& before_cancel) {
auto slot = GetCurrentSlot();
if (slot == Slot::Unknown) {
return false;
@@ -1177,15 +1188,30 @@
// If all snapshots were reflashed, then cancel the entire update.
if (AreAllSnapshotsCancelled(lock)) {
- RemoveAllUpdateState(lock);
- return true;
+ LOG(WARNING) << "Detected re-flashing, cancelling unverified update.";
+ return RemoveAllUpdateState(lock, before_cancel);
}
- // This unverified update might be rolled back, or it might not (b/147347110
- // comment #77). Take no action, as update_engine is responsible for deciding
- // whether to cancel.
- LOG(ERROR) << "Update state is being processed before reboot, taking no action.";
- return false;
+ // If update has been rolled back, then cancel the entire update.
+ // Client (update_engine) is responsible for doing additional cleanup work on its own states
+ // when ProcessUpdateState() returns UpdateState::Cancelled.
+ auto current_slot = GetCurrentSlot();
+ if (current_slot != Slot::Source) {
+ LOG(INFO) << "Update state is being processed while booting at " << current_slot
+ << " slot, taking no action.";
+ return false;
+ }
+
+ // current_slot == Source. Attempt to detect rollbacks.
+ if (access(GetRollbackIndicatorPath().c_str(), F_OK) != 0) {
+ // This unverified update is not attempted. Take no action.
+ PLOG(INFO) << "Rollback indicator not detected. "
+ << "Update state is being processed before reboot, taking no action.";
+ return false;
+ }
+
+ LOG(WARNING) << "Detected rollback, cancelling unverified update.";
+ return RemoveAllUpdateState(lock, before_cancel);
}
std::unique_ptr<LpMetadata> SnapshotManager::ReadCurrentMetadata() {
@@ -1219,6 +1245,28 @@
return true;
}
+ std::map<std::string, bool> flashing_status;
+
+ if (!GetSnapshotFlashingStatus(lock, snapshots, &flashing_status)) {
+ LOG(WARNING) << "Failed to determine whether partitions have been flashed. Not"
+ << "removing update states.";
+ return false;
+ }
+
+ bool all_snapshots_cancelled = std::all_of(flashing_status.begin(), flashing_status.end(),
+ [](const auto& pair) { return pair.second; });
+
+ if (all_snapshots_cancelled) {
+ LOG(WARNING) << "All partitions are re-flashed after update, removing all update states.";
+ }
+ return all_snapshots_cancelled;
+}
+
+bool SnapshotManager::GetSnapshotFlashingStatus(LockedFile* lock,
+ const std::vector<std::string>& snapshots,
+ std::map<std::string, bool>* out) {
+ CHECK(lock);
+
auto source_slot_suffix = ReadUpdateSourceSlotSuffix();
if (source_slot_suffix.empty()) {
return false;
@@ -1244,20 +1292,17 @@
return false;
}
- bool all_snapshots_cancelled = true;
for (const auto& snapshot_name : snapshots) {
if (GetMetadataPartitionState(*metadata, snapshot_name) ==
MetadataPartitionState::Updated) {
- all_snapshots_cancelled = false;
- continue;
+ out->emplace(snapshot_name, false);
+ } else {
+ // Delete snapshots for partitions that are re-flashed after the update.
+ LOG(WARNING) << "Detected re-flashing of partition " << snapshot_name << ".";
+ out->emplace(snapshot_name, true);
}
- // Delete snapshots for partitions that are re-flashed after the update.
- LOG(WARNING) << "Detected re-flashing of partition " << snapshot_name << ".";
}
- if (all_snapshots_cancelled) {
- LOG(WARNING) << "All partitions are re-flashed after update, removing all update states.";
- }
- return all_snapshots_cancelled;
+ return true;
}
bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) {
@@ -1267,10 +1312,38 @@
return false;
}
+ std::map<std::string, bool> flashing_status;
+ if (!GetSnapshotFlashingStatus(lock, snapshots, &flashing_status)) {
+ LOG(WARNING) << "Failed to get flashing status";
+ }
+
+ auto current_slot = GetCurrentSlot();
bool ok = true;
bool has_mapped_cow_images = false;
for (const auto& name : snapshots) {
- if (!UnmapPartitionWithSnapshot(lock, name) || !DeleteSnapshot(lock, name)) {
+ // If booting off source slot, it is okay to unmap and delete all the snapshots.
+ // If boot indicator is missing, update state is None or Initiated, so
+ // it is also okay to unmap and delete all the snapshots.
+ // If booting off target slot,
+ // - should not unmap because:
+ // - In Android mode, snapshots are not mapped, but
+ // filesystems are mounting off dm-linear targets directly.
+ // - In recovery mode, assume nothing is mapped, so it is optional to unmap.
+ // - If partition is flashed or unknown, it is okay to delete snapshots.
+ // Otherwise (UPDATED flag), only delete snapshots if they are not mapped
+ // as dm-snapshot (for example, after merge completes).
+ bool should_unmap = current_slot != Slot::Target;
+ bool should_delete = ShouldDeleteSnapshot(lock, flashing_status, current_slot, name);
+
+ bool partition_ok = true;
+ if (should_unmap && !UnmapPartitionWithSnapshot(lock, name)) {
+ partition_ok = false;
+ }
+ if (partition_ok && should_delete && !DeleteSnapshot(lock, name)) {
+ partition_ok = false;
+ }
+
+ if (!partition_ok) {
// Remember whether or not we were able to unmap the cow image.
auto cow_image_device = GetCowImageDeviceName(name);
has_mapped_cow_images |=
@@ -1293,6 +1366,34 @@
return ok;
}
+// See comments in RemoveAllSnapshots().
+bool SnapshotManager::ShouldDeleteSnapshot(LockedFile* lock,
+ const std::map<std::string, bool>& flashing_status,
+ Slot current_slot, const std::string& name) {
+ if (current_slot != Slot::Target) {
+ return true;
+ }
+ auto it = flashing_status.find(name);
+ if (it == flashing_status.end()) {
+ LOG(WARNING) << "Can't determine flashing status for " << name;
+ return true;
+ }
+ if (it->second) {
+ // partition flashed, okay to delete obsolete snapshots
+ return true;
+ }
+ // partition updated, only delete if not dm-snapshot
+ SnapshotStatus status;
+ if (!ReadSnapshotStatus(lock, name, &status)) {
+ LOG(WARNING) << "Unable to read snapshot status for " << name
+ << ", guessing snapshot device name";
+ auto extra_name = GetSnapshotExtraDeviceName(name);
+ return !IsSnapshotDevice(name) && !IsSnapshotDevice(extra_name);
+ }
+ auto dm_name = GetSnapshotDeviceName(name, status);
+ return !IsSnapshotDevice(dm_name);
+}
+
UpdateState SnapshotManager::GetUpdateState(double* progress) {
// If we've never started an update, the state file won't exist.
auto state_file = GetStateFilePath();
@@ -1369,6 +1470,10 @@
return access(kBootIndicatorPath, F_OK) == 0;
}
+std::string SnapshotManager::GetGlobalRollbackIndicatorPath() {
+ return kRollbackIndicatorPath;
+}
+
bool SnapshotManager::NeedSnapshotsInFirstStageMount() {
// If we fail to read, we'll wind up using CreateLogicalPartitions, which
// will create devices that look like the old slot, except with extra
@@ -1379,12 +1484,14 @@
auto slot = GetCurrentSlot();
if (slot != Slot::Target) {
- if (slot == Slot::Source && !device_->IsRecovery()) {
+ if (slot == Slot::Source) {
// Device is rebooting into the original slot, so mark this as a
// rollback.
auto path = GetRollbackIndicatorPath();
if (!android::base::WriteStringToFile("1", path)) {
PLOG(ERROR) << "Unable to write rollback indicator: " << path;
+ } else {
+ LOG(INFO) << "Rollback detected, writing rollback indicator to " << path;
}
}
LOG(INFO) << "Not booting from new slot. Will not mount snapshots.";
@@ -2391,7 +2498,8 @@
return AutoUnmountDevice::New(device_->GetMetadataDir());
}
-UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_report) {
+UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_report,
+ const std::function<bool()>& before_cancel) {
{
auto lock = LockExclusive();
// Sync update state from file with bootloader.
@@ -2401,23 +2509,24 @@
}
}
- SnapshotMergeStats merge_stats(*this);
+ auto merge_stats = SnapshotMergeStats::GetInstance(*this);
unsigned int last_progress = 0;
- auto callback = [&]() -> void {
+ auto callback = [&]() -> bool {
double progress;
GetUpdateState(&progress);
if (last_progress < static_cast<unsigned int>(progress)) {
last_progress = progress;
LOG(INFO) << "Waiting for merge to complete: " << last_progress << "%.";
}
+ return true; // continue
};
LOG(INFO) << "Waiting for any previous merge request to complete. "
<< "This can take up to several minutes.";
- merge_stats.Resume();
- auto state = ProcessUpdateState(callback);
- merge_stats.set_state(state);
+ merge_stats->Start();
+ auto state = ProcessUpdateState(callback, before_cancel);
+ merge_stats->set_state(state);
if (state == UpdateState::None) {
LOG(INFO) << "Can't find any snapshot to merge.";
return state;
@@ -2428,10 +2537,6 @@
return state;
}
- // This is the first snapshot merge that is requested after OTA. We can
- // initialize the merge duration statistics.
- merge_stats.Start();
-
if (!InitiateMerge()) {
LOG(ERROR) << "Failed to initiate merge.";
return state;
@@ -2439,43 +2544,22 @@
// All other states can be handled by ProcessUpdateState.
LOG(INFO) << "Waiting for merge to complete. This can take up to several minutes.";
last_progress = 0;
- state = ProcessUpdateState(callback);
- merge_stats.set_state(state);
+ state = ProcessUpdateState(callback, before_cancel);
+ merge_stats->set_state(state);
}
LOG(INFO) << "Merge finished with state \"" << state << "\".";
if (stats_report) {
- *stats_report = merge_stats.GetReport();
+ auto result = merge_stats->Finish();
+ if (result) {
+ *stats_report = result->report();
+ } else {
+ LOG(WARNING) << "SnapshotMergeStatus::Finish failed.";
+ }
}
return state;
}
-Return SnapshotManager::WaitForMerge() {
- LOG(INFO) << "Waiting for any previous merge request to complete. "
- << "This can take up to several minutes.";
- while (true) {
- auto state = ProcessUpdateState();
- if (state == UpdateState::Unverified && GetCurrentSlot() == Slot::Target) {
- LOG(INFO) << "Wait for merge to be initiated.";
- std::this_thread::sleep_for(kUpdateStateCheckInterval);
- continue;
- }
- LOG(INFO) << "Wait for merge exits with state " << state;
- switch (state) {
- case UpdateState::None:
- [[fallthrough]];
- case UpdateState::MergeCompleted:
- [[fallthrough]];
- case UpdateState::Cancelled:
- return Return::Ok();
- case UpdateState::MergeNeedsReboot:
- return Return::NeedsReboot();
- default:
- return Return::Error();
- }
- }
-}
-
bool SnapshotManager::HandleImminentDataWipe(const std::function<void()>& callback) {
if (!device_->IsRecovery()) {
LOG(ERROR) << "Data wipes are only allowed in recovery.";
@@ -2506,7 +2590,10 @@
return false;
}
- UpdateState state = ProcessUpdateState(callback);
+ UpdateState state = ProcessUpdateState([&]() -> bool {
+ callback();
+ return true;
+ });
LOG(INFO) << "Update state in recovery: " << state;
switch (state) {
case UpdateState::MergeFailed:
diff --git a/fs_mgr/libsnapshot/snapshot_stats.cpp b/fs_mgr/libsnapshot/snapshot_stats.cpp
index 635b47d..5da7b98 100644
--- a/fs_mgr/libsnapshot/snapshot_stats.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stats.cpp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "snapshot_stats.h"
+#include <libsnapshot/snapshot_stats.h>
#include <sstream>
@@ -23,22 +23,17 @@
namespace android {
namespace snapshot {
-SnapshotMergeStats::SnapshotMergeStats(SnapshotManager& parent) : parent_(parent) {
- init_time_ = std::chrono::steady_clock::now();
+SnapshotMergeStats* SnapshotMergeStats::GetInstance(SnapshotManager& parent) {
+ static SnapshotMergeStats g_instance(parent.GetMergeStateFilePath());
+ CHECK(g_instance.path_ == parent.GetMergeStateFilePath());
+ return &g_instance;
}
-SnapshotMergeStats::~SnapshotMergeStats() {
- std::string error;
- auto file_path = parent_.GetMergeStateFilePath();
- if (!android::base::RemoveFileIfExists(file_path, &error)) {
- LOG(ERROR) << "Failed to remove merge statistics file " << file_path << ": " << error;
- return;
- }
-}
+SnapshotMergeStats::SnapshotMergeStats(const std::string& path) : path_(path), running_(false) {}
bool SnapshotMergeStats::ReadState() {
std::string contents;
- if (!android::base::ReadFileToString(parent_.GetMergeStateFilePath(), &contents)) {
+ if (!android::base::ReadFileToString(path_, &contents)) {
PLOG(INFO) << "Read merge statistics file failed";
return false;
}
@@ -55,34 +50,73 @@
LOG(ERROR) << "Unable to serialize SnapshotMergeStats.";
return false;
}
- auto file_path = parent_.GetMergeStateFilePath();
- if (!WriteStringToFileAtomic(contents, file_path)) {
+ if (!WriteStringToFileAtomic(contents, path_)) {
PLOG(ERROR) << "Could not write to merge statistics file";
return false;
}
return true;
}
-void SnapshotMergeStats::Start() {
- report_.set_resume_count(0);
- report_.set_state(UpdateState::None);
- WriteState();
+bool SnapshotMergeStats::DeleteState() {
+ std::string error;
+ if (!android::base::RemoveFileIfExists(path_, &error)) {
+ LOG(ERROR) << "Failed to remove merge statistics file " << path_ << ": " << error;
+ return false;
+ }
+ return true;
}
-void SnapshotMergeStats::Resume() {
- if (!ReadState()) {
- return;
+bool SnapshotMergeStats::Start() {
+ if (running_) {
+ LOG(ERROR) << "SnapshotMergeStats running_ == " << running_;
+ return false;
}
- report_.set_resume_count(report_.resume_count() + 1);
- WriteState();
+ running_ = true;
+
+ start_time_ = std::chrono::steady_clock::now();
+ if (ReadState()) {
+ report_.set_resume_count(report_.resume_count() + 1);
+ } else {
+ report_.set_resume_count(0);
+ report_.set_state(UpdateState::None);
+ }
+
+ return WriteState();
}
void SnapshotMergeStats::set_state(android::snapshot::UpdateState state) {
report_.set_state(state);
}
-SnapshotMergeReport SnapshotMergeStats::GetReport() {
- return report_;
+class SnapshotMergeStatsResultImpl : public SnapshotMergeStats::Result {
+ public:
+ SnapshotMergeStatsResultImpl(const SnapshotMergeReport& report,
+ std::chrono::steady_clock::duration merge_time)
+ : report_(report), merge_time_(merge_time) {}
+ const SnapshotMergeReport& report() const override { return report_; }
+ std::chrono::steady_clock::duration merge_time() const override { return merge_time_; }
+
+ private:
+ SnapshotMergeReport report_;
+ std::chrono::steady_clock::duration merge_time_;
+};
+
+std::unique_ptr<SnapshotMergeStats::Result> SnapshotMergeStats::Finish() {
+ if (!running_) {
+ LOG(ERROR) << "SnapshotMergeStats running_ == " << running_;
+ return nullptr;
+ }
+ running_ = false;
+
+ auto result = std::make_unique<SnapshotMergeStatsResultImpl>(
+ report_, std::chrono::steady_clock::now() - start_time_);
+
+ // We still want to report result if state is not deleted. Just leave
+ // it there and move on. A side effect is that it may be reported over and
+ // over again in the future, but there is nothing we can do.
+ (void)DeleteState();
+
+ return result;
}
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/snapshot_stats.h
deleted file mode 100644
index 60109a4..0000000
--- a/fs_mgr/libsnapshot/snapshot_stats.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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 <chrono>
-
-#include <android/snapshot/snapshot.pb.h>
-#include <libsnapshot/snapshot.h>
-
-namespace android {
-namespace snapshot {
-
-class SnapshotMergeStats {
- public:
- SnapshotMergeStats(SnapshotManager& parent);
- ~SnapshotMergeStats();
- void Start();
- void Resume();
- void set_state(android::snapshot::UpdateState state);
- SnapshotMergeReport GetReport();
-
- private:
- bool ReadState();
- bool WriteState();
-
- const SnapshotManager& parent_;
- SnapshotMergeReport report_;
- std::chrono::time_point<std::chrono::steady_clock> init_time_;
- std::chrono::time_point<std::chrono::steady_clock> end_time_;
-};
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 5d2840f..7d16ec2 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -506,9 +506,6 @@
}
TEST_F(SnapshotTest, FirstStageMountAndMerge) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
ASSERT_TRUE(AcquireLock());
static const uint64_t kDeviceSize = 1024 * 1024;
@@ -565,9 +562,6 @@
}
TEST_F(SnapshotTest, FlashSuperDuringMerge) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
ASSERT_TRUE(AcquireLock());
static const uint64_t kDeviceSize = 1024 * 1024;
@@ -979,9 +973,6 @@
// Also test UnmapUpdateSnapshot unmaps everything.
// Also test first stage mount and merge after this.
TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
// OTA client blindly unmaps all partitions that are possibly mapped.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
@@ -1129,9 +1120,6 @@
// Test that the old partitions are not modified.
TEST_F(SnapshotUpdateTest, TestRollback) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
// Execute the update.
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->UnmapUpdateSnapshot("sys_b"));
@@ -1309,9 +1297,6 @@
}
TEST_F(SnapshotUpdateTest, MergeCannotRemoveCow) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
// Make source partitions as big as possible to force COW image to be created.
SetSize(sys_, 5_MiB);
SetSize(vnd_, 5_MiB);
@@ -1585,48 +1570,6 @@
<< "FinishedSnapshotWrites should detect overflow of CoW device.";
}
-TEST_F(SnapshotUpdateTest, WaitForMerge) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
- GTEST_SKIP() << "WIP failure b/148889015";
-#endif
- AddOperationForPartitions();
-
- // Execute the update.
- ASSERT_TRUE(sm->BeginUpdate());
- ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
-
- // Write some data to target partitions.
- for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name));
- }
-
- ASSERT_TRUE(sm->FinishedSnapshotWrites());
-
- // Simulate shutting down the device.
- ASSERT_TRUE(UnmapAll());
-
- // After reboot, init does first stage mount.
- {
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
- ASSERT_NE(nullptr, init);
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
- }
-
- auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
- ASSERT_NE(nullptr, new_sm);
-
- auto waiter = std::async(std::launch::async, [&new_sm] { return new_sm->WaitForMerge(); });
- ASSERT_EQ(std::future_status::timeout, waiter.wait_for(1s))
- << "WaitForMerge should block when not initiated";
-
- auto merger =
- std::async(std::launch::async, [&new_sm] { return new_sm->InitiateMergeAndWait(); });
- // Small images, so should be merged pretty quickly.
- ASSERT_EQ(std::future_status::ready, waiter.wait_for(3s)) << "WaitForMerge did not finish";
- ASSERT_TRUE(waiter.get());
- ASSERT_THAT(merger.get(), AnyOf(UpdateState::None, UpdateState::MergeCompleted));
-}
-
TEST_F(SnapshotUpdateTest, LowSpace) {
static constexpr auto kMaxFree = 10_MiB;
auto userdata = std::make_unique<LowSpaceUserdata>();
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index e35ad4b..aa5e9c1 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -24,8 +24,10 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include <android/snapshot/snapshot.pb.h>
#include <libsnapshot/snapshot.h>
-#include "utility.h"
+#include <libsnapshot/snapshot_stats.h>
+#include <statslog.h>
#include "utility.h"
@@ -37,17 +39,29 @@
"Actions:\n"
" dump\n"
" Print snapshot states.\n"
- " merge [--logcat] [--log-to-file]\n"
+ " merge [--logcat] [--log-to-file] [--report] [--dry-run]\n"
" Initialize merge and wait for it to be completed.\n"
" If --logcat is specified, log to logcat.\n"
" If --log-to-file is specified, log to /data/misc/snapshotctl_log/.\n"
- " If both specified, log to both. If none specified, log to stdout.\n";
+ " If both specified, log to both. If none specified, log to stdout.\n"
+ " If --report is specified, send merge statistics to statsd.\n"
+ " If --dry-run flag, no real merge operation is is triggered, and\n"
+ " sample statistics are sent to statsd for testing purpose.\n";
return EX_USAGE;
}
namespace android {
namespace snapshot {
+static SnapshotMergeReport GetDummySnapshotMergeReport() {
+ SnapshotMergeReport fake_report;
+
+ fake_report.set_state(UpdateState::MergeCompleted);
+ fake_report.set_resume_count(56);
+
+ return fake_report;
+}
+
bool DumpCmdHandler(int /*argc*/, char** argv) {
android::base::InitLogging(argv, &android::base::StderrLogger);
return SnapshotManager::New()->Dump(std::cout);
@@ -113,28 +127,58 @@
};
bool MergeCmdHandler(int argc, char** argv) {
- auto begin = std::chrono::steady_clock::now();
+ std::chrono::milliseconds passed_ms;
+
+ bool report_to_statsd = false;
+ bool dry_run = false;
+ for (int i = 2; i < argc; ++i) {
+ if (argv[i] == "--report"s) {
+ report_to_statsd = true;
+ } else if (argv[i] == "--dry-run"s) {
+ dry_run = true;
+ }
+ }
// 'snapshotctl merge' is stripped away from arguments to
// Logger.
android::base::InitLogging(argv);
android::base::SetLogger(MergeCmdLogger(argc - 2, argv + 2));
- auto state = SnapshotManager::New()->InitiateMergeAndWait();
+ UpdateState state;
+ SnapshotMergeReport merge_report;
+ if (dry_run) {
+ merge_report = GetDummySnapshotMergeReport();
+ state = merge_report.state();
+ passed_ms = std::chrono::milliseconds(1234);
+ } else {
+ auto begin = std::chrono::steady_clock::now();
- // We could wind up in the Unverified state if the device rolled back or
- // hasn't fully rebooted. Ignore this.
- if (state == UpdateState::None || state == UpdateState::Unverified) {
- return true;
- }
- if (state == UpdateState::MergeCompleted) {
+ state = SnapshotManager::New()->InitiateMergeAndWait(&merge_report);
+
+ // We could wind up in the Unverified state if the device rolled back or
+ // hasn't fully rebooted. Ignore this.
+ if (state == UpdateState::None || state == UpdateState::Unverified) {
+ return true;
+ }
+
auto end = std::chrono::steady_clock::now();
- auto passed = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
- LOG(INFO) << "Snapshot merged in " << passed << " ms.";
+ passed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
+ }
+
+ if (report_to_statsd) {
+ android::util::stats_write(android::util::SNAPSHOT_MERGE_REPORTED,
+ static_cast<int32_t>(merge_report.state()),
+ static_cast<int64_t>(passed_ms.count()),
+ static_cast<int32_t>(merge_report.resume_count()));
+ }
+
+ if (state == UpdateState::MergeCompleted) {
+ LOG(INFO) << "Snapshot merged in " << passed_ms.count() << " ms.";
return true;
}
LOG(ERROR) << "Snapshot failed to merge with state \"" << state << "\".";
+
return false;
}
diff --git a/fs_mgr/libsnapshot/snapshotctl.rc b/fs_mgr/libsnapshot/snapshotctl.rc
deleted file mode 100644
index 5dbe352..0000000
--- a/fs_mgr/libsnapshot/snapshotctl.rc
+++ /dev/null
@@ -1,2 +0,0 @@
-on property:sys.boot_completed=1
- exec_background - root root -- /system/bin/snapshotctl merge --logcat --log-to-file
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 69b3150..3fec608 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -27,6 +27,7 @@
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
+#include <fs_mgr.h>
#include <fstab/fstab.h>
#include <gtest/gtest.h>
@@ -1015,6 +1016,10 @@
}
Fstab fstab;
ASSERT_TRUE(ReadDefaultFstab(&fstab)) << "Failed to read default fstab";
- ASSERT_NE(nullptr, GetMountedEntryForUserdata(&fstab))
+ Fstab proc_mounts;
+ ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &proc_mounts)) << "Failed to read /proc/mounts";
+ auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
+ ASSERT_NE(mounted_entry, nullptr) << "/data is not mounted";
+ ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, *mounted_entry))
<< "/data wasn't mounted from default fstab";
}
diff --git a/init/init.cpp b/init/init.cpp
index b0f929c..63aefc1 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -120,7 +120,7 @@
}
};
- if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result) {
+ if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result.ok()) {
LOG(FATAL) << result.error();
}
}
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index aa36849..2175075 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -323,10 +323,20 @@
}
if (bootstrap_ns_id != GetMountNamespaceId() && bootstrap_ns_fd.get() != -1 &&
IsApexUpdatable()) {
+ // The property service thread and its descendent threads must be in the correct mount
+ // namespace to call Service::Start(), however setns() only operates on a single thread and
+ // fails when secondary threads attempt to join the same mount namespace. Therefore, we
+ // must join the property service thread and its descendents before the setns() call. Those
+ // threads are then started again after the setns() call, and they'll be in the proper
+ // namespace.
+ PausePropertyService();
+
if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
PLOG(ERROR) << "Failed to switch to bootstrap mount namespace.";
return false;
}
+
+ ResumePropertyService();
}
return true;
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index f7cc36e..cad192d 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -96,8 +96,10 @@
return ret;
}
-static void PersistRebootReason(const char* reason) {
- SetProperty(LAST_REBOOT_REASON_PROPERTY, reason);
+static void PersistRebootReason(const char* reason, bool write_to_property) {
+ if (write_to_property) {
+ SetProperty(LAST_REBOOT_REASON_PROPERTY, reason);
+ }
WriteStringToFile(reason, LAST_REBOOT_REASON_FILE);
}
@@ -535,14 +537,6 @@
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", reboot_target: " << reboot_target;
- // If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
- // worry about unmounting it.
- if (!IsDataMounted()) {
- sync();
- RebootSystem(cmd, reboot_target);
- abort();
- }
-
// Ensure last reboot reason is reduced to canonical
// alias reported in bootloader or system boot reason.
size_t skip = 0;
@@ -552,9 +546,17 @@
reasons[1] == "hard" || reasons[1] == "warm")) {
skip = strlen("reboot,");
}
- PersistRebootReason(reason.c_str() + skip);
+ PersistRebootReason(reason.c_str() + skip, true);
sync();
+ // If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
+ // worry about unmounting it.
+ if (!IsDataMounted()) {
+ sync();
+ RebootSystem(cmd, reboot_target);
+ abort();
+ }
+
bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
auto shutdown_timeout = 0ms;
@@ -818,6 +820,7 @@
LOG(INFO) << "Re-enabling service '" << s->name() << "'";
s->Enable();
}
+ ServiceList::GetInstance().ResetState();
LeaveShutdown();
ActionManager::GetInstance().QueueEventTrigger("userspace-reboot-resume");
guard.Disable(); // Go on with userspace reboot.
@@ -836,7 +839,8 @@
if (!WaitForProperty("sys.boot_completed", "1", timeout)) {
LOG(ERROR) << "Failed to boot in " << timeout.count() << "ms. Switching to full reboot";
// In this case device is in a boot loop. Only way to recover is to do dirty reboot.
- PersistRebootReason("userspace_failed,watchdog_triggered");
+ // Since init might be wedged, don't try to write reboot reason into a persistent property.
+ PersistRebootReason("userspace_failed,watchdog_triggered", false);
RebootSystem(ANDROID_RB_RESTART2, "userspace_failed,watchdog_triggered");
}
LOG(INFO) << "Device booted, stopping userspace reboot watchdog";
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 2faa167..acbcbd6 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -66,6 +66,7 @@
#include <android-base/unique_fd.h>
#include <fs_avb/fs_avb.h>
#include <libgsi/libgsi.h>
+#include <libsnapshot/snapshot.h>
#include <selinux/android.h>
#include "debug_ramdisk.h"
@@ -78,6 +79,7 @@
using android::base::Timer;
using android::base::unique_fd;
using android::fs_mgr::AvbHandle;
+using android::snapshot::SnapshotManager;
namespace android {
namespace init {
@@ -538,6 +540,8 @@
// adb remount, snapshot-based updates, and DSUs all create files during
// first-stage init.
selinux_android_restorecon("/metadata", SELINUX_ANDROID_RESTORECON_RECURSE);
+
+ selinux_android_restorecon(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0);
}
int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/init/service_list.h b/init/service_list.h
index 8cbc878..280a228 100644
--- a/init/service_list.h
+++ b/init/service_list.h
@@ -81,6 +81,11 @@
bool IsServicesUpdated() const { return services_update_finished_; }
void DelayService(const Service& service) REQUIRES(service_lock);
+ void ResetState() {
+ post_data_ = false;
+ services_update_finished_ = false;
+ }
+
private:
std::vector<std::unique_ptr<Service>> services_;
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 565f2c3..57531c8 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -44,12 +44,20 @@
recovery_available: true,
native_bridge_supported: true,
export_include_dirs: ["include"],
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
}
cc_library {
name: "libbacktrace",
vendor_available: false,
recovery_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
vndk: {
enabled: true,
support_system_process: true,
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index e47560f..d7175e0 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -38,4 +38,8 @@
enabled: true,
},
},
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.adbd",
+ ],
}
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 8e90ddf..3b2f30c 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -29,6 +29,10 @@
vendor_available: true,
recovery_available: true,
host_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
native_bridge_supported: true,
export_include_dirs: ["include"],
target: {
@@ -137,6 +141,10 @@
},
recovery_available: true,
host_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
native_bridge_supported: true,
srcs: [
"config_utils.cpp",
diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h
index e12c32c..c74ee3e 100644
--- a/libcutils/include/cutils/trace.h
+++ b/libcutils/include/cutils/trace.h
@@ -88,12 +88,6 @@
#error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h
#endif
-// Set this to 0 to revert to the old Binder-based atrace implementation.
-// This is only here in case rollbacks do not apply cleanly.
-// TODO(fmayer): Remove this once we are confident this won't need to be
-// rolled back, no later than 2020-03-01.
-#define ATRACE_SHMEM 1
-
/**
* Opens the trace file for writing and reads the property for initial tags.
* The atrace.tags.enableflags property sets the tags to trace.
@@ -121,15 +115,11 @@
* prevent tracing within the Zygote process.
*/
void atrace_set_tracing_enabled(bool enabled);
+
/**
- * If !ATRACE_SHMEM:
- * Flag indicating whether setup has been completed, initialized to 0.
- * Nonzero indicates setup has completed.
- * Note: This does NOT indicate whether or not setup was successful.
- * If ATRACE_SHMEM:
- * This is always set to false. This forces code that uses an old version
- * of this header to always call into atrace_setup, in which we call
- * atrace_init unconditionally.
+ * This is always set to false. This forces code that uses an old version
+ * of this header to always call into atrace_setup, in which we call
+ * atrace_init unconditionally.
*/
extern atomic_bool atrace_is_ready;
@@ -154,28 +144,8 @@
#define ATRACE_INIT() atrace_init()
#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags()
-#if ATRACE_SHMEM
void atrace_init();
uint64_t atrace_get_enabled_tags();
-#else
-static inline void atrace_init()
-{
- if (CC_UNLIKELY(!atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
- atrace_setup();
- }
-}
-
-/**
- * Get the mask of all tags currently enabled.
- * It can be used as a guard condition around more expensive trace calculations.
- * Every trace function calls this, which ensures atrace_init is run.
- */
-static inline uint64_t atrace_get_enabled_tags()
-{
- atrace_init();
- return atrace_enabled_tags;
-}
-#endif
/**
* Test if a given tag is currently enabled.
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index 9ca1729..5a09a2d 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -41,9 +41,6 @@
} else {
atrace_enabled_tags = atrace_get_property();
}
-#if !ATRACE_SHMEM
- atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
-#endif
}
static void atrace_seq_number_changed(uint32_t prev_seq_no, uint32_t seq_no) {
@@ -69,11 +66,7 @@
void atrace_setup()
{
-#if ATRACE_SHMEM
atrace_init();
-#else
- pthread_once(&atrace_once_control, atrace_init_once);
-#endif
}
void atrace_begin_body(const char* name)
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index a57a4c5..3ec98b3 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -71,8 +71,6 @@
static const prop_info* atrace_property_info = reinterpret_cast<const prop_info*>(empty_pi);
#endif
-#if ATRACE_SHMEM
-
/**
* This is called when the sequence number of debug.atrace.tags.enableflags
* changes and we need to reload the enabled tags.
@@ -96,7 +94,6 @@
atrace_init();
return atrace_enabled_tags;
}
-#endif
// Set whether this process is debuggable, which determines whether
// application-level tracing is allowed when the ro.debuggable system property
@@ -186,19 +183,17 @@
void atrace_update_tags()
{
uint64_t tags;
- if (ATRACE_SHMEM || CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
- if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
- tags = atrace_get_property();
- pthread_mutex_lock(&atrace_tags_mutex);
- atrace_enabled_tags = tags;
- pthread_mutex_unlock(&atrace_tags_mutex);
- } else {
- // Tracing is disabled for this process, so we simply don't
- // initialize the tags.
- pthread_mutex_lock(&atrace_tags_mutex);
- atrace_enabled_tags = ATRACE_TAG_NOT_READY;
- pthread_mutex_unlock(&atrace_tags_mutex);
- }
+ if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
+ tags = atrace_get_property();
+ pthread_mutex_lock(&atrace_tags_mutex);
+ atrace_enabled_tags = tags;
+ pthread_mutex_unlock(&atrace_tags_mutex);
+ } else {
+ // Tracing is disabled for this process, so we simply don't
+ // initialize the tags.
+ pthread_mutex_lock(&atrace_tags_mutex);
+ atrace_enabled_tags = ATRACE_TAG_NOT_READY;
+ pthread_mutex_unlock(&atrace_tags_mutex);
}
}
diff --git a/libcutils/trace-host.cpp b/libcutils/trace-host.cpp
index c21d0ee..9781ad3 100644
--- a/libcutils/trace-host.cpp
+++ b/libcutils/trace-host.cpp
@@ -30,10 +30,8 @@
void atrace_async_end_body(const char* /*name*/, int32_t /*cookie*/) {}
void atrace_int_body(const char* /*name*/, int32_t /*value*/) {}
void atrace_int64_body(const char* /*name*/, int64_t /*value*/) {}
-#if ATRACE_SHMEM
void atrace_init() {}
uint64_t atrace_get_enabled_tags()
{
return ATRACE_TAG_NOT_READY;
}
-#endif
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 7f183c2..50faa2a 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -38,6 +38,10 @@
vendor_available: true,
ramdisk_available: true,
recovery_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
native_bridge_supported: true,
export_include_dirs: ["include"],
system_shared_libs: [],
@@ -101,11 +105,6 @@
versions: ["29", "30"],
},
- // TODO(tomcherry): Renable this before release branch is cut
- header_abi_checker: {
- enabled: false,
- },
-
cflags: [
"-Wall",
"-Werror",
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index c98455d..b9839d6 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -156,7 +156,7 @@
* Let the logging function choose the best log target.
* This is not part of the enum since adding either -1 or 0xFFFFFFFF forces the enum to be signed or
* unsigned, which breaks unfortunately common arithmetic against LOG_ID_MIN and LOG_ID_MAX. */
-#define LOG_ID_DEFAULT -1
+#define LOG_ID_DEFAULT (-1)
/**
* Writes the constant string `text` to the log buffer `id`,
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 1b6b0c6..0dbb94f 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -27,6 +27,7 @@
#include <android/set_abort_message.h>
#endif
+#include <atomic>
#include <shared_mutex>
#include <android-base/errno_restorer.h>
@@ -148,11 +149,9 @@
GetDefaultTag().assign(tag, 0, LOGGER_ENTRY_MAX_PAYLOAD);
}
-static int minimum_log_priority = ANDROID_LOG_DEFAULT;
+static std::atomic_int minimum_log_priority = ANDROID_LOG_DEFAULT;
int __android_log_set_minimum_priority(int priority) {
- int old_minimum_log_priority = minimum_log_priority;
- minimum_log_priority = priority;
- return old_minimum_log_priority;
+ return minimum_log_priority.exchange(priority, std::memory_order_relaxed);
}
int __android_log_get_minimum_priority() {
diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp
index e05a690..12474f1 100644
--- a/libprocessgroup/profiles/Android.bp
+++ b/libprocessgroup/profiles/Android.bp
@@ -106,3 +106,7 @@
},
},
}
+
+vts_config {
+ name: "VtsProcessgroupValidateTest",
+}
diff --git a/libprocessgroup/profiles/Android.mk b/libprocessgroup/profiles/Android.mk
deleted file mode 100644
index eab96d4..0000000
--- a/libprocessgroup/profiles/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := VtsProcessgroupValidateTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/libsync/OWNERS b/libsync/OWNERS
index dc61733..e75b15b 100644
--- a/libsync/OWNERS
+++ b/libsync/OWNERS
@@ -1,3 +1,3 @@
-ghackmann@google.com
+chrisforbes@google.com
+hridya@google.com
jessehall@google.com
-marissaw@google.com
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
index b265b61..ff886fd 100644
--- a/libsystem/Android.bp
+++ b/libsystem/Android.bp
@@ -4,6 +4,10 @@
recovery_available: true,
host_supported: true,
native_bridge_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
export_include_dirs: ["include"],
target: {
diff --git a/libsystem/OWNERS b/libsystem/OWNERS
index fdea804..4f800d4 100644
--- a/libsystem/OWNERS
+++ b/libsystem/OWNERS
@@ -1,7 +1,6 @@
# graphics/composer
adyabr@google.com
lpy@google.com
-marissaw@google.com
stoza@google.com
vhau@google.com
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 3695f72..36449eb 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -116,12 +116,6 @@
x86_64: {
srcs: ["AsmGetRegsX86_64.S"],
},
- mips: {
- srcs: ["AsmGetRegsMips.S"],
- },
- mips64: {
- srcs: ["AsmGetRegsMips64.S"],
- },
},
static_libs: [
diff --git a/libunwindstack/AsmGetRegsMips.S b/libunwindstack/AsmGetRegsMips.S
deleted file mode 100644
index 183d0a9..0000000
--- a/libunwindstack/AsmGetRegsMips.S
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
- .text
- .type AsmGetRegs, %function
- .globl AsmGetRegs
- .ent AsmGetRegs
- .balign 16
-AsmGetRegs:
- .cfi_startproc
- .cfi_def_cfa $sp, 0
- .set push
- .set noreorder
- .cpload $t9
- sw $zero, 0($a0)
- .set noat
- sw $at, 4($a0)
- .set at
- sw $v0, 8($a0)
- sw $v1, 12($a0)
- sw $a0, 16($a0)
- sw $a1, 20($a0)
- sw $a2, 24($a0)
- sw $a3, 28($a0)
- sw $t0, 32($a0)
- sw $t1, 36($a0)
- sw $t2, 40($a0)
- sw $t3, 44($a0)
- sw $t4, 48($a0)
- sw $t5, 52($a0)
- sw $t6, 56($a0)
- sw $t7, 60($a0)
- sw $s0, 64($a0)
- sw $s1, 68($a0)
- sw $s2, 72($a0)
- sw $s3, 76($a0)
- sw $s4, 80($a0)
- sw $s5, 84($a0)
- sw $s6, 88($a0)
- sw $s7, 92($a0)
- sw $t8, 96($a0)
- sw $t9, 100($a0)
- sw $k0, 104($a0)
- sw $k1, 108($a0)
- sw $gp, 112($a0)
- sw $sp, 116($a0)
- sw $s8, 120($a0)
- sw $ra, 124($a0)
- jalr $zero, $ra
- sw $ra, 128($a0) // set PC to the calling function
-
- .set pop
- .cfi_endproc
- .size AsmGetRegs, .-AsmGetRegs
- .end AsmGetRegs
diff --git a/libunwindstack/AsmGetRegsMips64.S b/libunwindstack/AsmGetRegsMips64.S
deleted file mode 100644
index 7a244f6..0000000
--- a/libunwindstack/AsmGetRegsMips64.S
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
- .text
- .type AsmGetRegs, %function
- .globl AsmGetRegs
- .ent AsmGetRegs
- .balign 16
-AsmGetRegs:
- .cfi_startproc
- .cfi_def_cfa $sp, 0
- .set push
- .set noreorder
- .cpload $t9
- sd $zero, 0($a0)
- .set noat
- sd $at, 8($a0)
- .set at
- sd $v0, 16($a0)
- sd $v1, 24($a0)
- sd $a0, 32($a0)
- sd $a1, 40($a0)
- sd $a2, 48($a0)
- sd $a3, 56($a0)
- sd $a4, 64($a0)
- sd $a5, 72($a0)
- sd $a6, 80($a0)
- sd $a7, 88($a0)
- sd $t0, 96($a0)
- sd $t1, 104($a0)
- sd $t2, 112($a0)
- sd $t3, 120($a0)
- sd $s0, 128($a0)
- sd $s1, 136($a0)
- sd $s2, 144($a0)
- sd $s3, 152($a0)
- sd $s4, 160($a0)
- sd $s5, 168($a0)
- sd $s6, 176($a0)
- sd $s7, 184($a0)
- sd $t8, 192($a0)
- sd $t9, 200($a0)
- sd $k0, 208($a0)
- sd $k1, 216($a0)
- sd $gp, 224($a0)
- sd $sp, 232($a0)
- sd $s8, 240($a0)
- sd $ra, 248($a0)
- jalr $zero, $ra
- sd $ra, 256($a0) // set PC to the calling function
-
- .set pop
- .cfi_endproc
- .size AsmGetRegs, .-AsmGetRegs
- .end AsmGetRegs
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index c7dec52..e0a785b 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -100,10 +100,6 @@
return ARCH_X86;
#elif defined(__x86_64__)
return ARCH_X86_64;
-#elif defined(__mips__) && !defined(__LP64__)
- return ARCH_MIPS;
-#elif defined(__mips__) && defined(__LP64__)
- return ARCH_MIPS64;
#else
abort();
#endif
@@ -119,10 +115,6 @@
regs = new RegsX86();
#elif defined(__x86_64__)
regs = new RegsX86_64();
-#elif defined(__mips__) && !defined(__LP64__)
- regs = new RegsMips();
-#elif defined(__mips__) && defined(__LP64__)
- regs = new RegsMips64();
#else
abort();
#endif
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index f0b5e3a..300a3ec 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -81,7 +81,7 @@
: "x12", "x13", "memory");
}
-#elif defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+#elif defined(__i386__) || defined(__x86_64__)
extern "C" void AsmGetRegs(void* regs);
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 9ddbedf..3ab619b 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -18,6 +18,10 @@
recovery_available: true,
host_supported: true,
native_bridge_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
header_libs: [
"liblog_headers",
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 013705b..1a4b47e 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -187,7 +187,7 @@
ANDROID_TRIVIAL_MOVE_TRAIT(String16)
static inline std::ostream& operator<<(std::ostream& os, const String16& str) {
- os << String8(str).c_str();
+ os << String8(str);
return os;
}
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index d0ad314..0bcb716 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -17,7 +17,8 @@
#ifndef ANDROID_STRING8_H
#define ANDROID_STRING8_H
-#include <string> // for std::string
+#include <iostream>
+#include <string>
#include <utils/Errors.h>
#include <utils/Unicode.h>
@@ -232,6 +233,11 @@
// require any change to the underlying SharedBuffer contents or reference count.
ANDROID_TRIVIAL_MOVE_TRAIT(String8)
+static inline std::ostream& operator<<(std::ostream& os, const String8& str) {
+ os << str.c_str();
+ return os;
+}
+
// ---------------------------------------------------------------------------
// No user servicable parts below.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 91dd7a5..fdc9d32 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -701,9 +701,7 @@
# A tmpfs directory, which will contain all apps CE DE data directory that
# bind mount from the original source.
- chown root root /data_mirror
- chmod 0700 /data_mirror
- mount tmpfs tmpfs /data_mirror mode=0700,uid=0,gid=1000 nodev noexec nosuid
+ mount tmpfs tmpfs /data_mirror nodev noexec nosuid mode=0700,uid=0,gid=1000
restorecon /data_mirror
mkdir /data_mirror/data_ce 0700 root root
mkdir /data_mirror/data_de 0700 root root
@@ -732,8 +730,15 @@
# Create root dir for Incremental Service
mkdir /data/incremental 0771 system system encryption=Require
+ # Create directories for statsd
+ mkdir /data/misc/stats-active-metric/ 0770 statsd system
+ mkdir /data/misc/stats-data/ 0770 statsd system
+ mkdir /data/misc/stats-metadata/ 0770 statsd system
+ mkdir /data/misc/stats-service/ 0770 statsd system
+ mkdir /data/misc/train-info/ 0770 statsd system
+
# Wait for apexd to finish activating APEXes before starting more processes.
- wait_for_prop apexd.status ready
+ wait_for_prop apexd.status activated
perform_apex_config
# Special-case /data/media/obb per b/64566063
@@ -748,7 +753,7 @@
# Allow apexd to snapshot and restore device encrypted apex data in the case
# of a rollback. This should be done immediately after DE_user data keys
# are loaded. APEXes should not access this data until this has been
- # completed.
+ # completed and apexd.status becomes "ready".
exec_start apexd-snapshotde
# Set SELinux security contexts on upgrade or policy update.
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp
index 432c434..cc92c68 100644
--- a/run-as/run-as.cpp
+++ b/run-as/run-as.cpp
@@ -247,12 +247,12 @@
std::string seinfo = std::string(info.seinfo) + ":fromRunAs";
if (selinux_android_setcontext(uid, 0, seinfo.c_str(), pkgname) < 0) {
- error(1, errno, "couldn't set SELinux security context");
+ error(1, errno, "couldn't set SELinux security context '%s'", seinfo.c_str());
}
// cd into the data directory, and set $HOME correspondingly.
if (TEMP_FAILURE_RETRY(chdir(info.data_dir)) == -1) {
- error(1, errno, "couldn't chdir to package's data directory");
+ error(1, errno, "couldn't chdir to package's data directory '%s'", info.data_dir);
}
setenv("HOME", info.data_dir, 1);