Merge "Bluetooth: log unexpected crashes and restarts"
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index c329fd1..aced75d 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -17,6 +17,11 @@
 package com.android.internal.os;
 
 import android.os.Process;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructCapUserData;
+import android.system.StructCapUserHeader;
 import android.util.Slog;
 import com.android.internal.os.Zygote.MethodAndArgsCaller;
 import dalvik.system.VMRuntime;
@@ -119,6 +124,7 @@
         command.append(' ');
         command.append(targetSdkVersion);
         Zygote.appendQuotedShellArgs(command, args);
+        preserveCapabilities();
         Zygote.execShell(command.toString());
     }
 
@@ -156,4 +162,57 @@
 
         RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
     }
+
+    /**
+     * Copy current capabilities to ambient capabilities. This is required for apps using
+     * capabilities, as execv will re-evaluate the capability set, and the set of sh is
+     * empty. Ambient capabilities have to be set to inherit them effectively.
+     *
+     * Note: This is BEST EFFORT ONLY. In case capabilities can't be raised, this function
+     *       will silently return. In THIS CASE ONLY, as this is a development feature, it
+     *       is better to return and try to run anyways, instead of blocking the wrapped app.
+     *       This is acceptable here as failure will leave the wrapped app with strictly less
+     *       capabilities, which may make it crash, but not exceed its allowances.
+     */
+    private static void preserveCapabilities() {
+        StructCapUserHeader header = new StructCapUserHeader(
+                OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
+        StructCapUserData[] data;
+        try {
+            data = Os.capget(header);
+        } catch (ErrnoException e) {
+            Slog.e(RuntimeInit.TAG, "RuntimeInit: Failed capget", e);
+            return;
+        }
+
+        if (data[0].permitted != data[0].inheritable ||
+                data[1].permitted != data[1].inheritable) {
+            data[0] = new StructCapUserData(data[0].effective, data[0].permitted,
+                    data[0].permitted);
+            data[1] = new StructCapUserData(data[1].effective, data[1].permitted,
+                    data[1].permitted);
+            try {
+                Os.capset(header, data);
+            } catch (ErrnoException e) {
+                Slog.e(RuntimeInit.TAG, "RuntimeInit: Failed capset", e);
+                return;
+            }
+        }
+
+        for (int i = 0; i < 64; i++) {
+            int dataIndex = OsConstants.CAP_TO_INDEX(i);
+            int capMask = OsConstants.CAP_TO_MASK(i);
+            if ((data[dataIndex].inheritable & capMask) != 0) {
+                try {
+                    Os.prctl(OsConstants.PR_CAP_AMBIENT, OsConstants.PR_CAP_AMBIENT_RAISE, i, 0,
+                            0);
+                } catch (ErrnoException ex) {
+                    // Only log here. Try to run the wrapped application even without this
+                    // ambient capability. It may crash after fork, but at least we'll try.
+                    Slog.e(RuntimeInit.TAG, "RuntimeInit: Failed to raise ambient capability "
+                            + i, ex);
+                }
+            }
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
index 7a4980a..56e977c 100644
--- a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
+++ b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
@@ -109,7 +109,7 @@
     }
 
     public static String expectedSchedulerGroup(int prio) {
-        return prio < Process.THREAD_PRIORITY_BACKGROUND ? "/" : "/bg_non_interactive";
+        return "/";
     }
 
     public void testPassPriorityToService() throws Exception {
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index e10db05..38d2a58 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -4320,6 +4320,7 @@
         if (curOff > (dtohl(entry.type->header.size)-sizeof(ResTable_map))) {
             ALOGW("ResTable_map at %d is beyond type chunk data %d",
                  (int)curOff, dtohl(entry.type->header.size));
+            free(set);
             return BAD_TYPE;
         }
         map = (const ResTable_map*)(((const uint8_t*)entry.type) + curOff);
@@ -4332,6 +4333,7 @@
             if (grp->dynamicRefTable.lookupResourceId(&newName) != NO_ERROR) {
                 ALOGE("Failed resolving ResTable_map name at %d with ident 0x%08x",
                         (int) curOff, (int) newName);
+                free(set);
                 return UNKNOWN_ERROR;
             }
         }
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 58c76ec..46f76b1 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.connectivity;
 
+import android.annotation.WorkerThread;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -73,7 +74,7 @@
     public static final String KEY_PROXY = "keyProxy";
     private String mCurrentPac;
     @GuardedBy("mProxyLock")
-    private Uri mPacUrl = Uri.EMPTY;
+    private volatile Uri mPacUrl = Uri.EMPTY;
 
     private AlarmManager mAlarmManager;
     @GuardedBy("mProxyLock")
@@ -86,29 +87,34 @@
     private int mCurrentDelay;
     private int mLastPort;
 
-    private boolean mHasSentBroadcast;
-    private boolean mHasDownloaded;
+    private volatile boolean mHasSentBroadcast;
+    private volatile boolean mHasDownloaded;
 
     private Handler mConnectivityHandler;
     private int mProxyMessage;
 
     /**
-     * Used for locking when setting mProxyService and all references to mPacUrl or mCurrentPac.
+     * Used for locking when setting mProxyService and all references to mCurrentPac.
      */
     private final Object mProxyLock = new Object();
 
+    /**
+     * Runnable to download PAC script.
+     * The behavior relies on the assamption it always run on mNetThread to guarantee that the
+     * latest data fetched from mPacUrl is stored in mProxyService.
+     */
     private Runnable mPacDownloader = new Runnable() {
         @Override
+        @WorkerThread
         public void run() {
             String file;
-            synchronized (mProxyLock) {
-                if (Uri.EMPTY.equals(mPacUrl)) return;
-                try {
-                    file = get(mPacUrl);
-                } catch (IOException ioe) {
-                    file = null;
-                    Log.w(TAG, "Failed to load PAC file: " + ioe);
-                }
+            final Uri pacUrl = mPacUrl;
+            if (Uri.EMPTY.equals(pacUrl)) return;
+            try {
+                file = get(pacUrl);
+            } catch (IOException ioe) {
+                file = null;
+                Log.w(TAG, "Failed to load PAC file: " + ioe);
             }
             if (file != null) {
                 synchronized (mProxyLock) {
@@ -171,9 +177,7 @@
                 // Allow to send broadcast, nothing to do.
                 return false;
             }
-            synchronized (mProxyLock) {
-                mPacUrl = proxy.getPacFileUrl();
-            }
+            mPacUrl = proxy.getPacFileUrl();
             mCurrentDelay = DELAY_1;
             mHasSentBroadcast = false;
             mHasDownloaded = false;