Merge "Add -e to the adb shell documentation."
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index ed9b736..6e4c4e8 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -468,6 +468,7 @@
     int stdin_fd, write_fd;
     bool raw_stdin;
     std::unique_ptr<ShellProtocol> protocol;
+    char escape_char;
 };
 
 // Loops to read from stdin and push the data to the given FD.
@@ -475,7 +476,6 @@
 // will take ownership of the object and delete it when finished.
 static void* stdin_read_thread_loop(void* x) {
     std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x));
-    int state = 0;
 
 #if !defined(_WIN32)
     // Mask SIGTTIN in case we're in a backgrounded process.
@@ -497,7 +497,7 @@
     // Set up the initial window size.
     send_window_size_change(args->stdin_fd, args->protocol);
 
-    char raw_buffer[1024];
+    char raw_buffer[BUFSIZ];
     char* buffer_ptr = raw_buffer;
     size_t buffer_size = sizeof(raw_buffer);
     if (args->protocol != nullptr) {
@@ -505,6 +505,14 @@
         buffer_size = args->protocol->data_capacity();
     }
 
+    // If we need to parse escape sequences, make life easy.
+    if (args->raw_stdin && args->escape_char != '\0') {
+        buffer_size = 1;
+    }
+
+    enum EscapeState { kMidFlow, kStartOfLine, kInEscape };
+    EscapeState state = kStartOfLine;
+
     while (true) {
         // Use unix_read() rather than adb_read() for stdin.
         D("stdin_read_thread_loop(): pre unix_read(fdi=%d,...)", args->stdin_fd);
@@ -530,36 +538,36 @@
             }
             break;
         }
-        // If we made stdin raw, check input for the "~." escape sequence. In
+        // If we made stdin raw, check input for escape sequences. In
         // this situation signals like Ctrl+C are sent remotely rather than
         // interpreted locally so this provides an emergency out if the remote
         // 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]) {
-                case '\n':
-                    state = 1;
-                    break;
-                case '\r':
-                    state = 1;
-                    break;
-                case '~':
-                    if (state == 1) {
-                        state++;
-                    } else {
-                        state = 0;
-                    }
-                    break;
-                case '.':
-                    if (state == 2) {
-                        fprintf(stderr,"\r\n* disconnect *\r\n");
+        if (args->raw_stdin && args->escape_char != '\0') {
+            char ch = buffer_ptr[0];
+            if (ch == args->escape_char) {
+                if (state == kStartOfLine) {
+                    state = kInEscape;
+                    // Swallow the escape character.
+                    continue;
+                } else {
+                    state = kMidFlow;
+                }
+            } else {
+                if (state == kInEscape) {
+                    if (ch == '.') {
+                        fprintf(stderr,"\r\n[ disconnected ]\r\n");
                         stdin_raw_restore();
                         exit(0);
+                    } else {
+                        // We swallowed an escape character that wasn't part of
+                        // a valid escape sequence; time to cough it up.
+                        buffer_ptr[0] = args->escape_char;
+                        buffer_ptr[1] = ch;
+                        ++r;
                     }
-                default:
-                    state = 0;
                 }
+                state = (ch == '\n' || ch == '\r') ? kStartOfLine : kMidFlow;
             }
         }
         if (args->protocol) {
@@ -604,6 +612,7 @@
 // On success returns the remote exit code if |use_shell_protocol| is true,
 // 0 otherwise. On failure returns 1.
 static int RemoteShell(bool use_shell_protocol, const std::string& type_arg,
+                       char escape_char,
                        const std::string& command) {
     std::string service_string = ShellServiceString(use_shell_protocol,
                                                     type_arg, command);
@@ -629,6 +638,7 @@
     args->stdin_fd = STDIN_FILENO;
     args->write_fd = fd;
     args->raw_stdin = raw_stdin;
+    args->escape_char = escape_char;
     if (use_shell_protocol) {
         args->protocol.reset(new ShellProtocol(args->write_fd));
     }
@@ -690,8 +700,17 @@
     --argc;
     ++argv;
     int t_arg_count = 0;
+    char escape_char = '~';
     while (argc) {
-        if (!strcmp(argv[0], "-T") || !strcmp(argv[0], "-t")) {
+        if (!strcmp(argv[0], "-e")) {
+            if (argc < 2 || !(strlen(argv[1]) == 1 || strcmp(argv[1], "none") == 0)) {
+                fprintf(stderr, "error: -e requires a single-character argument or 'none'\n");
+                return 1;
+            }
+            escape_char = (strcmp(argv[1], "none") == 0) ? 0 : argv[1][0];
+            argc -= 2;
+            argv += 2;
+        } else 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;
@@ -747,7 +766,7 @@
         command = android::base::Join(std::vector<const char*>(argv, argv + argc), ' ');
     }
 
-    return RemoteShell(use_shell_protocol, shell_type_arg, command);
+    return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command);
 }
 
 static int adb_download_buffer(const char *service, const char *fn, const void* data, unsigned sz,
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 8c3ca63..b8d758f 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -142,9 +142,11 @@
     // AID_SDCARD_R to allow reading from the SD card
     // AID_SDCARD_RW to allow writing to the SD card
     // AID_NET_BW_STATS to read out qtaguid statistics
+    // AID_READPROC for reading /proc entries across UID boundaries
     gid_t groups[] = {AID_ADB,      AID_LOG,       AID_INPUT,
                       AID_INET,     AID_NET_BT,    AID_NET_BT_ADMIN,
-                      AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS};
+                      AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS,
+                      AID_READPROC };
     if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
         PLOG(FATAL) << "Could not set supplental groups";
     }
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 268a11f..3322763 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -209,6 +209,17 @@
         line_printer_.Print(s, LinePrinter::FULL);
     }
 
+    void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
+        std::string s = "adb: warning: ";
+
+        va_list ap;
+        va_start(ap, fmt);
+        android::base::StringAppendV(&s, fmt, ap);
+        va_end(ap);
+
+        line_printer_.Print(s, LinePrinter::FULL);
+    }
+
     uint64_t total_bytes;
 
     // TODO: add a char[max] buffer here, to replace syncsendbuf...
@@ -533,7 +544,7 @@
                 dirlist.push_back(ci);
             } else {
                 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
-                    sc.Error("skipping special file '%s'", lpath.c_str());
+                    sc.Warning("skipping special file '%s'", lpath.c_str());
                 } else {
                     ci.time = st.st_mtime;
                     ci.size = st.st_size;
@@ -554,7 +565,7 @@
     if (empty_dir) {
         // TODO(b/25566053): Make pushing empty directories work.
         // TODO(b/25457350): We don't preserve permissions on directories.
-        sc.Error("skipping empty directory '%s'", lpath.c_str());
+        sc.Warning("skipping empty directory '%s'", lpath.c_str());
         copyinfo ci = mkcopyinfo(adb_dirname(lpath), adb_dirname(rpath),
                                  adb_basename(lpath), S_IFDIR);
         ci.skip = true;
@@ -709,8 +720,7 @@
             ci.size = size;
             filelist->push_back(ci);
         } else {
-            sc.Print(android::base::StringPrintf("skipping special file '%s'\n",
-                                                 name));
+            sc.Warning("skipping special file '%s'\n", name);
         }
     };
 
@@ -852,7 +862,8 @@
             continue;
         }
 
-        if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
+        if (S_ISREG(mode) || S_ISLNK(mode)) {
+            // TODO(b/25601283): symlinks shouldn't be handled as files.
             std::string path_holder;
             struct stat st;
             if (stat(dst_path, &st) == 0) {
diff --git a/debuggerd/debuggerd.rc b/debuggerd/debuggerd.rc
index 4be2e5d..e43fe96 100644
--- a/debuggerd/debuggerd.rc
+++ b/debuggerd/debuggerd.rc
@@ -1,3 +1,4 @@
 service debuggerd /system/bin/debuggerd
     class main
+    group root readproc
     writepid /dev/cpuset/system-background/tasks
diff --git a/debuggerd/debuggerd64.rc b/debuggerd/debuggerd64.rc
index c6e7bf2..35b5af3 100644
--- a/debuggerd/debuggerd64.rc
+++ b/debuggerd/debuggerd64.rc
@@ -1,3 +1,4 @@
 service debuggerd64 /system/bin/debuggerd64
     class main
+    group root readproc
     writepid /dev/cpuset/system-background/tasks
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index c7eb34b..e2133e9 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -101,6 +101,7 @@
 #define AID_NET_BW_STATS  3006  /* read bandwidth statistics */
 #define AID_NET_BW_ACCT   3007  /* change bandwidth statistics accounting */
 #define AID_NET_BT_STACK  3008  /* bluetooth: access config files */
+#define AID_READPROC      3009  /* Allow /proc read access */
 
 /* The range 5000-5999 is also reserved for OEM, and must never be used here. */
 #define AID_OEM_RESERVED_2_START 5000
@@ -191,6 +192,7 @@
     { "net_bw_stats",  AID_NET_BW_STATS, },
     { "net_bw_acct",   AID_NET_BW_ACCT, },
     { "net_bt_stack",  AID_NET_BT_STACK, },
+    { "readproc",      AID_READPROC, },
 
     { "everybody",     AID_EVERYBODY, },
     { "misc",          AID_MISC, },
diff --git a/init/init.cpp b/init/init.cpp
index 605674b..86aed9a 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -546,7 +546,8 @@
         mkdir("/dev/pts", 0755);
         mkdir("/dev/socket", 0755);
         mount("devpts", "/dev/pts", "devpts", 0, NULL);
-        mount("proc", "/proc", "proc", 0, NULL);
+        #define MAKE_STR(x) __STRING(x)
+        mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
         mount("sysfs", "/sys", "sysfs", 0, NULL);
     }
 
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.h b/libpixelflinger/codeflinger/MIPS64Assembler.h
index 3da291a..b43e5da 100644
--- a/libpixelflinger/codeflinger/MIPS64Assembler.h
+++ b/libpixelflinger/codeflinger/MIPS64Assembler.h
@@ -303,32 +303,7 @@
 
 
 protected:
-    // void string_detab(char *s);
-    // void string_pad(char *s, int padded_len);
-
     ArmToMips64Assembler *mParent;
-    sp<Assembly>    mAssembly;
-    uint32_t*       mBase;
-    uint32_t*       mPC;
-    uint32_t*       mPrologPC;
-    int64_t         mDuration;
-#if defined(WITH_LIB_HARDWARE)
-    bool            mQemuTracing;
-#endif
-
-    struct branch_target_t {
-        inline branch_target_t() : label(0), pc(0) { }
-        inline branch_target_t(const char* l, uint32_t* p)
-            : label(l), pc(p) { }
-        const char* label;
-        uint32_t*   pc;
-    };
-
-    Vector<branch_target_t>                 mBranchTargets;
-    KeyedVector< const char*, uint32_t* >   mLabels;
-    KeyedVector< uint32_t*, const char* >   mLabelsInverseMapping;
-    KeyedVector< uint32_t*, const char* >   mComments;
-
 
     // opcode field of all instructions
     enum opcode_field {
diff --git a/libsync/tests/sync_test.cpp b/libsync/tests/sync_test.cpp
index 55cd687..2c409dc 100644
--- a/libsync/tests/sync_test.cpp
+++ b/libsync/tests/sync_test.cpp
@@ -50,7 +50,7 @@
     bool isValid() const {
         if (m_fdInitialized) {
             int status = fcntl(m_fd, F_GETFD, 0);
-            if (status == 0)
+            if (status >= 0)
                 return true;
             else
                 return false;
@@ -92,7 +92,7 @@
     bool isValid() const {
         if (m_fdInitialized) {
             int status = fcntl(m_fd, F_GETFD, 0);
-            if (status == 0)
+            if (status >= 0)
                 return true;
             else
                 return false;
diff --git a/lmkd/lmkd.rc b/lmkd/lmkd.rc
index 7d6cb11..3bb84ab 100644
--- a/lmkd/lmkd.rc
+++ b/lmkd/lmkd.rc
@@ -1,5 +1,6 @@
 service lmkd /system/bin/lmkd
     class core
+    group root readproc
     critical
     socket lmkd seqpacket 0660 system system
     writepid /dev/cpuset/system-background/tasks
diff --git a/logd/logd.rc b/logd/logd.rc
index ecd2f0a..10f3553 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -3,7 +3,7 @@
     socket logd stream 0666 logd logd
     socket logdr seqpacket 0666 logd logd
     socket logdw dgram 0222 logd logd
-    group root system
+    group root system readproc
     writepid /dev/cpuset/system-background/tasks
 
 service logd-reinit /system/bin/logd --reinit
diff --git a/logd/main.cpp b/logd/main.cpp
index ad577d2..8e75b37 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -106,7 +106,9 @@
         return -1;
     }
 
-    if (setgroups(0, NULL) == -1) {
+    gid_t groups[] = { AID_READPROC };
+
+    if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) == -1) {
         return -1;
     }
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b80c454..17e87da 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -556,7 +556,7 @@
     console
     disabled
     user shell
-    group shell log
+    group shell log readproc
     seclabel u:r:shell:s0
 
 on property:ro.debuggable=1