Merge "StatsEventCompat"
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 703eb2f..fbfeb53 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -52,6 +52,8 @@
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
+typedef void(sync_ls_cb)(unsigned mode, uint64_t size, uint64_t time, const char* name);
+
struct syncsendbuf {
unsigned id;
unsigned size;
@@ -210,6 +212,7 @@
Error("failed to get feature set: %s", error.c_str());
} else {
have_stat_v2_ = CanUseFeature(features_, kFeatureStat2);
+ have_ls_v2_ = CanUseFeature(features_, kFeatureLs2);
fd.reset(adb_connect("sync:", &error));
if (fd < 0) {
Error("connect failed: %s", error.c_str());
@@ -357,7 +360,7 @@
<< msg.stat_v1.id;
}
- if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.time == 0) {
+ if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.mtime == 0) {
// There's no way for us to know what the error was.
errno = ENOPROTOOPT;
return false;
@@ -365,13 +368,52 @@
st->st_mode = msg.stat_v1.mode;
st->st_size = msg.stat_v1.size;
- st->st_ctime = msg.stat_v1.time;
- st->st_mtime = msg.stat_v1.time;
+ st->st_ctime = msg.stat_v1.mtime;
+ st->st_mtime = msg.stat_v1.mtime;
}
return true;
}
+ bool SendLs(const char* path) {
+ return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path);
+ }
+
+ private:
+ template <bool v2>
+ static bool FinishLsImpl(borrowed_fd fd, const std::function<sync_ls_cb>& callback) {
+ using dent_type =
+ std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>;
+
+ while (true) {
+ dent_type dent;
+ if (!ReadFdExactly(fd, &dent, sizeof(dent))) return false;
+
+ uint32_t expected_id = v2 ? ID_DENT_V2 : ID_DENT_V1;
+ if (dent.id == ID_DONE) return true;
+ if (dent.id != expected_id) return false;
+
+ // Maximum length of a file name excluding null terminator (NAME_MAX) on Linux is 255.
+ char buf[256];
+ size_t len = dent.namelen;
+ if (len > 255) return false;
+
+ if (!ReadFdExactly(fd, buf, len)) return false;
+ buf[len] = 0;
+
+ callback(dent.mode, dent.size, dent.mtime, buf);
+ }
+ }
+
+ public:
+ bool FinishLs(const std::function<sync_ls_cb>& callback) {
+ if (have_ls_v2_) {
+ return FinishLsImpl<true>(this->fd, callback);
+ } else {
+ return FinishLsImpl<false>(this->fd, callback);
+ }
+ }
+
// Sending header, payload, and footer in a single write makes a huge
// difference to "adb sync" performance.
bool SendSmallFile(const char* path_and_mode,
@@ -578,6 +620,7 @@
bool expect_done_;
FeatureSet features_;
bool have_stat_v2_;
+ bool have_ls_v2_;
TransferLedger global_ledger_;
TransferLedger current_ledger_;
@@ -609,28 +652,9 @@
}
};
-typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
-
static bool sync_ls(SyncConnection& sc, const char* path,
const std::function<sync_ls_cb>& func) {
- if (!sc.SendRequest(ID_LIST, path)) return false;
-
- while (true) {
- syncmsg msg;
- if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
-
- if (msg.dent.id == ID_DONE) return true;
- if (msg.dent.id != ID_DENT) return false;
-
- size_t len = msg.dent.namelen;
- if (len > 256) return false; // TODO: resize buffer? continue?
-
- char buf[257];
- if (!ReadFdExactly(sc.fd, buf, len)) return false;
- buf[len] = 0;
-
- func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
- }
+ return sc.SendLs(path) && sc.FinishLs(func);
}
static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) {
@@ -787,9 +811,8 @@
SyncConnection sc;
if (!sc.IsValid()) return false;
- return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
- const char* name) {
- printf("%08x %08x %08x %s\n", mode, size, time, name);
+ return sync_ls(sc, path, [](unsigned mode, uint64_t size, uint64_t time, const char* name) {
+ printf("%08x %08" PRIx64 " %08" PRIx64 " %s\n", mode, size, time, name);
});
}
@@ -1062,7 +1085,7 @@
file_list->push_back(ci);
// Put the files/dirs in rpath on the lists.
- auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
+ auto callback = [&](unsigned mode, uint64_t size, uint64_t time, const char* name) {
if (IsDotOrDotDot(name)) {
return;
}
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 0e70d47..d6af708 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -139,7 +139,7 @@
lstat(path, &st);
msg.stat_v1.mode = st.st_mode;
msg.stat_v1.size = st.st_size;
- msg.stat_v1.time = st.st_mtime;
+ msg.stat_v1.mtime = st.st_mtime;
return WriteFdExactly(s, &msg.stat_v1, sizeof(msg.stat_v1));
}
@@ -174,40 +174,73 @@
return WriteFdExactly(s, &msg.stat_v2, sizeof(msg.stat_v2));
}
+template <bool v2>
static bool do_list(int s, const char* path) {
dirent* de;
- syncmsg msg;
- msg.dent.id = ID_DENT;
+ using MessageType =
+ std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>;
+ MessageType msg;
+ uint32_t msg_id;
+ if constexpr (v2) {
+ msg_id = ID_DENT_V2;
+ } else {
+ msg_id = ID_DENT_V1;
+ }
std::unique_ptr<DIR, int(*)(DIR*)> d(opendir(path), closedir);
if (!d) goto done;
while ((de = readdir(d.get()))) {
+ memset(&msg, 0, sizeof(msg));
+ msg.id = msg_id;
+
std::string filename(StringPrintf("%s/%s", path, de->d_name));
struct stat st;
if (lstat(filename.c_str(), &st) == 0) {
- size_t d_name_length = strlen(de->d_name);
- msg.dent.mode = st.st_mode;
- msg.dent.size = st.st_size;
- msg.dent.time = st.st_mtime;
- msg.dent.namelen = d_name_length;
+ msg.mode = st.st_mode;
+ msg.size = st.st_size;
+ msg.mtime = st.st_mtime;
- if (!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ||
- !WriteFdExactly(s, de->d_name, d_name_length)) {
- return false;
+ if constexpr (v2) {
+ msg.dev = st.st_dev;
+ msg.ino = st.st_ino;
+ msg.nlink = st.st_nlink;
+ msg.uid = st.st_uid;
+ msg.gid = st.st_gid;
+ msg.atime = st.st_atime;
+ msg.ctime = st.st_ctime;
}
+ } else {
+ if constexpr (v2) {
+ msg.error = errno;
+ } else {
+ continue;
+ }
+ }
+
+ size_t d_name_length = strlen(de->d_name);
+ msg.namelen = d_name_length;
+
+ if (!WriteFdExactly(s, &msg, sizeof(msg)) ||
+ !WriteFdExactly(s, de->d_name, d_name_length)) {
+ return false;
}
}
done:
- msg.dent.id = ID_DONE;
- msg.dent.mode = 0;
- msg.dent.size = 0;
- msg.dent.time = 0;
- msg.dent.namelen = 0;
- return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
+ memset(&msg, 0, sizeof(msg));
+ msg.id = ID_DONE;
+ return WriteFdExactly(s, &msg, sizeof(msg));
+}
+
+static bool do_list_v1(int s, const char* path) {
+ return do_list<false>(s, path);
+}
+
+static bool do_list_v2(int s, const char* path) {
+ return do_list<true>(s, path);
}
// Make sure that SendFail from adb_io.cpp isn't accidentally used in this file.
@@ -499,8 +532,10 @@
return "lstat_v2";
case ID_STAT_V2:
return "stat_v2";
- case ID_LIST:
- return "list";
+ case ID_LIST_V1:
+ return "list_v1";
+ case ID_LIST_V2:
+ return "list_v2";
case ID_SEND:
return "send";
case ID_RECV:
@@ -546,8 +581,11 @@
case ID_STAT_V2:
if (!do_stat_v2(fd, request.id, name)) return false;
break;
- case ID_LIST:
- if (!do_list(fd, name)) return false;
+ case ID_LIST_V1:
+ if (!do_list_v1(fd, name)) return false;
+ break;
+ case ID_LIST_V2:
+ if (!do_list_v2(fd, name)) return false;
break;
case ID_SEND:
if (!do_send(fd, name, buffer)) return false;
diff --git a/adb/daemon/usb_ffs.cpp b/adb/daemon/usb_ffs.cpp
index 338d776..b19fa5d 100644
--- a/adb/daemon/usb_ffs.cpp
+++ b/adb/daemon/usb_ffs.cpp
@@ -84,7 +84,7 @@
using usb_os_desc_guid_t = usb_os_desc_ext_prop<20, 39>;
usb_os_desc_guid_t os_desc_guid = {
.bPropertyName = "DeviceInterfaceGUID",
- .bProperty = "{64379D6C-D531-4BED-BBEC-5A16FC07D6BC}",
+ .bProperty = "{F72FE0D4-CBCB-407D-8814-9ED673D0DD6B}",
};
struct usb_ext_prop_values {
diff --git a/adb/file_sync_protocol.h b/adb/file_sync_protocol.h
index 108639a..508c138 100644
--- a/adb/file_sync_protocol.h
+++ b/adb/file_sync_protocol.h
@@ -21,10 +21,14 @@
#define ID_LSTAT_V1 MKID('S', 'T', 'A', 'T')
#define ID_STAT_V2 MKID('S', 'T', 'A', '2')
#define ID_LSTAT_V2 MKID('L', 'S', 'T', '2')
-#define ID_LIST MKID('L', 'I', 'S', 'T')
+
+#define ID_LIST_V1 MKID('L', 'I', 'S', 'T')
+#define ID_LIST_V2 MKID('L', 'I', 'S', '2')
+#define ID_DENT_V1 MKID('D', 'E', 'N', 'T')
+#define ID_DENT_V2 MKID('D', 'N', 'T', '2')
+
#define ID_SEND MKID('S', 'E', 'N', 'D')
#define ID_RECV MKID('R', 'E', 'C', 'V')
-#define ID_DENT MKID('D', 'E', 'N', 'T')
#define ID_DONE MKID('D', 'O', 'N', 'E')
#define ID_DATA MKID('D', 'A', 'T', 'A')
#define ID_OKAY MKID('O', 'K', 'A', 'Y')
@@ -42,7 +46,7 @@
uint32_t id;
uint32_t mode;
uint32_t size;
- uint32_t time;
+ uint32_t mtime;
} stat_v1;
struct __attribute__((packed)) {
uint32_t id;
@@ -62,17 +66,32 @@
uint32_t id;
uint32_t mode;
uint32_t size;
- uint32_t time;
+ uint32_t mtime;
uint32_t namelen;
- } dent;
+ } dent_v1; // followed by `namelen` bytes of the name.
+ struct __attribute__((packed)) {
+ uint32_t id;
+ uint32_t error;
+ uint64_t dev;
+ uint64_t ino;
+ uint32_t mode;
+ uint32_t nlink;
+ uint32_t uid;
+ uint32_t gid;
+ uint64_t size;
+ int64_t atime;
+ int64_t mtime;
+ int64_t ctime;
+ uint32_t namelen;
+ } dent_v2; // followed by `namelen` bytes of the name.
struct __attribute__((packed)) {
uint32_t id;
uint32_t size;
- } data;
+ } data; // followed by `size` bytes of data.
struct __attribute__((packed)) {
uint32_t id;
uint32_t msglen;
- } status;
+ } status; // followed by `msglen` bytes of error message, if id == ID_FAIL.
};
#define SYNC_DATA_MAX (64 * 1024)
diff --git a/adb/transport.cpp b/adb/transport.cpp
index d9749ac..9dd6ec6 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -55,7 +55,7 @@
using android::base::ScopedLockAssertion;
static void remove_transport(atransport* transport);
-static void transport_unref(atransport* transport);
+static void transport_destroy(atransport* transport);
// TODO: unordered_map<TransportId, atransport*>
static auto& transport_list = *new std::list<atransport*>();
@@ -66,6 +66,7 @@
const char* const kFeatureShell2 = "shell_v2";
const char* const kFeatureCmd = "cmd";
const char* const kFeatureStat2 = "stat_v2";
+const char* const kFeatureLs2 = "ls_v2";
const char* const kFeatureLibusb = "libusb";
const char* const kFeaturePushSync = "push_sync";
const char* const kFeatureApex = "apex";
@@ -676,7 +677,6 @@
if (t->GetConnectionState() != kCsNoPerm) {
// The connection gets a reference to the atransport. It will release it
// upon a read/write error.
- t->ref_count++;
t->connection()->SetTransportName(t->serial_name());
t->connection()->SetReadCallback([t](Connection*, std::unique_ptr<apacket> p) {
if (!check_header(p.get(), t)) {
@@ -695,7 +695,7 @@
LOG(INFO) << t->serial_name() << ": connection terminated: " << error;
fdevent_run_on_main_thread([t]() {
handle_offline(t);
- transport_unref(t);
+ transport_destroy(t);
});
});
@@ -771,36 +771,27 @@
}
}
-static void transport_unref(atransport* t) {
+static void transport_destroy(atransport* t) {
check_main_thread();
CHECK(t != nullptr);
std::lock_guard<std::recursive_mutex> lock(transport_lock);
- CHECK_GT(t->ref_count, 0u);
- t->ref_count--;
- if (t->ref_count == 0) {
- LOG(INFO) << "destroying transport " << t->serial_name();
- t->connection()->Stop();
+ LOG(INFO) << "destroying transport " << t->serial_name();
+ t->connection()->Stop();
#if ADB_HOST
- if (t->IsTcpDevice() && !t->kicked()) {
- D("transport: %s unref (attempting reconnection)", t->serial.c_str());
+ if (t->IsTcpDevice() && !t->kicked()) {
+ D("transport: %s destroy (attempting reconnection)", t->serial.c_str());
- // We need to clear the transport's keys, so that on the next connection, it tries
- // again from the beginning.
- t->ResetKeys();
- reconnect_handler.TrackTransport(t);
- } else {
- D("transport: %s unref (kicking and closing)", t->serial.c_str());
- remove_transport(t);
- }
-#else
- D("transport: %s unref (kicking and closing)", t->serial.c_str());
- remove_transport(t);
+ // We need to clear the transport's keys, so that on the next connection, it tries
+ // again from the beginning.
+ t->ResetKeys();
+ reconnect_handler.TrackTransport(t);
+ return;
+ }
#endif
- } else {
- D("transport: %s unref (count=%zu)", t->serial.c_str(), t->ref_count);
- }
+ D("transport: %s destroy (kicking and closing)", t->serial.c_str());
+ remove_transport(t);
}
static int qual_match(const std::string& to_test, const char* prefix, const std::string& qual,
@@ -1045,6 +1036,7 @@
kFeatureShell2,
kFeatureCmd,
kFeatureStat2,
+ kFeatureLs2,
kFeatureFixedPushMkdir,
kFeatureApex,
kFeatureAbb,
diff --git a/adb/transport.h b/adb/transport.h
index 89d76b8..ea77117 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -57,6 +57,7 @@
// The 'cmd' command is available
extern const char* const kFeatureCmd;
extern const char* const kFeatureStat2;
+extern const char* const kFeatureLs2;
// The server is running with libusb enabled.
extern const char* const kFeatureLibusb;
// adbd supports `push --sync`.
@@ -266,7 +267,7 @@
usb_handle* GetUsbHandle() { return usb_handle_; }
const TransportId id;
- size_t ref_count = 0;
+
bool online = false;
TransportType type = kTransportAny;
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index b20f278..f3d7cb0 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -53,30 +53,34 @@
CapturedStdout() : CapturedStdFd(STDOUT_FILENO) {}
};
-#define ASSERT_MATCH(str, pattern) \
- do { \
- if (!std::regex_search((str), std::regex((pattern)))) { \
- FAIL() << "regex mismatch: expected " << (pattern) << " in:\n" << (str); \
- } \
+#define ASSERT_MATCH(str, pattern) \
+ do { \
+ auto __s = (str); \
+ if (!std::regex_search(__s, std::regex((pattern)))) { \
+ FAIL() << "regex mismatch: expected " << (pattern) << " in:\n" << __s; \
+ } \
} while (0)
-#define ASSERT_NOT_MATCH(str, pattern) \
- do { \
- if (std::regex_search((str), std::regex((pattern)))) { \
- FAIL() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << (str); \
- } \
+#define ASSERT_NOT_MATCH(str, pattern) \
+ do { \
+ auto __s = (str); \
+ if (std::regex_search(__s, std::regex((pattern)))) { \
+ FAIL() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << __s; \
+ } \
} while (0)
-#define EXPECT_MATCH(str, pattern) \
- do { \
- if (!std::regex_search((str), std::regex((pattern)))) { \
- ADD_FAILURE() << "regex mismatch: expected " << (pattern) << " in:\n" << (str); \
- } \
+#define EXPECT_MATCH(str, pattern) \
+ do { \
+ auto __s = (str); \
+ if (!std::regex_search(__s, std::regex((pattern)))) { \
+ ADD_FAILURE() << "regex mismatch: expected " << (pattern) << " in:\n" << __s; \
+ } \
} while (0)
-#define EXPECT_NOT_MATCH(str, pattern) \
- do { \
- if (std::regex_search((str), std::regex((pattern)))) { \
- ADD_FAILURE() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << (str); \
- } \
+#define EXPECT_NOT_MATCH(str, pattern) \
+ do { \
+ auto __s = (str); \
+ if (std::regex_search(__s, std::regex((pattern)))) { \
+ ADD_FAILURE() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << __s; \
+ } \
} while (0)
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index e279af9..a9342d8 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -577,8 +577,7 @@
} // namespace
void TransformFstabForDsu(Fstab* fstab, const std::vector<std::string>& dsu_partitions) {
- static constexpr char kGsiKeys[] =
- "/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey";
+ static constexpr char kDsuKeysDir[] = "/avb";
// Convert userdata
// Inherit fstab properties for userdata.
FstabEntry userdata;
@@ -624,29 +623,18 @@
.fs_type = "ext4",
.flags = MS_RDONLY,
.fs_options = "barrier=1",
- .avb_keys = kGsiKeys,
+ .avb_keys = kDsuKeysDir,
};
entry.fs_mgr_flags.wait = true;
entry.fs_mgr_flags.logical = true;
entry.fs_mgr_flags.first_stage_mount = true;
- // Use the system key which may be in the vbmeta or vbmeta_system
- // TODO: b/141284191
- entry.vbmeta_partition = "vbmeta";
- fstab->emplace_back(entry);
- entry.vbmeta_partition = "vbmeta_system";
- fstab->emplace_back(entry);
} else {
// If the corresponding partition exists, transform all its Fstab
// by pointing .blk_device to the DSU partition.
for (auto&& entry : entries) {
entry->blk_device = partition;
- if (entry->avb_keys.size() > 0) {
- entry->avb_keys += ":";
- }
- // If the DSU is signed by OEM, the original Fstab already has the information
- // required by avb, otherwise the DSU is GSI and will need the avb_keys as listed
- // below.
- entry->avb_keys += kGsiKeys;
+ // AVB keys for DSU should always be under kDsuKeysDir.
+ entry->avb_keys += kDsuKeysDir;
}
// Make sure the ext4 is included to support GSI.
auto partition_ext4 =
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 0579a3d..2337065 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -815,26 +815,72 @@
return "auto";
}
-std::string fs_mgr_overlayfs_scratch_device() {
- if (!scratch_device_cache.empty()) return scratch_device_cache;
+enum class ScratchStrategy {
+ kNone,
+ // DAP device, use logical partitions.
+ kDynamicPartition,
+ // Retrofit DAP device, use super_<other>.
+ kSuperOther,
+ // Pre-DAP device, uses the other slot.
+ kSystemOther
+};
- // Is this a multiple super device (retrofit)?
+static ScratchStrategy GetScratchStrategy(std::string* backing_device) {
auto slot_number = fs_mgr_overlayfs_slot_number();
auto super_device = fs_mgr_overlayfs_super_device(slot_number);
auto path = fs_mgr_overlayfs_super_device(slot_number == 0);
- if (super_device == path) {
- // Create from within single super device;
- auto& dm = DeviceMapper::Instance();
- const auto partition_name = android::base::Basename(kScratchMountPoint);
- if (!dm.GetDmDevicePathByName(partition_name, &path)) {
- // non-DAP A/B device?
- if (fs_mgr_access(super_device)) return "";
- auto other_slot = fs_mgr_get_other_slot_suffix();
- if (other_slot.empty()) return "";
- path = kPhysicalDevice + "system" + other_slot;
+ if (super_device != path) {
+ // Note: we do not check access() here, since in first-stage init we
+ // wouldn't have registed by-name symlinks for the device as it's
+ // normally not needed. The access checks elsewhere in this function
+ // are safe because system/super are always required.
+ *backing_device = path;
+ return ScratchStrategy::kSuperOther;
+ }
+ if (fs_mgr_access(super_device)) {
+ *backing_device = super_device;
+ return ScratchStrategy::kDynamicPartition;
+ }
+
+ auto other_slot = fs_mgr_get_other_slot_suffix();
+ if (!other_slot.empty()) {
+ path = kPhysicalDevice + "system" + other_slot;
+ if (fs_mgr_access(path)) {
+ *backing_device = path;
+ return ScratchStrategy::kSystemOther;
}
}
- return scratch_device_cache = path;
+ return ScratchStrategy::kNone;
+}
+
+// Return the scratch device if it exists.
+static std::string GetScratchDevice() {
+ std::string device;
+ ScratchStrategy strategy = GetScratchStrategy(&device);
+
+ switch (strategy) {
+ case ScratchStrategy::kSuperOther:
+ case ScratchStrategy::kSystemOther:
+ return device;
+ case ScratchStrategy::kDynamicPartition: {
+ auto& dm = DeviceMapper::Instance();
+ auto partition_name = android::base::Basename(kScratchMountPoint);
+ if (dm.GetState(partition_name) != DmDeviceState::INVALID &&
+ dm.GetDmDevicePathByName(partition_name, &device)) {
+ return device;
+ }
+ return "";
+ }
+ default:
+ return "";
+ }
+}
+
+std::string fs_mgr_overlayfs_scratch_device() {
+ if (!scratch_device_cache.empty()) return scratch_device_cache;
+
+ scratch_device_cache = GetScratchDevice();
+ return scratch_device_cache;
}
bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std::string& mnt_type) {
@@ -1066,6 +1112,25 @@
return candidates;
}
+static void TryMountScratch() {
+ auto scratch_device = fs_mgr_overlayfs_scratch_device();
+ if (!fs_mgr_overlayfs_scratch_can_be_mounted(scratch_device)) {
+ return;
+ }
+ if (!WaitForFile(scratch_device, 10s)) {
+ return;
+ }
+ const auto mount_type = fs_mgr_overlayfs_scratch_mount_type();
+ if (!fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type, true /* readonly */)) {
+ return;
+ }
+ auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir);
+ fs_mgr_overlayfs_umount_scratch();
+ if (has_overlayfs_dir) {
+ fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type);
+ }
+}
+
bool fs_mgr_overlayfs_mount_all(Fstab* fstab) {
auto ret = false;
if (fs_mgr_overlayfs_invalid()) return ret;
@@ -1080,19 +1145,7 @@
}
if (scratch_can_be_mounted) {
scratch_can_be_mounted = false;
- auto scratch_device = fs_mgr_overlayfs_scratch_device();
- if (fs_mgr_overlayfs_scratch_can_be_mounted(scratch_device) &&
- WaitForFile(scratch_device, 10s)) {
- const auto mount_type = fs_mgr_overlayfs_scratch_mount_type();
- if (fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type,
- true /* readonly */)) {
- auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir);
- fs_mgr_overlayfs_umount_scratch();
- if (has_overlayfs_dir) {
- fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type);
- }
- }
- }
+ TryMountScratch();
}
if (fs_mgr_overlayfs_mount(mount_point)) ret = true;
}
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 656d4dd..de0c636 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -17,7 +17,6 @@
liblog_sources = [
"log_event_list.cpp",
"log_event_write.cpp",
- "logger_lock.cpp",
"logger_name.cpp",
"logger_read.cpp",
"logger_write.cpp",
diff --git a/liblog/fake_log_device.cpp b/liblog/fake_log_device.cpp
index 4143fa6..fb3b9bc 100644
--- a/liblog/fake_log_device.cpp
+++ b/liblog/fake_log_device.cpp
@@ -48,21 +48,16 @@
#define TRACE(...) ((void)0)
#endif
-static int FakeAvailable(log_id_t);
-static int FakeOpen();
static void FakeClose();
static int FakeWrite(log_id_t log_id, struct timespec* ts, struct iovec* vec, size_t nr);
struct android_log_transport_write fakeLoggerWrite = {
- .name = "fake",
- .logMask = 0,
- .available = FakeAvailable,
- .open = FakeOpen,
.close = FakeClose,
.write = FakeWrite,
};
typedef struct LogState {
+ bool initialized = false;
/* global minimum priority */
int global_min_priority;
@@ -76,19 +71,8 @@
} tagSet[kTagSetSize];
} LogState;
-/*
- * Locking. Since we're emulating a device, we need to be prepared
- * to have multiple callers at the same time. This lock is used
- * to both protect the fd list and to prevent LogStates from being
- * freed out from under a user.
- */
-std::mutex mutex;
-
static LogState log_state;
-
-static int FakeAvailable(log_id_t) {
- return 0;
-}
+static std::mutex fake_log_mutex;
/*
* Configure logging based on ANDROID_LOG_TAGS environment variable. We
@@ -103,8 +87,8 @@
* We also want to check ANDROID_PRINTF_LOG to determine how the output
* will look.
*/
-int FakeOpen() {
- std::lock_guard guard{mutex};
+void InitializeLogStateLocked() {
+ log_state.initialized = true;
/* global min priority defaults to "info" level */
log_state.global_min_priority = ANDROID_LOG_INFO;
@@ -129,7 +113,7 @@
}
if (i == kMaxTagLen) {
TRACE("ERROR: env tag too long (%d chars max)\n", kMaxTagLen - 1);
- return 0;
+ return;
}
tagName[i] = '\0';
@@ -180,7 +164,7 @@
if (*tags != '\0' && !isspace(*tags)) {
TRACE("ERROR: garbage in tag env; expected whitespace\n");
TRACE(" env='%s'\n", tags);
- return 0;
+ return;
}
}
@@ -224,7 +208,6 @@
}
log_state.output_format = format;
- return 0;
}
/*
@@ -474,7 +457,11 @@
* Also guarantees that only one thread is in showLog() at a given
* time (if it matters).
*/
- std::lock_guard guard{mutex};
+ auto lock = std::lock_guard{fake_log_mutex};
+
+ if (!log_state.initialized) {
+ InitializeLogStateLocked();
+ }
if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS || log_id == LOG_ID_SECURITY) {
TRACE("%s: ignoring binary log\n", android_log_id_to_name(log_id));
@@ -532,7 +519,7 @@
* help debug HOST tools ...
*/
static void FakeClose() {
- std::lock_guard guard{mutex};
+ auto lock = std::lock_guard{fake_log_mutex};
memset(&log_state, 0, sizeof(log_state));
}
diff --git a/liblog/logd_writer.cpp b/liblog/logd_writer.cpp
index a22c3be..3c6eb69 100644
--- a/liblog/logd_writer.cpp
+++ b/liblog/logd_writer.cpp
@@ -30,97 +30,76 @@
#include <time.h>
#include <unistd.h>
+#include <shared_mutex>
+
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
#include "log_portability.h"
#include "logger.h"
+#include "rwlock.h"
#include "uio.h"
-static int logdAvailable(log_id_t LogId);
-static int logdOpen();
-static void logdClose();
-static int logdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
+static int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
+static void LogdClose();
struct android_log_transport_write logdLoggerWrite = {
- .name = "logd",
- .logMask = 0,
- .context.sock = -EBADF,
- .available = logdAvailable,
- .open = logdOpen,
- .close = logdClose,
- .write = logdWrite,
+ .close = LogdClose,
+ .write = LogdWrite,
};
-/* log_init_lock assumed */
-static int logdOpen() {
- int i, ret = 0;
+static int logd_socket;
+static RwLock logd_socket_lock;
- i = atomic_load(&logdLoggerWrite.context.sock);
- if (i < 0) {
- int sock = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
- if (sock < 0) {
- ret = -errno;
- } else {
- struct sockaddr_un un;
- memset(&un, 0, sizeof(struct sockaddr_un));
- un.sun_family = AF_UNIX;
- strcpy(un.sun_path, "/dev/socket/logdw");
-
- if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr*)&un, sizeof(struct sockaddr_un))) <
- 0) {
- ret = -errno;
- switch (ret) {
- case -ENOTCONN:
- case -ECONNREFUSED:
- case -ENOENT:
- i = atomic_exchange(&logdLoggerWrite.context.sock, ret);
- [[fallthrough]];
- default:
- break;
- }
- close(sock);
- } else {
- ret = atomic_exchange(&logdLoggerWrite.context.sock, sock);
- if ((ret >= 0) && (ret != sock)) {
- close(ret);
- }
- ret = 0;
- }
- }
+static void OpenSocketLocked() {
+ logd_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
+ if (logd_socket <= 0) {
+ return;
}
- return ret;
-}
+ sockaddr_un un = {};
+ un.sun_family = AF_UNIX;
+ strcpy(un.sun_path, "/dev/socket/logdw");
-static void __logdClose(int negative_errno) {
- int sock = atomic_exchange(&logdLoggerWrite.context.sock, negative_errno);
- if (sock >= 0) {
- close(sock);
+ if (TEMP_FAILURE_RETRY(
+ connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un))) < 0) {
+ close(logd_socket);
+ logd_socket = 0;
}
}
-static void logdClose() {
- __logdClose(-EBADF);
+static void OpenSocket() {
+ auto lock = std::unique_lock{logd_socket_lock};
+ if (logd_socket > 0) {
+ // Someone raced us and opened the socket already.
+ return;
+ }
+
+ OpenSocketLocked();
}
-static int logdAvailable(log_id_t logId) {
- if (logId >= LOG_ID_MAX || logId == LOG_ID_KERNEL) {
- return -EINVAL;
+static void ResetSocket(int old_socket) {
+ auto lock = std::unique_lock{logd_socket_lock};
+ if (old_socket != logd_socket) {
+ // Someone raced us and reset the socket already.
+ return;
}
- if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
- if (access("/dev/socket/logdw", W_OK) == 0) {
- return 0;
- }
- return -EBADF;
- }
- return 1;
+ close(logd_socket);
+ logd_socket = 0;
+ OpenSocketLocked();
}
-static int logdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
+static void LogdClose() {
+ auto lock = std::unique_lock{logd_socket_lock};
+ if (logd_socket > 0) {
+ close(logd_socket);
+ }
+ logd_socket = 0;
+}
+
+static int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
ssize_t ret;
- int sock;
static const unsigned headerLength = 1;
struct iovec newVec[nr + headerLength];
android_log_header_t header;
@@ -128,15 +107,16 @@
static atomic_int dropped;
static atomic_int droppedSecurity;
- sock = atomic_load(&logdLoggerWrite.context.sock);
- if (sock < 0) switch (sock) {
- case -ENOTCONN:
- case -ECONNREFUSED:
- case -ENOENT:
- break;
- default:
- return -EBADF;
- }
+ auto lock = std::shared_lock{logd_socket_lock};
+ if (logd_socket <= 0) {
+ lock.unlock();
+ OpenSocket();
+ lock.lock();
+ }
+
+ if (logd_socket <= 0) {
+ return -EBADF;
+ }
/* logd, after initialization and priv drop */
if (__android_log_uid() == AID_LOGD) {
@@ -155,41 +135,39 @@
newVec[0].iov_base = (unsigned char*)&header;
newVec[0].iov_len = sizeof(header);
- if (sock >= 0) {
- int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0, memory_order_relaxed);
- if (snapshot) {
- android_log_event_int_t buffer;
+ int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0, memory_order_relaxed);
+ if (snapshot) {
+ android_log_event_int_t buffer;
- header.id = LOG_ID_SECURITY;
- buffer.header.tag = LIBLOG_LOG_TAG;
- buffer.payload.type = EVENT_TYPE_INT;
- buffer.payload.data = snapshot;
+ header.id = LOG_ID_SECURITY;
+ buffer.header.tag = LIBLOG_LOG_TAG;
+ buffer.payload.type = EVENT_TYPE_INT;
+ buffer.payload.data = snapshot;
- newVec[headerLength].iov_base = &buffer;
- newVec[headerLength].iov_len = sizeof(buffer);
+ newVec[headerLength].iov_base = &buffer;
+ newVec[headerLength].iov_len = sizeof(buffer);
- ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
- if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
- atomic_fetch_add_explicit(&droppedSecurity, snapshot, memory_order_relaxed);
- }
+ ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, 2));
+ if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+ atomic_fetch_add_explicit(&droppedSecurity, snapshot, memory_order_relaxed);
}
- snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
- if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO, "liblog", strlen("liblog"),
- ANDROID_LOG_VERBOSE)) {
- android_log_event_int_t buffer;
+ }
+ snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+ if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO, "liblog", strlen("liblog"),
+ ANDROID_LOG_VERBOSE)) {
+ android_log_event_int_t buffer;
- header.id = LOG_ID_EVENTS;
- buffer.header.tag = LIBLOG_LOG_TAG;
- buffer.payload.type = EVENT_TYPE_INT;
- buffer.payload.data = snapshot;
+ header.id = LOG_ID_EVENTS;
+ buffer.header.tag = LIBLOG_LOG_TAG;
+ buffer.payload.type = EVENT_TYPE_INT;
+ buffer.payload.data = snapshot;
- newVec[headerLength].iov_base = &buffer;
- newVec[headerLength].iov_len = sizeof(buffer);
+ newVec[headerLength].iov_base = &buffer;
+ newVec[headerLength].iov_len = sizeof(buffer);
- ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
- if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
- atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
- }
+ ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, 2));
+ if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+ atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
}
}
@@ -208,49 +186,26 @@
}
}
- /*
- * The write below could be lost, but will never block.
- *
- * ENOTCONN occurs if logd has died.
- * ENOENT occurs if logd is not running and socket is missing.
- * ECONNREFUSED occurs if we can not reconnect to logd.
- * EAGAIN occurs if logd is overloaded.
- */
- if (sock < 0) {
- ret = sock;
- } else {
- ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
- if (ret < 0) {
- ret = -errno;
- }
+ // The write below could be lost, but will never block.
+ // EAGAIN occurs if logd is overloaded, other errors indicate that something went wrong with
+ // the connection, so we reset it and try again.
+ ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
+ if (ret < 0 && errno != EAGAIN) {
+ int old_socket = logd_socket;
+ lock.unlock();
+ ResetSocket(old_socket);
+ lock.lock();
+
+ ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
}
- switch (ret) {
- case -ENOTCONN:
- case -ECONNREFUSED:
- case -ENOENT:
- if (__android_log_trylock()) {
- return ret; /* in a signal handler? try again when less stressed */
- }
- __logdClose(ret);
- ret = logdOpen();
- __android_log_unlock();
- if (ret < 0) {
- return ret;
- }
-
- ret = TEMP_FAILURE_RETRY(writev(atomic_load(&logdLoggerWrite.context.sock), newVec, i));
- if (ret < 0) {
- ret = -errno;
- }
- [[fallthrough]];
- default:
- break;
+ if (ret < 0) {
+ ret = -errno;
}
if (ret > (ssize_t)sizeof(header)) {
ret -= sizeof(header);
- } else if (ret == -EAGAIN) {
+ } else if (ret < 0) {
atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
if (logId == LOG_ID_SECURITY) {
atomic_fetch_add_explicit(&droppedSecurity, 1, memory_order_relaxed);
diff --git a/liblog/logger.h b/liblog/logger.h
index 9d74d29..40d5fe5 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -26,20 +26,7 @@
__BEGIN_DECLS
-/* Union, sock or fd of zero is not allowed unless static initialized */
-union android_log_context_union {
- void* priv;
- atomic_int sock;
- atomic_int fd;
-};
-
struct android_log_transport_write {
- const char* name; /* human name to describe the transport */
- unsigned logMask; /* mask cache of available() success */
- union android_log_context_union context; /* Initialized by static allocation */
-
- int (*available)(log_id_t logId); /* Does not cause resources to be taken */
- int (*open)(); /* can be called multiple times, reusing current resources */
void (*close)(); /* free up resources */
/* write log to transport, returns number of bytes propagated, or -errno */
int (*write)(log_id_t logId, struct timespec* ts, struct iovec* vec,
@@ -83,8 +70,4 @@
}
#endif
-void __android_log_lock();
-int __android_log_trylock();
-void __android_log_unlock();
-
__END_DECLS
diff --git a/liblog/logger_lock.cpp b/liblog/logger_lock.cpp
deleted file mode 100644
index 4636b00..0000000
--- a/liblog/logger_lock.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2007-2016 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.
- */
-
-/*
- * Some OS specific dribs and drabs (locking etc).
- */
-
-#if !defined(_WIN32)
-#include <pthread.h>
-#endif
-
-#include "logger.h"
-
-#if !defined(_WIN32)
-static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-void __android_log_lock() {
-#if !defined(_WIN32)
- /*
- * If we trigger a signal handler in the middle of locked activity and the
- * signal handler logs a message, we could get into a deadlock state.
- */
- pthread_mutex_lock(&log_init_lock);
-#endif
-}
-
-int __android_log_trylock() {
-#if !defined(_WIN32)
- return pthread_mutex_trylock(&log_init_lock);
-#else
- return 0;
-#endif
-}
-
-void __android_log_unlock() {
-#if !defined(_WIN32)
- pthread_mutex_unlock(&log_init_lock);
-#endif
-}
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index e1772f1..d38b402 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -24,7 +24,6 @@
#include <android/set_abort_message.h>
#endif
-#include <log/event_tag_map.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -47,11 +46,8 @@
android_log_transport_write* android_log_persist_write = nullptr;
#endif
-static int __write_to_log_init(log_id_t, struct iovec* vec, size_t nr);
-static int (*write_to_log)(log_id_t, struct iovec* vec, size_t nr) = __write_to_log_init;
-
-static int check_log_uid_permissions() {
#if defined(__ANDROID__)
+static int check_log_uid_permissions() {
uid_t uid = __android_log_uid();
/* Matches clientHasLogCredentials() in logd */
@@ -88,51 +84,14 @@
}
}
}
-#endif
return 0;
}
-
-static void __android_log_cache_available(struct android_log_transport_write* node) {
- uint32_t i;
-
- if (node->logMask) {
- return;
- }
-
- for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- if (i != LOG_ID_KERNEL && (i != LOG_ID_SECURITY || check_log_uid_permissions() == 0) &&
- (*node->available)(static_cast<log_id_t>(i)) >= 0) {
- node->logMask |= 1 << i;
- }
- }
-}
-
-#if defined(__ANDROID__)
-static atomic_uintptr_t tagMap;
#endif
/*
* Release any logger resources. A new log write will immediately re-acquire.
*/
void __android_log_close() {
-#if defined(__ANDROID__)
- EventTagMap* m;
-#endif
-
- __android_log_lock();
-
- write_to_log = __write_to_log_init;
-
- /*
- * Threads that are actively writing at this point are not held back
- * by a lock and are at risk of dropping the messages with a return code
- * -EBADF. Prefer to return error code than add the overhead of a lock to
- * each log writing call to guarantee delivery. In addition, anyone
- * calling this is doing so to release the logging resources and shut down,
- * for them to do so with outstanding log requests in other threads is a
- * disengenuous use of this function.
- */
-
if (android_log_write != nullptr) {
android_log_write->close();
}
@@ -141,64 +100,18 @@
android_log_persist_write->close();
}
-#if defined(__ANDROID__)
- /*
- * Additional risk here somewhat mitigated by immediately unlock flushing
- * the processor cache. The multi-threaded race that we choose to accept,
- * to minimize locking, is an atomic_load in a writer picking up a value
- * just prior to entering this routine. There will be an use after free.
- *
- * Again, anyone calling this is doing so to release the logging resources
- * is most probably going to quiesce then shut down; or to restart after
- * a fork so the risk should be non-existent. For this reason we
- * choose a mitigation stance for efficiency instead of incuring the cost
- * of a lock for every log write.
- */
- m = (EventTagMap*)atomic_exchange(&tagMap, (uintptr_t)0);
-#endif
-
- __android_log_unlock();
-
-#if defined(__ANDROID__)
- if (m != (EventTagMap*)(uintptr_t)-1LL) android_closeEventTagMap(m);
-#endif
}
-static bool transport_initialize(android_log_transport_write* transport) {
- if (transport == nullptr) {
- return false;
- }
-
- __android_log_cache_available(transport);
- if (!transport->logMask) {
- return false;
- }
-
- // TODO: Do we actually need to call close() if open() fails?
- if (transport->open() < 0) {
- transport->close();
- return false;
- }
-
- return true;
-}
-
-/* log_init_lock assumed */
-static int __write_to_log_initialize() {
- if (!transport_initialize(android_log_write)) {
- return -ENODEV;
- }
-
- transport_initialize(android_log_persist_write);
-
- return 1;
-}
-
-static int __write_to_log_daemon(log_id_t log_id, struct iovec* vec, size_t nr) {
+static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
int ret, save_errno;
struct timespec ts;
save_errno = errno;
+
+ if (log_id == LOG_ID_KERNEL) {
+ return -EINVAL;
+ }
+
#if defined(__ANDROID__)
clock_gettime(android_log_clockid(), &ts);
@@ -219,49 +132,10 @@
return -EPERM;
}
} else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
- const char* tag;
- size_t len;
- EventTagMap *m, *f;
-
if (vec[0].iov_len < 4) {
errno = save_errno;
return -EINVAL;
}
-
- tag = NULL;
- len = 0;
- f = NULL;
- m = (EventTagMap*)atomic_load(&tagMap);
-
- if (!m) {
- ret = __android_log_trylock();
- m = (EventTagMap*)atomic_load(&tagMap); /* trylock flush cache */
- if (!m) {
- m = android_openEventTagMap(NULL);
- if (ret) { /* trylock failed, use local copy, mark for close */
- f = m;
- } else {
- if (!m) { /* One chance to open map file */
- m = (EventTagMap*)(uintptr_t)-1LL;
- }
- atomic_store(&tagMap, (uintptr_t)m);
- }
- }
- if (!ret) { /* trylock succeeded, unlock */
- __android_log_unlock();
- }
- }
- if (m && (m != (EventTagMap*)(uintptr_t)-1LL)) {
- tag = android_lookupEventTag_len(m, &len, *static_cast<uint32_t*>(vec[0].iov_base));
- }
- ret = __android_log_is_loggable_len(ANDROID_LOG_INFO, tag, len, ANDROID_LOG_VERBOSE);
- if (f) { /* local copy marked for close */
- android_closeEventTagMap(f);
- }
- if (!ret) {
- errno = save_errno;
- return -EPERM;
- }
} else {
int prio = *static_cast<int*>(vec[0].iov_base);
const char* tag = static_cast<const char*>(vec[1].iov_base);
@@ -283,9 +157,8 @@
#endif
ret = 0;
- size_t i = 1 << log_id;
- if (android_log_write != nullptr && (android_log_write->logMask & i)) {
+ if (android_log_write != nullptr) {
ssize_t retval;
retval = android_log_write->write(log_id, &ts, vec, nr);
if (ret >= 0) {
@@ -293,7 +166,7 @@
}
}
- if (android_log_persist_write != nullptr && (android_log_persist_write->logMask & i)) {
+ if (android_log_persist_write != nullptr) {
android_log_persist_write->write(log_id, &ts, vec, nr);
}
@@ -301,29 +174,6 @@
return ret;
}
-static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) {
- int ret, save_errno = errno;
-
- __android_log_lock();
-
- if (write_to_log == __write_to_log_init) {
- ret = __write_to_log_initialize();
- if (ret < 0) {
- __android_log_unlock();
- errno = save_errno;
- return ret;
- }
-
- write_to_log = __write_to_log_daemon;
- }
-
- __android_log_unlock();
-
- ret = write_to_log(log_id, vec, nr);
- errno = save_errno;
- return ret;
-}
-
int __android_log_write(int prio, const char* tag, const char* msg) {
return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
}
diff --git a/liblog/pmsg_writer.cpp b/liblog/pmsg_writer.cpp
index 54980d9..4f45780 100644
--- a/liblog/pmsg_writer.cpp
+++ b/liblog/pmsg_writer.cpp
@@ -25,68 +25,47 @@
#include <sys/types.h>
#include <time.h>
+#include <shared_mutex>
+
#include <log/log_properties.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
#include "log_portability.h"
#include "logger.h"
+#include "rwlock.h"
#include "uio.h"
-static int pmsgOpen();
-static void pmsgClose();
-static int pmsgAvailable(log_id_t logId);
-static int pmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
+static void PmsgClose();
+static int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
struct android_log_transport_write pmsgLoggerWrite = {
- .name = "pmsg",
- .logMask = 0,
- .context.fd = -1,
- .available = pmsgAvailable,
- .open = pmsgOpen,
- .close = pmsgClose,
- .write = pmsgWrite,
+ .close = PmsgClose,
+ .write = PmsgWrite,
};
-static int pmsgOpen() {
- int fd = atomic_load(&pmsgLoggerWrite.context.fd);
- if (fd < 0) {
- int i;
+static int pmsg_fd;
+static RwLock pmsg_fd_lock;
- fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- i = atomic_exchange(&pmsgLoggerWrite.context.fd, fd);
- if ((i >= 0) && (i != fd)) {
- close(i);
- }
+static void PmsgOpen() {
+ auto lock = std::unique_lock{pmsg_fd_lock};
+ if (pmsg_fd > 0) {
+ // Someone raced us and opened the socket already.
+ return;
}
- return fd;
+ pmsg_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
}
-static void pmsgClose() {
- int fd = atomic_exchange(&pmsgLoggerWrite.context.fd, -1);
- if (fd >= 0) {
- close(fd);
+static void PmsgClose() {
+ auto lock = std::unique_lock{pmsg_fd_lock};
+ if (pmsg_fd > 0) {
+ close(pmsg_fd);
}
+ pmsg_fd = 0;
}
-static int pmsgAvailable(log_id_t logId) {
- if (logId > LOG_ID_SECURITY) {
- return -EINVAL;
- }
- if ((logId != LOG_ID_SECURITY) && (logId != LOG_ID_EVENTS) && !__android_log_is_debuggable()) {
- return -EINVAL;
- }
- if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
- if (access("/dev/pmsg0", W_OK) == 0) {
- return 0;
- }
- return -EBADF;
- }
- return 1;
-}
-
-static int pmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
+static int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
static const unsigned headerLength = 2;
struct iovec newVec[nr + headerLength];
android_log_header_t header;
@@ -94,17 +73,31 @@
size_t i, payloadSize;
ssize_t ret;
- if ((logId == LOG_ID_EVENTS) && !__android_log_is_debuggable()) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
+ if (!__android_log_is_debuggable()) {
+ if (logId != LOG_ID_EVENTS && logId != LOG_ID_SECURITY) {
+ return -1;
}
- if (SNET_EVENT_LOG_TAG != *static_cast<uint32_t*>(vec[0].iov_base)) {
- return -EPERM;
+ if (logId == LOG_ID_EVENTS) {
+ if (vec[0].iov_len < 4) {
+ return -EINVAL;
+ }
+
+ if (SNET_EVENT_LOG_TAG != *static_cast<uint32_t*>(vec[0].iov_base)) {
+ return -EPERM;
+ }
}
}
- if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
+ auto lock = std::shared_lock{pmsg_fd_lock};
+
+ if (pmsg_fd <= 0) {
+ lock.unlock();
+ PmsgOpen();
+ lock.lock();
+ }
+
+ if (pmsg_fd <= 0) {
return -EBADF;
}
@@ -158,7 +151,7 @@
}
pmsgHeader.len += payloadSize;
- ret = TEMP_FAILURE_RETRY(writev(atomic_load(&pmsgLoggerWrite.context.fd), newVec, i));
+ ret = TEMP_FAILURE_RETRY(writev(pmsg_fd, newVec, i));
if (ret < 0) {
ret = errno ? -errno : -ENOTCONN;
}
@@ -193,7 +186,6 @@
/* Write a buffer as filename references (tag = <basedir>:<basename>) */
ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio, const char* filename,
const char* buf, size_t len) {
- bool weOpened;
size_t length, packet_len;
const char* tag;
char *cp, *slash;
@@ -233,7 +225,6 @@
vec[1].iov_base = (unsigned char*)tag;
vec[1].iov_len = length;
- weOpened = false;
for (ts.tv_nsec = 0, length = len; length; ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
ssize_t ret;
size_t transfer;
@@ -254,37 +245,15 @@
vec[2].iov_base = (unsigned char*)buf;
vec[2].iov_len = transfer;
- if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
- if (!weOpened) { /* Impossible for weOpened = true here */
- __android_log_lock();
- }
- weOpened = atomic_load(&pmsgLoggerWrite.context.fd) < 0;
- if (!weOpened) {
- __android_log_unlock();
- } else if (pmsgOpen() < 0) {
- __android_log_unlock();
- free(cp);
- return -EBADF;
- }
- }
-
- ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
+ ret = PmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
if (ret <= 0) {
- if (weOpened) {
- pmsgClose();
- __android_log_unlock();
- }
free(cp);
return ret ? ret : (len - length);
}
length -= transfer;
buf += transfer;
}
- if (weOpened) {
- pmsgClose();
- __android_log_unlock();
- }
free(cp);
return len;
}
diff --git a/liblog/rwlock.h b/liblog/rwlock.h
new file mode 100644
index 0000000..00f1806
--- /dev/null
+++ b/liblog/rwlock.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <pthread.h>
+
+// As of the end of Dec 2019, std::shared_mutex is *not* simply a pthread_rwlock, but rather a
+// combination of std::mutex and std::condition variable, which is obviously less efficient. This
+// immitates what std::shared_mutex should be doing and is compatible with std::shared_lock and
+// std::unique_lock.
+
+class RwLock {
+ public:
+ RwLock() {}
+ ~RwLock() {}
+
+ void lock() { pthread_rwlock_wrlock(&rwlock_); }
+ void unlock() { pthread_rwlock_unlock(&rwlock_); }
+
+ void lock_shared() { pthread_rwlock_rdlock(&rwlock_); }
+ void unlock_shared() { pthread_rwlock_unlock(&rwlock_); }
+
+ private:
+ pthread_rwlock_t rwlock_ = PTHREAD_RWLOCK_INITIALIZER;
+};
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
index 99df4ca..f58c524 100644
--- a/liblog/tests/Android.bp
+++ b/liblog/tests/Android.bp
@@ -62,6 +62,7 @@
"log_time_test.cpp",
"log_wrap_test.cpp",
"logprint_test.cpp",
+ "rwlock_test.cpp",
],
shared_libs: [
"libcutils",
diff --git a/liblog/tests/rwlock_test.cpp b/liblog/tests/rwlock_test.cpp
new file mode 100644
index 0000000..617d5c4
--- /dev/null
+++ b/liblog/tests/rwlock_test.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../rwlock.h"
+
+#include <chrono>
+#include <shared_mutex>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+using namespace std::literals;
+
+TEST(rwlock, reader_then_reader_lock) {
+ RwLock lock;
+
+ bool thread_ran = false;
+ auto read_guard = std::shared_lock{lock};
+
+ auto reader_thread = std::thread([&] {
+ auto read_guard = std::shared_lock{lock};
+ thread_ran = true;
+ });
+
+ auto end_time = std::chrono::steady_clock::now() + 1s;
+
+ while (std::chrono::steady_clock::now() < end_time) {
+ if (thread_ran) {
+ break;
+ }
+ }
+
+ EXPECT_EQ(true, thread_ran);
+
+ // Unlock the lock in case something went wrong, to ensure that we can still join() the thread.
+ read_guard.unlock();
+ reader_thread.join();
+}
+
+template <template <typename> typename L1, template <typename> typename L2>
+void TestBlockingLocks() {
+ RwLock lock;
+
+ bool thread_ran = false;
+ auto read_guard = L1{lock};
+
+ auto reader_thread = std::thread([&] {
+ auto read_guard = L2{lock};
+ thread_ran = true;
+ });
+
+ auto end_time = std::chrono::steady_clock::now() + 1s;
+
+ while (std::chrono::steady_clock::now() < end_time) {
+ if (thread_ran) {
+ break;
+ }
+ }
+
+ EXPECT_EQ(false, thread_ran);
+
+ read_guard.unlock();
+ reader_thread.join();
+
+ EXPECT_EQ(true, thread_ran);
+}
+
+TEST(rwlock, reader_then_writer_lock) {
+ TestBlockingLocks<std::shared_lock, std::unique_lock>();
+}
+
+TEST(rwlock, writer_then_reader_lock) {
+ TestBlockingLocks<std::unique_lock, std::shared_lock>();
+}
+
+TEST(rwlock, writer_then_writer_lock) {
+ TestBlockingLocks<std::unique_lock, std::unique_lock>();
+}
diff --git a/libstats/pull/stats_pull_atom_callback.cpp b/libstats/pull/stats_pull_atom_callback.cpp
index 011ab76..177bbba 100644
--- a/libstats/pull/stats_pull_atom_callback.cpp
+++ b/libstats/pull/stats_pull_atom_callback.cpp
@@ -22,7 +22,7 @@
#include <android/os/BnPullAtomCallback.h>
#include <android/os/IPullAtomResultReceiver.h>
-#include <android/os/IStatsManager.h>
+#include <android/os/IStatsd.h>
#include <android/util/StatsEventParcel.h>
#include <binder/IServiceManager.h>
#include "include/stats_pull_atom_callback.h"
@@ -90,10 +90,10 @@
};
static std::mutex pullAtomMutex;
-static android::sp<android::os::IStatsManager> sStatsd = nullptr;
+static android::sp<android::os::IStatsd> sStatsd = nullptr;
static std::map<int32_t, android::sp<StatsPullAtomCallbackInternal>> mPullers;
-static android::sp<android::os::IStatsManager> getStatsServiceLocked();
+static android::sp<android::os::IStatsd> getStatsServiceLocked();
class StatsDeathRecipient : public android::IBinder::DeathRecipient {
public:
@@ -106,7 +106,7 @@
if (sStatsd) {
sStatsd = nullptr;
}
- android::sp<android::os::IStatsManager> statsService = getStatsServiceLocked();
+ android::sp<android::os::IStatsd> statsService = getStatsServiceLocked();
if (statsService == nullptr) {
return;
}
@@ -120,7 +120,7 @@
static android::sp<StatsDeathRecipient> statsDeathRecipient = new StatsDeathRecipient();
-static android::sp<android::os::IStatsManager> getStatsServiceLocked() {
+static android::sp<android::os::IStatsd> getStatsServiceLocked() {
if (!sStatsd) {
// Fetch statsd.
const android::sp<android::IBinder> binder =
@@ -129,7 +129,7 @@
return nullptr;
}
binder->linkToDeath(statsDeathRecipient);
- sStatsd = android::interface_cast<android::os::IStatsManager>(binder);
+ sStatsd = android::interface_cast<android::os::IStatsd>(binder);
}
return sStatsd;
}
@@ -146,7 +146,7 @@
}
std::lock_guard<std::mutex> lg(pullAtomMutex);
- const android::sp<android::os::IStatsManager> statsService = getStatsServiceLocked();
+ const android::sp<android::os::IStatsd> statsService = getStatsServiceLocked();
if (statsService == nullptr) {
// Error - statsd not available
return;
diff --git a/libunwindstack/tests/DwarfCfaLogTest.cpp b/libunwindstack/tests/DwarfCfaLogTest.cpp
index 9dd0cdd..def4088 100644
--- a/libunwindstack/tests/DwarfCfaLogTest.cpp
+++ b/libunwindstack/tests/DwarfCfaLogTest.cpp
@@ -774,6 +774,6 @@
cfa_gnu_negative_offset_extended, cfa_register_override);
typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaLogTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfCfaLogTest, DwarfCfaLogTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfCfaLogTest, DwarfCfaLogTestTypes);
} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp
index dd71490..9c6ab05 100644
--- a/libunwindstack/tests/DwarfCfaTest.cpp
+++ b/libunwindstack/tests/DwarfCfaTest.cpp
@@ -963,6 +963,6 @@
cfa_register_override);
typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfCfaTest, DwarfCfaTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfCfaTest, DwarfCfaTestTypes);
} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index 2b36f17..b6f574a 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -825,6 +825,6 @@
GetFdeFromOffset64_lsda_address, GetFdeFromPc_interleaved);
typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index 4792fb5..46a25a4 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -128,6 +128,6 @@
REGISTER_TYPED_TEST_SUITE_P(DwarfEhFrameTest, GetFdeCieFromOffset32, GetFdeCieFromOffset64);
typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfEhFrameTest, DwarfEhFrameTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfEhFrameTest, DwarfEhFrameTestTypes);
} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 768a808..6aa3867 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -552,6 +552,6 @@
GetCieFde32, GetCieFde64, GetFdeFromPc_fde_not_found);
typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameWithHdrTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfEhFrameWithHdrTest, DwarfEhFrameWithHdrTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfEhFrameWithHdrTest, DwarfEhFrameWithHdrTestTypes);
} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfOpLogTest.cpp b/libunwindstack/tests/DwarfOpLogTest.cpp
index f4ade5d..8dbf6e8 100644
--- a/libunwindstack/tests/DwarfOpLogTest.cpp
+++ b/libunwindstack/tests/DwarfOpLogTest.cpp
@@ -68,6 +68,6 @@
REGISTER_TYPED_TEST_SUITE_P(DwarfOpLogTest, multiple_ops);
typedef ::testing::Types<uint32_t, uint64_t> DwarfOpLogTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfOpLogTest, DwarfOpLogTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfOpLogTest, DwarfOpLogTestTypes);
} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp
index 0898ec0..0e2d91a 100644
--- a/libunwindstack/tests/DwarfOpTest.cpp
+++ b/libunwindstack/tests/DwarfOpTest.cpp
@@ -1581,6 +1581,6 @@
is_dex_pc);
typedef ::testing::Types<uint32_t, uint64_t> DwarfOpTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfOpTest, DwarfOpTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfOpTest, DwarfOpTestTypes);
} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index a9d6dad..cac59b7 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -583,6 +583,6 @@
GetCfaLocationInfo_cie_not_cached, GetCfaLocationInfo_cie_cached, Log);
typedef ::testing::Types<uint32_t, uint64_t> DwarfSectionImplTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfSectionImplTest, DwarfSectionImplTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfSectionImplTest, DwarfSectionImplTestTypes);
} // namespace unwindstack
diff --git a/libunwindstack/tests/SymbolsTest.cpp b/libunwindstack/tests/SymbolsTest.cpp
index ae3c349..c58aeff 100644
--- a/libunwindstack/tests/SymbolsTest.cpp
+++ b/libunwindstack/tests/SymbolsTest.cpp
@@ -367,6 +367,6 @@
symtab_read_cached, get_global);
typedef ::testing::Types<Elf32_Sym, Elf64_Sym> SymbolsTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, SymbolsTest, SymbolsTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, SymbolsTest, SymbolsTestTypes);
} // namespace unwindstack
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index ebc0cde..2dbdb60 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -72,7 +72,7 @@
#
# create some directories (some are mount points) and symlinks
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
- dev proc sys system data odm oem acct config storage mnt apex debug_ramdisk \
+ dev proc sys system data data_mirror odm oem acct config storage mnt apex debug_ramdisk \
linkerconfig $(BOARD_ROOT_EXTRA_FOLDERS)); \
ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
diff --git a/rootdir/avb/Android.mk b/rootdir/avb/Android.mk
index 5dc019c..80573fb 100644
--- a/rootdir/avb/Android.mk
+++ b/rootdir/avb/Android.mk
@@ -16,6 +16,21 @@
include $(BUILD_PREBUILT)
#######################################
+# q-developer-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := q-developer-gsi.avbpubkey
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
+else
+LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb
+endif
+
+include $(BUILD_PREBUILT)
+
+#######################################
# r-gsi.avbpubkey
include $(CLEAR_VARS)
diff --git a/rootdir/avb/q-developer-gsi.avbpubkey b/rootdir/avb/q-developer-gsi.avbpubkey
new file mode 100644
index 0000000..0ace69d
--- /dev/null
+++ b/rootdir/avb/q-developer-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 2ec0669..b89c45e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -650,12 +650,35 @@
mkdir /data/user 0711 system system encryption=None
mkdir /data/user_de 0711 system system encryption=None
- symlink /data/data /data/user/0
+
+ # Unlink /data/user/0 if we previously symlink it to /data/data
+ rm /data/user/0
+
+ # Bind mount /data/user/0 to /data/data
+ mkdir /data/user/0 0700 system system encryption=None
+ mount none /data/data /data/user/0 bind rec
# Special-case /data/media/obb per b/64566063
mkdir /data/media 0770 media_rw media_rw encryption=None
mkdir /data/media/obb 0770 media_rw media_rw encryption=Attempt
+ # 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
+ restorecon /data_mirror
+ mkdir /data_mirror/data_ce 0700 root root
+ mkdir /data_mirror/data_de 0700 root root
+
+ # Create CE and DE data directory for default volume
+ mkdir /data_mirror/data_ce/null 0700 root root
+ mkdir /data_mirror/data_de/null 0700 root root
+
+ # Bind mount CE and DE data directory to mirror's default volume directory
+ mount none /data/user /data_mirror/data_ce/null bind rec
+ mount none /data/user_de /data_mirror/data_de/null bind rec
+
mkdir /data/cache 0770 system cache encryption=Require
mkdir /data/cache/recovery 0770 system cache
mkdir /data/cache/backup_stage 0700 system system
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index a1888fc..02d34ba 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -19,7 +19,9 @@
updatable
seclabel u:r:adbd:s0
-on boot
+# Set default value on sys.usb.configfs early in boot sequence. It will be
+# overridden in `on boot` action of init.hardware.rc.
+on init
setprop sys.usb.configfs 0
# Used to disable USB when switching states
@@ -133,3 +135,8 @@
on property:sys.usb.typec.power_role=sink
write /sys/class/dual_role_usb/otg_default/power_role ${sys.usb.typec.power_role}
setprop sys.usb.typec.state ${sys.usb.typec.power_role}
+
+on userspace-reboot-requested
+ setprop sys.usb.config ""
+ setprop sys.usb.configfs ""
+ setprop sys.usb.state ""
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index ec4f6ab..b5a5fb6 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -12,6 +12,7 @@
required: [
"auditctl",
"awk",
+ "bc",
"bzip2",
"ldd",
"logwrapper",