Merge "Added fuzzer for Unwinder"
diff --git a/adb/client/transport_mdns.cpp b/adb/client/transport_mdns.cpp
index 9611212..a0fc9ca 100644
--- a/adb/client/transport_mdns.cpp
+++ b/adb/client/transport_mdns.cpp
@@ -249,6 +249,9 @@
return false;
}
+ // Remove any services with the same instance name, as it may be a stale registration.
+ removeDNSService(regType_.c_str(), serviceName_.c_str());
+
// Add to the service registry before trying to auto-connect, since socket_spec_connect will
// check these registries for the ip address when connecting via mdns instance name.
int adbSecureServiceType = serviceIndex();
@@ -268,13 +271,6 @@
return false;
}
- if (!services->empty()) {
- // Remove the previous resolved service, if any.
- services->erase(std::remove_if(services->begin(), services->end(),
- [&](std::unique_ptr<ResolvedService>& service) {
- return (serviceName_ == service->serviceName());
- }));
- }
services->push_back(std::unique_ptr<ResolvedService>(this));
if (adb_DNSServiceShouldAutoConnect(regType_.c_str(), serviceName_.c_str())) {
@@ -327,6 +323,8 @@
static bool connectByServiceName(const ServiceRegistry& services,
const std::string& service_name);
+ static void removeDNSService(const char* regType, const char* serviceName);
+
private:
int clientVersion_ = ADB_SECURE_CLIENT_VERSION;
std::string addr_format_;
@@ -396,6 +394,37 @@
return false;
}
+// static
+void ResolvedService::removeDNSService(const char* regType, const char* serviceName) {
+ D("%s: regType=[%s] serviceName=[%s]", __func__, regType, serviceName);
+ int index = adb_DNSServiceIndexByName(regType);
+ ServiceRegistry* services;
+ switch (index) {
+ case kADBTransportServiceRefIndex:
+ services = sAdbTransportServices;
+ break;
+ case kADBSecurePairingServiceRefIndex:
+ services = sAdbSecurePairingServices;
+ break;
+ case kADBSecureConnectServiceRefIndex:
+ services = sAdbSecureConnectServices;
+ break;
+ default:
+ return;
+ }
+
+ if (services->empty()) {
+ return;
+ }
+
+ std::string sName(serviceName);
+ services->erase(std::remove_if(services->begin(), services->end(),
+ [&sName](std::unique_ptr<ResolvedService>& service) {
+ return (sName == service->serviceName());
+ }),
+ services->end());
+}
+
void adb_secure_foreach_pairing_service(const char* service_name,
adb_secure_foreach_service_callback cb) {
ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices, service_name, cb);
@@ -481,35 +510,6 @@
std::string regType_;
};
-static void adb_RemoveDNSService(const char* regType, const char* serviceName) {
- D("%s: regType=[%s] serviceName=[%s]", __func__, regType, serviceName);
- int index = adb_DNSServiceIndexByName(regType);
- ResolvedService::ServiceRegistry* services;
- switch (index) {
- case kADBTransportServiceRefIndex:
- services = ResolvedService::sAdbTransportServices;
- break;
- case kADBSecurePairingServiceRefIndex:
- services = ResolvedService::sAdbSecurePairingServices;
- break;
- case kADBSecureConnectServiceRefIndex:
- services = ResolvedService::sAdbSecureConnectServices;
- break;
- default:
- return;
- }
-
- if (services->empty()) {
- return;
- }
-
- std::string sName(serviceName);
- services->erase(std::remove_if(services->begin(), services->end(),
- [&sName](std::unique_ptr<ResolvedService>& service) {
- return (sName == service->serviceName());
- }));
-}
-
// Returns the version the device wanted to advertise,
// or -1 if parsing fails.
static int parse_version_from_txt_record(uint16_t txtLen, const unsigned char* txtRecord) {
@@ -612,7 +612,7 @@
} else {
D("%s: Discover lost serviceName=[%s] regtype=[%s] domain=[%s]", __func__, serviceName,
regtype, domain);
- adb_RemoveDNSService(regtype, serviceName);
+ ResolvedService::removeDNSService(regtype, serviceName);
}
}
diff --git a/adb/test_adb.py b/adb/test_adb.py
index b9f0d54..a32d875 100755
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -618,21 +618,37 @@
finally:
zeroconf_ctx.unregister_service(info)
+@contextlib.contextmanager
+def zeroconf_register_services(zeroconf_ctx, infos):
+ """Context manager for multiple zeroconf services
+
+ Registers all services given and unregisters all on cleanup. Returns the ServiceInfo
+ list supplied.
+ """
+
+ try:
+ for info in infos:
+ zeroconf_ctx.register_service(info)
+ yield infos
+ finally:
+ for info in infos:
+ zeroconf_ctx.unregister_service(info)
+
"""Should match the service names listed in adb_mdns.h"""
class MdnsTest:
"""Tests for adb mdns."""
+ @staticmethod
+ def _mdns_services(port):
+ output = subprocess.check_output(["adb", "-P", str(port), "mdns", "services"])
+ return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
+
+ @staticmethod
+ def _devices(port):
+ output = subprocess.check_output(["adb", "-P", str(port), "devices"])
+ return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
+
class Base(unittest.TestCase):
- @staticmethod
- def _mdns_services(port):
- output = subprocess.check_output(["adb", "-P", str(port), "mdns", "services"])
- return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
-
- @staticmethod
- def _devices(port):
- output = subprocess.check_output(["adb", "-P", str(port), "devices"])
- return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
-
@contextlib.contextmanager
def _adb_mdns_connect(self, server_port, mdns_instance, serial, should_connect):
"""Context manager for an ADB connection.
@@ -691,6 +707,50 @@
for line in MdnsTest._mdns_services(server_port)))
@unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
+ def test_mdns_services_register_unregister_multiple(self):
+ """Ensure that `adb mdns services` correctly adds and removes multiple services
+ """
+ from zeroconf import IPVersion, ServiceInfo
+
+ with adb_server() as server_port:
+ output = subprocess.check_output(["adb", "-P", str(server_port),
+ "mdns", "services"]).strip()
+ self.assertTrue(output.startswith(b"List of discovered mdns services"))
+
+ """TODO(joshuaduong): Add ipv6 tests once we have it working in adb"""
+ """Register/Unregister a service"""
+ with zeroconf_context(IPVersion.V4Only) as zc:
+ srvs = {
+ 'mdns_name': ["testservice0", "testservice1", "testservice2"],
+ 'mdns_type': "_" + self.service_name + "._tcp.",
+ 'ipaddr': [
+ socket.inet_aton("192.168.0.1"),
+ socket.inet_aton("10.0.0.255"),
+ socket.inet_aton("172.16.1.100")],
+ 'port': [10000, 20000, 65535]}
+ srv_infos = []
+ for i in range(len(srvs['mdns_name'])):
+ srv_infos.append(ServiceInfo(
+ srvs['mdns_type'] + "local.",
+ name=srvs['mdns_name'][i] + "." + srvs['mdns_type'] + "local.",
+ addresses=[srvs['ipaddr'][i]],
+ port=srvs['port'][i]))
+
+ """ Register all devices, then unregister"""
+ with zeroconf_register_services(zc, srv_infos) as infos:
+ """Give adb some time to register the service"""
+ time.sleep(1)
+ for i in range(len(srvs['mdns_name'])):
+ self.assertTrue(any((srvs['mdns_name'][i] in line and srvs['mdns_type'] in line)
+ for line in MdnsTest._mdns_services(server_port)))
+
+ """Give adb some time to unregister the service"""
+ time.sleep(1)
+ for i in range(len(srvs['mdns_name'])):
+ self.assertFalse(any((srvs['mdns_name'][i] in line and srvs['mdns_type'] in line)
+ for line in MdnsTest._mdns_services(server_port)))
+
+ @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
def test_mdns_connect(self):
"""Ensure that `adb connect` by mdns instance name works (for non-pairing services)
"""
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 5d6cee4..8979e9a 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -436,6 +436,8 @@
{"reboot,userspace_failed,watchdog_fork", 188},
{"reboot,userspace_failed,*", 189},
{"reboot,mount_userdata_failed", 190},
+ {"reboot,forcedsilent", 191},
+ {"reboot,forcednonsilent", 192},
};
// Converts a string value representing the reason the system booted to an
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index cd64599..ac784b2 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -149,6 +149,14 @@
darwin: {
enabled: false,
},
+ vendor: {
+ cflags: [
+ // Skipping entries in fstab should only be done in a system
+ // process as the config file is in /system_ext.
+ // Remove the op from the vendor variant.
+ "-DNO_SKIP_MOUNT",
+ ],
+ },
},
export_include_dirs: ["include_fstab"],
header_libs: [
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index f333a85..54102ec 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -696,7 +696,9 @@
TransformFstabForDsu(fstab, Split(lp_names, ","));
}
+#ifndef NO_SKIP_MOUNT
SkipMountingPartitions(fstab);
+#endif
EnableMandatoryFlags(fstab);
return true;
@@ -726,11 +728,14 @@
return false;
}
+#ifndef NO_SKIP_MOUNT
SkipMountingPartitions(fstab);
+#endif
return true;
}
+#ifndef NO_SKIP_MOUNT
// For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
// between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
// device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because
@@ -762,6 +767,7 @@
return true;
}
+#endif
// Loads the fstab file and combines with fstab entries passed in from device tree.
bool ReadDefaultFstab(Fstab* fstab) {
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 250cb82..8788b5a 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -280,5 +280,12 @@
return android::base::Join(argv, " ");
}
+std::string DmTargetUser::GetParameterString() const {
+ std::vector<std::string> argv;
+ argv.push_back(std::to_string(start()));
+ argv.push_back(std::to_string(size()));
+ return android::base::Join(argv, " ");
+}
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index f986cfe..57e3884 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -309,6 +309,14 @@
bool is_hw_wrapped_ = false;
};
+class DmTargetUser final : public DmTarget {
+ public:
+ DmTargetUser(uint64_t start, uint64_t length) : DmTarget(start, length) {}
+
+ std::string name() const override { return "user"; }
+ std::string GetParameterString() const override;
+};
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index c37d70e..ace6210 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -205,11 +205,18 @@
}
}
- if (IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false) &&
- !always_keep_source_slot) {
- if (!UpdateMetadataForInPlaceSnapshot(metadata.get(), source_slot_number,
- target_slot_number)) {
- return nullptr;
+ if (IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false)) {
+ if (always_keep_source_slot) {
+ // always_keep_source_slot implies the target build does not support snapshots.
+ // Clear unsupported attributes.
+ SetMetadataHeaderV0(metadata.get());
+ } else {
+ // !always_keep_source_slot implies the target build supports snapshots. Do snapshot
+ // updates.
+ if (!UpdateMetadataForInPlaceSnapshot(metadata.get(), source_slot_number,
+ target_slot_number)) {
+ return nullptr;
+ }
}
}
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 89a47b1..f2e7370 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -208,8 +208,10 @@
// metadata may not have the target slot's devices listed yet, in which
// case, it is automatically upgraded to include all available block
// devices.
- // If |always_keep_source_slot| is set, on a Virtual A/B device, source slot
- // partitions are kept. This is useful when applying a downgrade package.
+ // If |always_keep_source_slot| is set, on a Virtual A/B device
+ // - source slot partitions are kept.
+ // - UPDATED flag is cleared.
+ // This is useful when applying a downgrade package.
static std::unique_ptr<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener,
const std::string& source_partition,
uint32_t source_slot_number,
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 48c5c83..d8e171b 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -15,6 +15,7 @@
*/
#include <fcntl.h>
+#include <inttypes.h>
#include <stdint.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -29,6 +30,7 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <ext4_utils/ext4_utils.h>
#include <openssl/sha.h>
@@ -285,5 +287,42 @@
return true;
}
+inline std::string ToHexString(uint64_t value) {
+ return android::base::StringPrintf("0x%" PRIx64, value);
+}
+
+void SetMetadataHeaderV0(LpMetadata* metadata) {
+ if (metadata->header.minor_version <= LP_METADATA_MINOR_VERSION_MIN) {
+ return;
+ }
+ LINFO << "Forcefully setting metadata header version " << LP_METADATA_MAJOR_VERSION << "."
+ << metadata->header.minor_version << " to " << LP_METADATA_MAJOR_VERSION << "."
+ << LP_METADATA_MINOR_VERSION_MIN;
+ metadata->header.minor_version = LP_METADATA_MINOR_VERSION_MIN;
+ metadata->header.header_size = sizeof(LpMetadataHeaderV1_0);
+
+ // Retrofit Virtual A/B devices should have version 10.1, so flags shouldn't be set.
+ // Warn if this is the case, but zero it out anyways.
+ if (metadata->header.flags) {
+ LWARN << "Zeroing unexpected flags: " << ToHexString(metadata->header.flags);
+ }
+
+ // Zero out all fields beyond LpMetadataHeaderV0.
+ static_assert(sizeof(metadata->header) > sizeof(LpMetadataHeaderV1_0));
+ memset(reinterpret_cast<uint8_t*>(&metadata->header) + sizeof(LpMetadataHeaderV1_0), 0,
+ sizeof(metadata->header) - sizeof(LpMetadataHeaderV1_0));
+
+ // Clear partition attributes unknown to V0.
+ // On retrofit Virtual A/B devices, UPDATED flag may be set, so only log info here.
+ for (auto& partition : metadata->partitions) {
+ if (partition.attributes & ~LP_PARTITION_ATTRIBUTE_MASK_V0) {
+ LINFO << "Clearing " << GetPartitionName(partition)
+ << " partition attribute: " << ToHexString(partition.attributes);
+ }
+
+ partition.attributes &= LP_PARTITION_ATTRIBUTE_MASK_V0;
+ }
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index c4fe3ed..aa3a6a0 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -103,6 +103,10 @@
bool UpdateMetadataForInPlaceSnapshot(LpMetadata* metadata, uint32_t source_slot_number,
uint32_t target_slot_number);
+// Forcefully set metadata header version to 1.0, clearing any incompatible flags and attributes
+// so that when downgrading to a build with liblp V0, the device still boots.
+void SetMetadataHeaderV0(LpMetadata* metadata);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 55214f5..7488bda 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1846,7 +1846,7 @@
PLOG(ERROR) << "Open failed: " << file;
return nullptr;
}
- if (lock_flags != 0 && flock(fd, lock_flags) < 0) {
+ if (lock_flags != 0 && TEMP_FAILURE_RETRY(flock(fd, lock_flags)) < 0) {
PLOG(ERROR) << "Acquire flock failed: " << file;
return nullptr;
}
@@ -1857,7 +1857,7 @@
}
SnapshotManager::LockedFile::~LockedFile() {
- if (flock(fd_, LOCK_UN) < 0) {
+ if (TEMP_FAILURE_RETRY(flock(fd_, LOCK_UN)) < 0) {
PLOG(ERROR) << "Failed to unlock file: " << path_;
}
}
@@ -2520,7 +2520,19 @@
LOG(INFO) << "EnsureMetadataMounted does nothing in Android mode.";
return std::unique_ptr<AutoUnmountDevice>(new AutoUnmountDevice());
}
- return AutoUnmountDevice::New(device_->GetMetadataDir());
+ auto ret = AutoUnmountDevice::New(device_->GetMetadataDir());
+ if (ret == nullptr) return nullptr;
+
+ // In rescue mode, it is possible to erase and format metadata, but /metadata/ota is not
+ // created to execute snapshot updates. Hence, subsequent calls is likely to fail because
+ // Lock*() fails. By failing early and returning nullptr here, update_engine_sideload can
+ // treat this case as if /metadata is not mounted.
+ if (!LockShared()) {
+ LOG(WARNING) << "/metadata is mounted, but errors occur when acquiring a shared lock. "
+ "Subsequent calls to SnapshotManager will fail. Unmounting /metadata now.";
+ return nullptr;
+ }
+ return ret;
}
bool SnapshotManager::HandleImminentDataWipe(const std::function<void()>& callback) {
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 2738457..7a3d9a9 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -174,6 +174,8 @@
}
return std::make_unique<DmTargetSnapshot>(start_sector, num_sectors, base_device,
cow_device, mode, chunk_size);
+ } else if (target_type == "user") {
+ return std::make_unique<DmTargetUser>(start_sector, num_sectors);
} else {
std::cerr << "Unrecognized target type: " << target_type << std::endl;
return nullptr;
diff --git a/init/Android.bp b/init/Android.bp
index edf9099..3f2cd07 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -130,6 +130,7 @@
"libpropertyinfoserializer",
"libpropertyinfoparser",
"libsnapshot_init",
+ "libxml2",
"lib_apex_manifest_proto_lite",
"update_metadata-protos",
],
@@ -164,6 +165,9 @@
"selinux_policy_version",
],
srcs: init_common_sources + init_device_sources,
+ generated_sources: [
+ "apex-info-list",
+ ],
whole_static_libs: [
"libcap",
"com.android.sysprop.apex",
@@ -178,6 +182,12 @@
target: {
recovery: {
cflags: ["-DRECOVERY"],
+ exclude_static_libs: [
+ "libxml2",
+ ],
+ exclude_generated_sources: [
+ "apex-info-list",
+ ],
exclude_shared_libs: [
"libbinder",
"libutils",
@@ -212,6 +222,9 @@
target: {
recovery: {
cflags: ["-DRECOVERY"],
+ exclude_static_libs: [
+ "libxml2",
+ ],
exclude_shared_libs: [
"libbinder",
"libutils",
diff --git a/init/devices.cpp b/init/devices.cpp
index 9fbec64..53ca875 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -193,7 +193,8 @@
while (directory != "/" && directory != ".") {
std::string subsystem_link_path;
if (Realpath(directory + "/subsystem", &subsystem_link_path) &&
- subsystem_link_path == sysfs_mount_point_ + "/bus/platform") {
+ (subsystem_link_path == sysfs_mount_point_ + "/bus/platform" ||
+ subsystem_link_path == sysfs_mount_point_ + "/bus/amba")) {
// We need to remove the mount point that we added above before returning.
directory.erase(0, sysfs_mount_point_.size());
*platform_device_path = directory;
diff --git a/init/init.cpp b/init/init.cpp
index 631db8e..ba880ea 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -868,6 +868,8 @@
// Run all property triggers based on current state of the properties.
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
+ // Restore prio before main loop
+ setpriority(PRIO_PROCESS, 0, 0);
while (true) {
// By default, sleep until something happens.
auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
diff --git a/init/main.cpp b/init/main.cpp
index 38bc74b..23f5530 100644
--- a/init/main.cpp
+++ b/init/main.cpp
@@ -52,7 +52,8 @@
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
#endif
-
+ // Boost prio which will be restored later
+ setpriority(PRIO_PROCESS, 0, -20);
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index b9d5d67..f8359bc 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -27,10 +27,19 @@
#include <android-base/properties.h>
#include <android-base/result.h>
#include <android-base/unique_fd.h>
-#include <apex_manifest.pb.h>
#include "util.h"
+#ifndef RECOVERY
+#define ACTIVATE_FLATTENED_APEX 1
+#endif
+
+#ifdef ACTIVATE_FLATTENED_APEX
+#include <apex_manifest.pb.h>
+#include <com_android_apex.h>
+#include <selinux/android.h>
+#endif // ACTIVATE_FLATTENED_APEX
+
namespace android {
namespace init {
namespace {
@@ -106,6 +115,8 @@
return updatable;
}
+#ifdef ACTIVATE_FLATTENED_APEX
+
static Result<void> MountDir(const std::string& path, const std::string& mount_path) {
if (int ret = mkdir(mount_path.c_str(), 0755); ret != 0 && errno != EEXIST) {
return ErrnoError() << "Could not create mount point " << mount_path;
@@ -116,7 +127,7 @@
return {};
}
-static Result<std::string> GetApexName(const std::string& apex_dir) {
+static Result<apex::proto::ApexManifest> GetApexManifest(const std::string& apex_dir) {
const std::string manifest_path = apex_dir + "/apex_manifest.pb";
std::string content;
if (!android::base::ReadFileToString(manifest_path, &content)) {
@@ -126,11 +137,12 @@
if (!manifest.ParseFromString(content)) {
return Error() << "Can't parse manifest file: " << manifest_path;
}
- return manifest.name();
+ return manifest;
}
+template <typename Fn>
static Result<void> ActivateFlattenedApexesFrom(const std::string& from_dir,
- const std::string& to_dir) {
+ const std::string& to_dir, Fn on_activate) {
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(from_dir.c_str()), closedir);
if (!dir) {
return {};
@@ -140,15 +152,16 @@
if (entry->d_name[0] == '.') continue;
if (entry->d_type == DT_DIR) {
const std::string apex_path = from_dir + "/" + entry->d_name;
- const auto apex_name = GetApexName(apex_path);
- if (!apex_name.ok()) {
- LOG(ERROR) << apex_path << " is not an APEX directory: " << apex_name.error();
+ const auto apex_manifest = GetApexManifest(apex_path);
+ if (!apex_manifest.ok()) {
+ LOG(ERROR) << apex_path << " is not an APEX directory: " << apex_manifest.error();
continue;
}
- const std::string mount_path = to_dir + "/" + (*apex_name);
+ const std::string mount_path = to_dir + "/" + apex_manifest->name();
if (auto result = MountDir(apex_path, mount_path); !result.ok()) {
return result;
}
+ on_activate(apex_path, *apex_manifest);
}
}
return {};
@@ -167,15 +180,37 @@
"/vendor/apex",
};
+ std::vector<com::android::apex::ApexInfo> apex_infos;
+ auto on_activate = [&](const std::string& apex_path,
+ const apex::proto::ApexManifest& apex_manifest) {
+ apex_infos.emplace_back(apex_manifest.name(), apex_path, apex_path, apex_manifest.version(),
+ apex_manifest.versionname(), /*isFactory=*/true, /*isActive=*/true);
+ };
+
for (const auto& dir : kBuiltinDirsForApexes) {
- if (auto result = ActivateFlattenedApexesFrom(dir, kApexTop); !result.ok()) {
+ if (auto result = ActivateFlattenedApexesFrom(dir, kApexTop, on_activate); !result.ok()) {
LOG(ERROR) << result.error();
return false;
}
}
+
+ std::ostringstream oss;
+ com::android::apex::ApexInfoList apex_info_list(apex_infos);
+ com::android::apex::write(oss, apex_info_list);
+ const std::string kApexInfoList = kApexTop + "/apex-info-list.xml";
+ if (!android::base::WriteStringToFile(oss.str(), kApexInfoList)) {
+ PLOG(ERROR) << "Failed to write " << kApexInfoList;
+ return false;
+ }
+ if (selinux_android_restorecon(kApexInfoList.c_str(), 0) != 0) {
+ PLOG(ERROR) << "selinux_android_restorecon(" << kApexInfoList << ") failed";
+ }
+
return true;
}
+#endif // ACTIVATE_FLATTENED_APEX
+
static android::base::unique_fd bootstrap_ns_fd;
static android::base::unique_fd default_ns_fd;
@@ -269,9 +304,9 @@
default_ns_fd.reset(OpenMountNamespace());
default_ns_id = GetMountNamespaceId();
}
-
+#ifdef ACTIVATE_FLATTENED_APEX
success &= ActivateFlattenedApexesIfPossible();
-
+#endif
LOG(INFO) << "SetupMountNamespaces done";
return success;
}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 612854d..b593b62 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -51,6 +51,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -74,6 +75,7 @@
using namespace std::literals;
using android::base::GetProperty;
+using android::base::ParseInt;
using android::base::ReadFileToString;
using android::base::Split;
using android::base::StartsWith;
@@ -886,24 +888,60 @@
load_properties_from_file("/prop.default", nullptr, &properties);
}
+ // /<part>/etc/build.prop is the canonical location of the build-time properties since S.
+ // Falling back to /<part>/defalt.prop and /<part>/build.prop only when legacy path has to
+ // be supported, which is controlled by the support_legacy_path_until argument.
+ const auto load_properties_from_partition = [&properties](const std::string& partition,
+ int support_legacy_path_until) {
+ auto path = "/" + partition + "/etc/build.prop";
+ if (load_properties_from_file(path.c_str(), nullptr, &properties)) {
+ return;
+ }
+ // To read ro.<partition>.build.version.sdk, temporarily load the legacy paths into a
+ // separate map. Then by comparing its value with legacy_version, we know that if the
+ // partition is old enough so that we need to respect the legacy paths.
+ std::map<std::string, std::string> temp;
+ auto legacy_path1 = "/" + partition + "/default.prop";
+ auto legacy_path2 = "/" + partition + "/build.prop";
+ load_properties_from_file(legacy_path1.c_str(), nullptr, &temp);
+ load_properties_from_file(legacy_path2.c_str(), nullptr, &temp);
+ bool support_legacy_path = false;
+ auto version_prop_name = "ro." + partition + ".build.version.sdk";
+ auto it = temp.find(version_prop_name);
+ if (it == temp.end()) {
+ // This is embarassing. Without the prop, we can't determine how old the partition is.
+ // Let's be conservative by assuming it is very very old.
+ support_legacy_path = true;
+ } else if (int value;
+ ParseInt(it->second.c_str(), &value) && value <= support_legacy_path_until) {
+ support_legacy_path = true;
+ }
+ if (support_legacy_path) {
+ // We don't update temp into properties directly as it might skip any (future) logic
+ // for resolving duplicates implemented in load_properties_from_file. Instead, read
+ // the files again into the properties map.
+ load_properties_from_file(legacy_path1.c_str(), nullptr, &properties);
+ load_properties_from_file(legacy_path2.c_str(), nullptr, &properties);
+ } else {
+ LOG(FATAL) << legacy_path1 << " and " << legacy_path2 << " were not loaded "
+ << "because " << version_prop_name << "(" << it->second << ") is newer "
+ << "than " << support_legacy_path_until;
+ }
+ };
+
+ // Order matters here. The more the partition is specific to a product, the higher its
+ // precedence is.
load_properties_from_file("/system/build.prop", nullptr, &properties);
- load_properties_from_file("/system_ext/build.prop", nullptr, &properties);
-
- // TODO(b/117892318): uncomment the following condition when vendor.imgs for
- // aosp_* targets are all updated.
-// if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_R__) {
- load_properties_from_file("/vendor/default.prop", nullptr, &properties);
-// }
+ load_properties_from_partition("system_ext", /* support_legacy_path_until */ 30);
+ // TODO(b/117892318): uncomment the following condition when vendor.imgs for aosp_* targets are
+ // all updated.
+ // if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_R__) {
+ load_properties_from_file("/vendor/default.prop", nullptr, &properties);
+ // }
load_properties_from_file("/vendor/build.prop", nullptr, &properties);
+ load_properties_from_partition("odm", /* support_legacy_path_until */ 28);
+ load_properties_from_partition("product", /* support_legacy_path_until */ 30);
- if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
- load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);
- } else {
- load_properties_from_file("/odm/default.prop", nullptr, &properties);
- load_properties_from_file("/odm/build.prop", nullptr, &properties);
- }
-
- load_properties_from_file("/product/build.prop", nullptr, &properties);
load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
if (access(kDebugRamdiskProp, R_OK) == 0) {
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index f3dd538..9d4ea8c 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -18,6 +18,8 @@
#include <fcntl.h>
#include <poll.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include <unistd.h>
#include <android-base/file.h>
@@ -181,6 +183,8 @@
trigger_shutdown = [](const std::string& command) { shutdown_command = command; };
auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
+ // Restore prio before main loop
+ setpriority(PRIO_PROCESS, 0, 0);
subcontext_process.MainLoop();
return 0;
}
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 7514b61..54659c5 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -321,6 +321,8 @@
while (waitpid(-1, nullptr, WNOHANG) > 0) {
}
+ // Restore prio before main loop
+ setpriority(PRIO_PROCESS, 0, 0);
uevent_listener.Poll([&uevent_handlers](const Uevent& uevent) {
for (auto& uevent_handler : uevent_handlers) {
uevent_handler->HandleUevent(uevent);
diff --git a/liblog/logprint.cpp b/liblog/logprint.cpp
index 238431f..a5c5edd 100644
--- a/liblog/logprint.cpp
+++ b/liblog/logprint.cpp
@@ -78,18 +78,21 @@
static bool descriptive_output = false;
/*
- * gnome-terminal color tags
- * See http://misc.flogisoft.com/bash/tip_colors_and_formatting
- * for ideas on how to set the forground color of the text for xterm.
- * The color manipulation character stream is defined as:
- * ESC [ 3 8 ; 5 ; <color#> m
+ * 8-bit color tags. See ECMA-48 Set Graphics Rendition in
+ * [console_codes(4)](https://man7.org/linux/man-pages/man4/console_codes.4.html).
+ *
+ * The text manipulation character stream is defined as:
+ * ESC [ <parameter #> m
+ *
+ * We use "set <color> foreground" escape sequences instead of
+ * "256/24-bit foreground color". This allows colors to render
+ * according to user preferences in terminal emulator settings
*/
-#define ANDROID_COLOR_BLUE 75
-#define ANDROID_COLOR_DEFAULT 231
-#define ANDROID_COLOR_GREEN 40
-#define ANDROID_COLOR_ORANGE 166
-#define ANDROID_COLOR_RED 196
-#define ANDROID_COLOR_YELLOW 226
+#define ANDROID_COLOR_BLUE 34
+#define ANDROID_COLOR_DEFAULT 39
+#define ANDROID_COLOR_GREEN 32
+#define ANDROID_COLOR_RED 31
+#define ANDROID_COLOR_YELLOW 33
static FilterInfo* filterinfo_new(const char* tag, android_LogPriority pri) {
FilterInfo* p_ret;
@@ -165,7 +168,7 @@
case ANDROID_LOG_VERBOSE: return ANDROID_COLOR_DEFAULT;
case ANDROID_LOG_DEBUG: return ANDROID_COLOR_BLUE;
case ANDROID_LOG_INFO: return ANDROID_COLOR_GREEN;
- case ANDROID_LOG_WARN: return ANDROID_COLOR_ORANGE;
+ case ANDROID_LOG_WARN: return ANDROID_COLOR_YELLOW;
case ANDROID_LOG_ERROR: return ANDROID_COLOR_RED;
case ANDROID_LOG_FATAL: return ANDROID_COLOR_RED;
case ANDROID_LOG_SILENT: return ANDROID_COLOR_DEFAULT;
@@ -1499,7 +1502,7 @@
*/
if (p_format->colored_output) {
prefixLen =
- snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[38;5;%dm", colorFromPri(entry->priority));
+ snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[%dm", colorFromPri(entry->priority));
prefixLen = MIN(prefixLen, sizeof(prefixBuf));
const char suffixContents[] = "\x1B[0m";
diff --git a/libmodprobe/include/modprobe/modprobe.h b/libmodprobe/include/modprobe/modprobe.h
index 4806b08..baee4f9 100644
--- a/libmodprobe/include/modprobe/modprobe.h
+++ b/libmodprobe/include/modprobe/modprobe.h
@@ -37,7 +37,6 @@
void ResetModuleCount() { module_count_ = 0; }
int GetModuleCount() { return module_count_; }
void EnableBlocklist(bool enable);
- void EnableVerbose(bool enable);
private:
std::string MakeCanonical(const std::string& module_path);
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index 5a6ae8b..bbdd317 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -343,14 +343,6 @@
blocklist_enabled = enable;
}
-void Modprobe::EnableVerbose(bool enable) {
- if (enable) {
- android::base::SetMinimumLogSeverity(android::base::VERBOSE);
- } else {
- android::base::SetMinimumLogSeverity(android::base::INFO);
- }
-}
-
std::vector<std::string> Modprobe::GetDependencies(const std::string& module) {
auto it = module_deps_.find(module);
if (it == module_deps_.end()) {
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 4af4589..a638fca 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -44,6 +44,11 @@
#define TASK_PROFILE_DB_FILE "/etc/task_profiles.json"
#define TASK_PROFILE_DB_VENDOR_FILE "/vendor/etc/task_profiles.json"
+void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) {
+ controller_ = controller;
+ file_name_ = file_name;
+}
+
bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const {
std::string subgroup;
if (!controller()->GetTaskGroup(tid, &subgroup)) {
@@ -380,15 +385,16 @@
std::string controller_name = attr[i]["Controller"].asString();
std::string file_attr = attr[i]["File"].asString();
- if (attributes_.find(name) == attributes_.end()) {
- auto controller = cg_map.FindController(controller_name);
- if (controller.HasValue()) {
+ auto controller = cg_map.FindController(controller_name);
+ if (controller.HasValue()) {
+ auto iter = attributes_.find(name);
+ if (iter == attributes_.end()) {
attributes_[name] = std::make_unique<ProfileAttribute>(controller, file_attr);
} else {
- LOG(WARNING) << "Controller " << controller_name << " is not found";
+ iter->second->Reset(controller, file_attr);
}
} else {
- LOG(WARNING) << "Attribute " << name << " is already defined";
+ LOG(WARNING) << "Controller " << controller_name << " is not found";
}
}
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 28bc00c..2983a09 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -33,6 +33,7 @@
const CgroupController* controller() const { return &controller_; }
const std::string& file_name() const { return file_name_; }
+ void Reset(const CgroupController& controller, const std::string& file_name);
bool GetPathForTask(int tid, std::string* path) const;
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 7392806..9bd15c6 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -78,6 +78,9 @@
"libcutils",
"liblog",
],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
target: {
android: {
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index cf98dad..d15fa2b 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -402,8 +402,8 @@
" time — Display the date, invocation time, priority/tag, and PID of the\n"
" process issuing the message.\n"
"\nAdverb modifiers can be used in combination:\n"
- " color — Display in highlighted color to match priority. i.e. \x1B[38;5;231mVERBOSE\n"
- " \x1B[38;5;75mDEBUG \x1B[38;5;40mINFO \x1B[38;5;166mWARNING \x1B[38;5;196mERROR FATAL\x1B[0m\n"
+ " color — Display in highlighted color to match priority. i.e. \x1B[39mVERBOSE\n"
+ " \x1B[34mDEBUG \x1B[32mINFO \x1B[33mWARNING \x1B[31mERROR FATAL\x1B[0m\n"
" descriptive — events logs only, descriptions from event-log-tags database.\n"
" epoch — Display time as seconds since Jan 1 1970.\n"
" monotonic — Display time as cpu seconds since last boot.\n"
diff --git a/logd/CompressionEngine.cpp b/logd/CompressionEngine.cpp
index f9c5979..da2628c 100644
--- a/logd/CompressionEngine.cpp
+++ b/logd/CompressionEngine.cpp
@@ -27,7 +27,7 @@
return *engine;
}
-bool ZlibCompressionEngine::Compress(std::span<uint8_t> in, std::vector<uint8_t>& out) {
+bool ZlibCompressionEngine::Compress(SerializedData& in, size_t data_length, SerializedData& out) {
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
@@ -37,34 +37,34 @@
LOG(FATAL) << "deflateInit() failed";
}
- CHECK_LE(in.size(), static_cast<int64_t>(std::numeric_limits<uint32_t>::max()));
- uint32_t out_size = deflateBound(&strm, in.size());
+ CHECK_LE(data_length, in.size());
+ CHECK_LE(in.size(), std::numeric_limits<uint32_t>::max());
+ uint32_t deflate_bound = deflateBound(&strm, in.size());
- out.resize(out_size);
- strm.avail_in = in.size();
- strm.next_in = const_cast<uint8_t*>(in.data());
- strm.avail_out = out_size;
+ out.Resize(deflate_bound);
+
+ strm.avail_in = data_length;
+ strm.next_in = in.data();
+ strm.avail_out = out.size();
strm.next_out = out.data();
ret = deflate(&strm, Z_FINISH);
CHECK_EQ(ret, Z_STREAM_END);
- uint32_t compressed_data_size = strm.total_out;
+ uint32_t compressed_size = strm.total_out;
deflateEnd(&strm);
- out.resize(compressed_data_size);
+
+ out.Resize(compressed_size);
return true;
}
-bool ZlibCompressionEngine::Decompress(const std::vector<uint8_t>& in, std::vector<uint8_t>& out,
- size_t out_size) {
- out.resize(out_size);
-
+bool ZlibCompressionEngine::Decompress(SerializedData& in, SerializedData& out) {
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = in.size();
- strm.next_in = const_cast<uint8_t*>(in.data());
+ strm.next_in = in.data();
strm.avail_out = out.size();
strm.next_out = out.data();
@@ -79,22 +79,22 @@
return true;
}
-bool ZstdCompressionEngine::Compress(std::span<uint8_t> in, std::vector<uint8_t>& out) {
- size_t out_size = ZSTD_compressBound(in.size());
- out.resize(out_size);
+bool ZstdCompressionEngine::Compress(SerializedData& in, size_t data_length, SerializedData& out) {
+ CHECK_LE(data_length, in.size());
- out_size = ZSTD_compress(out.data(), out_size, in.data(), in.size(), 1);
+ size_t compress_bound = ZSTD_compressBound(data_length);
+ out.Resize(compress_bound);
+
+ size_t out_size = ZSTD_compress(out.data(), out.size(), in.data(), data_length, 1);
if (ZSTD_isError(out_size)) {
LOG(FATAL) << "ZSTD_compress failed: " << ZSTD_getErrorName(out_size);
}
- out.resize(out_size);
+ out.Resize(out_size);
return true;
}
-bool ZstdCompressionEngine::Decompress(const std::vector<uint8_t>& in, std::vector<uint8_t>& out,
- size_t out_size) {
- out.resize(out_size);
+bool ZstdCompressionEngine::Decompress(SerializedData& in, SerializedData& out) {
size_t result = ZSTD_decompress(out.data(), out.size(), in.data(), in.size());
if (ZSTD_isError(result)) {
LOG(FATAL) << "ZSTD_decompress failed: " << ZSTD_getErrorName(result);
diff --git a/logd/CompressionEngine.h b/logd/CompressionEngine.h
index d760cea..0f760ed 100644
--- a/logd/CompressionEngine.h
+++ b/logd/CompressionEngine.h
@@ -16,8 +16,9 @@
#pragma once
-#include <span>
-#include <vector>
+#include <memory>
+
+#include "SerializedData.h"
class CompressionEngine {
public:
@@ -25,23 +26,20 @@
virtual ~CompressionEngine(){};
- virtual bool Compress(std::span<uint8_t> in, std::vector<uint8_t>& out) = 0;
- // Decompress the contents of `in` into `out`. `out_size` must be set to the decompressed size
- // of the contents.
- virtual bool Decompress(const std::vector<uint8_t>& in, std::vector<uint8_t>& out,
- size_t out_size) = 0;
+ virtual bool Compress(SerializedData& in, size_t data_length, SerializedData& out) = 0;
+ // Decompress the contents of `in` into `out`. `out.size()` must be set to the decompressed
+ // size of the contents.
+ virtual bool Decompress(SerializedData& in, SerializedData& out) = 0;
};
class ZlibCompressionEngine : public CompressionEngine {
public:
- bool Compress(std::span<uint8_t> in, std::vector<uint8_t>& out) override;
- bool Decompress(const std::vector<uint8_t>& in, std::vector<uint8_t>& out,
- size_t out_size) override;
+ bool Compress(SerializedData& in, size_t data_length, SerializedData& out) override;
+ bool Decompress(SerializedData& in, SerializedData& out) override;
};
class ZstdCompressionEngine : public CompressionEngine {
public:
- bool Compress(std::span<uint8_t> in, std::vector<uint8_t>& out) override;
- bool Decompress(const std::vector<uint8_t>& in, std::vector<uint8_t>& out,
- size_t out_size) override;
+ bool Compress(SerializedData& in, size_t data_length, SerializedData& out) override;
+ bool Decompress(SerializedData& in, SerializedData& out) override;
};
\ No newline at end of file
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index 8e18f9d..1b7107f 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -276,7 +276,9 @@
cp++;
}
} else if (warn) {
+#ifdef __ANDROID__
LOG(ERROR) << "Cannot read " << filename;
+#endif
}
}
diff --git a/logd/SerializedData.h b/logd/SerializedData.h
new file mode 100644
index 0000000..d3d1e18
--- /dev/null
+++ b/logd/SerializedData.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+#include <algorithm>
+#include <memory>
+
+// This class is used instead of std::string or std::vector because their clear(), erase(), etc
+// functions don't actually deallocate. shrink_to_fit() does deallocate but is not guaranteed to
+// work and swapping with an empty string/vector is clunky.
+class SerializedData {
+ public:
+ SerializedData() {}
+ SerializedData(size_t size) : data_(new uint8_t[size]), size_(size) {}
+
+ void Resize(size_t new_size) {
+ if (size_ == 0) {
+ data_.reset(new uint8_t[new_size]);
+ size_ = new_size;
+ } else if (new_size == 0) {
+ data_.reset();
+ size_ = 0;
+ } else if (new_size != size_) {
+ std::unique_ptr<uint8_t[]> new_data(new uint8_t[new_size]);
+ size_t copy_size = std::min(size_, new_size);
+ memcpy(new_data.get(), data_.get(), copy_size);
+ data_.swap(new_data);
+ size_ = new_size;
+ }
+ }
+
+ uint8_t* data() { return data_.get(); }
+ const uint8_t* data() const { return data_.get(); }
+ size_t size() const { return size_; }
+
+ private:
+ std::unique_ptr<uint8_t[]> data_;
+ size_t size_ = 0;
+};
\ No newline at end of file
diff --git a/logd/SerializedFlushToState.cpp b/logd/SerializedFlushToState.cpp
index 6e2e8b0..2633348 100644
--- a/logd/SerializedFlushToState.cpp
+++ b/logd/SerializedFlushToState.cpp
@@ -121,7 +121,7 @@
log_positions_[log_id]->read_offset += entry->total_len();
- AddMinHeapEntry(log_id);
+ logs_needed_from_next_position_[log_id] = true;
return top;
}
diff --git a/logd/SerializedFlushToState.h b/logd/SerializedFlushToState.h
index 74b3de5..0b20822 100644
--- a/logd/SerializedFlushToState.h
+++ b/logd/SerializedFlushToState.h
@@ -61,15 +61,13 @@
if (logs_ == nullptr) logs_ = logs;
}
- // Checks to see if any log buffers set in logs_needed_from_next_position_ have new logs and
- // calls AddMinHeapEntry() if so.
- void CheckForNewLogs();
+ bool HasUnreadLogs() {
+ CheckForNewLogs();
+ return !min_heap_.empty();
+ }
- bool HasUnreadLogs() { return !min_heap_.empty(); }
-
- // Pops the next unread log from the min heap. Add the next log for that log_id to the min heap
- // if one is available otherwise set logs_needed_from_next_position_ to indicate that we're
- // waiting for more logs.
+ // Pops the next unread log from the min heap and sets logs_needed_from_next_position_ to
+ // indicate that we're waiting for more logs from the associated log buffer.
MinHeapElement PopNextUnreadLog();
// If the parent log buffer prunes logs, the reference that this class contains may become
@@ -86,6 +84,10 @@
// first chunk and then first log entry within that chunk that is greater or equal to start().
void CreateLogPosition(log_id_t log_id);
+ // Checks to see if any log buffers set in logs_needed_from_next_position_ have new logs and
+ // calls AddMinHeapEntry() if so.
+ void CheckForNewLogs();
+
std::list<SerializedLogChunk>* logs_ = nullptr;
// An optional structure that contains an iterator to the serialized log buffer and offset into
// it that this logger should handle next.
diff --git a/logd/SerializedFlushToStateTest.cpp b/logd/SerializedFlushToStateTest.cpp
index a1d21ac..f4515c8 100644
--- a/logd/SerializedFlushToStateTest.cpp
+++ b/logd/SerializedFlushToStateTest.cpp
@@ -89,7 +89,6 @@
for (uint32_t mask = 0; mask < max_mask; ++mask) {
auto state = SerializedFlushToState{sequence, mask};
state.InitializeLogs(log_chunks_);
- state.CheckForNewLogs();
TestReading(sequence, mask, state);
}
}
@@ -109,7 +108,6 @@
state.InitializeLogs(log_chunks_);
int loop_count = 0;
while (write_logs(loop_count++)) {
- state.CheckForNewLogs();
TestReading(sequence, mask, state);
sequence_numbers_per_buffer_.clear();
}
@@ -149,7 +147,7 @@
// Add a chunk with the given messages to the a given log buffer. Keep track of the sequence
// numbers for future validation. Optionally mark the block as having finished writing.
- void AddChunkWithMessages(int buffer, bool finish_writing,
+ void AddChunkWithMessages(bool finish_writing, int buffer,
const std::vector<std::string>& messages) {
auto chunk = SerializedLogChunk{kChunkSize};
for (const auto& message : messages) {
@@ -252,3 +250,41 @@
TestAllReadingWithFutureMessages(write_logs);
}
+
+TEST_F(SerializedFlushToStateTest, no_dangling_references) {
+ AddChunkWithMessages(true, 0, {"1st", "2nd"});
+ AddChunkWithMessages(true, 0, {"3rd", "4th"});
+
+ auto state = SerializedFlushToState{1, kLogMaskAll};
+ state.InitializeLogs(log_chunks_);
+
+ ASSERT_EQ(log_chunks_[0].size(), 2U);
+ auto first_chunk = log_chunks_[0].begin();
+ auto second_chunk = std::next(first_chunk);
+
+ ASSERT_TRUE(state.HasUnreadLogs());
+ auto first_log = state.PopNextUnreadLog();
+ EXPECT_STREQ(first_log.entry->msg(), "1st");
+ EXPECT_EQ(first_chunk->reader_ref_count(), 1U);
+ EXPECT_EQ(second_chunk->reader_ref_count(), 0U);
+
+ ASSERT_TRUE(state.HasUnreadLogs());
+ auto second_log = state.PopNextUnreadLog();
+ EXPECT_STREQ(second_log.entry->msg(), "2nd");
+ EXPECT_EQ(first_chunk->reader_ref_count(), 1U);
+ EXPECT_EQ(second_chunk->reader_ref_count(), 0U);
+
+ ASSERT_TRUE(state.HasUnreadLogs());
+ auto third_log = state.PopNextUnreadLog();
+ EXPECT_STREQ(third_log.entry->msg(), "3rd");
+ EXPECT_EQ(first_chunk->reader_ref_count(), 0U);
+ EXPECT_EQ(second_chunk->reader_ref_count(), 1U);
+
+ ASSERT_TRUE(state.HasUnreadLogs());
+ auto fourth_log = state.PopNextUnreadLog();
+ EXPECT_STREQ(fourth_log.entry->msg(), "4th");
+ EXPECT_EQ(first_chunk->reader_ref_count(), 0U);
+ EXPECT_EQ(second_chunk->reader_ref_count(), 1U);
+
+ EXPECT_FALSE(state.HasUnreadLogs());
+}
\ No newline at end of file
diff --git a/logd/SerializedLogBuffer.cpp b/logd/SerializedLogBuffer.cpp
index 70b800f..0f30794 100644
--- a/logd/SerializedLogBuffer.cpp
+++ b/logd/SerializedLogBuffer.cpp
@@ -16,8 +16,9 @@
#include "SerializedLogBuffer.h"
+#include <sys/prctl.h>
+
#include <limits>
-#include <thread>
#include <android-base/logging.h>
#include <android-base/scopeguard.h>
@@ -31,7 +32,11 @@
Init();
}
-SerializedLogBuffer::~SerializedLogBuffer() {}
+SerializedLogBuffer::~SerializedLogBuffer() {
+ if (deleter_thread_.joinable()) {
+ deleter_thread_.join();
+ }
+}
void SerializedLogBuffer::Init() {
log_id_for_each(i) {
@@ -119,15 +124,44 @@
}
}
+void SerializedLogBuffer::StartDeleterThread() {
+ if (deleter_thread_running_) {
+ return;
+ }
+ if (deleter_thread_.joinable()) {
+ deleter_thread_.join();
+ }
+ auto new_thread = std::thread([this] { DeleterThread(); });
+ deleter_thread_.swap(new_thread);
+ deleter_thread_running_ = true;
+}
+
// Decompresses the chunks, call LogStatistics::Subtract() on each entry, then delete the chunks and
// the list. Note that the SerializedLogChunk objects have been removed from logs_ and their
// references have been deleted from any SerializedFlushToState objects, so this can be safely done
-// without holding lock_. It is done in a separate thread to avoid delaying the writer thread. The
-// lambda for the thread takes ownership of the 'chunks' list and thus when the thread ends and the
-// lambda is deleted, the objects are deleted.
-void SerializedLogBuffer::DeleteLogChunks(std::list<SerializedLogChunk>&& chunks, log_id_t log_id) {
- auto delete_thread = std::thread{[chunks = std::move(chunks), log_id, this]() mutable {
- for (auto& chunk : chunks) {
+// without holding lock_. It is done in a separate thread to avoid delaying the writer thread.
+void SerializedLogBuffer::DeleterThread() {
+ prctl(PR_SET_NAME, "logd.deleter");
+ while (true) {
+ std::list<SerializedLogChunk> local_chunks_to_delete;
+ log_id_t log_id;
+ {
+ auto lock = std::lock_guard{lock_};
+ log_id_for_each(i) {
+ if (!chunks_to_delete_[i].empty()) {
+ local_chunks_to_delete = std::move(chunks_to_delete_[i]);
+ chunks_to_delete_[i].clear();
+ log_id = i;
+ break;
+ }
+ }
+ if (local_chunks_to_delete.empty()) {
+ deleter_thread_running_ = false;
+ return;
+ }
+ }
+
+ for (auto& chunk : local_chunks_to_delete) {
chunk.IncReaderRefCount();
int read_offset = 0;
while (read_offset < chunk.write_offset()) {
@@ -137,8 +171,7 @@
}
chunk.DecReaderRefCount(false);
}
- }};
- delete_thread.detach();
+ }
}
void SerializedLogBuffer::NotifyReadersOfPrune(
@@ -164,13 +197,9 @@
}
}
+ StartDeleterThread();
+
auto& log_buffer = logs_[log_id];
-
- std::list<SerializedLogChunk> chunks_to_prune;
- auto prune_chunks = android::base::make_scope_guard([&chunks_to_prune, log_id, this] {
- DeleteLogChunks(std::move(chunks_to_prune), log_id);
- });
-
auto it = log_buffer.begin();
while (it != log_buffer.end()) {
if (oldest != nullptr && it->highest_sequence_number() >= oldest->start()) {
@@ -193,7 +222,8 @@
}
} else {
size_t buffer_size = it_to_prune->PruneSize();
- chunks_to_prune.splice(chunks_to_prune.end(), log_buffer, it_to_prune);
+ chunks_to_delete_[log_id].splice(chunks_to_delete_[log_id].end(), log_buffer,
+ it_to_prune);
if (buffer_size >= bytes_to_free) {
return true;
}
@@ -246,7 +276,6 @@
auto& state = reinterpret_cast<SerializedFlushToState&>(abstract_state);
state.InitializeLogs(logs_);
- state.CheckForNewLogs();
while (state.HasUnreadLogs()) {
MinHeapElement top = state.PopNextUnreadLog();
@@ -279,10 +308,6 @@
return false;
}
lock.lock();
-
- // Since we released the log above, buffers that aren't in our min heap may now have had
- // logs added, so re-check them.
- state.CheckForNewLogs();
}
state.set_start(state.start() + 1);
diff --git a/logd/SerializedLogBuffer.h b/logd/SerializedLogBuffer.h
index 346f51f..421d419 100644
--- a/logd/SerializedLogBuffer.h
+++ b/logd/SerializedLogBuffer.h
@@ -21,6 +21,7 @@
#include <list>
#include <mutex>
#include <queue>
+#include <thread>
#include <vector>
#include <android-base/thread_annotations.h>
@@ -60,7 +61,9 @@
REQUIRES_SHARED(lock_);
void NotifyReadersOfPrune(log_id_t log_id, const std::list<SerializedLogChunk>::iterator& chunk)
REQUIRES(reader_list_->reader_threads_lock());
- void DeleteLogChunks(std::list<SerializedLogChunk>&& chunks, log_id_t log_id);
+
+ void StartDeleterThread() REQUIRES(lock_);
+ void DeleterThread();
LogReaderList* reader_list_;
LogTags* tags_;
@@ -70,5 +73,9 @@
std::list<SerializedLogChunk> logs_[LOG_ID_MAX] GUARDED_BY(lock_);
RwLock lock_;
+ std::list<SerializedLogChunk> chunks_to_delete_[LOG_ID_MAX] GUARDED_BY(lock_);
+ std::thread deleter_thread_ GUARDED_BY(lock_);
+ bool deleter_thread_running_ GUARDED_BY(lock_) = false;
+
std::atomic<uint64_t> sequence_ = 1;
};
diff --git a/logd/SerializedLogChunk.cpp b/logd/SerializedLogChunk.cpp
index 2516003..e444856 100644
--- a/logd/SerializedLogChunk.cpp
+++ b/logd/SerializedLogChunk.cpp
@@ -25,14 +25,13 @@
}
void SerializedLogChunk::Compress() {
- if (compressed_log_.empty()) {
- CompressionEngine::GetInstance().Compress({contents_.data(), write_offset_},
- compressed_log_);
+ if (compressed_log_.size() == 0) {
+ CompressionEngine::GetInstance().Compress(contents_, write_offset_, compressed_log_);
LOG(INFO) << "Compressed Log, buffer max size: " << contents_.size()
<< " size used: " << write_offset_
<< " compressed size: " << compressed_log_.size();
}
- contents_.resize(0);
+ contents_.Resize(0);
}
// TODO: Develop a better reference counting strategy to guard against the case where the writer is
@@ -41,7 +40,8 @@
if (++reader_ref_count_ != 1 || writer_active_) {
return;
}
- CompressionEngine::GetInstance().Decompress(compressed_log_, contents_, write_offset_);
+ contents_.Resize(write_offset_);
+ CompressionEngine::GetInstance().Decompress(compressed_log_, contents_);
}
void SerializedLogChunk::DecReaderRefCount(bool compress) {
@@ -90,7 +90,7 @@
// Clear the old compressed logs and set write_offset_ appropriately for DecReaderRefCount()
// to compress the new partially cleared log.
if (new_write_offset != write_offset_) {
- compressed_log_.clear();
+ compressed_log_.Resize(0);
write_offset_ = new_write_offset;
}
diff --git a/logd/SerializedLogChunk.h b/logd/SerializedLogChunk.h
index a8ac8cd..65a1e86 100644
--- a/logd/SerializedLogChunk.h
+++ b/logd/SerializedLogChunk.h
@@ -18,14 +18,14 @@
#include <sys/types.h>
-#include <vector>
-
#include "LogWriter.h"
+#include "SerializedData.h"
#include "SerializedLogEntry.h"
class SerializedLogChunk {
public:
explicit SerializedLogChunk(size_t size) : contents_(size) {}
+ SerializedLogChunk(SerializedLogChunk&& other) noexcept = default;
~SerializedLogChunk();
void Compress();
@@ -60,13 +60,16 @@
int write_offset() const { return write_offset_; }
uint64_t highest_sequence_number() const { return highest_sequence_number_; }
+ // Exposed for testing
+ uint32_t reader_ref_count() const { return reader_ref_count_; }
+
private:
// The decompressed contents of this log buffer. Deallocated when the ref_count reaches 0 and
// writer_active_ is false.
- std::vector<uint8_t> contents_;
+ SerializedData contents_;
int write_offset_ = 0;
uint32_t reader_ref_count_ = 0;
bool writer_active_ = true;
uint64_t highest_sequence_number_ = 1;
- std::vector<uint8_t> compressed_log_;
+ SerializedData compressed_log_;
};
diff --git a/logd/fuzz/Android.bp b/logd/fuzz/Android.bp
index 9834ff0..d346cd7 100644
--- a/logd/fuzz/Android.bp
+++ b/logd/fuzz/Android.bp
@@ -13,11 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-cc_fuzz {
- name: "log_buffer_log_fuzzer",
- srcs: [
- "log_buffer_log_fuzzer.cpp",
- ],
+
+cc_defaults {
+ name: "log_fuzzer_defaults",
static_libs: [
"libbase",
"libcutils",
@@ -25,9 +23,28 @@
"liblog",
"liblogd",
"libcutils",
- "libsysutils",
"libz",
"libzstd",
],
- cflags: ["-Werror"],
+ cflags: ["-Wextra"],
+ host_supported: true,
+}
+
+cc_fuzz {
+ name: "log_buffer_log_fuzzer",
+ defaults: ["log_fuzzer_defaults"],
+ srcs: [
+ "log_buffer_log_fuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "serialized_log_buffer_fuzzer",
+ defaults: ["log_fuzzer_defaults"],
+ srcs: [
+ "serialized_log_buffer_fuzzer.cpp",
+ ],
+ corpus: [
+ "corpus/logentry_use_after_compress",
+ ]
}
diff --git a/logd/fuzz/corpus/logentry_use_after_compress b/logd/fuzz/corpus/logentry_use_after_compress
new file mode 100644
index 0000000..2081b13
--- /dev/null
+++ b/logd/fuzz/corpus/logentry_use_after_compress
Binary files differ
diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp
index a7a1792..1dc996c 100644
--- a/logd/fuzz/log_buffer_log_fuzzer.cpp
+++ b/logd/fuzz/log_buffer_log_fuzzer.cpp
@@ -15,10 +15,13 @@
*/
#include <string>
+#include <android-base/logging.h>
+
#include "../ChattyLogBuffer.h"
#include "../LogReaderList.h"
#include "../LogReaderThread.h"
#include "../LogStatistics.h"
+#include "../SerializedLogBuffer.h"
// We don't want to waste a lot of entropy on messages
#define MAX_MSG_LENGTH 5
@@ -27,7 +30,20 @@
#define MIN_TAG_ID 1000
#define TAG_MOD 10
-namespace android {
+#ifndef __ANDROID__
+unsigned long __android_logger_get_buffer_size(log_id_t) {
+ return 1024 * 1024;
+}
+
+bool __android_logger_valid_buffer_size(unsigned long) {
+ return true;
+}
+#endif
+
+char* android::uidToName(uid_t) {
+ return strdup("fake");
+}
+
struct LogInput {
public:
log_id_t log_id;
@@ -79,9 +95,13 @@
return 1;
}
-char* uidToName(uid_t) {
- return strdup("fake");
-}
+class NoopWriter : public LogWriter {
+ public:
+ NoopWriter() : LogWriter(0, true) {}
+ bool Write(const logger_entry&, const char*) override { return true; }
+
+ std::string name() const override { return "noop_writer"; }
+};
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// We want a random tag length and a random remaining message length
@@ -89,11 +109,18 @@
return 0;
}
+ android::base::SetMinimumLogSeverity(android::base::ERROR);
+
LogReaderList reader_list;
LogTags tags;
PruneList prune_list;
LogStatistics stats(true);
- LogBuffer* log_buffer = new ChattyLogBuffer(&reader_list, &tags, &prune_list, &stats);
+ std::unique_ptr<LogBuffer> log_buffer;
+#ifdef FUZZ_SERIALIZED
+ log_buffer.reset(new SerializedLogBuffer(&reader_list, &tags, &stats));
+#else
+ log_buffer.reset(new ChattyLogBuffer(&reader_list, &tags, &prune_list, &stats));
+#endif
size_t data_left = size;
const uint8_t** pdata = &data;
@@ -102,12 +129,30 @@
log_id_for_each(i) { log_buffer->SetSize(i, 10000); }
while (data_left >= sizeof(LogInput) + 2 * sizeof(uint8_t)) {
- if (!write_log_messages(pdata, &data_left, log_buffer, &stats)) {
+ if (!write_log_messages(pdata, &data_left, log_buffer.get(), &stats)) {
return 0;
}
}
+ // Read out all of the logs.
+ {
+ auto lock = std::unique_lock{reader_list.reader_threads_lock()};
+ std::unique_ptr<LogWriter> test_writer(new NoopWriter());
+ std::unique_ptr<LogReaderThread> log_reader(
+ new LogReaderThread(log_buffer.get(), &reader_list, std::move(test_writer), true, 0,
+ kLogMaskAll, 0, {}, 1, {}));
+ reader_list.reader_threads().emplace_back(std::move(log_reader));
+ }
+
+ // Wait until the reader has finished.
+ while (true) {
+ usleep(50);
+ auto lock = std::unique_lock{reader_list.reader_threads_lock()};
+ if (reader_list.reader_threads().size() == 0) {
+ break;
+ }
+ }
+
log_id_for_each(i) { log_buffer->Clear(i, 0); }
return 0;
}
-} // namespace android
diff --git a/logd/fuzz/serialized_log_buffer_fuzzer.cpp b/logd/fuzz/serialized_log_buffer_fuzzer.cpp
new file mode 100644
index 0000000..d4795b0
--- /dev/null
+++ b/logd/fuzz/serialized_log_buffer_fuzzer.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define FUZZ_SERIALIZED
+
+#include "log_buffer_log_fuzzer.cpp"
diff --git a/logd/main.cpp b/logd/main.cpp
index 46b6567..e1ec52b 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -69,49 +69,42 @@
// has a 'sigstop' feature that sends SIGSTOP to a service immediately before calling exec(). This
// allows debuggers, etc to be attached to logd at the very beginning, while still having init
// handle the user, groups, capabilities, files, etc setup.
-static int drop_privs(bool klogd, bool auditd) {
- sched_param param = {};
-
+static void DropPrivs(bool klogd, bool auditd) {
if (set_sched_policy(0, SP_BACKGROUND) < 0) {
- PLOG(ERROR) << "failed to set background scheduling policy";
- return -1;
+ PLOG(FATAL) << "failed to set background scheduling policy";
}
+ sched_param param = {};
if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) {
- PLOG(ERROR) << "failed to set batch scheduler";
- return -1;
+ PLOG(FATAL) << "failed to set batch scheduler";
}
if (!__android_logger_property_get_bool("ro.debuggable", BOOL_DEFAULT_FALSE) &&
prctl(PR_SET_DUMPABLE, 0) == -1) {
- PLOG(ERROR) << "failed to clear PR_SET_DUMPABLE";
- return -1;
+ PLOG(FATAL) << "failed to clear PR_SET_DUMPABLE";
}
std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(), cap_free);
if (cap_clear(caps.get()) < 0) {
- return -1;
+ PLOG(FATAL) << "cap_clear() failed";
}
- std::vector<cap_value_t> cap_value;
if (klogd) {
- cap_value.emplace_back(CAP_SYSLOG);
+ cap_value_t cap_syslog = CAP_SYSLOG;
+ if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, &cap_syslog, CAP_SET) < 0 ||
+ cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, &cap_syslog, CAP_SET) < 0) {
+ PLOG(FATAL) << "Failed to set CAP_SYSLOG";
+ }
}
if (auditd) {
- cap_value.emplace_back(CAP_AUDIT_CONTROL);
- }
-
- if (cap_set_flag(caps.get(), CAP_PERMITTED, cap_value.size(), cap_value.data(), CAP_SET) < 0) {
- return -1;
- }
- if (cap_set_flag(caps.get(), CAP_EFFECTIVE, cap_value.size(), cap_value.data(), CAP_SET) < 0) {
- return -1;
+ cap_value_t cap_audit_control = CAP_AUDIT_CONTROL;
+ if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, &cap_audit_control, CAP_SET) < 0 ||
+ cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, &cap_audit_control, CAP_SET) < 0) {
+ PLOG(FATAL) << "Failed to set CAP_AUDIT_CONTROL";
+ }
}
if (cap_set_proc(caps.get()) < 0) {
- PLOG(ERROR) << "failed to set CAP_SYSLOG or CAP_AUDIT_CONTROL";
- return -1;
+ PLOG(FATAL) << "cap_set_proc() failed";
}
-
- return 0;
}
char* android::uidToName(uid_t u) {
@@ -254,9 +247,7 @@
}
bool auditd = __android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE);
- if (drop_privs(klogd, auditd) != 0) {
- return EXIT_FAILURE;
- }
+ DropPrivs(klogd, auditd);
// A cache of event log tags
LogTags log_tags;
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 01551e2..fb6f1be 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -445,6 +445,9 @@
# Load persist properties and override properties (if enabled) from /data.
trigger load_persist_props_action
+ # Should be before netd, but after apex, properties and logging is available.
+ trigger load_bpf_programs
+
# Now we can start zygote for devices with file based encryption
trigger zygote-start
@@ -517,6 +520,13 @@
mkdir /metadata/apex 0700 root system
mkdir /metadata/apex/sessions 0700 root system
+ # On some devices we see a weird behaviour in which /metadata/apex doesn't
+ # have a correct label. To workaround this bug, explicitly call restorecon
+ # on /metadata/apex. For most of the boot sequences /metadata/apex will
+ # already have a correct selinux label, meaning that this call will be a
+ # no-op.
+ restorecon_recursive /metadata/apex
+
on late-fs
# Ensure that tracefs has the correct permissions.
# This does not work correctly if it is called in post-fs.
diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp
index 3ffa74e..7df7b71 100644
--- a/toolbox/modprobe.cpp
+++ b/toolbox/modprobe.cpp
@@ -17,11 +17,16 @@
#include <ctype.h>
#include <getopt.h>
#include <stdlib.h>
-#include <iostream>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/strings.h>
#include <modprobe/modprobe.h>
+namespace {
+
enum modprobe_mode {
AddModulesMode,
RemoveModulesMode,
@@ -29,47 +34,104 @@
ShowDependenciesMode,
};
-static void print_usage(void) {
- std::cerr << "Usage:" << std::endl;
- std::cerr << std::endl;
- std::cerr << " modprobe [-alrqvsDb] [-d DIR] [MODULE]+" << std::endl;
- std::cerr << " modprobe [-alrqvsDb] [-d DIR] MODULE [symbol=value][...]" << std::endl;
- std::cerr << std::endl;
- std::cerr << "Options:" << std::endl;
- std::cerr << " -b: Apply blocklist to module names too" << std::endl;
- std::cerr << " -d: Load modules from DIR, option may be used multiple times" << std::endl;
- std::cerr << " -D: Print dependencies for modules only, do not load";
- std::cerr << " -h: Print this help" << std::endl;
- std::cerr << " -l: List modules matching pattern" << std::endl;
- std::cerr << " -r: Remove MODULE (multiple modules may be specified)" << std::endl;
- std::cerr << " -q: Quiet" << std::endl;
- std::cerr << " -v: Verbose" << std::endl;
- std::cerr << std::endl;
+void print_usage(void) {
+ LOG(INFO) << "Usage:";
+ LOG(INFO);
+ // -d option is required on Android
+ LOG(INFO) << " modprobe [options] -d DIR [--all=FILE|MODULE]...";
+ LOG(INFO) << " modprobe [options] -d DIR MODULE [symbol=value]...";
+ LOG(INFO);
+ LOG(INFO) << "Options:";
+ LOG(INFO) << " --all=FILE: FILE to acquire module names from";
+ LOG(INFO) << " -b, --use-blocklist: Apply blocklist to module names too";
+ LOG(INFO) << " -d, --dirname=DIR: Load modules from DIR, option may be used multiple times";
+ LOG(INFO) << " -D, --show-depends: Print dependencies for modules only, do not load";
+ LOG(INFO) << " -h, --help: Print this help";
+ LOG(INFO) << " -l, --list: List modules matching pattern";
+ LOG(INFO) << " -r, --remove: Remove MODULE (multiple modules may be specified)";
+ LOG(INFO) << " -s, --syslog: print to syslog also";
+ LOG(INFO) << " -q, --quiet: disable messages";
+ LOG(INFO) << " -v, --verbose: enable more messages, even more with a second -v";
+ LOG(INFO);
}
-#define check_mode() \
- if (mode != AddModulesMode) { \
- std::cerr << "Error, multiple mode flags specified" << std::endl; \
- print_usage(); \
- return EXIT_FAILURE; \
+#define check_mode() \
+ if (mode != AddModulesMode) { \
+ LOG(ERROR) << "multiple mode flags specified"; \
+ print_usage(); \
+ return EXIT_FAILURE; \
}
+std::string stripComments(const std::string& str) {
+ for (std::string rv = str;;) {
+ auto comment = rv.find('#');
+ if (comment == std::string::npos) return rv;
+ auto end = rv.find('\n', comment);
+ if (end != std::string::npos) end = end - comment;
+ rv.erase(comment, end);
+ }
+ /* NOTREACHED */
+}
+
+auto syslog = false;
+
+void MyLogger(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
+ const char* file, unsigned int line, const char* message) {
+ android::base::StdioLogger(id, severity, tag, file, line, message);
+ if (syslog && message[0]) {
+ android::base::KernelLogger(id, severity, tag, file, line, message);
+ }
+}
+
+} // anonymous namespace
+
extern "C" int modprobe_main(int argc, char** argv) {
+ android::base::InitLogging(argv, MyLogger);
+ android::base::SetMinimumLogSeverity(android::base::INFO);
+
std::vector<std::string> modules;
std::string module_parameters;
+ std::string mods;
std::vector<std::string> mod_dirs;
modprobe_mode mode = AddModulesMode;
bool blocklist = false;
- bool verbose = false;
int rv = EXIT_SUCCESS;
int opt;
- while ((opt = getopt(argc, argv, "abd:Dhlqrv")) != -1) {
+ int option_index = 0;
+ // NB: We have non-standard short options -l and -D to make it easier for
+ // OEMs to transition from toybox.
+ // clang-format off
+ static struct option long_options[] = {
+ { "all", optional_argument, 0, 'a' },
+ { "use-blocklist", no_argument, 0, 'b' },
+ { "dirname", required_argument, 0, 'd' },
+ { "show-depends", no_argument, 0, 'D' },
+ { "help", no_argument, 0, 'h' },
+ { "list", no_argument, 0, 'l' },
+ { "quiet", no_argument, 0, 'q' },
+ { "remove", no_argument, 0, 'r' },
+ { "syslog", no_argument, 0, 's' },
+ { "verbose", no_argument, 0, 'v' },
+ };
+ // clang-format on
+ while ((opt = getopt_long(argc, argv, "a::bd:Dhlqrsv", long_options, &option_index)) != -1) {
switch (opt) {
case 'a':
// toybox modprobe supported -a to load multiple modules, this
- // is supported here by default, ignore flag
+ // is supported here by default, ignore flag if no argument.
check_mode();
+ if (optarg == NULL) break;
+ if (!android::base::ReadFileToString(optarg, &mods)) {
+ PLOG(ERROR) << "Failed to open " << optarg;
+ rv = EXIT_FAILURE;
+ }
+ for (auto mod : android::base::Split(stripComments(mods), "\n")) {
+ mod = android::base::Trim(mod);
+ if (mod == "") continue;
+ if (std::find(modules.begin(), modules.end(), mod) != modules.end()) continue;
+ modules.emplace_back(mod);
+ }
break;
case 'b':
blocklist = true;
@@ -82,24 +144,33 @@
mode = ShowDependenciesMode;
break;
case 'h':
+ android::base::SetMinimumLogSeverity(android::base::INFO);
print_usage();
- return EXIT_SUCCESS;
+ return rv;
case 'l':
check_mode();
mode = ListModulesMode;
break;
case 'q':
- verbose = false;
+ android::base::SetMinimumLogSeverity(android::base::WARNING);
break;
case 'r':
check_mode();
mode = RemoveModulesMode;
break;
+ case 's':
+ syslog = true;
+ break;
case 'v':
- verbose = true;
+ if (android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ } else {
+ android::base::SetMinimumLogSeverity(android::base::DEBUG);
+ }
break;
default:
- std::cerr << "Unrecognized option: " << opt << std::endl;
+ LOG(ERROR) << "Unrecognized option: " << opt;
+ print_usage();
return EXIT_FAILURE;
}
}
@@ -118,39 +189,33 @@
}
}
- if (verbose) {
- std::cout << "mode is " << mode << std::endl;
- std::cout << "verbose is " << verbose << std::endl;
- std::cout << "mod_dirs is: " << android::base::Join(mod_dirs, "") << std::endl;
- std::cout << "modules is: " << android::base::Join(modules, "") << std::endl;
- std::cout << "module parameters is: " << android::base::Join(module_parameters, "")
- << std::endl;
- }
+ LOG(DEBUG) << "mode is " << mode;
+ LOG(DEBUG) << "mod_dirs is: " << android::base::Join(mod_dirs, " ");
+ LOG(DEBUG) << "modules is: " << android::base::Join(modules, " ");
+ LOG(DEBUG) << "module parameters is: " << android::base::Join(module_parameters, " ");
if (modules.empty()) {
if (mode == ListModulesMode) {
// emulate toybox modprobe list with no pattern (list all)
modules.emplace_back("*");
} else {
- std::cerr << "No modules given." << std::endl;
+ LOG(ERROR) << "No modules given.";
print_usage();
return EXIT_FAILURE;
}
}
if (mod_dirs.empty()) {
- std::cerr << "No module configuration directories given." << std::endl;
+ LOG(ERROR) << "No module configuration directories given.";
print_usage();
return EXIT_FAILURE;
}
if (parameter_count && modules.size() > 1) {
- std::cerr << "Only one module may be loaded when specifying module parameters."
- << std::endl;
+ LOG(ERROR) << "Only one module may be loaded when specifying module parameters.";
print_usage();
return EXIT_FAILURE;
}
Modprobe m(mod_dirs);
- m.EnableVerbose(verbose);
if (blocklist) {
m.EnableBlocklist(true);
}
@@ -159,19 +224,19 @@
switch (mode) {
case AddModulesMode:
if (!m.LoadWithAliases(module, true, module_parameters)) {
- std::cerr << "Failed to load module " << module;
+ PLOG(ERROR) << "Failed to load module " << module;
rv = EXIT_FAILURE;
}
break;
case RemoveModulesMode:
if (!m.Remove(module)) {
- std::cerr << "Failed to remove module " << module;
+ PLOG(ERROR) << "Failed to remove module " << module;
rv = EXIT_FAILURE;
}
break;
case ListModulesMode: {
std::vector<std::string> list = m.ListModules(module);
- std::cout << android::base::Join(list, "\n") << std::endl;
+ LOG(INFO) << android::base::Join(list, "\n");
break;
}
case ShowDependenciesMode: {
@@ -182,17 +247,17 @@
rv = EXIT_FAILURE;
break;
}
- std::cout << "Dependencies for " << module << ":" << std::endl;
- std::cout << "Soft pre-dependencies:" << std::endl;
- std::cout << android::base::Join(pre_deps, "\n") << std::endl;
- std::cout << "Hard dependencies:" << std::endl;
- std::cout << android::base::Join(deps, "\n") << std::endl;
- std::cout << "Soft post-dependencies:" << std::endl;
- std::cout << android::base::Join(post_deps, "\n") << std::endl;
+ LOG(INFO) << "Dependencies for " << module << ":";
+ LOG(INFO) << "Soft pre-dependencies:";
+ LOG(INFO) << android::base::Join(pre_deps, "\n");
+ LOG(INFO) << "Hard dependencies:";
+ LOG(INFO) << android::base::Join(deps, "\n");
+ LOG(INFO) << "Soft post-dependencies:";
+ LOG(INFO) << android::base::Join(post_deps, "\n");
break;
}
default:
- std::cerr << "Bad mode";
+ LOG(ERROR) << "Bad mode";
rv = EXIT_FAILURE;
}
}