Reconcile with jb-mr2-release - do not merge

Change-Id: Ia1e9aa160247d491cc60c1dcc7a73c8545410d78
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index ad65dfb..55aabdd 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -20,6 +20,7 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <unistd.h>
 #include <cutils/compiler.h>
 
@@ -62,7 +63,8 @@
 #define ATRACE_TAG_VIDEO            (1<<9)
 #define ATRACE_TAG_CAMERA           (1<<10)
 #define ATRACE_TAG_HAL              (1<<11)
-#define ATRACE_TAG_LAST             ATRACE_TAG_HAL
+#define ATRACE_TAG_APP              (1<<12)
+#define ATRACE_TAG_LAST             ATRACE_TAG_APP
 
 // Reserved for initialization.
 #define ATRACE_TAG_NOT_READY        (1LL<<63)
@@ -97,6 +99,14 @@
 void atrace_update_tags();
 
 /**
+ * Set whether the process is debuggable.  By default the process is not
+ * considered debuggable.  If the process is not debuggable then application-
+ * level tracing is not allowed unless the ro.debuggable system property is
+ * set to '1'.
+ */
+void atrace_set_debuggable(bool debuggable);
+
+/**
  * Flag indicating whether setup has been completed, initialized to 0.
  * Nonzero indicates setup has completed.
  * Note: This does NOT indicate whether or not setup was successful.
diff --git a/libcutils/trace.c b/libcutils/trace.c
index 152ea61..047f889 100644
--- a/libcutils/trace.c
+++ b/libcutils/trace.c
@@ -18,6 +18,7 @@
 #include <fcntl.h>
 #include <limits.h>
 #include <pthread.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
@@ -29,11 +30,81 @@
 #define LOG_TAG "cutils-trace"
 #include <cutils/log.h>
 
-int32_t               atrace_is_ready     = 0;
-int                   atrace_marker_fd    = -1;
-uint64_t              atrace_enabled_tags = ATRACE_TAG_NOT_READY;
-static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT;
-static pthread_mutex_t atrace_tags_mutex = PTHREAD_MUTEX_INITIALIZER;
+int32_t                atrace_is_ready      = 0;
+int                    atrace_marker_fd     = -1;
+uint64_t               atrace_enabled_tags  = ATRACE_TAG_NOT_READY;
+static bool            atrace_is_debuggable = false;
+static pthread_once_t  atrace_once_control  = PTHREAD_ONCE_INIT;
+static pthread_mutex_t atrace_tags_mutex    = PTHREAD_MUTEX_INITIALIZER;
+
+// Set whether this process is debuggable, which determines whether
+// application-level tracing is allowed when the ro.debuggable system property
+// is not set to '1'.
+void atrace_set_debuggable(bool debuggable)
+{
+    atrace_is_debuggable = debuggable;
+    atrace_update_tags();
+}
+
+// Check whether the given command line matches one of the comma-separated
+// values listed in the app_cmdlines property.
+static bool atrace_is_cmdline_match(const char* cmdline) {
+    char value[PROPERTY_VALUE_MAX];
+    char* start = value;
+
+    property_get("debug.atrace.app_cmdlines", value, "");
+
+    while (start != NULL) {
+        char* end = strchr(start, ',');
+
+        if (end != NULL) {
+            *end = '\0';
+            end++;
+        }
+
+        if (strcmp(cmdline, start) == 0) {
+            return true;
+        }
+
+        start = end;
+    }
+
+    return false;
+}
+
+// Determine whether application-level tracing is enabled for this process.
+static bool atrace_is_app_tracing_enabled()
+{
+    bool sys_debuggable = false;
+    bool proc_debuggable = false;
+    char value[PROPERTY_VALUE_MAX];
+    bool result = false;
+
+    // Check whether the system is debuggable.
+    property_get("ro.debuggable", value, "0");
+    if (value[0] == '1') {
+        sys_debuggable = true;
+    }
+
+    if (sys_debuggable || atrace_is_debuggable) {
+        // Check whether tracing is enabled for this process.
+        FILE * file = fopen("/proc/self/cmdline", "r");
+        if (file) {
+            char cmdline[4096];
+            if (fgets(cmdline, sizeof(cmdline), file)) {
+                result = atrace_is_cmdline_match(cmdline);
+            } else {
+                ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
+            }
+            fclose(file);
+        } else {
+            ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
+                    errno);
+        }
+    }
+
+    return result;
+}
 
 // Read the sysprop and return the value tags should be set to
 static uint64_t atrace_get_property()
@@ -52,6 +123,15 @@
         ALOGE("Error parsing trace property: Number too large: %s", value);
         return 0;
     }
+
+    // Only set the "app" tag if this process was selected for app-level debug
+    // tracing.
+    if (atrace_is_app_tracing_enabled()) {
+        tags |= ATRACE_TAG_APP;
+    } else {
+        tags &= ~ATRACE_TAG_APP;
+    }
+
     return (tags | ATRACE_TAG_ALWAYS) & ATRACE_TAG_VALID_MASK;
 }
 
diff --git a/run-as/package.c b/run-as/package.c
index 683dae6..27fc1eb 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -47,15 +47,18 @@
 /* Copy 'srclen' string bytes from 'src' into buffer 'dst' of size 'dstlen'
  * This function always zero-terminate the destination buffer unless
  * 'dstlen' is 0, even in case of overflow.
+ * Returns a pointer into the src string, leaving off where the copy
+ * has stopped. The copy will stop when dstlen, srclen or a null
+ * character on src has been reached.
  */
-static void
+static const char*
 string_copy(char* dst, size_t dstlen, const char* src, size_t srclen)
 {
     const char* srcend = src + srclen;
     const char* dstend = dst + dstlen;
 
     if (dstlen == 0)
-        return;
+        return src;
 
     dstend--; /* make room for terminating zero */
 
@@ -63,6 +66,7 @@
         *dst++ = *src++;
 
     *dst = '\0'; /* zero-terminate result */
+    return src;
 }
 
 /* Open 'filename' and map it into our address-space.
@@ -428,6 +432,7 @@
     info->uid          = 0;
     info->isDebuggable = 0;
     info->dataDir[0]   = '\0';
+    info->seinfo[0]    = '\0';
 
     buffer = map_file(PACKAGES_LIST_FILE, &buffer_len);
     if (buffer == NULL)
@@ -438,13 +443,14 @@
 
     /* expect the following format on each line of the control file:
      *
-     *  <pkgName> <uid> <debugFlag> <dataDir>
+     *  <pkgName> <uid> <debugFlag> <dataDir> <seinfo>
      *
      * where:
      *  <pkgName>    is the package's name
      *  <uid>        is the application-specific user Id (decimal)
      *  <debugFlag>  is 1 if the package is debuggable, or 0 otherwise
      *  <dataDir>    is the path to the package's data directory (e.g. /data/data/com.example.foo)
+     *  <seinfo>     is the seinfo label associated with the package
      *
      * The file is generated in com.android.server.PackageManagerService.Settings.writeLP()
      */
@@ -500,7 +506,18 @@
         if (q == p)
             goto BAD_FORMAT;
 
-        string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
+        p = string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
+
+        /* skip spaces */
+        if (parse_spaces(&p, end) < 0)
+            goto BAD_FORMAT;
+
+        /* fifth field is the seinfo string */
+        q = skip_non_spaces(p, end);
+        if (q == p)
+            goto BAD_FORMAT;
+
+        string_copy(info->seinfo, sizeof info->seinfo, p, q - p);
 
         /* Ignore the rest */
         result = 0;
diff --git a/run-as/package.h b/run-as/package.h
index 852af06..34603c0 100644
--- a/run-as/package.h
+++ b/run-as/package.h
@@ -30,6 +30,7 @@
     uid_t  uid;
     char   isDebuggable;
     char   dataDir[PATH_MAX];
+    char   seinfo[PATH_MAX];
 } PackageInfo;
 
 /* see documentation in package.c for these functiosn */
diff --git a/run-as/run-as.c b/run-as/run-as.c
index 9eb09ae..3c0ecc4 100644
--- a/run-as/run-as.c
+++ b/run-as/run-as.c
@@ -163,7 +163,7 @@
         return 1;
     }
 
-    if (selinux_android_setcontext(uid, 0, NULL, pkgname) < 0) {
+    if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
         panic("Could not set SELinux security context:  %s\n", strerror(errno));
         return 1;
     }