Merge "Fastboot changes to support A/B partitioning"
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index f7b2e4e..fd61bda 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -33,6 +33,7 @@
#include "adb_trace.h"
#include "sysdeps.h"
+ADB_MUTEX_DEFINE(basename_lock);
ADB_MUTEX_DEFINE(dirname_lock);
bool getcwd(std::string* s) {
@@ -69,13 +70,31 @@
}
std::string adb_basename(const std::string& path) {
- size_t base = path.find_last_of(OS_PATH_SEPARATORS);
- return (base != std::string::npos) ? path.substr(base + 1) : path;
+ // Copy path because basename may modify the string passed in.
+ std::string result(path);
+
+ // Use lock because basename() may write to a process global and return a
+ // pointer to that. Note that this locking strategy only works if all other
+ // callers to dirname in the process also grab this same lock.
+ adb_mutex_lock(&basename_lock);
+
+ // Note that if std::string uses copy-on-write strings, &str[0] will cause
+ // the copy to be made, so there is no chance of us accidentally writing to
+ // the storage for 'path'.
+ char* name = basename(&result[0]);
+
+ // In case dirname returned a pointer to a process global, copy that string
+ // before leaving the lock.
+ result.assign(name);
+
+ adb_mutex_unlock(&basename_lock);
+
+ return result;
}
std::string adb_dirname(const std::string& path) {
// Copy path because dirname may modify the string passed in.
- std::string parent_storage(path);
+ std::string result(path);
// Use lock because dirname() may write to a process global and return a
// pointer to that. Note that this locking strategy only works if all other
@@ -85,11 +104,11 @@
// Note that if std::string uses copy-on-write strings, &str[0] will cause
// the copy to be made, so there is no chance of us accidentally writing to
// the storage for 'path'.
- char* parent = dirname(&parent_storage[0]);
+ char* parent = dirname(&result[0]);
// In case dirname returned a pointer to a process global, copy that string
// before leaving the lock.
- const std::string result(parent);
+ result.assign(parent);
adb_mutex_unlock(&dirname_lock);
@@ -115,9 +134,7 @@
// - Recursive, so it uses stack space relative to number of directory
// components.
- const std::string parent(adb_dirname(path));
-
- if (directory_exists(parent)) {
+ if (directory_exists(path)) {
return true;
}
@@ -125,19 +142,21 @@
// This can happen on Windows when walking up the directory hierarchy and not
// finding anything that already exists (unlike POSIX that will eventually
// find . or /).
+ const std::string parent(adb_dirname(path));
+
if (parent == path) {
errno = ENOENT;
return false;
}
- // Recursively make parent directories of 'parent'.
+ // Recursively make parent directories of 'path'.
if (!mkdirs(parent)) {
return false;
}
- // Now that the parent directory hierarchy of 'parent' has been ensured,
+ // Now that the parent directory hierarchy of 'path' has been ensured,
// create parent itself.
- if (adb_mkdir(parent, 0775) == -1) {
+ if (adb_mkdir(path, 0775) == -1) {
// Can't just check for errno == EEXIST because it might be a file that
// exists.
const int saved_errno = errno;
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 4a2787a..93c20cb 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -102,6 +102,13 @@
TEST(adb_utils, adb_basename) {
EXPECT_EQ("sh", adb_basename("/system/bin/sh"));
EXPECT_EQ("sh", adb_basename("sh"));
+ EXPECT_EQ("sh", adb_basename("/system/bin/sh/"));
+}
+
+TEST(adb_utils, adb_dirname) {
+ EXPECT_EQ("/system/bin", adb_dirname("/system/bin/sh"));
+ EXPECT_EQ(".", adb_dirname("sh"));
+ EXPECT_EQ("/system/bin", adb_dirname("/system/bin/sh/"));
}
TEST(adb_utils, parse_host_and_port) {
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index ffde619..785fef3 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -41,6 +41,7 @@
#if !defined(_WIN32)
#include <signal.h>
+#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#endif
@@ -247,17 +248,17 @@
#if defined(_WIN32)
// Implemented in sysdeps_win32.cpp.
-void stdin_raw_init(int fd);
-void stdin_raw_restore(int fd);
+void stdin_raw_init();
+void stdin_raw_restore();
#else
static termios g_saved_terminal_state;
-static void stdin_raw_init(int fd) {
- if (tcgetattr(fd, &g_saved_terminal_state)) return;
+static void stdin_raw_init() {
+ if (tcgetattr(STDIN_FILENO, &g_saved_terminal_state)) return;
termios tio;
- if (tcgetattr(fd, &tio)) return;
+ if (tcgetattr(STDIN_FILENO, &tio)) return;
cfmakeraw(&tio);
@@ -265,11 +266,11 @@
tio.c_cc[VTIME] = 0;
tio.c_cc[VMIN] = 1;
- tcsetattr(fd, TCSAFLUSH, &tio);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
}
-static void stdin_raw_restore(int fd) {
- tcsetattr(fd, TCSAFLUSH, &g_saved_terminal_state);
+static void stdin_raw_restore() {
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &g_saved_terminal_state);
}
#endif
@@ -358,7 +359,7 @@
D("copy_to_file(%d -> %d)", inFd, outFd);
if (inFd == STDIN_FILENO) {
- stdin_raw_init(STDIN_FILENO);
+ stdin_raw_init();
#ifdef _WIN32
old_stdin_mode = _setmode(STDIN_FILENO, _O_BINARY);
if (old_stdin_mode == -1) {
@@ -400,7 +401,7 @@
}
if (inFd == STDIN_FILENO) {
- stdin_raw_restore(STDIN_FILENO);
+ stdin_raw_restore();
#ifdef _WIN32
if (_setmode(STDIN_FILENO, old_stdin_mode) == -1) {
fatal_errno("could not restore stdin mode");
@@ -420,7 +421,44 @@
free(buf);
}
-namespace {
+static std::string format_host_command(const char* command,
+ TransportType type, const char* serial) {
+ if (serial) {
+ return android::base::StringPrintf("host-serial:%s:%s", serial, command);
+ }
+
+ const char* prefix = "host";
+ if (type == kTransportUsb) {
+ prefix = "host-usb";
+ } else if (type == kTransportLocal) {
+ prefix = "host-local";
+ }
+ return android::base::StringPrintf("%s:%s", prefix, command);
+}
+
+// Returns the FeatureSet for the indicated transport.
+static FeatureSet GetFeatureSet(TransportType transport_type, const char* serial) {
+ std::string result, error;
+ if (adb_query(format_host_command("features", transport_type, serial), &result, &error)) {
+ return StringToFeatureSet(result);
+ }
+ return FeatureSet();
+}
+
+static void send_window_size_change(int fd, std::unique_ptr<ShellProtocol>& shell) {
+#if !defined(_WIN32)
+ // Old devices can't handle window size changes.
+ if (shell == nullptr) return;
+
+ winsize ws;
+ if (ioctl(fd, TIOCGWINSZ, &ws) == -1) return;
+
+ // Send the new window size as human-readable ASCII for debugging convenience.
+ size_t l = snprintf(shell->data(), shell->data_capacity(), "%dx%d,%dx%d",
+ ws.ws_row, ws.ws_col, ws.ws_xpixel, ws.ws_ypixel);
+ shell->Write(ShellProtocol::kIdWindowSizeChange, l + 1);
+#endif
+}
// Used to pass multiple values to the stdin read thread.
struct StdinReadArgs {
@@ -429,38 +467,56 @@
std::unique_ptr<ShellProtocol> protocol;
};
-} // namespace
-
// Loops to read from stdin and push the data to the given FD.
// The argument should be a pointer to a StdinReadArgs object. This function
// will take ownership of the object and delete it when finished.
-static void* stdin_read_thread(void* x) {
+static void* stdin_read_thread_loop(void* x) {
std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x));
int state = 0;
- adb_thread_setname("stdin reader");
-
-#ifndef _WIN32
- // Mask SIGTTIN in case we're in a backgrounded process
+#if !defined(_WIN32)
+ // Mask SIGTTIN in case we're in a backgrounded process.
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGTTIN);
pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
#endif
+#if !defined(_WIN32)
+ // Unblock SIGWINCH for this thread, so our read(2) below will be
+ // interrupted if the window size changes.
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGWINCH);
+ pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);
+#endif
+
+ // Set up the initial window size.
+ send_window_size_change(args->stdin_fd, args->protocol);
+
char raw_buffer[1024];
char* buffer_ptr = raw_buffer;
size_t buffer_size = sizeof(raw_buffer);
- if (args->protocol) {
+ if (args->protocol != nullptr) {
buffer_ptr = args->protocol->data();
buffer_size = args->protocol->data_capacity();
}
while (true) {
// Use unix_read() rather than adb_read() for stdin.
- D("stdin_read_thread(): pre unix_read(fdi=%d,...)", args->stdin_fd);
+ D("stdin_read_thread_loop(): pre unix_read(fdi=%d,...)", args->stdin_fd);
+#if !defined(_WIN32)
+#undef read
+ int r = read(args->stdin_fd, buffer_ptr, buffer_size);
+ if (r == -1 && errno == EINTR) {
+ send_window_size_change(args->stdin_fd, args->protocol);
+ continue;
+ }
+#define read ___xxx_read
+#else
int r = unix_read(args->stdin_fd, buffer_ptr, buffer_size);
- D("stdin_read_thread(): post unix_read(fdi=%d,...)", args->stdin_fd);
+#endif
+ D("stdin_read_thread_loop(): post unix_read(fdi=%d,...)", args->stdin_fd);
if (r <= 0) {
// Only devices using the shell protocol know to close subprocess
// stdin. For older devices we want to just leave the connection
@@ -477,8 +533,8 @@
// process starts ignoring the signal. SSH also does this, see the
// "escape characters" section on the ssh man page for more info.
if (args->raw_stdin) {
- for (int n = 0; n < r; n++){
- switch(buffer_ptr[n]) {
+ for (int n = 0; n < r; n++) {
+ switch (buffer_ptr[n]) {
case '\n':
state = 1;
break;
@@ -486,16 +542,16 @@
state = 1;
break;
case '~':
- if(state == 1) {
+ if (state == 1) {
state++;
} else {
state = 0;
}
break;
case '.':
- if(state == 2) {
- stdin_raw_restore(args->stdin_fd);
- fprintf(stderr,"\n* disconnect *\n");
+ if (state == 2) {
+ fprintf(stderr,"\r\n* disconnect *\r\n");
+ stdin_raw_restore();
exit(0);
}
default:
@@ -574,53 +630,121 @@
args->protocol.reset(new ShellProtocol(args->write_fd));
}
- if (raw_stdin) {
- stdin_raw_init(STDIN_FILENO);
- }
+ if (raw_stdin) stdin_raw_init();
- int exit_code = 0;
- if (!adb_thread_create(stdin_read_thread, args)) {
+#if !defined(_WIN32)
+ // Ensure our process is notified if the local window size changes.
+ // We use sigaction(2) to ensure that the SA_RESTART flag is not set,
+ // because the whole reason we're sending signals is to unblock the read(2)!
+ // That also means we don't need to do anything in the signal handler:
+ // the side effect of delivering the signal is all we need.
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = [](int) {};
+ sa.sa_flags = 0;
+ sigaction(SIGWINCH, &sa, nullptr);
+
+ // Now block SIGWINCH in this thread (the main thread) and all threads spawned
+ // from it. The stdin read thread will unblock this signal to ensure that it's
+ // the thread that receives the signal.
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGWINCH);
+ pthread_sigmask(SIG_BLOCK, &mask, nullptr);
+#endif
+
+ // TODO: combine read_and_dump with stdin_read_thread to make life simpler?
+ int exit_code = 1;
+ if (!adb_thread_create(stdin_read_thread_loop, args)) {
PLOG(ERROR) << "error starting stdin read thread";
- exit_code = 1;
delete args;
} else {
exit_code = read_and_dump(fd, use_shell_protocol);
}
- if (raw_stdin) {
- stdin_raw_restore(STDIN_FILENO);
- }
+ // TODO: properly exit stdin_read_thread_loop and close |fd|.
- // TODO(dpursell): properly exit stdin_read_thread and close |fd|.
+ // TODO: we should probably install signal handlers for this.
+ // TODO: can we use atexit? even on Windows?
+ if (raw_stdin) stdin_raw_restore();
return exit_code;
}
+static int adb_shell(int argc, const char** argv,
+ TransportType transport_type, const char* serial) {
+ FeatureSet features = GetFeatureSet(transport_type, serial);
-static std::string format_host_command(const char* command, TransportType type, const char* serial) {
- if (serial) {
- return android::base::StringPrintf("host-serial:%s:%s", serial, command);
+ bool use_shell_protocol = CanUseFeature(features, kFeatureShell2);
+ if (!use_shell_protocol) {
+ D("shell protocol not supported, using raw data transfer");
+ } else {
+ D("using shell protocol");
}
- const char* prefix = "host";
- if (type == kTransportUsb) {
- prefix = "host-usb";
- } else if (type == kTransportLocal) {
- prefix = "host-local";
+ // Parse shell-specific command-line options.
+ // argv[0] is always "shell".
+ --argc;
+ ++argv;
+ int t_arg_count = 0;
+ while (argc) {
+ if (!strcmp(argv[0], "-T") || !strcmp(argv[0], "-t")) {
+ if (!CanUseFeature(features, kFeatureShell2)) {
+ fprintf(stderr, "error: target doesn't support PTY args -Tt\n");
+ return 1;
+ }
+ // Like ssh, -t arguments are cumulative so that multiple -t's
+ // are needed to force a PTY.
+ if (argv[0][1] == 't') {
+ ++t_arg_count;
+ } else {
+ t_arg_count = -1;
+ }
+ --argc;
+ ++argv;
+ } else if (!strcmp(argv[0], "-x")) {
+ use_shell_protocol = false;
+ --argc;
+ ++argv;
+ } else {
+ break;
+ }
}
- return android::base::StringPrintf("%s:%s", prefix, command);
-}
-// Returns the FeatureSet for the indicated transport.
-static FeatureSet GetFeatureSet(TransportType transport_type,
- const char* serial) {
- std::string result, error;
-
- if (adb_query(format_host_command("features", transport_type, serial),
- &result, &error)) {
- return StringToFeatureSet(result);
+ std::string shell_type_arg;
+ if (CanUseFeature(features, kFeatureShell2)) {
+ if (t_arg_count < 0) {
+ shell_type_arg = kShellServiceArgRaw;
+ } else if (t_arg_count == 0) {
+ // If stdin isn't a TTY, default to a raw shell; this lets
+ // things like `adb shell < my_script.sh` work as expected.
+ // Otherwise leave |shell_type_arg| blank which uses PTY for
+ // interactive shells and raw for non-interactive.
+ if (!unix_isatty(STDIN_FILENO)) {
+ shell_type_arg = kShellServiceArgRaw;
+ }
+ } else if (t_arg_count == 1) {
+ // A single -t arg isn't enough to override implicit -T.
+ if (!unix_isatty(STDIN_FILENO)) {
+ fprintf(stderr,
+ "Remote PTY will not be allocated because stdin is not a terminal.\n"
+ "Use multiple -t options to force remote PTY allocation.\n");
+ shell_type_arg = kShellServiceArgRaw;
+ } else {
+ shell_type_arg = kShellServiceArgPty;
+ }
+ } else {
+ shell_type_arg = kShellServiceArgPty;
+ }
}
- return FeatureSet();
+
+ std::string command;
+ if (argc) {
+ // We don't escape here, just like ssh(1). http://b/20564385.
+ command = android::base::Join(std::vector<const char*>(argv, argv + argc), ' ');
+ }
+
+ return RemoteShell(use_shell_protocol, shell_type_arg, command);
}
static int adb_download_buffer(const char *service, const char *fn, const void* data, unsigned sz,
@@ -928,7 +1052,7 @@
}
static int backup(int argc, const char** argv) {
- const char* filename = "./backup.ab";
+ const char* filename = "backup.ab";
/* find, extract, and use any -f argument */
for (int i = 1; i < argc; i++) {
@@ -950,7 +1074,6 @@
if (argc < 2) return usage();
adb_unlink(filename);
- mkdirs(filename);
int outFd = adb_creat(filename, 0640);
if (outFd < 0) {
fprintf(stderr, "adb: unable to open file %s\n", filename);
@@ -1343,94 +1466,8 @@
else if (!strcmp(argv[0], "emu")) {
return adb_send_emulator_command(argc, argv, serial);
}
- else if (!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
- char h = (argv[0][0] == 'h');
-
- FeatureSet features = GetFeatureSet(transport_type, serial);
-
- bool use_shell_protocol = CanUseFeature(features, kFeatureShell2);
- if (!use_shell_protocol) {
- D("shell protocol not supported, using raw data transfer");
- } else {
- D("using shell protocol");
- }
-
- // Parse shell-specific command-line options.
- // argv[0] is always "shell".
- --argc;
- ++argv;
- int t_arg_count = 0;
- while (argc) {
- if (!strcmp(argv[0], "-T") || !strcmp(argv[0], "-t")) {
- if (!CanUseFeature(features, kFeatureShell2)) {
- fprintf(stderr, "error: target doesn't support PTY args -Tt\n");
- return 1;
- }
- // Like ssh, -t arguments are cumulative so that multiple -t's
- // are needed to force a PTY.
- if (argv[0][1] == 't') {
- ++t_arg_count;
- } else {
- t_arg_count = -1;
- }
- --argc;
- ++argv;
- } else if (!strcmp(argv[0], "-x")) {
- use_shell_protocol = false;
- --argc;
- ++argv;
- } else {
- break;
- }
- }
-
- std::string shell_type_arg;
- if (CanUseFeature(features, kFeatureShell2)) {
- if (t_arg_count < 0) {
- shell_type_arg = kShellServiceArgRaw;
- } else if (t_arg_count == 0) {
- // If stdin isn't a TTY, default to a raw shell; this lets
- // things like `adb shell < my_script.sh` work as expected.
- // Otherwise leave |shell_type_arg| blank which uses PTY for
- // interactive shells and raw for non-interactive.
- if (!unix_isatty(STDIN_FILENO)) {
- shell_type_arg = kShellServiceArgRaw;
- }
- } else if (t_arg_count == 1) {
- // A single -t arg isn't enough to override implicit -T.
- if (!unix_isatty(STDIN_FILENO)) {
- fprintf(stderr,
- "Remote PTY will not be allocated because stdin is not a terminal.\n"
- "Use multiple -t options to force remote PTY allocation.\n");
- shell_type_arg = kShellServiceArgRaw;
- } else {
- shell_type_arg = kShellServiceArgPty;
- }
- } else {
- shell_type_arg = kShellServiceArgPty;
- }
- }
-
- std::string command;
- if (argc) {
- // We don't escape here, just like ssh(1). http://b/20564385.
- command = android::base::Join(
- std::vector<const char*>(argv, argv + argc), ' ');
- }
-
- if (h) {
- printf("\x1b[41;33m");
- fflush(stdout);
- }
-
- r = RemoteShell(use_shell_protocol, shell_type_arg, command);
-
- if (h) {
- printf("\x1b[0m");
- fflush(stdout);
- }
-
- return r;
+ else if (!strcmp(argv[0], "shell")) {
+ return adb_shell(argc, argv, transport_type, serial);
}
else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
int exec_in = !strcmp(argv[0], "exec-in");
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 4458c85..06eb34d 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -54,7 +54,7 @@
struct PollNode {
fdevent* fde;
- pollfd pollfd;
+ ::pollfd pollfd;
PollNode(fdevent* fde) : fde(fde) {
memset(&pollfd, 0, sizeof(pollfd));
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 7a60580..d2bc3cd 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -28,6 +28,7 @@
#include <unistd.h>
#include <utime.h>
+#include <functional>
#include <memory>
#include <vector>
@@ -230,9 +231,10 @@
}
};
-typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name, void* cookie);
+typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
-static bool sync_ls(SyncConnection& sc, const char* path, sync_ls_cb func, void* cookie) {
+static bool sync_ls(SyncConnection& sc, const char* path,
+ std::function<sync_ls_cb> func) {
if (!sc.SendRequest(ID_LIST, path)) return false;
while (true) {
@@ -249,7 +251,7 @@
if (!ReadFdExactly(sc.fd, buf, len)) return false;
buf[len] = 0;
- func(msg.dent.mode, msg.dent.size, msg.dent.time, buf, cookie);
+ func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
}
}
@@ -390,7 +392,12 @@
if (!sc.SendRequest(ID_RECV, rpath)) return false;
adb_unlink(lpath);
- mkdirs(lpath);
+ if (!mkdirs(adb_dirname(lpath))) {
+ sc.Error("failed to create parent directory '%s': %s",
+ adb_dirname(lpath).c_str(), strerror(errno));
+ return false;
+ }
+
int lfd = adb_creat(lpath, 0644);
if (lfd < 0) {
sc.Error("cannot create '%s': %s", lpath, strerror(errno));
@@ -448,65 +455,45 @@
return true;
}
-static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
- const char* name, void* /*cookie*/) {
- printf("%08x %08x %08x %s\n", mode, size, time, name);
-}
-
bool do_sync_ls(const char* path) {
SyncConnection sc;
if (!sc.IsValid()) return false;
- return sync_ls(sc, path, do_sync_ls_cb, 0);
+ return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
+ const char* name) {
+ printf("%08x %08x %08x %s\n", mode, size, time, name);
+ });
}
struct copyinfo
{
- copyinfo *next;
- const char *src;
- const char *dst;
+ std::string src;
+ std::string dst;
unsigned int time;
unsigned int mode;
uint64_t size;
- int flag;
+ bool skip;
};
-static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
- int slen = strlen(spath);
- int dlen = strlen(dpath);
- int nlen = strlen(name);
- int ssize = slen + nlen + 2;
- int dsize = dlen + nlen + 2;
-
- copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
- if (ci == 0) {
- fprintf(stderr, "out of memory\n");
- abort();
- }
-
- ci->next = 0;
- ci->time = 0;
- ci->mode = 0;
- ci->size = 0;
- ci->flag = 0;
- ci->src = (const char*)(ci + 1);
- ci->dst = ci->src + ssize;
- snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
- snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
-
- return ci;
+static copyinfo mkcopyinfo(const char* spath, const char* dpath, const char* name, bool isdir) {
+ copyinfo result;
+ result.src = android::base::StringPrintf(isdir ? "%s%s/" : "%s%s", spath, name);
+ result.dst = android::base::StringPrintf(isdir ? "%s%s/" : "%s%s", dpath, name);
+ result.time = 0;
+ result.mode = 0;
+ result.size = 0;
+ result.skip = false;
+ return result;
}
static bool IsDotOrDotDot(const char* name) {
return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
}
-static int local_build_list(SyncConnection& sc,
- copyinfo** filelist, const char* lpath, const char* rpath) {
- copyinfo *dirlist = 0;
- copyinfo *ci, *next;
-
- std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
+static int local_build_list(SyncConnection& sc, std::vector<copyinfo>* filelist,
+ const char* lpath, const char* rpath) {
+ std::vector<copyinfo> dirlist;
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath), closedir);
if (!dir) {
sc.Error("cannot open '%s': %s", lpath, strerror(errno));
return -1;
@@ -527,33 +514,27 @@
struct stat st;
if (!lstat(stat_path, &st)) {
if (S_ISDIR(st.st_mode)) {
- ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
- ci->next = dirlist;
- dirlist = ci;
+ dirlist.push_back(mkcopyinfo(lpath, rpath, de->d_name, 1));
} else {
- ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
- sc.Error("skipping special file '%s'", ci->src);
- free(ci);
+ sc.Error("skipping special file '%s'", lpath);
} else {
- ci->time = st.st_mtime;
- ci->mode = st.st_mode;
- ci->size = st.st_size;
- ci->next = *filelist;
- *filelist = ci;
+ copyinfo ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
+ ci.time = st.st_mtime;
+ ci.mode = st.st_mode;
+ ci.size = st.st_size;
+ filelist->push_back(ci);
}
}
} else {
- sc.Error("cannot lstat '%s': %s",stat_path , strerror(errno));
+ sc.Error("cannot lstat '%s': %s", stat_path, strerror(errno));
}
}
// Close this directory and recurse.
dir.reset();
- for (ci = dirlist; ci != 0; ci = next) {
- next = ci->next;
- local_build_list(sc, filelist, ci->src, ci->dst);
- free(ci);
+ for (const copyinfo& ci : dirlist) {
+ local_build_list(sc, filelist, ci.src.c_str(), ci.dst.c_str());
}
return 0;
@@ -561,8 +542,7 @@
static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
bool check_timestamps, bool list_only) {
- copyinfo *filelist = 0;
- copyinfo *ci, *next;
+ std::vector<copyinfo> filelist;
int pushed = 0;
int skipped = 0;
@@ -587,28 +567,29 @@
}
if (check_timestamps) {
- for (ci = filelist; ci != 0; ci = ci->next) {
- if (!sc.SendRequest(ID_STAT, ci->dst)) return false;
+ for (const copyinfo& ci : filelist) {
+ if (!sc.SendRequest(ID_STAT, ci.dst.c_str())) return false;
}
- for(ci = filelist; ci != 0; ci = ci->next) {
+ for (copyinfo& ci : filelist) {
unsigned int timestamp, mode, size;
if (!sync_finish_stat(sc, ×tamp, &mode, &size)) return false;
- if (size == ci->size) {
+ if (size == ci.size) {
/* for links, we cannot update the atime/mtime */
- if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
- (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
- ci->flag = 1;
+ if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
+ (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) {
+ ci.skip = true;
}
}
}
}
- for (ci = filelist; ci != 0; ci = next) {
- next = ci->next;
- if (ci->flag == 0) {
+
+ for (const copyinfo& ci : filelist) {
+ if (!ci.skip) {
if (list_only) {
- fprintf(stderr, "would push: %s -> %s\n", ci->src, ci->dst);
+ fprintf(stderr, "would push: %s -> %s\n", ci.src.c_str(),
+ ci.dst.c_str());
} else {
- if (!sync_send(sc, ci->src, ci->dst, ci->time, ci->mode)) {
+ if (!sync_send(sc, ci.src.c_str(), ci.dst.c_str(), ci.time, ci.mode)) {
return false;
}
}
@@ -616,7 +597,6 @@
} else {
skipped++;
}
- free(ci);
}
sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s\n", rpath, pushed,
@@ -676,67 +656,43 @@
return success;
}
-struct sync_ls_build_list_cb_args {
- SyncConnection* sc;
- copyinfo** filelist;
- copyinfo** dirlist;
- const char* rpath;
- const char* lpath;
-};
-
-static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
- const char* name, void* cookie)
-{
- sync_ls_build_list_cb_args* args = static_cast<sync_ls_build_list_cb_args*>(cookie);
- copyinfo *ci;
-
- if (S_ISDIR(mode)) {
- copyinfo **dirlist = args->dirlist;
-
- // Don't try recursing down "." or "..".
- if (IsDotOrDotDot(name)) return;
-
- ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
- ci->next = *dirlist;
- *dirlist = ci;
- } else if (S_ISREG(mode) || S_ISLNK(mode)) {
- copyinfo **filelist = args->filelist;
-
- ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
- ci->time = time;
- ci->mode = mode;
- ci->size = size;
- ci->next = *filelist;
- *filelist = ci;
- } else {
- args->sc->Printf("skipping special file '%s'\n", name);
- }
-}
-
-static bool remote_build_list(SyncConnection& sc, copyinfo **filelist,
- const char *rpath, const char *lpath) {
- copyinfo* dirlist = nullptr;
-
- sync_ls_build_list_cb_args args;
- args.sc = ≻
- args.filelist = filelist;
- args.dirlist = &dirlist;
- args.rpath = rpath;
- args.lpath = lpath;
+static bool remote_build_list(SyncConnection& sc,
+ std::vector<copyinfo>* filelist,
+ const char* rpath, const char* lpath) {
+ std::vector<copyinfo> dirlist;
// Put the files/dirs in rpath on the lists.
- if (!sync_ls(sc, rpath, sync_ls_build_list_cb, &args)) {
+ auto callback = [&](unsigned mode, unsigned size, unsigned time,
+ const char* name) {
+ if (S_ISDIR(mode)) {
+ // Don't try recursing down "." or "..".
+ if (IsDotOrDotDot(name)) return;
+
+ dirlist.push_back(mkcopyinfo(rpath, lpath, name, 1));
+ } else if (S_ISREG(mode) || S_ISLNK(mode)) {
+ copyinfo ci = mkcopyinfo(rpath, lpath, name, 0);
+ ci.time = time;
+ ci.mode = mode;
+ ci.size = size;
+ filelist->push_back(ci);
+ } else {
+ sc.Print(android::base::StringPrintf("skipping special file '%s'\n",
+ name));
+ }
+ };
+
+ if (!sync_ls(sc, rpath, callback)) {
return false;
}
// Recurse into each directory we found.
- while (dirlist != NULL) {
- copyinfo* next = dirlist->next;
- if (!remote_build_list(sc, filelist, dirlist->src, dirlist->dst)) {
+ while (!dirlist.empty()) {
+ copyinfo current = dirlist.back();
+ dirlist.pop_back();
+ if (!remote_build_list(sc, filelist, current.src.c_str(),
+ current.dst.c_str())) {
return false;
}
- free(dirlist);
- dirlist = next;
}
return true;
@@ -748,7 +704,7 @@
int r1 = utime(lpath, ×);
/* use umask for permissions */
- mode_t mask=umask(0000);
+ mode_t mask = umask(0000);
umask(mask);
int r2 = chmod(lpath, mode & ~mask);
@@ -766,29 +722,29 @@
// Recursively build the list of files to copy.
sc.Print("pull: building file list...");
- copyinfo* filelist = nullptr;
- if (!remote_build_list(sc, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
+ std::vector<copyinfo> filelist;
+ if (!remote_build_list(sc, &filelist, rpath_clean.c_str(),
+ lpath_clean.c_str())) {
+ return false;
+ }
int pulled = 0;
int skipped = 0;
- copyinfo* ci = filelist;
- while (ci) {
- copyinfo* next = ci->next;
- if (ci->flag == 0) {
- sc.Printf("pull: %s -> %s", ci->src, ci->dst);
- if (!sync_recv(sc, ci->src, ci->dst)) {
+ for (const copyinfo &ci : filelist) {
+ if (!ci.skip) {
+ sc.Printf("pull: %s -> %s", ci.src.c_str(), ci.dst.c_str());
+ if (!sync_recv(sc, ci.src.c_str(), ci.dst.c_str())) {
return false;
}
- if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
+ if (copy_attrs &&
+ set_time_and_mode(ci.dst.c_str(), ci.time, ci.mode)) {
return false;
}
pulled++;
} else {
skipped++;
}
- free(ci);
- ci = next;
}
sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s\n", rpath, pulled,
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 298ed82..7484a7c 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -32,6 +32,7 @@
#include "adb.h"
#include "adb_io.h"
+#include "adb_utils.h"
#include "private/android_filesystem_config.h"
#include <base/stringprintf.h>
@@ -53,8 +54,6 @@
if (path[0] != '/') return false;
std::vector<std::string> path_components = android::base::Split(path, "/");
- path_components.pop_back(); // For "/system/bin/sh", only create "/system/bin".
-
std::string partial_path;
for (const auto& path_component : path_components) {
if (partial_path.back() != OS_PATH_SEPARATOR) partial_path += OS_PATH_SEPARATOR;
@@ -149,7 +148,7 @@
int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
if (fd < 0 && errno == ENOENT) {
- if (!secure_mkdirs(path)) {
+ if (!secure_mkdirs(adb_dirname(path))) {
SendSyncFailErrno(s, "secure_mkdirs failed");
goto fail;
}
@@ -244,7 +243,7 @@
ret = symlink(&buffer[0], path.c_str());
if (ret && errno == ENOENT) {
- if (!secure_mkdirs(path)) {
+ if (!secure_mkdirs(adb_dirname(path))) {
SendSyncFailErrno(s, "secure_mkdirs failed");
return false;
}
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index be5921d..e3fde26 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -513,6 +513,18 @@
if (stdinout_sfd_.valid()) {
switch (input_->id()) {
+ case ShellProtocol::kIdWindowSizeChange:
+ int rows, cols, x_pixels, y_pixels;
+ if (sscanf(input_->data(), "%dx%d,%dx%d",
+ &rows, &cols, &x_pixels, &y_pixels) == 4) {
+ winsize ws;
+ ws.ws_row = rows;
+ ws.ws_col = cols;
+ ws.ws_xpixel = x_pixels;
+ ws.ws_ypixel = y_pixels;
+ ioctl(stdinout_sfd_.fd(), TIOCSWINSZ, &ws);
+ }
+ break;
case ShellProtocol::kIdStdin:
input_bytes_left_ = input_->data_length();
break;
@@ -531,8 +543,7 @@
// non-interactively which is rare and unsupported.
// If necessary, the client can manually close the shell
// with `exit` or by killing the adb client process.
- D("can't close input for PTY FD %d",
- stdinout_sfd_.fd());
+ D("can't close input for PTY FD %d", stdinout_sfd_.fd());
}
break;
}
diff --git a/adb/shell_service.h b/adb/shell_service.h
index 01410a9..63c00da 100644
--- a/adb/shell_service.h
+++ b/adb/shell_service.h
@@ -54,8 +54,15 @@
kIdStdout = 1,
kIdStderr = 2,
kIdExit = 3,
- kIdCloseStdin = 4, // Close subprocess stdin if possible.
- kIdInvalid = 255, // Indicates an invalid or unknown packet.
+
+ // Close subprocess stdin if possible.
+ kIdCloseStdin = 4,
+
+ // Window size change (an ASCII version of struct winsize).
+ kIdWindowSizeChange = 5,
+
+ // Indicates an invalid or unknown packet.
+ kIdInvalid = 255,
};
// ShellPackets will probably be too large to allocate on the stack so they
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index d2e6cdb..e325889 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -3342,44 +3342,41 @@
static DWORD _old_console_mode; // previous GetConsoleMode() result
static HANDLE _console_handle; // when set, console mode should be restored
-void stdin_raw_init(const int fd) {
- if (STDIN_FILENO == fd) {
- const HANDLE in = _get_console_handle(fd, &_old_console_mode);
+void stdin_raw_init() {
+ const HANDLE in = _get_console_handle(STDIN_FILENO, &_old_console_mode);
- // Disable ENABLE_PROCESSED_INPUT so that Ctrl-C is read instead of
- // calling the process Ctrl-C routine (configured by
- // SetConsoleCtrlHandler()).
- // Disable ENABLE_LINE_INPUT so that input is immediately sent.
- // Disable ENABLE_ECHO_INPUT to disable local echo. Disabling this
- // flag also seems necessary to have proper line-ending processing.
- if (!SetConsoleMode(in, _old_console_mode & ~(ENABLE_PROCESSED_INPUT |
- ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))) {
- // This really should not fail.
- D("stdin_raw_init: SetConsoleMode() failed: %s",
- SystemErrorCodeToString(GetLastError()).c_str());
- }
-
- // Once this is set, it means that stdin has been configured for
- // reading from and that the old console mode should be restored later.
- _console_handle = in;
-
- // Note that we don't need to configure C Runtime line-ending
- // translation because _console_read() does not call the C Runtime to
- // read from the console.
+ // Disable ENABLE_PROCESSED_INPUT so that Ctrl-C is read instead of
+ // calling the process Ctrl-C routine (configured by
+ // SetConsoleCtrlHandler()).
+ // Disable ENABLE_LINE_INPUT so that input is immediately sent.
+ // Disable ENABLE_ECHO_INPUT to disable local echo. Disabling this
+ // flag also seems necessary to have proper line-ending processing.
+ if (!SetConsoleMode(in, _old_console_mode & ~(ENABLE_PROCESSED_INPUT |
+ ENABLE_LINE_INPUT |
+ ENABLE_ECHO_INPUT))) {
+ // This really should not fail.
+ D("stdin_raw_init: SetConsoleMode() failed: %s",
+ SystemErrorCodeToString(GetLastError()).c_str());
}
+
+ // Once this is set, it means that stdin has been configured for
+ // reading from and that the old console mode should be restored later.
+ _console_handle = in;
+
+ // Note that we don't need to configure C Runtime line-ending
+ // translation because _console_read() does not call the C Runtime to
+ // read from the console.
}
-void stdin_raw_restore(const int fd) {
- if (STDIN_FILENO == fd) {
- if (_console_handle != NULL) {
- const HANDLE in = _console_handle;
- _console_handle = NULL; // clear state
+void stdin_raw_restore() {
+ if (_console_handle != NULL) {
+ const HANDLE in = _console_handle;
+ _console_handle = NULL; // clear state
- if (!SetConsoleMode(in, _old_console_mode)) {
- // This really should not fail.
- D("stdin_raw_restore: SetConsoleMode() failed: %s",
- SystemErrorCodeToString(GetLastError()).c_str());
- }
+ if (!SetConsoleMode(in, _old_console_mode)) {
+ // This really should not fail.
+ D("stdin_raw_restore: SetConsoleMode() failed: %s",
+ SystemErrorCodeToString(GetLastError()).c_str());
}
}
}
diff --git a/crash_reporter/Android.mk b/crash_reporter/Android.mk
index c5ca4e4..81cb458 100644
--- a/crash_reporter/Android.mk
+++ b/crash_reporter/Android.mk
@@ -102,9 +102,13 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/$(OSRELEASED_DIRECTORY)
include $(BUILD_SYSTEM)/base_rules.mk
+# Optionally populate the BRILLO_CRASH_SERVER variable from a product
+# configuration file: brillo/crash_server.
+LOADED_BRILLO_CRASH_SERVER := $(call cfgtree-get-if-exists,brillo/crash_server)
+
# If the crash server isn't set, use a blank value. crash_sender
# will log it as a configuration error.
-$(LOCAL_BUILT_MODULE): BRILLO_CRASH_SERVER ?= ""
+$(LOCAL_BUILT_MODULE): BRILLO_CRASH_SERVER ?= "$(LOADED_BRILLO_CRASH_SERVER)"
$(LOCAL_BUILT_MODULE):
$(hide)mkdir -p $(dir $@)
echo $(BRILLO_CRASH_SERVER) > $@
diff --git a/debuggerd/debuggerd.rc b/debuggerd/debuggerd.rc
index 4338ae9..4be2e5d 100644
--- a/debuggerd/debuggerd.rc
+++ b/debuggerd/debuggerd.rc
@@ -1,2 +1,3 @@
service debuggerd /system/bin/debuggerd
class main
+ writepid /dev/cpuset/system-background/tasks
diff --git a/debuggerd/debuggerd64.rc b/debuggerd/debuggerd64.rc
index 341a329..c6e7bf2 100644
--- a/debuggerd/debuggerd64.rc
+++ b/debuggerd/debuggerd64.rc
@@ -1,2 +1,3 @@
service debuggerd64 /system/bin/debuggerd64
class main
+ writepid /dev/cpuset/system-background/tasks
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 765511f..be30d81 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -266,6 +266,11 @@
" partitions.\n"
" flashing get_unlock_ability Queries bootloader to see if the\n"
" device is unlocked.\n"
+ " flashing get_unlock_bootloader_nonce Queries the bootloader to get the\n"
+ " unlock nonce.\n"
+ " flashing unlock_bootloader <request> Issue unlock bootloader using request.\n"
+ " flashing lock_bootloader Locks the bootloader to prevent\n"
+ " bootloader version rollback.\n"
" erase <partition> Erase a flash partition.\n"
" format[:[<fs type>][:[<size>]] <partition>\n"
" Format a flash partition. Can\n"
@@ -584,7 +589,7 @@
static int64_t get_target_sparse_limit(usb_handle* usb) {
std::string max_download_size;
- if (!fb_getvar(usb, "max-download-size", &max_download_size)) {
+ if (!fb_getvar(usb, "max-download-size", &max_download_size) || max_download_size.empty()) {
fprintf(stderr, "target didn't report max-download-size\n");
return 0;
}
@@ -893,7 +898,28 @@
#define skip(n) do { argc -= (n); argv += (n); } while (0)
#define require(n) do { if (argc < (n)) {usage(); exit(1);}} while (0)
-static int do_oem_command(int argc, char** argv) {
+static int do_bypass_unlock_command(int argc, char **argv)
+{
+ if (argc <= 2) return 0;
+ skip(2);
+
+ /*
+ * Process unlock_bootloader, we have to load the message file
+ * and send that to the remote device.
+ */
+ require(1);
+
+ int64_t sz;
+ void* data = load_file(*argv, &sz);
+ if (data == nullptr) die("could not load '%s': %s", *argv, strerror(errno));
+ fb_queue_download("unlock_message", data, sz);
+ fb_queue_command("flashing unlock_bootloader", "unlocking bootloader");
+ skip(1);
+ return 0;
+}
+
+static int do_oem_command(int argc, char **argv)
+{
char command[256];
if (argc <= 1) return 0;
@@ -1004,6 +1030,10 @@
return;
}
+ // Some bootloaders (hammerhead, for example) use implicit hex.
+ // This code used to use strtol with base 16.
+ if (!android::base::StartsWith(partition_size, "0x")) partition_size = "0x" + partition_size;
+
int64_t size;
if (!android::base::ParseInt(partition_size.c_str(), &size)) {
fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str());
@@ -1320,12 +1350,18 @@
skip(2);
} else if(!strcmp(*argv, "oem")) {
argc = do_oem_command(argc, argv);
- } else if(!strcmp(*argv, "flashing") && argc == 2) {
- if(!strcmp(*(argv+1), "unlock") || !strcmp(*(argv+1), "lock")
- || !strcmp(*(argv+1), "unlock_critical")
- || !strcmp(*(argv+1), "lock_critical")
- || !strcmp(*(argv+1), "get_unlock_ability")) {
- argc = do_oem_command(argc, argv);
+ } else if(!strcmp(*argv, "flashing")) {
+ if (argc == 2 && (!strcmp(*(argv+1), "unlock") ||
+ !strcmp(*(argv+1), "lock") ||
+ !strcmp(*(argv+1), "unlock_critical") ||
+ !strcmp(*(argv+1), "lock_critical") ||
+ !strcmp(*(argv+1), "get_unlock_ability") ||
+ !strcmp(*(argv+1), "get_unlock_bootloader_nonce") ||
+ !strcmp(*(argv+1), "lock_bootloader"))) {
+ argc = do_oem_command(argc, argv);
+ } else
+ if (argc == 3 && !strcmp(*(argv+1), "unlock_bootloader")) {
+ argc = do_bypass_unlock_command(argc, argv);
} else {
usage();
return 1;
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h
index 75fe11d..c8010ca 100644
--- a/gatekeeperd/SoftGateKeeper.h
+++ b/gatekeeperd/SoftGateKeeper.h
@@ -25,8 +25,10 @@
#include <crypto_scrypt.h>
}
+#include <base/memory.h>
#include <UniquePtr.h>
#include <gatekeeper/gatekeeper.h>
+
#include <iostream>
#include <unordered_map>
@@ -150,14 +152,15 @@
}
bool DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) {
- FastHashMap::const_iterator it = fast_hash_map_.find(expected_handle->user_id);
+ uint64_t user_id = android::base::get_unaligned(&expected_handle->user_id);
+ FastHashMap::const_iterator it = fast_hash_map_.find(user_id);
if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) {
return true;
} else {
if (GateKeeper::DoVerify(expected_handle, password)) {
uint64_t salt;
GetRandom(&salt, sizeof(salt));
- fast_hash_map_[expected_handle->user_id] = ComputeFastHash(password, salt);
+ fast_hash_map_[user_id] = ComputeFastHash(password, salt);
return true;
}
}
diff --git a/gatekeeperd/tests/Android.mk b/gatekeeperd/tests/Android.mk
index 6fc4ac0..a62b1d4 100644
--- a/gatekeeperd/tests/Android.mk
+++ b/gatekeeperd/tests/Android.mk
@@ -20,7 +20,7 @@
LOCAL_MODULE := gatekeeperd-unit-tests
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
-LOCAL_SHARED_LIBRARIES := libgatekeeper libcrypto
+LOCAL_SHARED_LIBRARIES := libgatekeeper libcrypto libbase
LOCAL_STATIC_LIBRARIES := libscrypt_static
LOCAL_C_INCLUDES := external/scrypt/lib/crypto
LOCAL_SRC_FILES := \
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index e280fdc..cb77a8e 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -183,6 +183,7 @@
props.chargerWirelessOnline = false;
props.batteryStatus = BATTERY_STATUS_UNKNOWN;
props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
+ props.maxChargingCurrent = 0;
if (!mHealthdConfig->batteryPresentPath.isEmpty())
props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
@@ -246,6 +247,15 @@
KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
mChargerNames[i].string());
}
+ path.clear();
+ path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
+ mChargerNames[i].string());
+ if (access(path.string(), R_OK) == 0) {
+ int maxChargingCurrent = getIntField(path);
+ if (props.maxChargingCurrent < maxChargingCurrent) {
+ props.maxChargingCurrent = maxChargingCurrent;
+ }
+ }
}
}
}
@@ -382,9 +392,9 @@
int v;
char vs[128];
- snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d\n",
+ snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d\n",
props.chargerAcOnline, props.chargerUsbOnline,
- props.chargerWirelessOnline);
+ props.chargerWirelessOnline, props.maxChargingCurrent);
write(fd, vs, strlen(vs));
snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
props.batteryStatus, props.batteryHealth, props.batteryPresent);
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index 20a379e..1741fb2 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -17,10 +17,9 @@
#ifndef ANDROID_UTILS_LRU_CACHE_H
#define ANDROID_UTILS_LRU_CACHE_H
+#include <memory>
#include <unordered_set>
-#include <UniquePtr.h>
-
#include "utils/TypeHelpers.h" // hash_t
namespace android {
@@ -91,7 +90,7 @@
return result;
}
- UniquePtr<LruCacheSet> mSet;
+ std::unique_ptr<LruCacheSet> mSet;
OnEntryRemoved<TKey, TValue>* mListener;
Entry* mOldest;
Entry* mYoungest;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 3ffa2e8..36ecbb8 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -788,13 +788,13 @@
return 0;
}
-int do_load_persist_props(const std::vector<std::string>& args) {
+static int do_load_persist_props(const std::vector<std::string>& args) {
load_persist_props();
return 0;
}
-static int do_load_all_props(const std::vector<std::string>& args) {
- load_all_props();
+static int do_load_system_props(const std::vector<std::string>& args) {
+ load_system_props();
return 0;
}
@@ -818,16 +818,26 @@
return 0;
}
+static bool is_file_crypto() {
+ std::string value = property_get("ro.crypto.type");
+ return value == "file";
+}
+
static int do_installkey(const std::vector<std::string>& args) {
- std::string prop_value = property_get("ro.crypto.type");
- if (prop_value != "file") {
+ if (!is_file_crypto()) {
return 0;
}
-
return e4crypt_create_device_key(args[1].c_str(),
do_installkeys_ensure_dir_exists);
}
+static int do_setusercryptopolicies(const std::vector<std::string>& args) {
+ if (!is_file_crypto()) {
+ return 0;
+ }
+ return e4crypt_set_user_crypto_policies(args[1].c_str());
+}
+
BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
static const Map builtin_functions = {
@@ -846,8 +856,8 @@
{"ifup", {1, 1, do_ifup}},
{"insmod", {1, kMax, do_insmod}},
{"installkey", {1, 1, do_installkey}},
- {"load_all_props", {0, 0, do_load_all_props}},
{"load_persist_props", {0, 0, do_load_persist_props}},
+ {"load_system_props", {0, 0, do_load_system_props}},
{"loglevel", {1, 1, do_loglevel}},
{"mkdir", {1, 4, do_mkdir}},
{"mount_all", {1, 1, do_mount_all}},
@@ -860,6 +870,7 @@
{"rmdir", {1, 1, do_rmdir}},
{"setprop", {2, 2, do_setprop}},
{"setrlimit", {3, 3, do_setrlimit}},
+ {"setusercryptopolicies", {1, 1, do_setusercryptopolicies}},
{"start", {1, 1, do_start}},
{"stop", {1, 1, do_stop}},
{"swapon_all", {1, 1, do_swapon_all}},
diff --git a/init/property_service.cpp b/init/property_service.cpp
index ebf768e..96b4a37 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -559,16 +559,10 @@
close(fd);
}
-void load_all_props() {
+void load_system_props() {
load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
-
- load_override_properties();
-
- /* Read persistent properties after all default values have been loaded. */
- load_persistent_properties();
-
load_recovery_id_prop();
}
diff --git a/init/property_service.h b/init/property_service.h
index 1a48fb1..8b76d2b 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -30,7 +30,7 @@
extern void property_init(void);
extern void property_load_boot_defaults(void);
extern void load_persist_props(void);
-extern void load_all_props(void);
+extern void load_system_props(void);
extern void start_property_service(void);
void get_property_workspace(int *fd, int *sz);
std::string property_get(const char* name);
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index bdee28f..a4310ae 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -191,7 +191,11 @@
* };
*/
- clock_gettime(CLOCK_REALTIME, &ts);
+ if (android_log_timestamp() == 'm') {
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ } else {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ }
pmsg_header.magic = LOGGER_MAGIC;
pmsg_header.len = sizeof(pmsg_header) + sizeof(header);
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 0ea2269..9f12c96 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -203,7 +203,7 @@
p_ret->year_output = false;
p_ret->zone_output = false;
p_ret->epoch_output = false;
- p_ret->monotonic_output = false;
+ p_ret->monotonic_output = android_log_timestamp() == 'm';
return p_ret;
}
@@ -1261,10 +1261,13 @@
now = entry->tv_sec;
nsec = entry->tv_nsec;
if (p_format->monotonic_output) {
- struct timespec time;
- convertMonotonic(&time, entry);
- now = time.tv_sec;
- nsec = time.tv_nsec;
+ // prevent convertMonotonic from being called if logd is monotonic
+ if (android_log_timestamp() != 'm') {
+ struct timespec time;
+ convertMonotonic(&time, entry);
+ now = time.tv_sec;
+ nsec = time.tv_nsec;
+ }
}
if (now < 0) {
nsec = NS_PER_SEC - nsec;
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 11e7988..65a3fdf 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -14,8 +14,6 @@
codeflinger/load_store.cpp \
codeflinger/blending.cpp \
codeflinger/texturing.cpp \
- codeflinger/tinyutils/SharedBuffer.cpp \
- codeflinger/tinyutils/VectorImpl.cpp \
fixed.cpp.arm \
picker.cpp.arm \
pixelflinger.cpp.arm \
@@ -63,8 +61,9 @@
LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
-LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS) \
+ external/safe-iop/include
+LOCAL_SHARED_LIBRARIES := libcutils liblog libutils
# Really this should go away entirely or at least not depend on
# libhardware, but this at least gets us built.
diff --git a/libpixelflinger/codeflinger/ARMAssembler.h b/libpixelflinger/codeflinger/ARMAssembler.h
index c03dd9a..e0c7646 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.h
+++ b/libpixelflinger/codeflinger/ARMAssembler.h
@@ -21,9 +21,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include "tinyutils/Vector.h"
-#include "tinyutils/KeyedVector.h"
#include "tinyutils/smartpointer.h"
+#include "utils/Vector.h"
+#include "utils/KeyedVector.h"
#include "ARMAssemblerInterface.h"
#include "CodeCache.h"
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.h b/libpixelflinger/codeflinger/Arm64Assembler.h
index 8479270..c9be116 100644
--- a/libpixelflinger/codeflinger/Arm64Assembler.h
+++ b/libpixelflinger/codeflinger/Arm64Assembler.h
@@ -32,9 +32,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include "tinyutils/Vector.h"
-#include "tinyutils/KeyedVector.h"
#include "tinyutils/smartpointer.h"
+#include "utils/Vector.h"
+#include "utils/KeyedVector.h"
#include "tinyutils/smartpointer.h"
#include "codeflinger/ARMAssemblerInterface.h"
diff --git a/libpixelflinger/codeflinger/CodeCache.h b/libpixelflinger/codeflinger/CodeCache.h
index fa67dd0..0fb6fd5 100644
--- a/libpixelflinger/codeflinger/CodeCache.h
+++ b/libpixelflinger/codeflinger/CodeCache.h
@@ -23,7 +23,7 @@
#include <pthread.h>
#include <sys/types.h>
-#include "tinyutils/KeyedVector.h"
+#include "utils/KeyedVector.h"
#include "tinyutils/smartpointer.h"
namespace android {
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.h b/libpixelflinger/codeflinger/MIPSAssembler.h
index 430ab06..8fea8cb 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.h
+++ b/libpixelflinger/codeflinger/MIPSAssembler.h
@@ -21,9 +21,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include "tinyutils/KeyedVector.h"
-#include "tinyutils/Vector.h"
#include "tinyutils/smartpointer.h"
+#include "utils/KeyedVector.h"
+#include "utils/Vector.h"
#include "ARMAssemblerInterface.h"
#include "CodeCache.h"
diff --git a/libpixelflinger/codeflinger/tinyutils/Errors.h b/libpixelflinger/codeflinger/tinyutils/Errors.h
deleted file mode 100644
index 47ae9d7..0000000
--- a/libpixelflinger/codeflinger/tinyutils/Errors.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_PIXELFLINGER_ERRORS_H
-#define ANDROID_PIXELFLINGER_ERRORS_H
-
-#include <sys/types.h>
-#include <errno.h>
-
-namespace android {
-namespace tinyutils {
-
-// use this type to return error codes
-typedef int32_t status_t;
-
-/*
- * Error codes.
- * All error codes are negative values.
- */
-
-enum {
- NO_ERROR = 0, // No errors.
- NO_MEMORY = -ENOMEM,
- BAD_VALUE = -EINVAL,
- BAD_INDEX = -EOVERFLOW,
- NAME_NOT_FOUND = -ENOENT,
-};
-
-
-} // namespace tinyutils
-} // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_ERRORS_H
diff --git a/libpixelflinger/codeflinger/tinyutils/KeyedVector.h b/libpixelflinger/codeflinger/tinyutils/KeyedVector.h
deleted file mode 100644
index 9d8668b..0000000
--- a/libpixelflinger/codeflinger/tinyutils/KeyedVector.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_PIXELFLINGER_KEYED_VECTOR_H
-#define ANDROID_PIXELFLINGER_KEYED_VECTOR_H
-
-#include <assert.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "Errors.h"
-#include "SortedVector.h"
-#include "TypeHelpers.h"
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-namespace tinyutils {
-
-template <typename KEY, typename VALUE>
-class KeyedVector
-{
-public:
- typedef KEY key_type;
- typedef VALUE value_type;
-
- inline KeyedVector();
-
- /*
- * empty the vector
- */
-
- inline void clear() { mVector.clear(); }
-
- /*!
- * vector stats
- */
-
- //! returns number of items in the vector
- inline size_t size() const { return mVector.size(); }
- //! returns wether or not the vector is empty
- inline bool isEmpty() const { return mVector.isEmpty(); }
- //! returns how many items can be stored without reallocating the backing store
- inline size_t capacity() const { return mVector.capacity(); }
- //! setst the capacity. capacity can never be reduced less than size()
- inline ssize_t setCapacity(size_t size) { return mVector.setCapacity(size); }
-
- /*!
- * accessors
- */
- const VALUE& valueFor(const KEY& key) const;
- const VALUE& valueAt(size_t index) const;
- const KEY& keyAt(size_t index) const;
- ssize_t indexOfKey(const KEY& key) const;
-
- /*!
- * modifing the array
- */
-
- VALUE& editValueFor(const KEY& key);
- VALUE& editValueAt(size_t index);
-
- /*!
- * add/insert/replace items
- */
-
- ssize_t add(const KEY& key, const VALUE& item);
- ssize_t replaceValueFor(const KEY& key, const VALUE& item);
- ssize_t replaceValueAt(size_t index, const VALUE& item);
-
- /*!
- * remove items
- */
-
- ssize_t removeItem(const KEY& key);
- ssize_t removeItemsAt(size_t index, size_t count = 1);
-
-private:
- SortedVector< key_value_pair_t<KEY, VALUE> > mVector;
-};
-
-// ---------------------------------------------------------------------------
-
-/**
- * Variation of KeyedVector that holds a default value to return when
- * valueFor() is called with a key that doesn't exist.
- */
-template <typename KEY, typename VALUE>
-class DefaultKeyedVector : public KeyedVector<KEY, VALUE>
-{
-public:
- inline DefaultKeyedVector(const VALUE& defValue = VALUE());
- const VALUE& valueFor(const KEY& key) const;
-
-private:
- VALUE mDefault;
-};
-
-// ---------------------------------------------------------------------------
-
-template<typename KEY, typename VALUE> inline
-KeyedVector<KEY,VALUE>::KeyedVector()
-{
-}
-
-template<typename KEY, typename VALUE> inline
-ssize_t KeyedVector<KEY,VALUE>::indexOfKey(const KEY& key) const {
- return mVector.indexOf( key_value_pair_t<KEY,VALUE>(key) );
-}
-
-template<typename KEY, typename VALUE> inline
-const VALUE& KeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
- ssize_t i = indexOfKey(key);
- assert(i>=0);
- return mVector.itemAt(i).value;
-}
-
-template<typename KEY, typename VALUE> inline
-const VALUE& KeyedVector<KEY,VALUE>::valueAt(size_t index) const {
- return mVector.itemAt(index).value;
-}
-
-template<typename KEY, typename VALUE> inline
-const KEY& KeyedVector<KEY,VALUE>::keyAt(size_t index) const {
- return mVector.itemAt(index).key;
-}
-
-template<typename KEY, typename VALUE> inline
-VALUE& KeyedVector<KEY,VALUE>::editValueFor(const KEY& key) {
- ssize_t i = indexOfKey(key);
- assert(i>=0);
- return mVector.editItemAt(i).value;
-}
-
-template<typename KEY, typename VALUE> inline
-VALUE& KeyedVector<KEY,VALUE>::editValueAt(size_t index) {
- return mVector.editItemAt(index).value;
-}
-
-template<typename KEY, typename VALUE> inline
-ssize_t KeyedVector<KEY,VALUE>::add(const KEY& key, const VALUE& value) {
- return mVector.add( key_value_pair_t<KEY,VALUE>(key, value) );
-}
-
-template<typename KEY, typename VALUE> inline
-ssize_t KeyedVector<KEY,VALUE>::replaceValueFor(const KEY& key, const VALUE& value) {
- key_value_pair_t<KEY,VALUE> pair(key, value);
- mVector.remove(pair);
- return mVector.add(pair);
-}
-
-template<typename KEY, typename VALUE> inline
-ssize_t KeyedVector<KEY,VALUE>::replaceValueAt(size_t index, const VALUE& item) {
- if (index<size()) {
- mVector.editValueAt(index).value = item;
- return index;
- }
- return BAD_INDEX;
-}
-
-template<typename KEY, typename VALUE> inline
-ssize_t KeyedVector<KEY,VALUE>::removeItem(const KEY& key) {
- return mVector.remove(key_value_pair_t<KEY,VALUE>(key));
-}
-
-template<typename KEY, typename VALUE> inline
-ssize_t KeyedVector<KEY, VALUE>::removeItemsAt(size_t index, size_t count) {
- return mVector.removeItemsAt(index, count);
-}
-
-// ---------------------------------------------------------------------------
-
-template<typename KEY, typename VALUE> inline
-DefaultKeyedVector<KEY,VALUE>::DefaultKeyedVector(const VALUE& defValue)
- : mDefault(defValue)
-{
-}
-
-template<typename KEY, typename VALUE> inline
-const VALUE& DefaultKeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
- ssize_t i = indexOfKey(key);
- return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
-}
-
-} // namespace tinyutils
-} // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_KEYED_VECTOR_H
diff --git a/libpixelflinger/codeflinger/tinyutils/SharedBuffer.cpp b/libpixelflinger/codeflinger/tinyutils/SharedBuffer.cpp
deleted file mode 100644
index ef453fa..0000000
--- a/libpixelflinger/codeflinger/tinyutils/SharedBuffer.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2005 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 <stdlib.h>
-#include <string.h>
-
-#include <cutils/atomic.h>
-
-#include "SharedBuffer.h"
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-namespace tinyutils {
-
-SharedBuffer* SharedBuffer::alloc(size_t size)
-{
- SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
- if (sb) {
- sb->mRefs = 1;
- sb->mSize = size;
- }
- return sb;
-}
-
-
-ssize_t SharedBuffer::dealloc(const SharedBuffer* released)
-{
- if (released->mRefs != 0) return -1; // XXX: invalid operation
- free(const_cast<SharedBuffer*>(released));
- return 0;
-}
-
-SharedBuffer* SharedBuffer::edit() const
-{
- if (onlyOwner()) {
- return const_cast<SharedBuffer*>(this);
- }
- SharedBuffer* sb = alloc(mSize);
- if (sb) {
- memcpy(sb->data(), data(), size());
- release();
- }
- return sb;
-}
-
-SharedBuffer* SharedBuffer::editResize(size_t newSize) const
-{
- if (onlyOwner()) {
- SharedBuffer* buf = const_cast<SharedBuffer*>(this);
- if (buf->mSize == newSize) return buf;
- buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
- if (buf != NULL) {
- buf->mSize = newSize;
- return buf;
- }
- }
- SharedBuffer* sb = alloc(newSize);
- if (sb) {
- const size_t mySize = mSize;
- memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize);
- release();
- }
- return sb;
-}
-
-SharedBuffer* SharedBuffer::attemptEdit() const
-{
- if (onlyOwner()) {
- return const_cast<SharedBuffer*>(this);
- }
- return 0;
-}
-
-SharedBuffer* SharedBuffer::reset(size_t new_size) const
-{
- // cheap-o-reset.
- SharedBuffer* sb = alloc(new_size);
- if (sb) {
- release();
- }
- return sb;
-}
-
-void SharedBuffer::acquire() const {
- android_atomic_inc(&mRefs);
-}
-
-int32_t SharedBuffer::release(uint32_t flags) const
-{
- int32_t prev = 1;
- if (onlyOwner() || ((prev = android_atomic_dec(&mRefs)) == 1)) {
- mRefs = 0;
- if ((flags & eKeepStorage) == 0) {
- free(const_cast<SharedBuffer*>(this));
- }
- }
- return prev;
-}
-
-} // namespace tinyutils
-} // namespace android
diff --git a/libpixelflinger/codeflinger/tinyutils/SharedBuffer.h b/libpixelflinger/codeflinger/tinyutils/SharedBuffer.h
deleted file mode 100644
index d69b417..0000000
--- a/libpixelflinger/codeflinger/tinyutils/SharedBuffer.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_PIXELFLINGER_SHARED_BUFFER_H
-#define ANDROID_PIXELFLINGER_SHARED_BUFFER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-namespace tinyutils {
-
-class SharedBuffer
-{
-public:
-
- /* flags to use with release() */
- enum {
- eKeepStorage = 0x00000001
- };
-
- /*! allocate a buffer of size 'size' and acquire() it.
- * call release() to free it.
- */
- static SharedBuffer* alloc(size_t size);
-
- /*! free the memory associated with the SharedBuffer.
- * Fails if there are any users associated with this SharedBuffer.
- * In other words, the buffer must have been release by all its
- * users.
- */
- static ssize_t dealloc(const SharedBuffer* released);
-
- //! get the SharedBuffer from the data pointer
- static inline const SharedBuffer* sharedBuffer(const void* data);
-
- //! access the data for read
- inline const void* data() const;
-
- //! access the data for read/write
- inline void* data();
-
- //! get size of the buffer
- inline size_t size() const;
-
- //! get back a SharedBuffer object from its data
- static inline SharedBuffer* bufferFromData(void* data);
-
- //! get back a SharedBuffer object from its data
- static inline const SharedBuffer* bufferFromData(const void* data);
-
- //! get the size of a SharedBuffer object from its data
- static inline size_t sizeFromData(const void* data);
-
- //! edit the buffer (get a writtable, or non-const, version of it)
- SharedBuffer* edit() const;
-
- //! edit the buffer, resizing if needed
- SharedBuffer* editResize(size_t size) const;
-
- //! like edit() but fails if a copy is required
- SharedBuffer* attemptEdit() const;
-
- //! resize and edit the buffer, loose it's content.
- SharedBuffer* reset(size_t size) const;
-
- //! acquire/release a reference on this buffer
- void acquire() const;
-
- /*! release a reference on this buffer, with the option of not
- * freeing the memory associated with it if it was the last reference
- * returns the previous reference count
- */
- int32_t release(uint32_t flags = 0) const;
-
- //! returns wether or not we're the only owner
- inline bool onlyOwner() const;
-
-
-private:
- inline SharedBuffer() { }
- inline ~SharedBuffer() { }
- inline SharedBuffer(const SharedBuffer&);
-
- // 16 bytes. must be sized to preserve correct alingment.
- mutable int32_t mRefs;
- size_t mSize;
- uint32_t mReserved[2];
-};
-
-// ---------------------------------------------------------------------------
-
-const SharedBuffer* SharedBuffer::sharedBuffer(const void* data) {
- return data ? reinterpret_cast<const SharedBuffer *>(data)-1 : 0;
-}
-
-const void* SharedBuffer::data() const {
- return this + 1;
-}
-
-void* SharedBuffer::data() {
- return this + 1;
-}
-
-size_t SharedBuffer::size() const {
- return mSize;
-}
-
-SharedBuffer* SharedBuffer::bufferFromData(void* data)
-{
- return ((SharedBuffer*)data)-1;
-}
-
-const SharedBuffer* SharedBuffer::bufferFromData(const void* data)
-{
- return ((const SharedBuffer*)data)-1;
-}
-
-size_t SharedBuffer::sizeFromData(const void* data)
-{
- return (((const SharedBuffer*)data)-1)->mSize;
-}
-
-bool SharedBuffer::onlyOwner() const {
- return (mRefs == 1);
-}
-
-} // namespace tinyutils
-} // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_SHARED_BUFFER_H
diff --git a/libpixelflinger/codeflinger/tinyutils/SortedVector.h b/libpixelflinger/codeflinger/tinyutils/SortedVector.h
deleted file mode 100644
index a2b7005..0000000
--- a/libpixelflinger/codeflinger/tinyutils/SortedVector.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_PIXELFLINGER_SORTED_VECTOR_H
-#define ANDROID_PIXELFLINGER_SORTED_VECTOR_H
-
-#include <assert.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "Vector.h"
-#include "VectorImpl.h"
-#include "TypeHelpers.h"
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-namespace tinyutils {
-
-template <class TYPE>
-class SortedVector : private SortedVectorImpl
-{
-public:
- typedef TYPE value_type;
-
- /*!
- * Constructors and destructors
- */
-
- SortedVector();
- SortedVector(const SortedVector<TYPE>& rhs);
- virtual ~SortedVector();
-
- /*! copy operator */
- const SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const;
- SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs);
-
- /*
- * empty the vector
- */
-
- inline void clear() { VectorImpl::clear(); }
-
- /*!
- * vector stats
- */
-
- //! returns number of items in the vector
- inline size_t size() const { return VectorImpl::size(); }
- //! returns wether or not the vector is empty
- inline bool isEmpty() const { return VectorImpl::isEmpty(); }
- //! returns how many items can be stored without reallocating the backing store
- inline size_t capacity() const { return VectorImpl::capacity(); }
- //! setst the capacity. capacity can never be reduced less than size()
- inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
-
- /*!
- * C-style array access
- */
-
- //! read-only C-style access
- inline const TYPE* array() const;
-
- //! read-write C-style access. BE VERY CAREFUL when modifying the array
- //! you ust keep it sorted! You usually don't use this function.
- TYPE* editArray();
-
- //! finds the index of an item
- ssize_t indexOf(const TYPE& item) const;
-
- //! finds where this item should be inserted
- size_t orderOf(const TYPE& item) const;
-
-
- /*!
- * accessors
- */
-
- //! read-only access to an item at a given index
- inline const TYPE& operator [] (size_t index) const;
- //! alternate name for operator []
- inline const TYPE& itemAt(size_t index) const;
- //! stack-usage of the vector. returns the top of the stack (last element)
- const TYPE& top() const;
- //! same as operator [], but allows to access the vector backward (from the end) with a negative index
- const TYPE& mirrorItemAt(ssize_t index) const;
-
- /*!
- * modifing the array
- */
-
- //! add an item in the right place (and replace the one that is there)
- ssize_t add(const TYPE& item);
-
- //! editItemAt() MUST NOT change the order of this item
- TYPE& editItemAt(size_t index) {
- return *( static_cast<TYPE *>(VectorImpl::editItemLocation(index)) );
- }
-
- //! merges a vector into this one
- ssize_t merge(const Vector<TYPE>& vector);
- ssize_t merge(const SortedVector<TYPE>& vector);
-
- //! removes an item
- ssize_t remove(const TYPE&);
-
- //! remove several items
- inline ssize_t removeItemsAt(size_t index, size_t count = 1);
- //! remove one item
- inline ssize_t removeAt(size_t index) { return removeItemsAt(index); }
-
-protected:
- virtual void do_construct(void* storage, size_t num) const;
- virtual void do_destroy(void* storage, size_t num) const;
- virtual void do_copy(void* dest, const void* from, size_t num) const;
- virtual void do_splat(void* dest, const void* item, size_t num) const;
- virtual void do_move_forward(void* dest, const void* from, size_t num) const;
- virtual void do_move_backward(void* dest, const void* from, size_t num) const;
- virtual int do_compare(const void* lhs, const void* rhs) const;
-};
-
-
-// ---------------------------------------------------------------------------
-// No user serviceable parts from here...
-// ---------------------------------------------------------------------------
-
-template<class TYPE> inline
-SortedVector<TYPE>::SortedVector()
- : SortedVectorImpl(sizeof(TYPE),
- ((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
- |(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
- |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
- |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
- )
-{
-}
-
-template<class TYPE> inline
-SortedVector<TYPE>::SortedVector(const SortedVector<TYPE>& rhs)
- : SortedVectorImpl(rhs) {
-}
-
-template<class TYPE> inline
-SortedVector<TYPE>::~SortedVector() {
- finish_vector();
-}
-
-template<class TYPE> inline
-SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
- SortedVectorImpl::operator = (rhs);
- return *this;
-}
-
-template<class TYPE> inline
-const SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
- SortedVectorImpl::operator = (rhs);
- return *this;
-}
-
-template<class TYPE> inline
-const TYPE* SortedVector<TYPE>::array() const {
- return static_cast<const TYPE *>(arrayImpl());
-}
-
-template<class TYPE> inline
-TYPE* SortedVector<TYPE>::editArray() {
- return static_cast<TYPE *>(editArrayImpl());
-}
-
-
-template<class TYPE> inline
-const TYPE& SortedVector<TYPE>::operator[](size_t index) const {
- assert( index<size() );
- return *(array() + index);
-}
-
-template<class TYPE> inline
-const TYPE& SortedVector<TYPE>::itemAt(size_t index) const {
- return operator[](index);
-}
-
-template<class TYPE> inline
-const TYPE& SortedVector<TYPE>::mirrorItemAt(ssize_t index) const {
- assert( (index>0 ? index : -index)<size() );
- return *(array() + ((index<0) ? (size()-index) : index));
-}
-
-template<class TYPE> inline
-const TYPE& SortedVector<TYPE>::top() const {
- return *(array() + size() - 1);
-}
-
-template<class TYPE> inline
-ssize_t SortedVector<TYPE>::add(const TYPE& item) {
- return SortedVectorImpl::add(&item);
-}
-
-template<class TYPE> inline
-ssize_t SortedVector<TYPE>::indexOf(const TYPE& item) const {
- return SortedVectorImpl::indexOf(&item);
-}
-
-template<class TYPE> inline
-size_t SortedVector<TYPE>::orderOf(const TYPE& item) const {
- return SortedVectorImpl::orderOf(&item);
-}
-
-template<class TYPE> inline
-ssize_t SortedVector<TYPE>::merge(const Vector<TYPE>& vector) {
- return SortedVectorImpl::merge(reinterpret_cast<const VectorImpl&>(vector));
-}
-
-template<class TYPE> inline
-ssize_t SortedVector<TYPE>::merge(const SortedVector<TYPE>& vector) {
- return SortedVectorImpl::merge(reinterpret_cast<const SortedVectorImpl&>(vector));
-}
-
-template<class TYPE> inline
-ssize_t SortedVector<TYPE>::remove(const TYPE& item) {
- return SortedVectorImpl::remove(&item);
-}
-
-template<class TYPE> inline
-ssize_t SortedVector<TYPE>::removeItemsAt(size_t index, size_t count) {
- return VectorImpl::removeItemsAt(index, count);
-}
-
-// ---------------------------------------------------------------------------
-
-template<class TYPE>
-void SortedVector<TYPE>::do_construct(void* storage, size_t num) const {
- construct_type( reinterpret_cast<TYPE*>(storage), num );
-}
-
-template<class TYPE>
-void SortedVector<TYPE>::do_destroy(void* storage, size_t num) const {
- destroy_type( reinterpret_cast<TYPE*>(storage), num );
-}
-
-template<class TYPE>
-void SortedVector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
- copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
-}
-
-template<class TYPE>
-void SortedVector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
- splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
-}
-
-template<class TYPE>
-void SortedVector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
- move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
-}
-
-template<class TYPE>
-void SortedVector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
- move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
-}
-
-template<class TYPE>
-int SortedVector<TYPE>::do_compare(const void* lhs, const void* rhs) const {
- return compare_type( *reinterpret_cast<const TYPE*>(lhs), *reinterpret_cast<const TYPE*>(rhs) );
-}
-
-} // namespace tinyutils
-} // namespace android
-
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_SORTED_VECTOR_H
diff --git a/libpixelflinger/codeflinger/tinyutils/TypeHelpers.h b/libpixelflinger/codeflinger/tinyutils/TypeHelpers.h
deleted file mode 100644
index 7abff07..0000000
--- a/libpixelflinger/codeflinger/tinyutils/TypeHelpers.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_PIXELFLINGER_TYPE_HELPERS_H
-#define ANDROID_PIXELFLINGER_TYPE_HELPERS_H
-
-#include <new>
-#include <stdint.h>
-#include <string.h>
-#include <sys/types.h>
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-namespace tinyutils {
-
-/*
- * Types traits
- */
-
-template <typename T> struct trait_trivial_ctor { enum { value = false }; };
-template <typename T> struct trait_trivial_dtor { enum { value = false }; };
-template <typename T> struct trait_trivial_copy { enum { value = false }; };
-template <typename T> struct trait_trivial_assign{ enum { value = false }; };
-
-template <typename T> struct trait_pointer { enum { value = false }; };
-template <typename T> struct trait_pointer<T*> { enum { value = true }; };
-
-#define ANDROID_BASIC_TYPES_TRAITS( T ) \
- template<> struct trait_trivial_ctor< T > { enum { value = true }; }; \
- template<> struct trait_trivial_dtor< T > { enum { value = true }; }; \
- template<> struct trait_trivial_copy< T > { enum { value = true }; }; \
- template<> struct trait_trivial_assign< T >{ enum { value = true }; };
-
-#define ANDROID_TYPE_TRAITS( T, ctor, dtor, copy, assign ) \
- template<> struct trait_trivial_ctor< T > { enum { value = ctor }; }; \
- template<> struct trait_trivial_dtor< T > { enum { value = dtor }; }; \
- template<> struct trait_trivial_copy< T > { enum { value = copy }; }; \
- template<> struct trait_trivial_assign< T >{ enum { value = assign }; };
-
-template <typename TYPE>
-struct traits {
- enum {
- is_pointer = trait_pointer<TYPE>::value,
- has_trivial_ctor = is_pointer || trait_trivial_ctor<TYPE>::value,
- has_trivial_dtor = is_pointer || trait_trivial_dtor<TYPE>::value,
- has_trivial_copy = is_pointer || trait_trivial_copy<TYPE>::value,
- has_trivial_assign = is_pointer || trait_trivial_assign<TYPE>::value
- };
-};
-
-template <typename T, typename U>
-struct aggregate_traits {
- enum {
- is_pointer = false,
- has_trivial_ctor = traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
- has_trivial_dtor = traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
- has_trivial_copy = traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
- has_trivial_assign = traits<T>::has_trivial_assign && traits<U>::has_trivial_assign
- };
-};
-
-// ---------------------------------------------------------------------------
-
-/*
- * basic types traits
- */
-
-ANDROID_BASIC_TYPES_TRAITS( void );
-ANDROID_BASIC_TYPES_TRAITS( bool );
-ANDROID_BASIC_TYPES_TRAITS( char );
-ANDROID_BASIC_TYPES_TRAITS( unsigned char );
-ANDROID_BASIC_TYPES_TRAITS( short );
-ANDROID_BASIC_TYPES_TRAITS( unsigned short );
-ANDROID_BASIC_TYPES_TRAITS( int );
-ANDROID_BASIC_TYPES_TRAITS( unsigned int );
-ANDROID_BASIC_TYPES_TRAITS( long );
-ANDROID_BASIC_TYPES_TRAITS( unsigned long );
-ANDROID_BASIC_TYPES_TRAITS( long long );
-ANDROID_BASIC_TYPES_TRAITS( unsigned long long );
-ANDROID_BASIC_TYPES_TRAITS( float );
-ANDROID_BASIC_TYPES_TRAITS( double );
-
-// ---------------------------------------------------------------------------
-
-
-/*
- * compare and order types
- */
-
-template<typename TYPE> inline
-int strictly_order_type(const TYPE& lhs, const TYPE& rhs) {
- return (lhs < rhs) ? 1 : 0;
-}
-
-template<typename TYPE> inline
-int compare_type(const TYPE& lhs, const TYPE& rhs) {
- return strictly_order_type(rhs, lhs) - strictly_order_type(lhs, rhs);
-}
-
-/*
- * create, destroy, copy and assign types...
- */
-
-template<typename TYPE> inline
-void construct_type(TYPE* p, size_t n) {
- if (!traits<TYPE>::has_trivial_ctor) {
- while (n--) {
- new(p++) TYPE;
- }
- }
-}
-
-template<typename TYPE> inline
-void destroy_type(TYPE* p, size_t n) {
- if (!traits<TYPE>::has_trivial_dtor) {
- while (n--) {
- p->~TYPE();
- p++;
- }
- }
-}
-
-template<typename TYPE> inline
-void copy_type(TYPE* d, const TYPE* s, size_t n) {
- if (!traits<TYPE>::has_trivial_copy) {
- while (n--) {
- new(d) TYPE(*s);
- d++, s++;
- }
- } else {
- memcpy(d,s,n*sizeof(TYPE));
- }
-}
-
-template<typename TYPE> inline
-void assign_type(TYPE* d, const TYPE* s, size_t n) {
- if (!traits<TYPE>::has_trivial_assign) {
- while (n--) {
- *d++ = *s++;
- }
- } else {
- memcpy(d,s,n*sizeof(TYPE));
- }
-}
-
-template<typename TYPE> inline
-void splat_type(TYPE* where, const TYPE* what, size_t n) {
- if (!traits<TYPE>::has_trivial_copy) {
- while (n--) {
- new(where) TYPE(*what);
- where++;
- }
- } else {
- while (n--) {
- *where++ = *what;
- }
- }
-}
-
-template<typename TYPE> inline
-void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
- if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
- d += n;
- s += n;
- while (n--) {
- --d, --s;
- if (!traits<TYPE>::has_trivial_copy) {
- new(d) TYPE(*s);
- } else {
- *d = *s;
- }
- if (!traits<TYPE>::has_trivial_dtor) {
- s->~TYPE();
- }
- }
- } else {
- memmove(d,s,n*sizeof(TYPE));
- }
-}
-
-template<typename TYPE> inline
-void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
- if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
- while (n--) {
- if (!traits<TYPE>::has_trivial_copy) {
- new(d) TYPE(*s);
- } else {
- *d = *s;
- }
- if (!traits<TYPE>::has_trivial_dtor) {
- s->~TYPE();
- }
- d++, s++;
- }
- } else {
- memmove(d,s,n*sizeof(TYPE));
- }
-}
-// ---------------------------------------------------------------------------
-
-/*
- * a key/value pair
- */
-
-template <typename KEY, typename VALUE>
-struct key_value_pair_t {
- KEY key;
- VALUE value;
- key_value_pair_t() { }
- key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { }
- key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v) { }
- key_value_pair_t(const KEY& k) : key(k) { }
- inline bool operator < (const key_value_pair_t& o) const {
- return strictly_order_type(key, o.key);
- }
-};
-
-template<>
-template <typename K, typename V>
-struct trait_trivial_ctor< key_value_pair_t<K, V> >
-{ enum { value = aggregate_traits<K,V>::has_trivial_ctor }; };
-template<>
-template <typename K, typename V>
-struct trait_trivial_dtor< key_value_pair_t<K, V> >
-{ enum { value = aggregate_traits<K,V>::has_trivial_dtor }; };
-template<>
-template <typename K, typename V>
-struct trait_trivial_copy< key_value_pair_t<K, V> >
-{ enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
-template<>
-template <typename K, typename V>
-struct trait_trivial_assign< key_value_pair_t<K, V> >
-{ enum { value = aggregate_traits<K,V>::has_trivial_assign};};
-
-// ---------------------------------------------------------------------------
-
-} // namespace tinyutils
-} // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_TYPE_HELPERS_H
diff --git a/libpixelflinger/codeflinger/tinyutils/Vector.h b/libpixelflinger/codeflinger/tinyutils/Vector.h
deleted file mode 100644
index c07a17a..0000000
--- a/libpixelflinger/codeflinger/tinyutils/Vector.h
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_PIXELFLINGER_VECTOR_H
-#define ANDROID_PIXELFLINGER_VECTOR_H
-
-#include <new>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <cutils/log.h>
-
-#include "Errors.h"
-#include "VectorImpl.h"
-#include "TypeHelpers.h"
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-namespace tinyutils {
-
-/*!
- * The main templated vector class ensuring type safety
- * while making use of VectorImpl.
- * This is the class users want to use.
- */
-
-template <class TYPE>
-class Vector : private VectorImpl
-{
-public:
- typedef TYPE value_type;
-
- /*!
- * Constructors and destructors
- */
-
- Vector();
- Vector(const Vector<TYPE>& rhs);
- virtual ~Vector();
-
- /*! copy operator */
- const Vector<TYPE>& operator = (const Vector<TYPE>& rhs) const;
- Vector<TYPE>& operator = (const Vector<TYPE>& rhs);
-
- /*
- * empty the vector
- */
-
- inline void clear() { VectorImpl::clear(); }
-
- /*!
- * vector stats
- */
-
- //! returns number of items in the vector
- inline size_t size() const { return VectorImpl::size(); }
- //! returns wether or not the vector is empty
- inline bool isEmpty() const { return VectorImpl::isEmpty(); }
- //! returns how many items can be stored without reallocating the backing store
- inline size_t capacity() const { return VectorImpl::capacity(); }
- //! setst the capacity. capacity can never be reduced less than size()
- inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
-
- /*!
- * C-style array access
- */
-
- //! read-only C-style access
- inline const TYPE* array() const;
- //! read-write C-style access
- TYPE* editArray();
-
- /*!
- * accessors
- */
-
- //! read-only access to an item at a given index
- inline const TYPE& operator [] (size_t index) const;
- //! alternate name for operator []
- inline const TYPE& itemAt(size_t index) const;
- //! stack-usage of the vector. returns the top of the stack (last element)
- const TYPE& top() const;
- //! same as operator [], but allows to access the vector backward (from the end) with a negative index
- const TYPE& mirrorItemAt(ssize_t index) const;
-
- /*!
- * modifing the array
- */
-
- //! copy-on write support, grants write access to an item
- TYPE& editItemAt(size_t index);
- //! grants right acces to the top of the stack (last element)
- TYPE& editTop();
-
- /*!
- * append/insert another vector
- */
-
- //! insert another vector at a given index
- ssize_t insertVectorAt(const Vector<TYPE>& vector, size_t index);
-
- //! append another vector at the end of this one
- ssize_t appendVector(const Vector<TYPE>& vector);
-
-
- /*!
- * add/insert/replace items
- */
-
- //! insert one or several items initialized with their default constructor
- inline ssize_t insertAt(size_t index, size_t numItems = 1);
- //! insert on onr several items initialized from a prototype item
- ssize_t insertAt(const TYPE& prototype_item, size_t index, size_t numItems = 1);
- //! pop the top of the stack (removes the last element). No-op if the stack's empty
- inline void pop();
- //! pushes an item initialized with its default constructor
- inline void push();
- //! pushes an item on the top of the stack
- void push(const TYPE& item);
- //! same as push() but returns the index the item was added at (or an error)
- inline ssize_t add();
- //! same as push() but returns the index the item was added at (or an error)
- ssize_t add(const TYPE& item);
- //! replace an item with a new one initialized with its default constructor
- inline ssize_t replaceAt(size_t index);
- //! replace an item with a new one
- ssize_t replaceAt(const TYPE& item, size_t index);
-
- /*!
- * remove items
- */
-
- //! remove several items
- inline ssize_t removeItemsAt(size_t index, size_t count = 1);
- //! remove one item
- inline ssize_t removeAt(size_t index) { return removeItemsAt(index); }
-
- /*!
- * sort (stable) the array
- */
-
- typedef int (*compar_t)(const TYPE* lhs, const TYPE* rhs);
- typedef int (*compar_r_t)(const TYPE* lhs, const TYPE* rhs, void* state);
-
- inline status_t sort(compar_t cmp);
- inline status_t sort(compar_r_t cmp, void* state);
-
-protected:
- virtual void do_construct(void* storage, size_t num) const;
- virtual void do_destroy(void* storage, size_t num) const;
- virtual void do_copy(void* dest, const void* from, size_t num) const;
- virtual void do_splat(void* dest, const void* item, size_t num) const;
- virtual void do_move_forward(void* dest, const void* from, size_t num) const;
- virtual void do_move_backward(void* dest, const void* from, size_t num) const;
-};
-
-
-// ---------------------------------------------------------------------------
-// No user serviceable parts from here...
-// ---------------------------------------------------------------------------
-
-template<class TYPE> inline
-Vector<TYPE>::Vector()
- : VectorImpl(sizeof(TYPE),
- ((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
- |(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
- |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
- |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
- )
-{
-}
-
-template<class TYPE> inline
-Vector<TYPE>::Vector(const Vector<TYPE>& rhs)
- : VectorImpl(rhs) {
-}
-
-template<class TYPE> inline
-Vector<TYPE>::~Vector() {
- finish_vector();
-}
-
-template<class TYPE> inline
-Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) {
- VectorImpl::operator = (rhs);
- return *this;
-}
-
-template<class TYPE> inline
-const Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) const {
- VectorImpl::operator = (rhs);
- return *this;
-}
-
-template<class TYPE> inline
-const TYPE* Vector<TYPE>::array() const {
- return static_cast<const TYPE *>(arrayImpl());
-}
-
-template<class TYPE> inline
-TYPE* Vector<TYPE>::editArray() {
- return static_cast<TYPE *>(editArrayImpl());
-}
-
-
-template<class TYPE> inline
-const TYPE& Vector<TYPE>::operator[](size_t index) const {
- LOG_FATAL_IF( index>=size(),
- "itemAt: index %d is past size %d", (int)index, (int)size() );
- return *(array() + index);
-}
-
-template<class TYPE> inline
-const TYPE& Vector<TYPE>::itemAt(size_t index) const {
- return operator[](index);
-}
-
-template<class TYPE> inline
-const TYPE& Vector<TYPE>::mirrorItemAt(ssize_t index) const {
- LOG_FATAL_IF( (index>0 ? index : -index)>=size(),
- "mirrorItemAt: index %d is past size %d",
- (int)index, (int)size() );
- return *(array() + ((index<0) ? (size()-index) : index));
-}
-
-template<class TYPE> inline
-const TYPE& Vector<TYPE>::top() const {
- return *(array() + size() - 1);
-}
-
-template<class TYPE> inline
-TYPE& Vector<TYPE>::editItemAt(size_t index) {
- return *( static_cast<TYPE *>(editItemLocation(index)) );
-}
-
-template<class TYPE> inline
-TYPE& Vector<TYPE>::editTop() {
- return *( static_cast<TYPE *>(editItemLocation(size()-1)) );
-}
-
-template<class TYPE> inline
-ssize_t Vector<TYPE>::insertVectorAt(const Vector<TYPE>& vector, size_t index) {
- return VectorImpl::insertVectorAt(reinterpret_cast<const VectorImpl&>(vector), index);
-}
-
-template<class TYPE> inline
-ssize_t Vector<TYPE>::appendVector(const Vector<TYPE>& vector) {
- return VectorImpl::appendVector(reinterpret_cast<const VectorImpl&>(vector));
-}
-
-template<class TYPE> inline
-ssize_t Vector<TYPE>::insertAt(const TYPE& item, size_t index, size_t numItems) {
- return VectorImpl::insertAt(&item, index, numItems);
-}
-
-template<class TYPE> inline
-void Vector<TYPE>::push(const TYPE& item) {
- return VectorImpl::push(&item);
-}
-
-template<class TYPE> inline
-ssize_t Vector<TYPE>::add(const TYPE& item) {
- return VectorImpl::add(&item);
-}
-
-template<class TYPE> inline
-ssize_t Vector<TYPE>::replaceAt(const TYPE& item, size_t index) {
- return VectorImpl::replaceAt(&item, index);
-}
-
-template<class TYPE> inline
-ssize_t Vector<TYPE>::insertAt(size_t index, size_t numItems) {
- return VectorImpl::insertAt(index, numItems);
-}
-
-template<class TYPE> inline
-void Vector<TYPE>::pop() {
- VectorImpl::pop();
-}
-
-template<class TYPE> inline
-void Vector<TYPE>::push() {
- VectorImpl::push();
-}
-
-template<class TYPE> inline
-ssize_t Vector<TYPE>::add() {
- return VectorImpl::add();
-}
-
-template<class TYPE> inline
-ssize_t Vector<TYPE>::replaceAt(size_t index) {
- return VectorImpl::replaceAt(index);
-}
-
-template<class TYPE> inline
-ssize_t Vector<TYPE>::removeItemsAt(size_t index, size_t count) {
- return VectorImpl::removeItemsAt(index, count);
-}
-
-// ---------------------------------------------------------------------------
-
-template<class TYPE>
-void Vector<TYPE>::do_construct(void* storage, size_t num) const {
- construct_type( reinterpret_cast<TYPE*>(storage), num );
-}
-
-template<class TYPE>
-void Vector<TYPE>::do_destroy(void* storage, size_t num) const {
- destroy_type( reinterpret_cast<TYPE*>(storage), num );
-}
-
-template<class TYPE>
-void Vector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
- copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
-}
-
-template<class TYPE>
-void Vector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
- splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
-}
-
-template<class TYPE>
-void Vector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
- move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
-}
-
-template<class TYPE>
-void Vector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
- move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
-}
-
-} // namespace tinyutils
-} // namespace android
-
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_VECTOR_H
diff --git a/libpixelflinger/codeflinger/tinyutils/VectorImpl.cpp b/libpixelflinger/codeflinger/tinyutils/VectorImpl.cpp
deleted file mode 100644
index 689129a..0000000
--- a/libpixelflinger/codeflinger/tinyutils/VectorImpl.cpp
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * Copyright 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Vector"
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include <cutils/log.h>
-
-#include "Errors.h"
-#include "SharedBuffer.h"
-#include "VectorImpl.h"
-
-/*****************************************************************************/
-
-
-namespace android {
-namespace tinyutils {
-
-// ----------------------------------------------------------------------------
-
-const size_t kMinVectorCapacity = 4;
-
-static inline size_t max(size_t a, size_t b) {
- return a>b ? a : b;
-}
-
-// ----------------------------------------------------------------------------
-
-VectorImpl::VectorImpl(size_t itemSize, uint32_t flags)
- : mStorage(0), mCount(0), mFlags(flags), mItemSize(itemSize)
-{
-}
-
-VectorImpl::VectorImpl(const VectorImpl& rhs)
- : mStorage(rhs.mStorage), mCount(rhs.mCount),
- mFlags(rhs.mFlags), mItemSize(rhs.mItemSize)
-{
- if (mStorage) {
- SharedBuffer::sharedBuffer(mStorage)->acquire();
- }
-}
-
-VectorImpl::~VectorImpl()
-{
- ALOG_ASSERT(!mCount,
- "[%p] "
- "subclasses of VectorImpl must call finish_vector()"
- " in their destructor. Leaking %d bytes.",
- this, (int)(mCount*mItemSize));
- // We can't call _do_destroy() here because the vtable is already gone.
-}
-
-VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
-{
- ALOG_ASSERT(mItemSize == rhs.mItemSize,
- "Vector<> have different types (this=%p, rhs=%p)", this, &rhs);
- if (this != &rhs) {
- release_storage();
- if (rhs.mCount) {
- mStorage = rhs.mStorage;
- mCount = rhs.mCount;
- SharedBuffer::sharedBuffer(mStorage)->acquire();
- } else {
- mStorage = 0;
- mCount = 0;
- }
- }
- return *this;
-}
-
-void* VectorImpl::editArrayImpl()
-{
- if (mStorage) {
- SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage)->attemptEdit();
- if (sb == 0) {
- sb = SharedBuffer::alloc(capacity() * mItemSize);
- if (sb) {
- _do_copy(sb->data(), mStorage, mCount);
- release_storage();
- mStorage = sb->data();
- }
- }
- }
- return mStorage;
-}
-
-size_t VectorImpl::capacity() const
-{
- if (mStorage) {
- return SharedBuffer::sharedBuffer(mStorage)->size() / mItemSize;
- }
- return 0;
-}
-
-ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index)
-{
- if (index > size())
- return BAD_INDEX;
- void* where = _grow(index, vector.size());
- if (where) {
- _do_copy(where, vector.arrayImpl(), vector.size());
- }
- return where ? index : (ssize_t)NO_MEMORY;
-}
-
-ssize_t VectorImpl::appendVector(const VectorImpl& vector)
-{
- return insertVectorAt(vector, size());
-}
-
-ssize_t VectorImpl::insertAt(size_t index, size_t numItems)
-{
- return insertAt(0, index, numItems);
-}
-
-ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems)
-{
- if (index > size())
- return BAD_INDEX;
- void* where = _grow(index, numItems);
- if (where) {
- if (item) {
- _do_splat(where, item, numItems);
- } else {
- _do_construct(where, numItems);
- }
- }
- return where ? index : (ssize_t)NO_MEMORY;
-}
-
-void VectorImpl::pop()
-{
- if (size())
- removeItemsAt(size()-1, 1);
-}
-
-void VectorImpl::push()
-{
- push(0);
-}
-
-void VectorImpl::push(const void* item)
-{
- insertAt(item, size());
-}
-
-ssize_t VectorImpl::add()
-{
- return add(0);
-}
-
-ssize_t VectorImpl::add(const void* item)
-{
- return insertAt(item, size());
-}
-
-ssize_t VectorImpl::replaceAt(size_t index)
-{
- return replaceAt(0, index);
-}
-
-ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
-{
- ALOG_ASSERT(index<size(),
- "[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
-
- void* item = editItemLocation(index);
- if (item == 0)
- return NO_MEMORY;
- _do_destroy(item, 1);
- if (prototype == 0) {
- _do_construct(item, 1);
- } else {
- _do_copy(item, prototype, 1);
- }
- return ssize_t(index);
-}
-
-ssize_t VectorImpl::removeItemsAt(size_t index, size_t count)
-{
- ALOG_ASSERT((index+count)<=size(),
- "[%p] remove: index=%d, count=%d, size=%d",
- this, (int)index, (int)count, (int)size());
-
- if ((index+count) > size())
- return BAD_VALUE;
- _shrink(index, count);
- return index;
-}
-
-void VectorImpl::finish_vector()
-{
- release_storage();
- mStorage = 0;
- mCount = 0;
-}
-
-void VectorImpl::clear()
-{
- _shrink(0, mCount);
-}
-
-void* VectorImpl::editItemLocation(size_t index)
-{
- ALOG_ASSERT(index<capacity(),
- "[%p] itemLocation: index=%d, capacity=%d, count=%d",
- this, (int)index, (int)capacity(), (int)mCount);
-
- void* buffer = editArrayImpl();
- if (buffer)
- return reinterpret_cast<char*>(buffer) + index*mItemSize;
- return 0;
-}
-
-const void* VectorImpl::itemLocation(size_t index) const
-{
- ALOG_ASSERT(index<capacity(),
- "[%p] editItemLocation: index=%d, capacity=%d, count=%d",
- this, (int)index, (int)capacity(), (int)mCount);
-
- const void* buffer = arrayImpl();
- if (buffer)
- return reinterpret_cast<const char*>(buffer) + index*mItemSize;
- return 0;
-}
-
-ssize_t VectorImpl::setCapacity(size_t new_capacity)
-{
- size_t current_capacity = capacity();
- ssize_t amount = new_capacity - size();
- if (amount <= 0) {
- // we can't reduce the capacity
- return current_capacity;
- }
- SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
- if (sb) {
- void* array = sb->data();
- _do_copy(array, mStorage, size());
- release_storage();
- mStorage = const_cast<void*>(array);
- } else {
- return NO_MEMORY;
- }
- return new_capacity;
-}
-
-void VectorImpl::release_storage()
-{
- if (mStorage) {
- const SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage);
- if (sb->release(SharedBuffer::eKeepStorage) == 1) {
- _do_destroy(mStorage, mCount);
- SharedBuffer::dealloc(sb);
- }
- }
-}
-
-void* VectorImpl::_grow(size_t where, size_t amount)
-{
-// ALOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
-// this, (int)where, (int)amount, (int)mCount, (int)capacity());
-
- if (where > mCount)
- where = mCount;
-
- const size_t new_size = mCount + amount;
- if (capacity() < new_size) {
- const size_t new_capacity = max(kMinVectorCapacity, ((new_size*3)+1)/2);
-// ALOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity);
- if ((mStorage) &&
- (mCount==where) &&
- (mFlags & HAS_TRIVIAL_COPY) &&
- (mFlags & HAS_TRIVIAL_DTOR))
- {
- const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
- SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
- mStorage = sb->data();
- } else {
- SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
- if (sb) {
- void* array = sb->data();
- if (where>0) {
- _do_copy(array, mStorage, where);
- }
- if (mCount>where) {
- const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize;
- void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
- _do_copy(dest, from, mCount-where);
- }
- release_storage();
- mStorage = const_cast<void*>(array);
- }
- }
- } else {
- ssize_t s = mCount-where;
- if (s>0) {
- void* array = editArrayImpl();
- void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
- const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
- _do_move_forward(to, from, s);
- }
- }
- mCount += amount;
- void* free_space = const_cast<void*>(itemLocation(where));
- return free_space;
-}
-
-void VectorImpl::_shrink(size_t where, size_t amount)
-{
- if (!mStorage)
- return;
-
-// ALOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
-// this, (int)where, (int)amount, (int)mCount, (int)capacity());
-
- if (where >= mCount)
- where = mCount - amount;
-
- const size_t new_size = mCount - amount;
- if (new_size*3 < capacity()) {
- const size_t new_capacity = max(kMinVectorCapacity, new_size*2);
-// ALOGV("shrink vector %p, new_capacity=%d", this, (int)new_capacity);
- if ((where == mCount-amount) &&
- (mFlags & HAS_TRIVIAL_COPY) &&
- (mFlags & HAS_TRIVIAL_DTOR))
- {
- const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
- SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
- mStorage = sb->data();
- } else {
- SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
- if (sb) {
- void* array = sb->data();
- if (where>0) {
- _do_copy(array, mStorage, where);
- }
- if (mCount > where+amount) {
- const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize;
- void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
- _do_copy(dest, from, mCount-(where+amount));
- }
- release_storage();
- mStorage = const_cast<void*>(array);
- }
- }
- } else {
- void* array = editArrayImpl();
- void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
- _do_destroy(to, amount);
- ssize_t s = mCount-(where+amount);
- if (s>0) {
- const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
- _do_move_backward(to, from, s);
- }
- }
-
- // adjust the number of items...
- mCount -= amount;
-}
-
-size_t VectorImpl::itemSize() const {
- return mItemSize;
-}
-
-void VectorImpl::_do_construct(void* storage, size_t num) const
-{
- if (!(mFlags & HAS_TRIVIAL_CTOR)) {
- do_construct(storage, num);
- }
-}
-
-void VectorImpl::_do_destroy(void* storage, size_t num) const
-{
- if (!(mFlags & HAS_TRIVIAL_DTOR)) {
- do_destroy(storage, num);
- }
-}
-
-void VectorImpl::_do_copy(void* dest, const void* from, size_t num) const
-{
- if (!(mFlags & HAS_TRIVIAL_COPY)) {
- do_copy(dest, from, num);
- } else {
- memcpy(dest, from, num*itemSize());
- }
-}
-
-void VectorImpl::_do_splat(void* dest, const void* item, size_t num) const {
- do_splat(dest, item, num);
-}
-
-void VectorImpl::_do_move_forward(void* dest, const void* from, size_t num) const {
- do_move_forward(dest, from, num);
-}
-
-void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) const {
- do_move_backward(dest, from, num);
-}
-
-void VectorImpl::reservedVectorImpl1() { }
-void VectorImpl::reservedVectorImpl2() { }
-void VectorImpl::reservedVectorImpl3() { }
-void VectorImpl::reservedVectorImpl4() { }
-void VectorImpl::reservedVectorImpl5() { }
-void VectorImpl::reservedVectorImpl6() { }
-void VectorImpl::reservedVectorImpl7() { }
-void VectorImpl::reservedVectorImpl8() { }
-
-/*****************************************************************************/
-
-SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags)
- : VectorImpl(itemSize, flags)
-{
-}
-
-SortedVectorImpl::SortedVectorImpl(const VectorImpl& rhs)
-: VectorImpl(rhs)
-{
-}
-
-SortedVectorImpl::~SortedVectorImpl()
-{
-}
-
-SortedVectorImpl& SortedVectorImpl::operator = (const SortedVectorImpl& rhs)
-{
- return static_cast<SortedVectorImpl&>( VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)) );
-}
-
-ssize_t SortedVectorImpl::indexOf(const void* item) const
-{
- return _indexOrderOf(item);
-}
-
-size_t SortedVectorImpl::orderOf(const void* item) const
-{
- size_t o;
- _indexOrderOf(item, &o);
- return o;
-}
-
-ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const
-{
- // binary search
- ssize_t err = NAME_NOT_FOUND;
- ssize_t l = 0;
- ssize_t h = size()-1;
- ssize_t mid;
- const void* a = arrayImpl();
- const size_t s = itemSize();
- while (l <= h) {
- mid = l + (h - l)/2;
- const void* const curr = reinterpret_cast<const char *>(a) + (mid*s);
- const int c = do_compare(curr, item);
- if (c == 0) {
- err = l = mid;
- break;
- } else if (c < 0) {
- l = mid + 1;
- } else {
- h = mid - 1;
- }
- }
- if (order) *order = l;
- return err;
-}
-
-ssize_t SortedVectorImpl::add(const void* item)
-{
- size_t order;
- ssize_t index = _indexOrderOf(item, &order);
- if (index < 0) {
- index = VectorImpl::insertAt(item, order, 1);
- } else {
- index = VectorImpl::replaceAt(item, index);
- }
- return index;
-}
-
-ssize_t SortedVectorImpl::merge(const VectorImpl& vector)
-{
- // naive merge...
- if (!vector.isEmpty()) {
- const void* buffer = vector.arrayImpl();
- const size_t is = itemSize();
- size_t s = vector.size();
- for (size_t i=0 ; i<s ; i++) {
- ssize_t err = add( reinterpret_cast<const char*>(buffer) + i*is );
- if (err<0) {
- return err;
- }
- }
- }
- return NO_ERROR;
-}
-
-ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector)
-{
- // we've merging a sorted vector... nice!
- ssize_t err = NO_ERROR;
- if (!vector.isEmpty()) {
- // first take care of the case where the vectors are sorted together
- if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) {
- err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&>(vector), 0);
- } else if (do_compare(vector.arrayImpl(), itemLocation(size()-1)) >= 0) {
- err = VectorImpl::appendVector(static_cast<const VectorImpl&>(vector));
- } else {
- // this could be made a little better
- err = merge(static_cast<const VectorImpl&>(vector));
- }
- }
- return err;
-}
-
-ssize_t SortedVectorImpl::remove(const void* item)
-{
- ssize_t i = indexOf(item);
- if (i>=0) {
- VectorImpl::removeItemsAt(i, 1);
- }
- return i;
-}
-
-void SortedVectorImpl::reservedSortedVectorImpl1() { };
-void SortedVectorImpl::reservedSortedVectorImpl2() { };
-void SortedVectorImpl::reservedSortedVectorImpl3() { };
-void SortedVectorImpl::reservedSortedVectorImpl4() { };
-void SortedVectorImpl::reservedSortedVectorImpl5() { };
-void SortedVectorImpl::reservedSortedVectorImpl6() { };
-void SortedVectorImpl::reservedSortedVectorImpl7() { };
-void SortedVectorImpl::reservedSortedVectorImpl8() { };
-
-
-/*****************************************************************************/
-
-} // namespace tinyutils
-} // namespace android
-
diff --git a/libpixelflinger/codeflinger/tinyutils/VectorImpl.h b/libpixelflinger/codeflinger/tinyutils/VectorImpl.h
deleted file mode 100644
index 56089b3..0000000
--- a/libpixelflinger/codeflinger/tinyutils/VectorImpl.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_PIXELFLINGER_VECTOR_IMPL_H
-#define ANDROID_PIXELFLINGER_VECTOR_IMPL_H
-
-#include <assert.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-// ---------------------------------------------------------------------------
-// No user serviceable parts in here...
-// ---------------------------------------------------------------------------
-
-namespace android {
-namespace tinyutils {
-
-/*!
- * Implementation of the guts of the vector<> class
- * this ensures backward binary compatibility and
- * reduces code size.
- * For performance reasons, we expose mStorage and mCount
- * so these fields are set in stone.
- *
- */
-
-class VectorImpl
-{
-public:
- enum { // flags passed to the ctor
- HAS_TRIVIAL_CTOR = 0x00000001,
- HAS_TRIVIAL_DTOR = 0x00000002,
- HAS_TRIVIAL_COPY = 0x00000004,
- HAS_TRIVIAL_ASSIGN = 0x00000008
- };
-
- VectorImpl(size_t itemSize, uint32_t flags);
- VectorImpl(const VectorImpl& rhs);
- virtual ~VectorImpl();
-
- /*! must be called from subclasses destructor */
- void finish_vector();
-
- VectorImpl& operator = (const VectorImpl& rhs);
-
- /*! C-style array access */
- inline const void* arrayImpl() const { return mStorage; }
- void* editArrayImpl();
-
- /*! vector stats */
- inline size_t size() const { return mCount; }
- inline bool isEmpty() const { return mCount == 0; }
- size_t capacity() const;
- ssize_t setCapacity(size_t size);
-
- /*! append/insert another vector */
- ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
- ssize_t appendVector(const VectorImpl& vector);
-
- /*! add/insert/replace items */
- ssize_t insertAt(size_t where, size_t numItems = 1);
- ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
- void pop();
- void push();
- void push(const void* item);
- ssize_t add();
- ssize_t add(const void* item);
- ssize_t replaceAt(size_t index);
- ssize_t replaceAt(const void* item, size_t index);
-
- /*! remove items */
- ssize_t removeItemsAt(size_t index, size_t count = 1);
- void clear();
-
- const void* itemLocation(size_t index) const;
- void* editItemLocation(size_t index);
-
-protected:
- size_t itemSize() const;
- void release_storage();
-
- virtual void do_construct(void* storage, size_t num) const = 0;
- virtual void do_destroy(void* storage, size_t num) const = 0;
- virtual void do_copy(void* dest, const void* from, size_t num) const = 0;
- virtual void do_splat(void* dest, const void* item, size_t num) const = 0;
- virtual void do_move_forward(void* dest, const void* from, size_t num) const = 0;
- virtual void do_move_backward(void* dest, const void* from, size_t num) const = 0;
-
- // take care of FBC...
- virtual void reservedVectorImpl1();
- virtual void reservedVectorImpl2();
- virtual void reservedVectorImpl3();
- virtual void reservedVectorImpl4();
- virtual void reservedVectorImpl5();
- virtual void reservedVectorImpl6();
- virtual void reservedVectorImpl7();
- virtual void reservedVectorImpl8();
-
-private:
- void* _grow(size_t where, size_t amount);
- void _shrink(size_t where, size_t amount);
-
- inline void _do_construct(void* storage, size_t num) const;
- inline void _do_destroy(void* storage, size_t num) const;
- inline void _do_copy(void* dest, const void* from, size_t num) const;
- inline void _do_splat(void* dest, const void* item, size_t num) const;
- inline void _do_move_forward(void* dest, const void* from, size_t num) const;
- inline void _do_move_backward(void* dest, const void* from, size_t num) const;
-
- // These 2 fields are exposed in the inlines below,
- // so they're set in stone.
- void * mStorage; // base address of the vector
- size_t mCount; // number of items
-
- const uint32_t mFlags;
- const size_t mItemSize;
-};
-
-
-
-class SortedVectorImpl : public VectorImpl
-{
-public:
- SortedVectorImpl(size_t itemSize, uint32_t flags);
- SortedVectorImpl(const VectorImpl& rhs);
- virtual ~SortedVectorImpl();
-
- SortedVectorImpl& operator = (const SortedVectorImpl& rhs);
-
- //! finds the index of an item
- ssize_t indexOf(const void* item) const;
-
- //! finds where this item should be inserted
- size_t orderOf(const void* item) const;
-
- //! add an item in the right place (or replaces it if there is one)
- ssize_t add(const void* item);
-
- //! merges a vector into this one
- ssize_t merge(const VectorImpl& vector);
- ssize_t merge(const SortedVectorImpl& vector);
-
- //! removes an item
- ssize_t remove(const void* item);
-
-protected:
- virtual int do_compare(const void* lhs, const void* rhs) const = 0;
-
- // take care of FBC...
- virtual void reservedSortedVectorImpl1();
- virtual void reservedSortedVectorImpl2();
- virtual void reservedSortedVectorImpl3();
- virtual void reservedSortedVectorImpl4();
- virtual void reservedSortedVectorImpl5();
- virtual void reservedSortedVectorImpl6();
- virtual void reservedSortedVectorImpl7();
- virtual void reservedSortedVectorImpl8();
-
-private:
- ssize_t _indexOrderOf(const void* item, size_t* order = 0) const;
-
- // these are made private, because they can't be used on a SortedVector
- // (they don't have an implementation either)
- ssize_t add();
- void pop();
- void push();
- void push(const void* item);
- ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
- ssize_t appendVector(const VectorImpl& vector);
- ssize_t insertAt(size_t where, size_t numItems = 1);
- ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
- ssize_t replaceAt(size_t index);
- ssize_t replaceAt(const void* item, size_t index);
-};
-
-} // namespace tinyutils
-} // namespace android
-
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_VECTOR_IMPL_H
diff --git a/libutils/Android.mk b/libutils/Android.mk
index bae16bb..631b5a3 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -53,6 +53,7 @@
LOCAL_CFLAGS_windows := -DMB_CUR_MAX=1
LOCAL_MULTILIB := both
LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_C_INCLUDES += external/safe-iop/include
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -85,6 +86,7 @@
LOCAL_MODULE := libutils
LOCAL_CLANG := true
LOCAL_SANITIZE := integer
+LOCAL_C_INCLUDES += external/safe-iop/include
include $(BUILD_STATIC_LIBRARY)
# For the device, shared
@@ -98,6 +100,7 @@
libdl \
liblog
LOCAL_CFLAGS := -Werror
+LOCAL_C_INCLUDES += external/safe-iop/include
LOCAL_CLANG := true
LOCAL_SANITIZE := integer
diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
index 0bfb520..699da74 100644
--- a/libutils/CallStack.cpp
+++ b/libutils/CallStack.cpp
@@ -16,11 +16,12 @@
#define LOG_TAG "CallStack"
+#include <memory>
+
#include <utils/CallStack.h>
#include <utils/Printer.h>
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <UniquePtr.h>
#include <backtrace/Backtrace.h>
@@ -40,7 +41,7 @@
void CallStack::update(int32_t ignoreDepth, pid_t tid) {
mFrameLines.clear();
- UniquePtr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid));
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid));
if (!backtrace->Unwind(ignoreDepth)) {
ALOGW("%s: Failed to unwind callstack.", __FUNCTION__);
}
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index 2ac158b..e8d40ed 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <cutils/log.h>
+#include <safe_iop.h>
#include <utils/Errors.h>
#include <utils/VectorImpl.h>
@@ -86,14 +87,19 @@
void* VectorImpl::editArrayImpl()
{
if (mStorage) {
- SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage)->attemptEdit();
- if (sb == 0) {
- sb = SharedBuffer::alloc(capacity() * mItemSize);
- if (sb) {
- _do_copy(sb->data(), mStorage, mCount);
- release_storage();
- mStorage = sb->data();
- }
+ const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage);
+ SharedBuffer* editable = sb->attemptEdit();
+ if (editable == 0) {
+ // If we're here, we're not the only owner of the buffer.
+ // We must make a copy of it.
+ editable = SharedBuffer::alloc(sb->size());
+ // Fail instead of returning a pointer to storage that's not
+ // editable. Otherwise we'd be editing the contents of a buffer
+ // for which we're not the only owner, which is undefined behaviour.
+ LOG_ALWAYS_FATAL_IF(editable == NULL);
+ _do_copy(editable->data(), mStorage, mCount);
+ release_storage();
+ mStorage = editable->data();
}
}
return mStorage;
@@ -329,13 +335,15 @@
ssize_t VectorImpl::setCapacity(size_t new_capacity)
{
- size_t current_capacity = capacity();
- ssize_t amount = new_capacity - size();
- if (amount <= 0) {
- // we can't reduce the capacity
- return current_capacity;
- }
- SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+ // The capacity must always be greater than or equal to the size
+ // of this vector.
+ if (new_capacity <= size()) {
+ return capacity();
+ }
+
+ size_t new_allocation_size = 0;
+ LOG_ALWAYS_FATAL_IF(!safe_mul(&new_allocation_size, new_capacity, mItemSize));
+ SharedBuffer* sb = SharedBuffer::alloc(new_allocation_size);
if (sb) {
void* array = sb->data();
_do_copy(array, mStorage, size());
@@ -377,9 +385,28 @@
"[%p] _grow: where=%d, amount=%d, count=%d",
this, (int)where, (int)amount, (int)mCount); // caller already checked
- const size_t new_size = mCount + amount;
+ size_t new_size;
+ LOG_ALWAYS_FATAL_IF(!safe_add(&new_size, mCount, amount), "new_size overflow");
+
if (capacity() < new_size) {
- const size_t new_capacity = max(kMinVectorCapacity, ((new_size*3)+1)/2);
+ // NOTE: This implementation used to resize vectors as per ((3*x + 1) / 2)
+ // (sigh..). Also note, the " + 1" was necessary to handle the special case
+ // where x == 1, where the resized_capacity will be equal to the old
+ // capacity without the +1. The old calculation wouldn't work properly
+ // if x was zero.
+ //
+ // This approximates the old calculation, using (x + (x/2) + 1) instead.
+ size_t new_capacity = 0;
+ LOG_ALWAYS_FATAL_IF(!safe_add(&new_capacity, new_size, (new_size / 2)),
+ "new_capacity overflow");
+ LOG_ALWAYS_FATAL_IF(!safe_add(&new_capacity, new_capacity, static_cast<size_t>(1u)),
+ "new_capacity overflow");
+ new_capacity = max(kMinVectorCapacity, new_capacity);
+
+ size_t new_alloc_size = 0;
+ LOG_ALWAYS_FATAL_IF(!safe_mul(&new_alloc_size, new_capacity, mItemSize),
+ "new_alloc_size overflow");
+
// ALOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity);
if ((mStorage) &&
(mCount==where) &&
@@ -387,14 +414,14 @@
(mFlags & HAS_TRIVIAL_DTOR))
{
const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
- SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
+ SharedBuffer* sb = cur_sb->editResize(new_alloc_size);
if (sb) {
mStorage = sb->data();
} else {
return NULL;
}
} else {
- SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+ SharedBuffer* sb = SharedBuffer::alloc(new_alloc_size);
if (sb) {
void* array = sb->data();
if (where != 0) {
@@ -436,10 +463,19 @@
"[%p] _shrink: where=%d, amount=%d, count=%d",
this, (int)where, (int)amount, (int)mCount); // caller already checked
- const size_t new_size = mCount - amount;
- if (new_size*3 < capacity()) {
- const size_t new_capacity = max(kMinVectorCapacity, new_size*2);
-// ALOGV("shrink vector %p, new_capacity=%d", this, (int)new_capacity);
+ size_t new_size;
+ LOG_ALWAYS_FATAL_IF(!safe_sub(&new_size, mCount, amount));
+
+ if (new_size < (capacity() / 2)) {
+ // NOTE: (new_size * 2) is safe because capacity didn't overflow and
+ // new_size < (capacity / 2)).
+ const size_t new_capacity = max(kMinVectorCapacity, new_size * 2);
+
+ // NOTE: (new_capacity * mItemSize), (where * mItemSize) and
+ // ((where + amount) * mItemSize) beyond this point are safe because
+ // we are always reducing the capacity of the underlying SharedBuffer.
+ // In other words, (old_capacity * mItemSize) did not overflow, and
+ // where < (where + amount) < new_capacity < old_capacity.
if ((where == new_size) &&
(mFlags & HAS_TRIVIAL_COPY) &&
(mFlags & HAS_TRIVIAL_DTOR))
diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk
index cb9e8a2..8f07f1a 100644
--- a/libutils/tests/Android.mk
+++ b/libutils/tests/Android.mk
@@ -38,3 +38,11 @@
libutils \
include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libutils_tests_host
+LOCAL_SRC_FILES := Vector_test.cpp
+LOCAL_STATIC_LIBRARIES := libutils liblog
+
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index 0ba7161..d9b32f9 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "Vector_test"
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
#include <utils/Vector.h>
#include <cutils/log.h>
#include <gtest/gtest.h>
@@ -71,5 +73,80 @@
EXPECT_EQ(other[3], 5);
}
+// TODO: gtest isn't capable of parsing Abort messages formatted by
+// Android (fails differently on host and target), so we always need to
+// use an empty error message for death tests.
+TEST_F(VectorTest, SetCapacity_Overflow) {
+ Vector<int> vector;
+ EXPECT_DEATH(vector.setCapacity(SIZE_MAX / sizeof(int) + 1), "");
+}
+
+TEST_F(VectorTest, SetCapacity_ShrinkBelowSize) {
+ Vector<int> vector;
+ vector.add(1);
+ vector.add(2);
+ vector.add(3);
+ vector.add(4);
+
+ vector.setCapacity(8);
+ ASSERT_EQ(8, vector.capacity());
+ vector.setCapacity(2);
+ ASSERT_EQ(8, vector.capacity());
+}
+
+// NOTE: All of the tests below are useless because of the "TODO" above.
+// We have no way of knowing *why* the process crashed. Given that we're
+// inserting a NULL array, we'll fail with a SIGSEGV eventually. We need
+// the ability to make assertions on the abort message to make sure we're
+// failing for the right reasons.
+TEST_F(VectorTest, _grow_OverflowSize) {
+ Vector<int> vector;
+ vector.add(1);
+
+ // Checks that the size calculation (not the capacity calculation) doesn't
+ // overflow : the size here will be (1 + SIZE_MAX).
+ //
+ // EXPECT_DEATH(vector.insertArrayAt(NULL, 0, SIZE_MAX), "new_size_overflow");
+ EXPECT_DEATH(vector.insertArrayAt(NULL, 0, SIZE_MAX), "");
+}
+
+TEST_F(VectorTest, _grow_OverflowCapacityDoubling) {
+ Vector<int> vector;
+
+ // This should fail because the calculated capacity will overflow even though
+ // the size of the vector doesn't.
+ //
+ // EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX - 1)), "new_capacity_overflow");
+ EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX - 1)), "");
+}
+
+TEST_F(VectorTest, _grow_OverflowBufferAlloc) {
+ Vector<int> vector;
+ // This should fail because the capacity * sizeof(int) overflows, even
+ // though the capacity itself doesn't.
+ //
+ // EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX / 2)), "new_alloc_size overflow");
+ EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX / 2)), "");
+}
+
+TEST_F(VectorTest, editArray_Shared) {
+ Vector<int> vector1;
+ vector1.add(1);
+ vector1.add(2);
+ vector1.add(3);
+ vector1.add(4);
+
+ Vector<int> vector2 = vector1;
+ ASSERT_EQ(vector1.array(), vector2.array());
+ // We must make a copy here, since we're not the exclusive owners
+ // of this array.
+ ASSERT_NE(vector1.editArray(), vector2.editArray());
+
+ // Vector doesn't implement operator ==.
+ ASSERT_EQ(vector1.size(), vector2.size());
+ for (size_t i = 0; i < vector1.size(); ++i) {
+ EXPECT_EQ(vector1[i], vector2[i]);
+ }
+}
} // namespace android
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 22a7c53..f117cc5 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -267,12 +267,12 @@
if (z_stream_->avail_out == 0) {
// The output is full, let's write it to disk.
- size_t dataToWrite = z_stream_->next_out - buffer_.data();
- if (fwrite(buffer_.data(), 1, dataToWrite, file_) != dataToWrite) {
+ size_t write_bytes = z_stream_->next_out - buffer_.data();
+ if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
return HandleError(kIoError);
}
- file->compressed_size += dataToWrite;
- current_offset_ += dataToWrite;
+ file->compressed_size += write_bytes;
+ current_offset_ += write_bytes;
// Reset the output buffer for the next input.
z_stream_->next_out = buffer_.data();
@@ -288,18 +288,32 @@
assert(z_stream_->next_out != nullptr);
assert(z_stream_->avail_out != 0);
- int zerr = deflate(z_stream_.get(), Z_FINISH);
+ // Keep deflating while there isn't enough space in the buffer to
+ // to complete the compress.
+ int zerr;
+ while ((zerr = deflate(z_stream_.get(), Z_FINISH)) == Z_OK) {
+ assert(z_stream_->avail_out == 0);
+ size_t write_bytes = z_stream_->next_out - buffer_.data();
+ if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
+ return HandleError(kIoError);
+ }
+ file->compressed_size += write_bytes;
+ current_offset_ += write_bytes;
+
+ z_stream_->next_out = buffer_.data();
+ z_stream_->avail_out = buffer_.size();
+ }
if (zerr != Z_STREAM_END) {
return HandleError(kZlibError);
}
- size_t dataToWrite = z_stream_->next_out - buffer_.data();
- if (dataToWrite != 0) {
- if (fwrite(buffer_.data(), 1, dataToWrite, file_) != dataToWrite) {
+ size_t write_bytes = z_stream_->next_out - buffer_.data();
+ if (write_bytes != 0) {
+ if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
return HandleError(kIoError);
}
- file->compressed_size += dataToWrite;
- current_offset_ += dataToWrite;
+ file->compressed_size += write_bytes;
+ current_offset_ += write_bytes;
}
z_stream_.reset();
return kNoError;
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index 046f195..f752b7e 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -20,6 +20,7 @@
#include <base/test_utils.h>
#include <gtest/gtest.h>
#include <memory>
+#include <vector>
struct zipwriter : public ::testing::Test {
TemporaryFile* temp_file_;
@@ -168,3 +169,40 @@
CloseArchive(handle);
}
+
+TEST_F(zipwriter, WriteCompressedZipFlushFull) {
+ // This exact data will cause the Finish() to require multiple calls
+ // to deflate() because the ZipWriter buffer isn't big enough to hold
+ // the entire compressed data buffer.
+ constexpr size_t kBufSize = 10000000;
+ std::vector<uint8_t> buffer(kBufSize);
+ size_t prev = 1;
+ for (size_t i = 0; i < kBufSize; i++) {
+ buffer[i] = i + prev;
+ prev = i;
+ }
+
+ ZipWriter writer(file_);
+ ASSERT_EQ(0, writer.StartEntry("file.txt", ZipWriter::kCompress));
+ ASSERT_EQ(0, writer.WriteBytes(buffer.data(), buffer.size()));
+ ASSERT_EQ(0, writer.FinishEntry());
+ ASSERT_EQ(0, writer.Finish());
+
+ ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
+
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
+
+ ZipEntry data;
+ ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
+ EXPECT_EQ(kCompressDeflated, data.method);
+ EXPECT_EQ(kBufSize, data.uncompressed_length);
+
+ std::vector<uint8_t> decompress(kBufSize);
+ memset(decompress.data(), 0, kBufSize);
+ ASSERT_EQ(0, ExtractToMemory(handle, &data, decompress.data(), decompress.size()));
+ EXPECT_EQ(0, memcmp(decompress.data(), buffer.data(), kBufSize))
+ << "Input buffer and output buffer are different.";
+
+ CloseArchive(handle);
+}
diff --git a/lmkd/lmkd.rc b/lmkd/lmkd.rc
index 83c5ff0..7d6cb11 100644
--- a/lmkd/lmkd.rc
+++ b/lmkd/lmkd.rc
@@ -2,3 +2,4 @@
class core
critical
socket lmkd seqpacket 0660 system system
+ writepid /dev/cpuset/system-background/tasks
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index cb9a85b..4d7adf1 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -399,6 +399,10 @@
}
log_time now(CLOCK_REALTIME);
+ bool monotonic = android_log_timestamp() == 'm';
+ if (monotonic) {
+ now = log_time(CLOCK_MONOTONIC);
+ }
std::string directory;
char *file = strrchr(outputFileName, '/');
@@ -417,7 +421,11 @@
struct dirent *dp;
while ((dp = readdir(dir.get())) != NULL) {
if ((dp->d_type != DT_REG)
- || strncmp(dp->d_name, file, len)
+ // If we are using realtime, check all files that match the
+ // basename for latest time. If we are using monotonic time
+ // then only check the main file because time cycles on
+ // every reboot.
+ || strncmp(dp->d_name, file, len + monotonic)
|| (dp->d_name[len]
&& ((dp->d_name[len] != '.')
|| !isdigit(dp->d_name[len+1])))) {
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
index 33d39ac..cf0e0d2 100644
--- a/logcat/logcatd.rc
+++ b/logcat/logcatd.rc
@@ -11,3 +11,4 @@
# logd for write to /data/misc/logd, log group for read from log daemon
user logd
group log
+ writepid /dev/cpuset/system-background/tasks
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 610a6ec..153a3fd 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -75,6 +75,12 @@
}
TEST(logcat, year) {
+
+ if (android_log_timestamp() == 'm') {
+ fprintf(stderr, "Skipping test, logd is monotonic time\n");
+ return;
+ }
+
FILE *fp;
char needle[32];
@@ -108,7 +114,44 @@
ASSERT_EQ(3, count);
}
+// Return a pointer to each null terminated -v long time field.
+char *fgetLongTime(char *buffer, size_t buflen, FILE *fp) {
+ while (fgets(buffer, buflen, fp)) {
+ char *cp = buffer;
+ if (*cp != '[') {
+ continue;
+ }
+ while (*++cp == ' ') {
+ ;
+ }
+ char *ep = cp;
+ while (isdigit(*ep)) {
+ ++ep;
+ }
+ if ((*ep != '-') && (*ep != '.')) {
+ continue;
+ }
+ // Find PID field
+ while (((ep = strchr(ep, ':'))) && (*++ep != ' ')) {
+ ;
+ }
+ if (!ep) {
+ continue;
+ }
+ ep -= 7;
+ *ep = '\0';
+ return cp;
+ }
+ return NULL;
+}
+
TEST(logcat, tz) {
+
+ if (android_log_timestamp() == 'm') {
+ fprintf(stderr, "Skipping test, logd is monotonic time\n");
+ return;
+ }
+
FILE *fp;
ASSERT_TRUE(NULL != (fp = popen(
@@ -119,11 +162,8 @@
int count = 0;
- while (fgets(buffer, sizeof(buffer), fp)) {
- if ((buffer[0] == '[') && (buffer[1] == ' ')
- && isdigit(buffer[2]) && isdigit(buffer[3])
- && (buffer[4] == '-')
- && (strstr(buffer, " -0700 ") || strstr(buffer, " -0800 "))) {
+ while (fgetLongTime(buffer, sizeof(buffer), fp)) {
+ if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) {
++count;
}
}
@@ -144,11 +184,8 @@
int count = 0;
- while (fgets(buffer, sizeof(buffer), fp)) {
- if ((buffer[0] == '[') && (buffer[1] == ' ')
- && isdigit(buffer[2]) && isdigit(buffer[3])
- && (buffer[4] == '-')
- && (strstr(buffer, " -0700 ") || strstr(buffer, " -0800 "))) {
+ while (fgetLongTime(buffer, sizeof(buffer), fp)) {
+ if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) {
++count;
}
}
@@ -169,12 +206,8 @@
int count = 0;
- while (fgets(buffer, sizeof(buffer), fp)) {
- if ((buffer[0] == '[') && (buffer[1] == ' ')
- && isdigit(buffer[2]) && isdigit(buffer[3])
- && (buffer[4] == '-')) {
- ++count;
- }
+ while (fgetLongTime(buffer, sizeof(buffer), fp)) {
+ ++count;
}
pclose(fp);
@@ -193,12 +226,8 @@
int count = 0;
- while (fgets(buffer, sizeof(buffer), fp)) {
- if ((buffer[0] == '[') && (buffer[1] == ' ')
- && isdigit(buffer[2]) && isdigit(buffer[3])
- && (buffer[4] == '-')) {
- ++count;
- }
+ while (fgetLongTime(buffer, sizeof(buffer), fp)) {
+ ++count;
}
pclose(fp);
@@ -217,12 +246,8 @@
int count = 0;
- while (fgets(buffer, sizeof(buffer), fp)) {
- if ((buffer[0] == '[') && (buffer[1] == ' ')
- && isdigit(buffer[2]) && isdigit(buffer[3])
- && (buffer[4] == '-')) {
- ++count;
- }
+ while (fgetLongTime(buffer, sizeof(buffer), fp)) {
+ ++count;
}
pclose(fp);
@@ -241,12 +266,8 @@
int count = 0;
- while (fgets(buffer, sizeof(buffer), fp)) {
- if ((buffer[0] == '[') && (buffer[1] == ' ')
- && isdigit(buffer[2]) && isdigit(buffer[3])
- && (buffer[4] == '-')) {
- ++count;
- }
+ while (fgetLongTime(buffer, sizeof(buffer), fp)) {
+ ++count;
}
pclose(fp);
@@ -263,21 +284,15 @@
char *last_timestamp = NULL;
char *first_timestamp = NULL;
int count = 0;
- const unsigned int time_length = 18;
- const unsigned int time_offset = 2;
- while (fgets(buffer, sizeof(buffer), fp)) {
- if ((buffer[0] == '[') && (buffer[1] == ' ')
- && isdigit(buffer[time_offset]) && isdigit(buffer[time_offset + 1])
- && (buffer[time_offset + 2] == '-')) {
- ++count;
- buffer[time_length + time_offset] = '\0';
- if (!first_timestamp) {
- first_timestamp = strdup(buffer + time_offset);
- }
- free(last_timestamp);
- last_timestamp = strdup(buffer + time_offset);
+ char *cp;
+ while ((cp = fgetLongTime(buffer, sizeof(buffer), fp))) {
+ ++count;
+ if (!first_timestamp) {
+ first_timestamp = strdup(cp);
}
+ free(last_timestamp);
+ last_timestamp = strdup(cp);
}
pclose(fp);
@@ -292,28 +307,24 @@
int second_count = 0;
int last_timestamp_count = -1;
- while (fgets(buffer, sizeof(buffer), fp)) {
- if ((buffer[0] == '[') && (buffer[1] == ' ')
- && isdigit(buffer[time_offset]) && isdigit(buffer[time_offset + 1])
- && (buffer[time_offset + 2] == '-')) {
- ++second_count;
- buffer[time_length + time_offset] = '\0';
- if (first_timestamp) {
- // we can get a transitory *extremely* rare failure if hidden
- // underneath the time is *exactly* XX-XX XX:XX:XX.XXX000000
- EXPECT_STREQ(buffer + time_offset, first_timestamp);
- free(first_timestamp);
- first_timestamp = NULL;
- }
- if (!strcmp(buffer + time_offset, last_timestamp)) {
- last_timestamp_count = second_count;
- }
+ while ((cp = fgetLongTime(buffer, sizeof(buffer), fp))) {
+ ++second_count;
+ if (first_timestamp) {
+ // we can get a transitory *extremely* rare failure if hidden
+ // underneath the time is *exactly* XX-XX XX:XX:XX.XXX000000
+ EXPECT_STREQ(cp, first_timestamp);
+ free(first_timestamp);
+ first_timestamp = NULL;
+ }
+ if (!strcmp(cp, last_timestamp)) {
+ last_timestamp_count = second_count;
}
}
pclose(fp);
free(last_timestamp);
last_timestamp = NULL;
+ free(first_timestamp);
EXPECT_TRUE(first_timestamp == NULL);
EXPECT_LE(count, second_count);
@@ -601,6 +612,9 @@
}
}
pclose(fp);
+ if ((count != 7) && (count != 8)) {
+ fprintf(stderr, "count=%d\n", count);
+ }
EXPECT_TRUE(count == 7 || count == 8);
}
}
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 2f7cbfb..143fb04 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -123,17 +123,19 @@
&& (*cp == ':')) {
memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
- //
- // We are either in 1970ish (MONOTONIC) or 2015+ish (REALTIME) so to
- // differentiate without prejudice, we use 1980 to delineate, earlier
- // is monotonic, later is real.
- //
-# define EPOCH_PLUS_10_YEARS (10 * 1461 / 4 * 24 * 60 * 60)
- if (now.tv_sec < EPOCH_PLUS_10_YEARS) {
- LogKlog::convertMonotonicToReal(now);
+ if (!isMonotonic()) {
+ if (android::isMonotonic(now)) {
+ LogKlog::convertMonotonicToReal(now);
+ }
+ } else {
+ if (!android::isMonotonic(now)) {
+ LogKlog::convertRealToMonotonic(now);
+ }
}
+ } else if (isMonotonic()) {
+ now = log_time(CLOCK_MONOTONIC);
} else {
- now.strptime("", ""); // side effect of setting CLOCK_REALTIME
+ now = log_time(CLOCK_REALTIME);
}
static const char pid_str[] = " pid=";
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 2342822..8a82630 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -29,6 +29,7 @@
public:
LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg);
int log(char *buf, size_t len);
+ bool isMonotonic() { return logbuf->isMonotonic(); }
protected:
virtual bool onDataAvailable(SocketClient *cli);
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 1de8e64..fd5c066 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -28,6 +28,7 @@
#include <log/logger.h>
#include "LogBuffer.h"
+#include "LogKlog.h"
#include "LogReader.h"
// Default
@@ -126,9 +127,48 @@
setSize(i, LOG_BUFFER_MIN_SIZE);
}
}
+ bool lastMonotonic = monotonic;
+ monotonic = android_log_timestamp() == 'm';
+ if (lastMonotonic == monotonic) {
+ return;
+ }
+
+ //
+ // Fixup all timestamps, may not be 100% accurate, but better than
+ // throwing what we have away when we get 'surprised' by a change.
+ // In-place element fixup so no need to check reader-lock. Entries
+ // should already be in timestamp order, but we could end up with a
+ // few out-of-order entries if new monotonics come in before we
+ // are notified of the reinit change in status. A Typical example would
+ // be:
+ // --------- beginning of system
+ // 10.494082 184 201 D Cryptfs : Just triggered post_fs_data
+ // --------- beginning of kernel
+ // 0.000000 0 0 I : Initializing cgroup subsys cpuacct
+ // as the act of mounting /data would trigger persist.logd.timestamp to
+ // be corrected. 1/30 corner case YMMV.
+ //
+ pthread_mutex_lock(&mLogElementsLock);
+ LogBufferElementCollection::iterator it = mLogElements.begin();
+ while((it != mLogElements.end())) {
+ LogBufferElement *e = *it;
+ if (monotonic) {
+ if (!android::isMonotonic(e->mRealTime)) {
+ LogKlog::convertRealToMonotonic(e->mRealTime);
+ }
+ } else {
+ if (android::isMonotonic(e->mRealTime)) {
+ LogKlog::convertMonotonicToReal(e->mRealTime);
+ }
+ }
+ ++it;
+ }
+ pthread_mutex_unlock(&mLogElementsLock);
}
-LogBuffer::LogBuffer(LastLogTimes *times) : mTimes(*times) {
+LogBuffer::LogBuffer(LastLogTimes *times):
+ monotonic(android_log_timestamp() == 'm'),
+ mTimes(*times) {
pthread_mutex_init(&mLogElementsLock, NULL);
init();
@@ -436,7 +476,10 @@
worst_sizes = sorted[0]->getSizes();
// Calculate threshold as 12.5% of available storage
size_t threshold = log_buffer_size(id) / 8;
- if (worst_sizes > threshold) {
+ if ((worst_sizes > threshold)
+ // Allow time horizon to extend roughly tenfold, assume
+ // average entry length is 100 characters.
+ && (worst_sizes > (10 * sorted[0]->getDropped()))) {
worst = sorted[0]->getKey();
second_worst_sizes = sorted[1]->getSizes();
if (second_worst_sizes < threshold) {
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 7ed92e9..c1fec73 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -32,6 +32,21 @@
#include "LogStatistics.h"
#include "LogWhiteBlackList.h"
+//
+// We are either in 1970ish (MONOTONIC) or 2015+ish (REALTIME) so to
+// differentiate without prejudice, we use 1980 to delineate, earlier
+// is monotonic, later is real.
+//
+namespace android {
+
+static bool isMonotonic(const log_time &mono) {
+ static const uint32_t EPOCH_PLUS_10_YEARS = 10 * 1461 / 4 * 24 * 60 * 60;
+
+ return mono.tv_sec < EPOCH_PLUS_10_YEARS;
+}
+
+}
+
typedef std::list<LogBufferElement *> LogBufferElementCollection;
class LogBuffer {
@@ -49,11 +64,14 @@
unsigned long mMaxSize[LOG_ID_MAX];
+ bool monotonic;
+
public:
LastLogTimes &mTimes;
LogBuffer(LastLogTimes *times);
void init();
+ bool isMonotonic() { return monotonic; }
int log(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 30e43c6..09987ea 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -34,6 +34,9 @@
#define EXPIRE_RATELIMIT 10 // maximum rate in seconds to report expiration
class LogBufferElement {
+
+ friend LogBuffer;
+
const log_id_t mLogId;
const uid_t mUid;
const pid_t mPid;
@@ -44,7 +47,7 @@
unsigned short mDropped; // mMsg == NULL
};
const uint64_t mSequence;
- const log_time mRealTime;
+ log_time mRealTime;
static atomic_int_fast64_t sequence;
// assumption: mMsg == NULL
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index d28161e..da5e78d 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -330,6 +330,10 @@
}
*buf = cp;
+ if (isMonotonic()) {
+ return;
+ }
+
const char *b;
if (((b = strnstr(cp, len, suspendStr)))
&& ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
@@ -376,7 +380,11 @@
convertMonotonicToReal(now);
} else {
- now = log_time(CLOCK_REALTIME);
+ if (isMonotonic()) {
+ now = log_time(CLOCK_MONOTONIC);
+ } else {
+ now = log_time(CLOCK_REALTIME);
+ }
}
}
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 469affd..3c8cc87 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -43,7 +43,9 @@
int log(const char *buf, size_t len);
void synchronize(const char *buf, size_t len);
+ bool isMonotonic() { return logbuf->isMonotonic(); }
static void convertMonotonicToReal(log_time &real) { real += correction; }
+ static void convertRealToMonotonic(log_time &real) { real -= correction; }
protected:
void sniffTime(log_time &now, const char **buf, size_t len, bool reverse);
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 3833843..06135dd 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -114,15 +114,17 @@
log_time &start;
uint64_t &sequence;
uint64_t last;
+ bool isMonotonic;
public:
- LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence) :
+ LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence, bool isMonotonic) :
mPid(pid),
mLogMask(logMask),
startTimeSet(false),
start(start),
sequence(sequence),
- last(sequence) {
+ last(sequence),
+ isMonotonic(isMonotonic) {
}
static int callback(const LogBufferElement *element, void *obj) {
@@ -133,20 +135,24 @@
me->sequence = element->getSequence();
me->startTimeSet = true;
return -1;
- } else {
+ } else if (!me->isMonotonic ||
+ android::isMonotonic(element->getRealTime())) {
if (me->start < element->getRealTime()) {
me->sequence = me->last;
me->startTimeSet = true;
return -1;
}
me->last = element->getSequence();
+ } else {
+ me->last = element->getSequence();
}
}
return false;
}
bool found() { return startTimeSet; }
- } logFindStart(logMask, pid, start, sequence);
+ } logFindStart(logMask, pid, start, sequence,
+ logbuf().isMonotonic() && android::isMonotonic(start));
logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli),
logFindStart.callback, &logFindStart);
diff --git a/logd/README.property b/logd/README.property
index 05ef528..e4b23a9 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -25,6 +25,10 @@
"~!" which means to prune the oldest
entries of chattiest UID. At runtime
use: logcat -P "<string>"
+persist.logd.timestamp string The recording timestamp source. Default
+ is ro.logd.timestamp. "m[onotonic]" is
+ the only supported key character,
+ otherwise assumes realtime.
NB:
- Number support multipliers (K or M) for convenience. Range is limited
diff --git a/logd/logd.rc b/logd/logd.rc
index da6a0bc..ecd2f0a 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -4,7 +4,9 @@
socket logdr seqpacket 0666 logd logd
socket logdw dgram 0222 logd logd
group root system
+ writepid /dev/cpuset/system-background/tasks
service logd-reinit /system/bin/logd --reinit
oneshot
disabled
+ writepid /dev/cpuset/system-background/tasks
diff --git a/logd/main.cpp b/logd/main.cpp
index cf8cb8f..ad577d2 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -298,7 +298,7 @@
}
buf[--len] = '\0';
- if (kl) {
+ if (kl && kl->isMonotonic()) {
kl->synchronize(buf.get(), len);
}
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index b08c153..291c983 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -27,6 +27,7 @@
metrics_daemon_common := \
collectors/averaged_statistics_collector.cc \
+ collectors/cpu_usage_collector.cc \
collectors/disk_usage_collector.cc \
metrics_daemon.cc \
persistent_integer.cc \
@@ -41,6 +42,7 @@
metrics_tests_sources := \
collectors/averaged_statistics_collector_test.cc \
+ collectors/cpu_usage_collector_test.cc \
metrics_daemon_test.cc \
metrics_library_test.cc \
persistent_integer_test.cc \
diff --git a/metricsd/collectors/cpu_usage_collector.cc b/metricsd/collectors/cpu_usage_collector.cc
new file mode 100644
index 0000000..05934b4
--- /dev/null
+++ b/metricsd/collectors/cpu_usage_collector.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 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 "collectors/cpu_usage_collector.h"
+
+#include <base/bind.h>
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/message_loop/message_loop.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
+#include <base/strings/string_util.h>
+#include <base/sys_info.h>
+
+#include "metrics/metrics_library.h"
+
+namespace {
+
+const char kCpuUsagePercent[] = "Platform.CpuUsage.Percent";
+const char kMetricsProcStatFileName[] = "/proc/stat";
+const int kMetricsProcStatFirstLineItemsCount = 11;
+
+// Collect every minute.
+const int kCollectionIntervalSecs = 60;
+
+} // namespace
+
+using base::TimeDelta;
+
+CpuUsageCollector::CpuUsageCollector(MetricsLibraryInterface* metrics_library) {
+ CHECK(metrics_library);
+ metrics_lib_ = metrics_library;
+ collect_interval_ = TimeDelta::FromSeconds(kCollectionIntervalSecs);
+}
+
+void CpuUsageCollector::Init() {
+ num_cpu_ = base::SysInfo::NumberOfProcessors();
+
+ // Get ticks per second (HZ) on this system.
+ // Sysconf cannot fail, so no sanity checks are needed.
+ ticks_per_second_ = sysconf(_SC_CLK_TCK);
+ CHECK_GT(ticks_per_second_, uint64_t(0))
+ << "Number of ticks per seconds should be positive.";
+
+ latest_cpu_use_ = GetCumulativeCpuUse();
+}
+
+void CpuUsageCollector::CollectCallback() {
+ Collect();
+ Schedule();
+}
+
+void CpuUsageCollector::Schedule() {
+ base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ base::Bind(&CpuUsageCollector::CollectCallback, base::Unretained(this)),
+ collect_interval_);
+}
+
+void CpuUsageCollector::Collect() {
+ TimeDelta cpu_use = GetCumulativeCpuUse();
+ TimeDelta diff_per_cpu = (cpu_use - latest_cpu_use_) / num_cpu_;
+ latest_cpu_use_ = cpu_use;
+
+ // Report the cpu usage as a percentage of the total cpu usage possible.
+ int percent_use = diff_per_cpu.InMilliseconds() * 100 /
+ (kCollectionIntervalSecs * 1000);
+
+ metrics_lib_->SendEnumToUMA(kCpuUsagePercent, percent_use, 101);
+}
+
+TimeDelta CpuUsageCollector::GetCumulativeCpuUse() {
+ base::FilePath proc_stat_path(kMetricsProcStatFileName);
+ std::string proc_stat_string;
+ if (!base::ReadFileToString(proc_stat_path, &proc_stat_string)) {
+ LOG(WARNING) << "cannot open " << kMetricsProcStatFileName;
+ return TimeDelta();
+ }
+
+ uint64_t user_ticks, user_nice_ticks, system_ticks;
+ if (!ParseProcStat(proc_stat_string, &user_ticks, &user_nice_ticks,
+ &system_ticks)) {
+ return TimeDelta();
+ }
+
+ uint64_t total = user_ticks + user_nice_ticks + system_ticks;
+ return TimeDelta::FromMicroseconds(
+ total * 1000 * 1000 / ticks_per_second_);
+}
+
+bool CpuUsageCollector::ParseProcStat(const std::string& stat_content,
+ uint64_t *user_ticks,
+ uint64_t *user_nice_ticks,
+ uint64_t *system_ticks) {
+ std::vector<std::string> proc_stat_lines;
+ base::SplitString(stat_content, '\n', &proc_stat_lines);
+ if (proc_stat_lines.empty()) {
+ LOG(WARNING) << "No lines found in " << kMetricsProcStatFileName;
+ return false;
+ }
+ std::vector<std::string> proc_stat_totals;
+ base::SplitStringAlongWhitespace(proc_stat_lines[0], &proc_stat_totals);
+
+ if (proc_stat_totals.size() != kMetricsProcStatFirstLineItemsCount ||
+ proc_stat_totals[0] != "cpu" ||
+ !base::StringToUint64(proc_stat_totals[1], user_ticks) ||
+ !base::StringToUint64(proc_stat_totals[2], user_nice_ticks) ||
+ !base::StringToUint64(proc_stat_totals[3], system_ticks)) {
+ LOG(WARNING) << "cannot parse first line: " << proc_stat_lines[0];
+ return false;
+ }
+ return true;
+}
diff --git a/metricsd/collectors/cpu_usage_collector.h b/metricsd/collectors/cpu_usage_collector.h
new file mode 100644
index 0000000..f81dfcb
--- /dev/null
+++ b/metricsd/collectors/cpu_usage_collector.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef METRICSD_COLLECTORS_CPU_USAGE_COLLECTOR_H_
+#define METRICSD_COLLECTORS_CPU_USAGE_COLLECTOR_H_
+
+#include <base/time/time.h>
+
+#include "metrics/metrics_library.h"
+
+class CpuUsageCollector {
+ public:
+ CpuUsageCollector(MetricsLibraryInterface* metrics_library);
+
+ // Initialize this collector's state.
+ void Init();
+
+ // Schedule a collection interval.
+ void Schedule();
+
+ // Callback called at the end of the collection interval.
+ void CollectCallback();
+
+ // Measure the cpu use and report it.
+ void Collect();
+
+ // Gets the current cumulated Cpu usage.
+ base::TimeDelta GetCumulativeCpuUse();
+
+ private:
+ FRIEND_TEST(CpuUsageTest, ParseProcStat);
+ bool ParseProcStat(const std::string& stat_content,
+ uint64_t *user_ticks,
+ uint64_t *user_nice_ticks,
+ uint64_t *system_ticks);
+
+ int num_cpu_;
+ uint32_t ticks_per_second_;
+
+ base::TimeDelta collect_interval_;
+ base::TimeDelta latest_cpu_use_;
+
+ MetricsLibraryInterface* metrics_lib_;
+};
+
+#endif // METRICSD_COLLECTORS_CPU_USAGE_COLLECTOR_H_
diff --git a/metricsd/collectors/cpu_usage_collector_test.cc b/metricsd/collectors/cpu_usage_collector_test.cc
new file mode 100644
index 0000000..ee5c92b
--- /dev/null
+++ b/metricsd/collectors/cpu_usage_collector_test.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 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 <gtest/gtest.h>
+
+#include "collectors/cpu_usage_collector.h"
+#include "metrics/metrics_library_mock.h"
+
+
+TEST(CpuUsageTest, ParseProcStat) {
+ MetricsLibraryMock metrics_lib_mock;
+ CpuUsageCollector collector(&metrics_lib_mock);
+ std::vector<std::string> invalid_contents = {
+ "",
+ // First line does not start with cpu.
+ "spu 17191 11 36579 151118 289 0 2 0 0 0\n"
+ "cpu0 1564 2 866 48650 68 0 2 0 0 0\n"
+ "cpu1 14299 0 35116 1844 81 0 0 0 0 0\n",
+ // One of the field is not a number.
+ "cpu a17191 11 36579 151118 289 0 2 0 0 0",
+ // To many numbers in the first line.
+ "cpu 17191 11 36579 151118 289 0 2 0 0 0 102"
+ };
+
+ uint64_t user, nice, system;
+ for (int i = 0; i < invalid_contents.size(); i++) {
+ ASSERT_FALSE(collector.ParseProcStat(invalid_contents[i], &user, &nice,
+ &system));
+ }
+
+ ASSERT_TRUE(collector.ParseProcStat(
+ std::string("cpu 17191 11 36579 151118 289 0 2 0 0 0"),
+ &user, &nice, &system));
+ ASSERT_EQ(17191, user);
+ ASSERT_EQ(11, nice);
+ ASSERT_EQ(36579, system);
+}
diff --git a/metricsd/metrics_daemon.cc b/metricsd/metrics_daemon.cc
index ed786e1..b606fd0 100644
--- a/metricsd/metrics_daemon.cc
+++ b/metricsd/metrics_daemon.cc
@@ -71,10 +71,8 @@
const int kMetricMeminfoInterval = 30; // seconds
-const char kMetricsProcStatFileName[] = "/proc/stat";
const char kMeminfoFileName[] = "/proc/meminfo";
const char kVmStatFileName[] = "/proc/vmstat";
-const int kMetricsProcStatFirstLineItemsCount = 11;
// Thermal CPU throttling.
@@ -103,9 +101,7 @@
MetricsDaemon::MetricsDaemon()
: memuse_final_time_(0),
- memuse_interval_index_(0),
- ticks_per_second_(0),
- latest_cpu_use_ticks_(0) {}
+ memuse_interval_index_(0) {}
MetricsDaemon::~MetricsDaemon() {
}
@@ -188,10 +184,6 @@
upload_interval_ = upload_interval;
server_ = server;
- // Get ticks per second (HZ) on this system.
- // Sysconf cannot fail, so no sanity checks are needed.
- ticks_per_second_ = sysconf(_SC_CLK_TCK);
-
daily_active_use_.reset(
new PersistentInteger("Platform.UseTime.PerDay"));
version_cumulative_active_use_.reset(
@@ -235,6 +227,7 @@
averaged_stats_collector_.reset(
new AveragedStatisticsCollector(metrics_lib_, diskstats_path,
kVmStatFileName));
+ cpu_usage_collector_.reset(new CpuUsageCollector(metrics_lib_));
}
int MetricsDaemon::OnInit() {
@@ -290,6 +283,7 @@
base::Bind(&MetricsDaemon::OnDisableMetrics, base::Unretained(this)));
}
+ latest_cpu_use_microseconds_ = cpu_usage_collector_->GetCumulativeCpuUse();
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
base::Bind(&MetricsDaemon::HandleUpdateStatsTimeout,
base::Unretained(this)),
@@ -404,53 +398,6 @@
return DBUS_HANDLER_RESULT_HANDLED;
}
-// One might argue that parts of this should go into
-// chromium/src/base/sys_info_chromeos.c instead, but put it here for now.
-
-TimeDelta MetricsDaemon::GetIncrementalCpuUse() {
- FilePath proc_stat_path = FilePath(kMetricsProcStatFileName);
- std::string proc_stat_string;
- if (!base::ReadFileToString(proc_stat_path, &proc_stat_string)) {
- LOG(WARNING) << "cannot open " << kMetricsProcStatFileName;
- return TimeDelta();
- }
-
- std::vector<std::string> proc_stat_lines;
- base::SplitString(proc_stat_string, '\n', &proc_stat_lines);
- if (proc_stat_lines.empty()) {
- LOG(WARNING) << "cannot parse " << kMetricsProcStatFileName
- << ": " << proc_stat_string;
- return TimeDelta();
- }
- std::vector<std::string> proc_stat_totals;
- base::SplitStringAlongWhitespace(proc_stat_lines[0], &proc_stat_totals);
-
- uint64_t user_ticks, user_nice_ticks, system_ticks;
- if (proc_stat_totals.size() != kMetricsProcStatFirstLineItemsCount ||
- proc_stat_totals[0] != "cpu" ||
- !base::StringToUint64(proc_stat_totals[1], &user_ticks) ||
- !base::StringToUint64(proc_stat_totals[2], &user_nice_ticks) ||
- !base::StringToUint64(proc_stat_totals[3], &system_ticks)) {
- LOG(WARNING) << "cannot parse first line: " << proc_stat_lines[0];
- return TimeDelta(base::TimeDelta::FromSeconds(0));
- }
-
- uint64_t total_cpu_use_ticks = user_ticks + user_nice_ticks + system_ticks;
-
- // Sanity check.
- if (total_cpu_use_ticks < latest_cpu_use_ticks_) {
- LOG(WARNING) << "CPU time decreasing from " << latest_cpu_use_ticks_
- << " to " << total_cpu_use_ticks;
- return TimeDelta();
- }
-
- uint64_t diff = total_cpu_use_ticks - latest_cpu_use_ticks_;
- latest_cpu_use_ticks_ = total_cpu_use_ticks;
- // Use microseconds to avoid significant truncations.
- return base::TimeDelta::FromMicroseconds(
- diff * 1000 * 1000 / ticks_per_second_);
-}
-
void MetricsDaemon::ProcessUserCrash() {
// Counts the active time up to now.
UpdateStats(TimeTicks::Now(), Time::Now());
@@ -506,6 +453,9 @@
void MetricsDaemon::StatsReporterInit() {
disk_usage_collector_->Schedule();
+ cpu_usage_collector_->Init();
+ cpu_usage_collector_->Schedule();
+
// Don't start a collection cycle during the first run to avoid delaying the
// boot.
averaged_stats_collector_->ScheduleWait();
@@ -910,7 +860,10 @@
version_cumulative_active_use_->Add(elapsed_seconds);
user_crash_interval_->Add(elapsed_seconds);
kernel_crash_interval_->Add(elapsed_seconds);
- version_cumulative_cpu_use_->Add(GetIncrementalCpuUse().InMilliseconds());
+ TimeDelta cpu_use = cpu_usage_collector_->GetCumulativeCpuUse();
+ version_cumulative_cpu_use_->Add(
+ (cpu_use - latest_cpu_use_microseconds_).InMilliseconds());
+ latest_cpu_use_microseconds_ = cpu_use;
last_update_stats_time_ = now_ticks;
const TimeDelta since_epoch = now_wall_time - Time::UnixEpoch();
diff --git a/metricsd/metrics_daemon.h b/metricsd/metrics_daemon.h
index 3d691c5..f12b02e 100644
--- a/metricsd/metrics_daemon.h
+++ b/metricsd/metrics_daemon.h
@@ -32,6 +32,7 @@
#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include "collectors/averaged_statistics_collector.h"
+#include "collectors/cpu_usage_collector.h"
#include "collectors/disk_usage_collector.h"
#include "metrics/metrics_library.h"
#include "persistent_integer.h"
@@ -164,10 +165,6 @@
// total number of kernel crashes since the last version update.
void SendKernelCrashesCumulativeCountStats();
- // Returns the total (system-wide) CPU usage between the time of the most
- // recent call to this function and now.
- base::TimeDelta GetIncrementalCpuUse();
-
// Sends a sample representing the number of seconds of active use
// for a 24-hour period and reset |use|.
void SendAndResetDailyUseSample(
@@ -268,12 +265,9 @@
// Selects the wait time for the next memory use callback.
unsigned int memuse_interval_index_;
- // The system "HZ", or frequency of ticks. Some system data uses ticks as a
- // unit, and this is used to convert to standard time units.
- uint32_t ticks_per_second_;
// Used internally by GetIncrementalCpuUse() to return the CPU utilization
// between calls.
- uint64_t latest_cpu_use_ticks_;
+ base::TimeDelta latest_cpu_use_microseconds_;
// Persistent values and accumulators for crash statistics.
scoped_ptr<PersistentInteger> daily_cycle_;
@@ -302,6 +296,8 @@
scoped_ptr<PersistentInteger> kernel_crashes_version_count_;
scoped_ptr<PersistentInteger> unclean_shutdowns_daily_count_;
scoped_ptr<PersistentInteger> unclean_shutdowns_weekly_count_;
+
+ scoped_ptr<CpuUsageCollector> cpu_usage_collector_;
scoped_ptr<DiskUsageCollector> disk_usage_collector_;
scoped_ptr<AveragedStatisticsCollector> averaged_stats_collector_;
diff --git a/packagelistparser/Android.mk b/packagelistparser/Android.mk
index 802a3cb..c8be050 100644
--- a/packagelistparser/Android.mk
+++ b/packagelistparser/Android.mk
@@ -6,9 +6,9 @@
LOCAL_MODULE := libpackagelistparser
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := packagelistparser.c
-LOCAL_COPY_HEADERS_TO := packagelistparser
-LOCAL_COPY_HEADERS := packagelistparser.h
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_CLANG := true
LOCAL_SANITIZE := integer
@@ -22,9 +22,9 @@
LOCAL_MODULE := libpackagelistparser
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := packagelistparser.c
-LOCAL_COPY_HEADERS_TO := packagelistparser
-LOCAL_COPY_HEADERS := packagelistparser.h
LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_CLANG := true
LOCAL_SANITIZE := integer
diff --git a/packagelistparser/packagelistparser.h b/packagelistparser/include/packagelistparser/packagelistparser.h
similarity index 100%
rename from packagelistparser/packagelistparser.h
rename to packagelistparser/include/packagelistparser/packagelistparser.h
diff --git a/packagelistparser/packagelistparser.c b/packagelistparser/packagelistparser.c
index 3e2539c..16052e2 100644
--- a/packagelistparser/packagelistparser.c
+++ b/packagelistparser/packagelistparser.c
@@ -29,7 +29,7 @@
#define LOG_TAG "packagelistparser"
#include <utils/Log.h>
-#include "packagelistparser.h"
+#include <packagelistparser/packagelistparser.h>
#define CLOGE(fmt, ...) \
do {\
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 38c686d..b80c454 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -7,6 +7,7 @@
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
+import /init.usb.configfs.rc
import /init.${ro.zygote}.rc
on early-init
@@ -86,10 +87,17 @@
write /proc/sys/kernel/panic_on_oops 1
write /proc/sys/kernel/hung_task_timeout_secs 0
write /proc/cpu/alignment 4
+
+ # scheduler tunables
+ # Disable auto-scaling of scheduler tunables with hotplug. The tunables
+ # will vary across devices in unpredictable ways if allowed to scale with
+ # cpu cores.
+ write /proc/sys/kernel/sched_tunable_scaling 0
write /proc/sys/kernel/sched_latency_ns 10000000
write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
write /proc/sys/kernel/sched_compat_yield 1
write /proc/sys/kernel/sched_child_runs_first 0
+
write /proc/sys/kernel/randomize_va_space 2
write /proc/sys/kernel/kptr_restrict 2
write /proc/sys/vm/mmap_min_addr 32768
@@ -131,20 +139,32 @@
mkdir /dev/cpuset
mount cpuset none /dev/cpuset
mkdir /dev/cpuset/foreground
+ mkdir /dev/cpuset/foreground/boost
mkdir /dev/cpuset/background
+ # system-background is for system tasks that should only run on
+ # little cores, not on bigs
+ # to be used only by init, so don't change the permissions
+ mkdir /dev/cpuset/system-background
# this ensures that the cpusets are present and usable, but the device's
# init.rc must actually set the correct cpus
write /dev/cpuset/foreground/cpus 0
+ write /dev/cpuset/foreground/boost/cpus 0
write /dev/cpuset/background/cpus 0
+ write /dev/cpuset/system-background/cpus 0
write /dev/cpuset/foreground/mems 0
+ write /dev/cpuset/foreground/boost/mems 0
write /dev/cpuset/background/mems 0
+ write /dev/cpuset/system-background/mems 0
chown system system /dev/cpuset
chown system system /dev/cpuset/foreground
+ chown system system /dev/cpuset/foreground/boost
chown system system /dev/cpuset/background
chown system system /dev/cpuset/tasks
chown system system /dev/cpuset/foreground/tasks
+ chown system system /dev/cpuset/foreground/boost/tasks
chown system system /dev/cpuset/background/tasks
chmod 0664 /dev/cpuset/foreground/tasks
+ chmod 0664 /dev/cpuset/foreground/boost/tasks
chmod 0664 /dev/cpuset/background/tasks
chmod 0664 /dev/cpuset/tasks
@@ -180,8 +200,11 @@
trigger late-init
# Load properties from /system/ + /factory after fs mount.
-on load_all_props_action
- load_all_props
+on load_system_props_action
+ load_system_props
+
+on load_persist_props_action
+ load_persist_props
start logd
start logd-reinit
@@ -194,12 +217,16 @@
trigger early-fs
trigger fs
trigger post-fs
- trigger post-fs-data
# Load properties from /system/ + /factory after fs mount. Place
# this in another action so that the load will be scheduled after the prior
# issued fs triggers have completed.
- trigger load_all_props_action
+ trigger load_system_props_action
+
+ # Now we can mount /data. File encryption requires keymaster to decrypt
+ # /data, which in turn can only be loaded when system properties are present
+ trigger post-fs-data
+ trigger load_persist_props_action
# Remove a file to wake up anything waiting for firmware.
trigger firmware_mounts_complete
@@ -349,6 +376,8 @@
mkdir /data/system/heapdump 0700 system system
mkdir /data/user 0711 system system
+ setusercryptopolicies /data/user
+
# Reload policy from /data/security if present.
setprop selinux.reload_policy 1
diff --git a/rootdir/init.usb.configfs.rc b/rootdir/init.usb.configfs.rc
new file mode 100644
index 0000000..186384b
--- /dev/null
+++ b/rootdir/init.usb.configfs.rc
@@ -0,0 +1,175 @@
+on property:sys.usb.config=none && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/UDC "none"
+ stop adbd
+ write /config/usb_gadget/g1/bDeviceClass 0
+ write /config/usb_gadget/g1/bDeviceSubClass 0
+ write /config/usb_gadget/g1/bDeviceProtocol 0
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=adb && property:sys.usb.configfs=1
+ start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=adb && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "adb"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f1
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mtp && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
+ start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp_adb"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
+ symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=ptp && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
+ start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp_adb"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1
+ symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=accessory && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=accessory,adb && property:sys.usb.configfs=1
+ start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=accessory,adb && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory_adb"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
+ symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=audio_source && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "audiosource"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/audio_source.gs2 /config/usb_gadget/g1/configs/b.1/f1
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=audio_source,adb && property:sys.usb.configfs=1
+ start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=audio_source,adb && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "audiosource_adb"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/audio_source.gs2 /config/usb_gadget/g1/configs/b.1/f1
+ symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=accessory,audio_source && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory_audiosource"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
+ symlink /config/usb_gadget/g1/functions/audio_source.gs3 /config/usb_gadget/g1/configs/b.1/f2
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=accessory,audio_source,adb && property:sys.usb.configfs=1
+ start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=accessory,audio_source,adb && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory_audiosource_adb"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
+ symlink /config/usb_gadget/g1/functions/audio_source.gs3 /config/usb_gadget/g1/configs/b.1/f2
+ symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f3
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=midi && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "midi"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/midi.gs5 /config/usb_gadget/g1/configs/b.1/f1
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=midi,adb && property:sys.usb.configfs=1
+ start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=midi,adb && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "midi_adb"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/midi.gs5 /config/usb_gadget/g1/configs/b.1/f1
+ symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=rndis && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/rndis.gs4 /config/usb_gadget/g1/configs/b.1/f1
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
+
+on property:sys.usb.config=rndis,adb && property:sys.usb.configfs=1
+ start adbd
+
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,adb && property:sys.usb.configfs=1
+ write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_adb"
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ symlink /config/usb_gadget/g1/functions/rndis.gs4 /config/usb_gadget/g1/configs/b.1/f1
+ symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
+ write /config/usb_gadget/g1/UDC ${sys.usb.controller}
+ setprop sys.usb.state ${sys.usb.config}
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 4e6f2a8..1fd1e2a 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -22,8 +22,11 @@
on property:ro.kernel.qemu=1
start adbd
+on boot
+ setprop sys.usb.configfs 0
+
# Used to disable USB when switching states
-on property:sys.usb.config=none
+on property:sys.usb.config=none && property:sys.usb.configfs=0
stop adbd
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/bDeviceClass 0
@@ -32,7 +35,7 @@
# adb only USB configuration
# This is the fallback configuration if the
# USB manager fails to set a standard configuration
-on property:sys.usb.config=adb
+on property:sys.usb.config=adb && property:sys.usb.configfs=0
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18d1
write /sys/class/android_usb/android0/idProduct 4EE7
@@ -42,7 +45,7 @@
setprop sys.usb.state ${sys.usb.config}
# USB accessory configuration
-on property:sys.usb.config=accessory
+on property:sys.usb.config=accessory && property:sys.usb.configfs=0
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18d1
write /sys/class/android_usb/android0/idProduct 2d00
@@ -51,7 +54,7 @@
setprop sys.usb.state ${sys.usb.config}
# USB accessory configuration, with adb
-on property:sys.usb.config=accessory,adb
+on property:sys.usb.config=accessory,adb && property:sys.usb.configfs=0
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18d1
write /sys/class/android_usb/android0/idProduct 2d01
@@ -61,7 +64,7 @@
setprop sys.usb.state ${sys.usb.config}
# audio accessory configuration
-on property:sys.usb.config=audio_source
+on property:sys.usb.config=audio_source && property:sys.usb.configfs=0
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18d1
write /sys/class/android_usb/android0/idProduct 2d02
@@ -70,7 +73,7 @@
setprop sys.usb.state ${sys.usb.config}
# audio accessory configuration, with adb
-on property:sys.usb.config=audio_source,adb
+on property:sys.usb.config=audio_source,adb && property:sys.usb.configfs=0
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18d1
write /sys/class/android_usb/android0/idProduct 2d03
@@ -80,7 +83,7 @@
setprop sys.usb.state ${sys.usb.config}
# USB and audio accessory configuration
-on property:sys.usb.config=accessory,audio_source
+on property:sys.usb.config=accessory,audio_source && property:sys.usb.configfs=0
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18d1
write /sys/class/android_usb/android0/idProduct 2d04
@@ -89,7 +92,7 @@
setprop sys.usb.state ${sys.usb.config}
# USB and audio accessory configuration, with adb
-on property:sys.usb.config=accessory,audio_source,adb
+on property:sys.usb.config=accessory,audio_source,adb && property:sys.usb.configfs=0
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18d1
write /sys/class/android_usb/android0/idProduct 2d05
@@ -102,3 +105,34 @@
# when changing the default configuration
on property:persist.sys.usb.config=*
setprop sys.usb.config ${persist.sys.usb.config}
+
+#
+# USB type C
+#
+
+# USB mode changes
+on property:sys.usb.typec.mode=dfp
+ write /sys/class/dual_role_usb/otg_default/mode ${sys.usb.typec.mode}
+ setprop sys.usb.typec.state ${sys.usb.typec.mode}
+
+on property:sys.usb.typec.mode=ufp
+ write /sys/class/dual_role_usb/otg_default/mode ${sys.usb.typec.mode}
+ setprop sys.usb.typec.state ${sys.usb.typec.mode}
+
+# USB data role changes
+on property:sys.usb.typec.data_role=device
+ write /sys/class/dual_role_usb/otg_default/data_role ${sys.usb.typec.data_role}
+ setprop sys.usb.typec.state ${sys.usb.typec.data_role}
+
+on property:sys.usb.typec.data_role=host
+ write /sys/class/dual_role_usb/otg_default/data_role ${sys.usb.typec.data_role}
+ setprop sys.usb.typec.state ${sys.usb.typec.data_role}
+
+# USB power role changes
+on property:sys.usb.typec.power_role=source
+ 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 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}
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 75961e6..ff25ac2 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -5,4 +5,4 @@
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
-
+ writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 68c0668..29bb1cf 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -5,8 +5,10 @@
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
+ writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
socket zygote_secondary stream 660 root system
onrestart restart zygote
+ writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index afb6d63..5497524 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -5,4 +5,4 @@
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
-
+ writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 979ab3b..8ed5e9e 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -5,8 +5,10 @@
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
+ writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
socket zygote_secondary stream 660 root system
onrestart restart zygote
+ writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
diff --git a/run-as/run-as.c b/run-as/run-as.c
index 3f32e7d..f0fd2fe 100644
--- a/run-as/run-as.c
+++ b/run-as/run-as.c
@@ -20,6 +20,8 @@
#include <dirent.h>
#include <errno.h>
+#include <paths.h>
+#include <pwd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -193,10 +195,21 @@
panic("Could not set SELinux security context: %s\n", strerror(errno));
}
- /* cd into the data directory */
+ // cd into the data directory, and set $HOME correspondingly.
if (TEMP_FAILURE_RETRY(chdir(info.dataDir)) < 0) {
panic("Could not cd to package's data directory: %s\n", strerror(errno));
}
+ setenv("HOME", info.dataDir, 1);
+
+ // Reset parts of the environment, like su would.
+ setenv("PATH", _PATH_DEFPATH, 1);
+ unsetenv("IFS");
+
+ // Set the user-specific parts for this user.
+ struct passwd* pw = getpwuid(uid);
+ setenv("LOGNAME", pw->pw_name, 1);
+ setenv("SHELL", pw->pw_shell, 1);
+ setenv("USER", pw->pw_name, 1);
/* User specified command for exec. */
if ((argc >= commandArgvOfs + 1) &&