Merge "Fix overflow in path building" into nyc-dev
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 5aa878b..3aa9199 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -65,6 +65,9 @@
static auto& gProductOutPath = *new std::string();
extern int gListenAll;
+static constexpr char BUGZ_OK_PREFIX[] = "OK:";
+static constexpr char BUGZ_FAIL_PREFIX[] = "FAIL:";
+
static std::string product_file(const char *extra) {
if (gProductOutPath.empty()) {
fprintf(stderr, "adb: Product directory not specified; "
@@ -170,7 +173,7 @@
" (-g: grant all runtime permissions)\n"
" adb uninstall [-k] <package> - remove this app package from the device\n"
" ('-k' means keep the data and cache directories)\n"
- " adb bugreport - return all information from the device\n"
+ " adb bugreport [<zip_file>] - return all information from the device\n"
" that should be included in a bug report.\n"
"\n"
" adb backup [-f <file>] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n"
@@ -285,7 +288,8 @@
// this expects that incoming data will use the shell protocol, in which case
// stdout/stderr are routed independently and the remote exit code will be
// returned.
-static int read_and_dump(int fd, bool use_shell_protocol=false) {
+// if |output| is non-null, stdout will be appended to it instead.
+static int read_and_dump(int fd, bool use_shell_protocol=false, std::string* output=nullptr) {
int exit_code = 0;
std::unique_ptr<ShellProtocol> protocol;
int length = 0;
@@ -330,8 +334,12 @@
}
}
- fwrite(buffer_ptr, 1, length, outfile);
- fflush(outfile);
+ if (output == nullptr) {
+ fwrite(buffer_ptr, 1, length, outfile);
+ fflush(outfile);
+ } else {
+ output->append(buffer_ptr, length);
+ }
}
return exit_code;
@@ -1121,7 +1129,8 @@
// resulting output.
static int send_shell_command(TransportType transport_type, const char* serial,
const std::string& command,
- bool disable_shell_protocol) {
+ bool disable_shell_protocol,
+ std::string* output=nullptr) {
int fd;
bool use_shell_protocol = false;
@@ -1156,7 +1165,7 @@
}
}
- int exit_code = read_and_dump(fd, use_shell_protocol);
+ int exit_code = read_and_dump(fd, use_shell_protocol, output);
if (adb_close(fd) < 0) {
PLOG(ERROR) << "failure closing FD " << fd;
@@ -1165,6 +1174,40 @@
return exit_code;
}
+static int bugreport(TransportType transport_type, const char* serial, int argc,
+ const char** argv) {
+ // No need for shell protocol with bugreport, always disable for simplicity.
+ if (argc == 1) return send_shell_command(transport_type, serial, "bugreport", true);
+ if (argc != 2) return usage();
+
+ // Zipped bugreport option - will call 'bugreportz', which prints the location of the generated
+ // file, then pull it to the destination file provided by the user.
+ const char* dest_file = argv[1];
+ std::string output;
+
+ int status = send_shell_command(transport_type, serial, "bugreportz", true, &output);
+ if (status != 0 || output.empty()) return status;
+ output = android::base::Trim(output);
+
+ if (android::base::StartsWith(output, BUGZ_OK_PREFIX)) {
+ const char* zip_file = &output[strlen(BUGZ_OK_PREFIX)];
+ std::vector<const char*> srcs{zip_file};
+ status = do_sync_pull(srcs, dest_file, true, dest_file) ? 0 : 1;
+ if (status != 0) {
+ fprintf(stderr, "Could not copy file '%s' to '%s'\n", zip_file, dest_file);
+ }
+ return status;
+ }
+ if (android::base::StartsWith(output, BUGZ_FAIL_PREFIX)) {
+ const char* error_message = &output[strlen(BUGZ_FAIL_PREFIX)];
+ fprintf(stderr, "device failed to take a zipped bugreport: %s\n", error_message);
+ return -1;
+ }
+ fprintf(stderr, "unexpected string (%s) returned by bugreportz, "
+ "device probably does not support -z option\n", output.c_str());
+ return -1;
+}
+
static int logcat(TransportType transport, const char* serial, int argc, const char** argv) {
char* log_tags = getenv("ANDROID_LOG_TAGS");
std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
@@ -1694,12 +1737,8 @@
} else if (!strcmp(argv[0], "root") || !strcmp(argv[0], "unroot")) {
return adb_root(argv[0]) ? 0 : 1;
} else if (!strcmp(argv[0], "bugreport")) {
- if (argc != 1) return usage();
- // No need for shell protocol with bugreport, always disable for
- // simplicity.
- return send_shell_command(transport_type, serial, "bugreport", true);
- }
- else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
+ return bugreport(transport_type, serial, argc, argv);
+ } else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
bool reverse = !strcmp(argv[0], "reverse");
++argv;
--argc;
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 6a9e163..651e8ca 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -518,7 +518,8 @@
return sc.CopyDone(lpath, rpath);
}
-static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
+static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
+ const char* name=nullptr) {
unsigned size = 0;
if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
@@ -574,7 +575,7 @@
bytes_copied += msg.data.size;
- sc.ReportProgress(rpath, bytes_copied, size);
+ sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, size);
}
adb_close(lfd);
@@ -927,7 +928,7 @@
}
bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
- bool copy_attrs) {
+ bool copy_attrs, const char* name) {
SyncConnection sc;
if (!sc.IsValid()) return false;
@@ -1022,7 +1023,7 @@
}
sc.SetExpectedTotalBytes(src_size);
- if (!sync_recv(sc, src_path, dst_path)) {
+ if (!sync_recv(sc, src_path, dst_path, name)) {
success = false;
continue;
}
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 460e9dc..0e25974 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -67,7 +67,7 @@
bool do_sync_ls(const char* path);
bool do_sync_push(const std::vector<const char*>& srcs, const char* dst);
bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
- bool copy_attrs);
+ bool copy_attrs, const char* name=nullptr);
bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index fa6f594..08fc5af 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -136,13 +136,41 @@
return kUnknownBootReason;
}
+// Returns the appropriate metric key prefix for the boot_complete metric such
+// that boot metrics after a system update are labeled as ota_boot_complete;
+// otherwise, they are labeled as boot_complete. This method encapsulates the
+// bookkeeping required to track when a system update has occurred by storing
+// the UTC timestamp of the system build date and comparing against the current
+// system build date.
+std::string CalculateBootCompletePrefix() {
+ static const std::string kBuildDateKey = "build_date";
+ std::string boot_complete_prefix = "boot_complete";
+
+ std::string build_date_str = GetProperty("ro.build.date.utc");
+ int32_t build_date = std::stoi(build_date_str);
+
+ BootEventRecordStore boot_event_store;
+ BootEventRecordStore::BootEventRecord record;
+ if (!boot_event_store.GetBootEvent(kBuildDateKey, &record) ||
+ build_date != record.second) {
+ boot_complete_prefix = "ota_" + boot_complete_prefix;
+ boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
+ }
+
+ return boot_complete_prefix;
+}
+
// Records several metrics related to the time it takes to boot the device,
// including disambiguating boot time on encrypted or non-encrypted devices.
void RecordBootComplete() {
BootEventRecordStore boot_event_store;
+ BootEventRecordStore::BootEventRecord record;
time_t uptime = bootstat::ParseUptime();
- BootEventRecordStore::BootEventRecord record;
+ // The boot_complete metric has two variants: boot_complete and
+ // ota_boot_complete. The latter signifies that the device is booting after
+ // a system update.
+ std::string boot_complete_prefix = CalculateBootCompletePrefix();
// post_decrypt_time_elapsed is only logged on encrypted devices.
if (boot_event_store.GetBootEvent("post_decrypt_time_elapsed", &record)) {
@@ -153,18 +181,18 @@
// Subtract the decryption time to normalize the boot cycle timing.
time_t boot_complete = uptime - record.second;
- boot_event_store.AddBootEventWithValue("boot_complete_post_decrypt",
+ boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt",
boot_complete);
} else {
- boot_event_store.AddBootEventWithValue("boot_complete_no_encryption",
+ boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
uptime);
}
// Record the total time from device startup to boot complete, regardless of
// encryption state.
- boot_event_store.AddBootEventWithValue("boot_complete", uptime);
+ boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime);
}
// Records the boot_reason metric by querying the ro.boot.bootreason system
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index bc072bc..70acd38 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -626,11 +626,18 @@
}
encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
} else {
- ERROR("Failed to mount an un-encryptable or wiped partition on"
- "%s at %s options: %s error: %s\n",
- fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
- fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
- ++error_count;
+ if (fs_mgr_is_nofail(&fstab->recs[attempted_idx])) {
+ ERROR("Ignoring failure to mount an un-encryptable or wiped partition on"
+ "%s at %s options: %s error: %s\n",
+ fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+ fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+ } else {
+ ERROR("Failed to mount an un-encryptable or wiped partition on"
+ "%s at %s options: %s error: %s\n",
+ fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+ fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+ ++error_count;
+ }
continue;
}
}
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index c8c624d..6d44e06 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -76,6 +76,7 @@
{ "notrim", MF_NOTRIM },
{ "formattable", MF_FORMATTABLE },
{ "slotselect", MF_SLOTSELECT },
+ { "nofail", MF_NOFAIL },
{ "defaults", 0 },
{ 0, 0 },
};
@@ -502,3 +503,8 @@
{
return fstab->fs_mgr_flags & MF_SLOTSELECT;
}
+
+int fs_mgr_is_nofail(struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_NOFAIL;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 181b6cd..46975f1 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -83,6 +83,7 @@
#define MF_FORMATTABLE 0x4000
#define MF_SLOTSELECT 0x8000
#define MF_FORCEFDEORFBE 0x10000
+#define MF_NOFAIL 0x40000
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 0404dbd..6f4580e 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -106,6 +106,7 @@
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
int fs_mgr_is_notrim(struct fstab_rec *fstab);
int fs_mgr_is_formattable(struct fstab_rec *fstab);
+int fs_mgr_is_nofail(struct fstab_rec *fstab);
int fs_mgr_swapon_all(struct fstab *fstab);
int fs_mgr_do_format(struct fstab_rec *fstab);
diff --git a/init/init.cpp b/init/init.cpp
index 0ff55a5..84da2b9 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -141,59 +141,19 @@
});
}
-static void msg_start(const std::string& name)
-{
- Service* svc = nullptr;
- std::vector<std::string> vargs;
-
- size_t colon_pos = name.find(':');
- if (colon_pos == std::string::npos) {
- svc = ServiceManager::GetInstance().FindServiceByName(name);
- } else {
- std::string service_name(name.substr(0, colon_pos));
- std::string args(name.substr(colon_pos + 1));
- vargs = android::base::Split(args, " ");
-
- svc = ServiceManager::GetInstance().FindServiceByName(service_name);
- }
-
- if (svc) {
- svc->Start(vargs);
- } else {
- ERROR("no such service '%s'\n", name.c_str());
- }
-}
-
-static void msg_stop(const std::string& name)
-{
+void handle_control_message(const std::string& msg, const std::string& name) {
Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
-
- if (svc) {
- svc->Stop();
- } else {
+ if (svc == nullptr) {
ERROR("no such service '%s'\n", name.c_str());
+ return;
}
-}
-static void msg_restart(const std::string& name)
-{
- Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
-
- if (svc) {
- svc->Restart();
- } else {
- ERROR("no such service '%s'\n", name.c_str());
- }
-}
-
-void handle_control_message(const std::string& msg, const std::string& arg)
-{
if (msg == "start") {
- msg_start(arg);
+ svc->Start();
} else if (msg == "stop") {
- msg_stop(arg);
+ svc->Stop();
} else if (msg == "restart") {
- msg_restart(arg);
+ svc->Restart();
} else {
ERROR("unknown control msg '%s'\n", msg.c_str());
}
diff --git a/init/service.cpp b/init/service.cpp
index bdecc32..f1ffa18 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -315,7 +315,7 @@
return (this->*handler)(args, err);
}
-bool Service::Start(const std::vector<std::string>& dynamic_args) {
+bool Service::Start() {
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
@@ -343,13 +343,6 @@
return false;
}
- if ((!(flags_ & SVC_ONESHOT)) && !dynamic_args.empty()) {
- ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
- args_[0].c_str());
- flags_ |= SVC_DISABLED;
- return false;
- }
-
std::string scon;
if (!seclabel_.empty()) {
scon = seclabel_;
@@ -471,9 +464,6 @@
for (const auto& s : args_) {
strs.push_back(const_cast<char*>(s.c_str()));
}
- for (const auto& s : dynamic_args) {
- strs.push_back(const_cast<char*>(s.c_str()));
- }
strs.push_back(nullptr);
if (execve(args_[0].c_str(), (char**) &strs[0], (char**) ENV) < 0) {
ERROR("cannot execve('%s'): %s\n", args_[0].c_str(), strerror(errno));
@@ -502,11 +492,6 @@
return true;
}
-bool Service::Start() {
- const std::vector<std::string> null_dynamic_args;
- return Start(null_dynamic_args);
-}
-
bool Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start();
diff --git a/init/service.h b/init/service.h
index 35abde9..d9d18ef 100644
--- a/init/service.h
+++ b/init/service.h
@@ -76,7 +76,6 @@
const std::string& seclabel, const std::vector<std::string>& args);
bool HandleLine(const std::vector<std::string>& args, std::string* err);
- bool Start(const std::vector<std::string>& dynamic_args);
bool Start();
bool StartIfNotDisabled();
bool Enable();
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 1a26695..b399643 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -148,7 +148,7 @@
}
/*
- * Try to get the scheduler group.
+ * Returns the path under the requested cgroup subsystem (if it exists)
*
* The data from /proc/<pid>/cgroup looks (something) like:
* 2:cpu:/bg_non_interactive
@@ -158,7 +158,7 @@
* the default cgroup. If the string is longer than "bufLen", the string
* will be truncated.
*/
-static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
+static int getCGroupSubsys(int tid, const char* subsys, char* buf, size_t bufLen)
{
#if defined(__ANDROID__)
char pathBuf[32];
@@ -172,7 +172,7 @@
while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) {
char *next = lineBuf;
- char *subsys;
+ char *found_subsys;
char *grp;
size_t len;
@@ -181,11 +181,11 @@
goto out_bad_data;
}
- if (!(subsys = strsep(&next, ":"))) {
+ if (!(found_subsys = strsep(&next, ":"))) {
goto out_bad_data;
}
- if (strcmp(subsys, "cpu")) {
+ if (strcmp(found_subsys, subsys)) {
/* Not the subsys we're looking for */
continue;
}
@@ -206,7 +206,7 @@
return 0;
}
- SLOGE("Failed to find cpu subsys");
+ SLOGE("Failed to find subsys %s", subsys);
fclose(fp);
return -1;
out_bad_data:
@@ -228,7 +228,23 @@
if (__sys_supports_schedgroups) {
char grpBuf[32];
- if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
+#ifdef USE_CPUSETS
+ if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0)
+ return -1;
+ if (grpBuf[0] == '\0') {
+ *policy = SP_FOREGROUND;
+ } else if (!strcmp(grpBuf, "foreground")) {
+ *policy = SP_FOREGROUND;
+ } else if (!strcmp(grpBuf, "background")) {
+ *policy = SP_BACKGROUND;
+ } else if (!strcmp(grpBuf, "top-app")) {
+ *policy = SP_TOP_APP;
+ } else {
+ errno = ERANGE;
+ return -1;
+ }
+#else
+ if (getCGroupSubsys(tid, "cpu", grpBuf, sizeof(grpBuf)) < 0)
return -1;
if (grpBuf[0] == '\0') {
*policy = SP_FOREGROUND;
@@ -238,6 +254,7 @@
errno = ERANGE;
return -1;
}
+#endif
} else {
int rc = sched_getscheduler(tid);
if (rc < 0)
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index ec7a941..f28a693 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -37,7 +37,8 @@
namespace android {
#if defined(__ANDROID__)
-static constexpr const char* kPublicNativeLibrariesConfig = "/system/etc/public.libraries.txt";
+static constexpr const char* kPublicNativeLibrariesSystemConfig = "/system/etc/public.libraries.txt";
+static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
static bool namespace_workaround_enabled(int32_t target_sdk_version) {
return target_sdk_version <= 23;
@@ -107,35 +108,51 @@
}
void Initialize() {
+ std::vector<std::string> sonames;
+
+ LOG_ALWAYS_FATAL_IF(!ReadConfig(kPublicNativeLibrariesSystemConfig, &sonames),
+ "Error reading public native library list from \"%s\": %s",
+ kPublicNativeLibrariesSystemConfig, strerror(errno));
+ // This file is optional, quietly ignore if the file does not exist.
+ ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
+
+ // android_init_namespaces() expects all the public libraries
+ // to be loaded so that they can be found by soname alone.
+ //
+ // TODO(dimitry): this is a bit misleading since we do not know
+ // if the vendor public library is going to be opened from /vendor/lib
+ // we might as well end up loading them from /system/lib
+ // For now we rely on CTS test to catch things like this but
+ // it should probably be addressed in the future.
+ for (const auto& soname : sonames) {
+ dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE);
+ }
+
+ public_libraries_ = base::Join(sonames, ':');
+ }
+
+ private:
+ bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames) {
// Read list of public native libraries from the config file.
std::string file_content;
- LOG_ALWAYS_FATAL_IF(!base::ReadFileToString(kPublicNativeLibrariesConfig, &file_content),
- "Error reading public native library list from \"%s\": %s",
- kPublicNativeLibrariesConfig, strerror(errno));
+ if(!base::ReadFileToString(configFile, &file_content)) {
+ return false;
+ }
std::vector<std::string> lines = base::Split(file_content, "\n");
- std::vector<std::string> sonames;
-
for (const auto& line : lines) {
auto trimmed_line = base::Trim(line);
if (trimmed_line[0] == '#' || trimmed_line.empty()) {
continue;
}
- sonames.push_back(trimmed_line);
+ sonames->push_back(trimmed_line);
}
- public_libraries_ = base::Join(sonames, ':');
-
- // android_init_namespaces() expects all the public libraries
- // to be loaded so that they can be found by soname alone.
- for (const auto& soname : sonames) {
- dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE);
- }
+ return true;
}
- private:
bool InitPublicNamespace(const char* library_path, int32_t target_sdk_version) {
std::string publicNativeLibraries = public_libraries_;
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a95eaa2..3e2f0a5 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -87,6 +87,7 @@
# Symlink to keep legacy apps working in multi-user world
symlink /storage/self/primary /sdcard
+ symlink /storage/self/primary /mnt/sdcard
symlink /mnt/user/0/primary /mnt/runtime/default/self/primary
# root memory control cgroup, used by lmkd