Merge "Fix blank Keyguard #4" into lmp-dev
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 0ee8d86f..47ea732 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1725,7 +1725,7 @@
         for (int i = 0; i < numViolations; ++i) {
             if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call.  i=" + i);
             ViolationInfo info = new ViolationInfo(p, !currentlyGathering);
-            if (info.crashInfo.stackTrace.length() > 10000) {
+            if (info.crashInfo.stackTrace != null && info.crashInfo.stackTrace.length() > 10000) {
                 // 10000 characters is way too large for this to be any sane kind of
                 // strict mode collection of stacks.  We've had a problem where we leave
                 // strict mode violations associated with the thread, and it keeps tacking
diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
index eeb6d58..e49b8c3 100644
--- a/core/java/android/util/LocalLog.java
+++ b/core/java/android/util/LocalLog.java
@@ -20,6 +20,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Calendar;
 import java.util.Iterator;
 import java.util.LinkedList;
 
@@ -30,18 +31,21 @@
 
     private LinkedList<String> mLog;
     private int mMaxLines;
-    private Time mNow;
+    private long mNow;
 
     public LocalLog(int maxLines) {
         mLog = new LinkedList<String>();
         mMaxLines = maxLines;
-        mNow = new Time();
     }
 
     public synchronized void log(String msg) {
         if (mMaxLines > 0) {
-            mNow.setToNow();
-            mLog.add(mNow.format("%H:%M:%S") + " - " + msg);
+            mNow = System.currentTimeMillis();
+            StringBuilder sb = new StringBuilder();
+            Calendar c = Calendar.getInstance();
+            c.setTimeInMillis(mNow);
+            sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
+            mLog.add(sb.toString() + " - " + msg);
             while (mLog.size() > mMaxLines) mLog.remove();
         }
     }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 5d2822d..1e46517 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -493,7 +493,6 @@
 
     private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
 
-    private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
     private static native long nCreateTextureLayer(long nativeProxy);
     private static native void nBuildLayer(long nativeProxy, long node);
     private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index a8edb77..6219956 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -320,13 +320,6 @@
     RenderProxy::invokeFunctor(functor, waitForCompletion);
 }
 
-static jlong android_view_ThreadedRenderer_createDisplayListLayer(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jint width, jint height) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    DeferredLayerUpdater* layer = proxy->createDisplayListLayer(width, height);
-    return reinterpret_cast<jlong>(layer);
-}
-
 static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
         jlong proxyPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -443,7 +436,6 @@
     { "nDestroy", "(J)V", (void*) android_view_ThreadedRenderer_destroy },
     { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
-    { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
     { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
     { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 836de45..a6d7e78 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -18,38 +18,52 @@
 #include "OpenGLRenderer.h"
 
 #include "LayerRenderer.h"
+#include "renderthread/EglManager.h"
+#include "renderthread/RenderTask.h"
 
 namespace android {
 namespace uirenderer {
 
-static void defaultLayerDestroyer(Layer* layer) {
-    Caches::getInstance().resourceCache.decrementRefcount(layer);
-}
+class DeleteLayerTask : public renderthread::RenderTask {
+public:
+    DeleteLayerTask(renderthread::EglManager& eglManager, Layer* layer)
+        : mEglManager(eglManager)
+        , mLayer(layer)
+    {}
 
-DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, LayerDestroyer destroyer)
+    virtual void run() {
+        mEglManager.requireGlContext();
+        LayerRenderer::destroyLayer(mLayer);
+        mLayer = 0;
+        delete this;
+    }
+
+private:
+    renderthread::EglManager& mEglManager;
+    Layer* mLayer;
+};
+
+DeferredLayerUpdater::DeferredLayerUpdater(renderthread::RenderThread& thread, Layer* layer)
         : mSurfaceTexture(0)
         , mTransform(0)
         , mNeedsGLContextAttach(false)
         , mUpdateTexImage(false)
         , mLayer(layer)
         , mCaches(Caches::getInstance())
-        , mDestroyer(destroyer) {
+        , mRenderThread(thread) {
     mWidth = mLayer->layer.getWidth();
     mHeight = mLayer->layer.getHeight();
     mBlend = mLayer->isBlend();
     mColorFilter = SkSafeRef(mLayer->getColorFilter());
     mAlpha = mLayer->getAlpha();
     mMode = mLayer->getMode();
-
-    if (!mDestroyer) {
-        mDestroyer = defaultLayerDestroyer;
-    }
 }
 
 DeferredLayerUpdater::~DeferredLayerUpdater() {
     SkSafeUnref(mColorFilter);
     setTransform(0);
-    mDestroyer(mLayer);
+    mRenderThread.queue(new DeleteLayerTask(mRenderThread.eglManager(), mLayer));
+    mLayer = 0;
 }
 
 void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
@@ -121,7 +135,12 @@
 
 void DeferredLayerUpdater::detachSurfaceTexture() {
     if (mSurfaceTexture.get()) {
-        mSurfaceTexture->detachFromContext();
+        mRenderThread.eglManager().requireGlContext();
+        status_t err = mSurfaceTexture->detachFromContext();
+        if (err != 0) {
+            // TODO: Elevate to fatal exception
+            ALOGE("Failed to detach SurfaceTexture from context %d", err);
+        }
         mSurfaceTexture = 0;
         mLayer->clearTexture();
     }
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index c838c32..dda3e89 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -25,19 +25,18 @@
 #include "Layer.h"
 #include "Rect.h"
 #include "RenderNode.h"
+#include "renderthread/RenderThread.h"
 
 namespace android {
 namespace uirenderer {
 
-typedef void (*LayerDestroyer)(Layer* layer);
-
 // Container to hold the properties a layer should be set to at the start
 // of a render pass
 class DeferredLayerUpdater : public VirtualLightRefBase {
 public:
     // Note that DeferredLayerUpdater assumes it is taking ownership of the layer
     // and will not call incrementRef on it as a result.
-    ANDROID_API DeferredLayerUpdater(Layer* layer, LayerDestroyer = 0);
+    ANDROID_API DeferredLayerUpdater(renderthread::RenderThread& thread, Layer* layer);
     ANDROID_API ~DeferredLayerUpdater();
 
     ANDROID_API bool setSize(uint32_t width, uint32_t height) {
@@ -99,8 +98,7 @@
 
     Layer* mLayer;
     Caches& mCaches;
-
-    LayerDestroyer mDestroyer;
+    renderthread::RenderThread& mRenderThread;
 
     void doUpdateTexImage();
 };
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 1c416a7..b50a433 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -344,11 +344,6 @@
     task->run();
 }
 
-Layer* CanvasContext::createRenderLayer(int width, int height) {
-    requireSurface();
-    return LayerRenderer::createRenderLayer(mRenderThread.renderState(), width, height);
-}
-
 Layer* CanvasContext::createTextureLayer() {
     requireSurface();
     return LayerRenderer::createTextureLayer(mRenderThread.renderState());
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 2460f6b8..d4282fa 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -83,7 +83,6 @@
 
     void runWithGlContext(RenderTask* task);
 
-    Layer* createRenderLayer(int width, int height);
     Layer* createTextureLayer();
 
     ANDROID_API static void setTextureAtlas(RenderThread& thread,
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 9528874..047819d 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -257,31 +257,16 @@
     RenderThread::getInstance().queue(task);
 }
 
-CREATE_BRIDGE3(createDisplayListLayer, CanvasContext* context, int width, int height) {
-    Layer* layer = args->context->createRenderLayer(args->width, args->height);
-    if (!layer) return 0;
-    return new DeferredLayerUpdater(layer, RenderProxy::enqueueDestroyLayer);
-}
-
-DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) {
-    SETUP_TASK(createDisplayListLayer);
-    args->width = width;
-    args->height = height;
-    args->context = mContext;
-    void* retval = postAndWait(task);
-    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
-    return layer;
-}
-
-CREATE_BRIDGE1(createTextureLayer, CanvasContext* context) {
+CREATE_BRIDGE2(createTextureLayer, RenderThread* thread, CanvasContext* context) {
     Layer* layer = args->context->createTextureLayer();
     if (!layer) return 0;
-    return new DeferredLayerUpdater(layer, RenderProxy::enqueueDestroyLayer);
+    return new DeferredLayerUpdater(*args->thread, layer);
 }
 
 DeferredLayerUpdater* RenderProxy::createTextureLayer() {
     SETUP_TASK(createTextureLayer);
     args->context = mContext;
+    args->thread = &mRenderThread;
     void* retval = postAndWait(task);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
     return layer;
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 8b8d99c..678e7e2 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -80,7 +80,6 @@
     ANDROID_API void runWithGlContext(RenderTask* task);
 
     static void enqueueDestroyLayer(Layer* layer);
-    ANDROID_API DeferredLayerUpdater* createDisplayListLayer(int width, int height);
     ANDROID_API DeferredLayerUpdater* createTextureLayer();
     ANDROID_API void buildLayer(RenderNode* node);
     ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 3c2ad0e..0336f11 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -572,7 +572,8 @@
 
                 // USE_SESSIONS
                 if (mSession != null && mMetadataBuilder != null) {
-                    mSession.setMetadata(mMetadataBuilder.build());
+                    mMediaMetadata = mMetadataBuilder.build();
+                    mSession.setMetadata(mMediaMetadata);
                 }
                 mApplied = true;
             }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 3453a67..34e57bc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -506,7 +506,14 @@
     }
 
     private void fullyPopulateCaches(final int userHandle) {
-        DatabaseHelper dbHelper = mOpenHelpers.get(userHandle);
+        DatabaseHelper dbHelper;
+        synchronized (this) {
+            dbHelper = mOpenHelpers.get(userHandle);
+        }
+        if (dbHelper == null) {
+            // User is gone.
+            return;
+        }
         // Only populate the globals cache once, for the owning user
         if (userHandle == UserHandle.USER_OWNER) {
             fullyPopulateCache(dbHelper, TABLE_GLOBAL, sGlobalCache);
@@ -611,10 +618,15 @@
 
         long oldId = Binder.clearCallingIdentity();
         try {
-            DatabaseHelper dbHelper = mOpenHelpers.get(callingUser);
+            DatabaseHelper dbHelper;
+            synchronized (this) {
+                dbHelper = mOpenHelpers.get(callingUser);
+            }
             if (null == dbHelper) {
                 establishDbTracking(callingUser);
-                dbHelper = mOpenHelpers.get(callingUser);
+                synchronized (this) {
+                    dbHelper = mOpenHelpers.get(callingUser);
+                }
             }
             return dbHelper;
         } finally {
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index dfcdaa0..b0b2886 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -23,6 +23,7 @@
 import com.android.internal.R;
 import com.android.internal.widget.LockPatternUtils;
 
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -370,6 +371,11 @@
                         new DialogInterface.OnClickListener() {
                             @Override
                             public void onClick(DialogInterface dialog, int which) {
+                                // don't actually trigger the bugreport if we are running stability
+                                // tests via monkey
+                                if (ActivityManager.isUserAMonkey()) {
+                                    return;
+                                }
                                 // Add a little delay before executing, to give the
                                 // dialog a chance to go away before it takes a
                                 // screenshot.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7d4156f..aff64e3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -764,6 +764,35 @@
                 .getAccessibilityFocusClickPointInScreenNotLocked(outPoint);
     }
 
+    /**
+     * Gets the bounds of the active window.
+     *
+     * @param outBounds The output to which to write the bounds.
+     */
+    boolean getActiveWindowBounds(Rect outBounds) {
+        // TODO: This should be refactored to work with accessibility
+        // focus in multiple windows.
+        IBinder token;
+        synchronized (mLock) {
+            final int windowId = mSecurityPolicy.mActiveWindowId;
+            token = mGlobalWindowTokens.get(windowId);
+            if (token == null) {
+                token = getCurrentUserStateLocked().mWindowTokens.get(windowId);
+            }
+        }
+        mWindowManagerService.getWindowFrame(token, outBounds);
+        if (!outBounds.isEmpty()) {
+            return true;
+        }
+        return false;
+    }
+
+    boolean accessibilityFocusOnlyInActiveWindow() {
+        synchronized (mLock) {
+            return mWindowsForAccessibilityCallback == null;
+        }
+    }
+
     int getActiveWindowId() {
         return mSecurityPolicy.getActiveWindowId();
     }
@@ -1581,10 +1610,15 @@
         if (userState.mUserId != UserHandle.USER_OWNER) {
             return;
         }
-        if (hasRunningServicesLocked(userState) && LockPatternUtils.isDeviceEncrypted()) {
-            // If there are running accessibility services we do not have encryption as
-            // the user needs the accessibility layer to be running to authenticate.
-            mLockPatternUtils.clearEncryptionPassword();
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (hasRunningServicesLocked(userState) && LockPatternUtils.isDeviceEncrypted()) {
+                // If there are running accessibility services we do not have encryption as
+                // the user needs the accessibility layer to be running to authenticate.
+                mLockPatternUtils.clearEncryptionPassword();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
     }
 
@@ -3207,6 +3241,13 @@
                     point.y = (int) (point.y * (1 / spec.scale));
                 }
 
+                // Make sure the point is within the window.
+                Rect windowBounds = mTempRect;
+                getActiveWindowBounds(windowBounds);
+                if (!windowBounds.contains(point.x, point.y)) {
+                    return false;
+                }
+
                 // Make sure the point is within the screen.
                 Point screenSize = mTempPoint;
                 mDefaultDisplay.getRealSize(screenSize);
@@ -3566,6 +3607,9 @@
         }
 
         private void notifyWindowsChanged() {
+            if (mWindowsForAccessibilityCallback == null) {
+                return;
+            }
             final long identity = Binder.clearCallingIdentity();
             try {
                 // Let the client know the windows changed.
@@ -3650,6 +3694,10 @@
         }
 
         private boolean isRetrievalAllowingWindow(int windowId) {
+            // The system gets to interact with any window it wants.
+            if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+                return true;
+            }
             if (windowId == mActiveWindowId) {
                 return true;
             }
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 94befad..b9ed89b 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -205,6 +205,9 @@
     // The long pressing pointer Y if coordinate remapping is needed.
     private int mLongPressingPointerDeltaY;
 
+    // The id of the last touch explored window.
+    private int mLastTouchedWindowId;
+
     // Whether touch exploration is in progress.
     private boolean mTouchExplorationInProgress;
 
@@ -365,6 +368,11 @@
                     mInjectedPointerTracker.mLastInjectedHoverEventForClick.recycle();
                     mInjectedPointerTracker.mLastInjectedHoverEventForClick = null;
                 }
+                mLastTouchedWindowId = -1;
+            } break;
+            case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
+            case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
+                mLastTouchedWindowId = event.getWindowId();
             } break;
         }
         if (mNext != null) {
@@ -1208,6 +1216,24 @@
                 MAX_DRAGGING_ANGLE_COS);
     }
 
+    private boolean computeClickLocation(Point outLocation) {
+        MotionEvent lastExploreEvent = mInjectedPointerTracker.getLastInjectedHoverEventForClick();
+        if (lastExploreEvent != null) {
+            final int lastExplorePointerIndex = lastExploreEvent.getActionIndex();
+            outLocation.x = (int) lastExploreEvent.getX(lastExplorePointerIndex);
+            outLocation.y = (int) lastExploreEvent.getY(lastExplorePointerIndex);
+            if (!mAms.accessibilityFocusOnlyInActiveWindow()
+                    || mLastTouchedWindowId == mAms.getActiveWindowId()) {
+                mAms.getAccessibilityFocusClickPointInScreen(outLocation);
+            }
+            return true;
+        }
+        if (mAms.getAccessibilityFocusClickPointInScreen(outLocation)) {
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Gets the symbolic name of a state.
      *
@@ -1284,10 +1310,12 @@
                 return;
             }
 
+            int clickLocationX;
+            int clickLocationY;
+
             final int pointerId = mEvent.getPointerId(mEvent.getActionIndex());
             final int pointerIndex = mEvent.findPointerIndex(pointerId);
 
-
             Point clickLocation = mTempPoint;
             if (!computeClickLocation(clickLocation)) {
                 return;
@@ -1311,27 +1339,6 @@
         }
     }
 
-    private boolean computeClickLocation(Point outPoint) {
-        // Try to click on the accessiblity focused view and if that
-        // fails try the last touch explored location, if such.
-        Point point = mTempPoint;
-        if (mAms.getAccessibilityFocusClickPointInScreen(point)) {
-            outPoint.x = point.x;
-            outPoint.y = point.y;
-            return true;
-        } else {
-            MotionEvent lastExploreEvent =
-                    mInjectedPointerTracker.getLastInjectedHoverEventForClick();
-            if (lastExploreEvent != null) {
-                final int lastExplorePointerIndex = lastExploreEvent.getActionIndex();
-                outPoint.x = (int) lastExploreEvent.getX(lastExplorePointerIndex);
-                outPoint.y = (int) lastExploreEvent.getY(lastExplorePointerIndex);
-                return true;
-            }
-        }
-        return false;
-    }
-
     /**
      * Class for delayed sending of hover enter and move events.
      */
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 47396bd..8b524dd 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -58,6 +58,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Locale;
 import java.util.TimeZone;
@@ -141,6 +142,25 @@
     private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
             new SparseArray<>();
 
+    // Alarm delivery ordering bookkeeping
+    static final int PRIO_TICK = 0;
+    static final int PRIO_WAKEUP = 1;
+    static final int PRIO_NORMAL = 2;
+
+    class PriorityClass {
+        int seq;
+        int priority;
+
+        PriorityClass() {
+            seq = mCurrentSeq - 1;
+            priority = PRIO_NORMAL;
+        }
+    }
+
+    final HashMap<String, PriorityClass> mPriorities =
+            new HashMap<String, PriorityClass>();
+    int mCurrentSeq = 0;
+
     class WakeupEvent {
         public long when;
         public int uid;
@@ -356,22 +376,62 @@
     final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
         @Override
         public int compare(Alarm lhs, Alarm rhs) {
-            if ((!lhs.operation.getCreatorPackage().equals(rhs.operation.getCreatorPackage()))
-                    && lhs.wakeup != rhs.wakeup) {
-                // We want to put wakeup alarms before non-wakeup alarms, since they are
-                // the things that drive most activity in the alarm manager.  However,
-                // alarms from the same package should always be ordered strictly by time.
-                return lhs.wakeup ? -1 : 1;
+            // priority class trumps everything.  TICK < WAKEUP < NORMAL
+            if (lhs.priorityClass.priority < rhs.priorityClass.priority) {
+                return -1;
+            } else if (lhs.priorityClass.priority > rhs.priorityClass.priority) {
+                return 1;
             }
+
+            // within each class, sort by nominal delivery time
             if (lhs.whenElapsed < rhs.whenElapsed) {
                 return -1;
             } else if (lhs.whenElapsed > rhs.whenElapsed) {
                 return 1;
             }
+
+            // same priority class + same target delivery time
             return 0;
         }
     };
 
+    void calculateDeliveryPriorities(ArrayList<Alarm> alarms) {
+        final int N = alarms.size();
+        for (int i = 0; i < N; i++) {
+            Alarm a = alarms.get(i);
+
+            final int alarmPrio;
+            if (Intent.ACTION_TIME_TICK.equals(a.operation.getIntent().getAction())) {
+                alarmPrio = PRIO_TICK;
+            } else if (a.wakeup) {
+                alarmPrio = PRIO_WAKEUP;
+            } else {
+                alarmPrio = PRIO_NORMAL;
+            }
+
+            PriorityClass packagePrio = a.priorityClass;
+            if (packagePrio == null) packagePrio = mPriorities.get(a.operation.getCreatorPackage());
+            if (packagePrio == null) {
+                packagePrio = a.priorityClass = new PriorityClass(); // lowest prio & stale sequence
+                mPriorities.put(a.operation.getCreatorPackage(), packagePrio);
+            }
+            a.priorityClass = packagePrio;
+
+            if (packagePrio.seq != mCurrentSeq) {
+                // first alarm we've seen in the current delivery generation from this package
+                packagePrio.priority = alarmPrio;
+                packagePrio.seq = mCurrentSeq;
+            } else {
+                // Multiple alarms from this package being delivered in this generation;
+                // bump the package's delivery class if it's warranted.
+                // TICK < WAKEUP < NORMAL
+                if (alarmPrio < packagePrio.priority) {
+                    packagePrio.priority = alarmPrio;
+                }
+            }
+        }
+    }
+
     // minimum recurrence period or alarm futurity for us to be able to fuzz it
     static final long MIN_FUZZABLE_INTERVAL = 10000;
     static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
@@ -1381,6 +1441,10 @@
             }
         }
 
+        // This is a new alarm delivery set; bump the sequence number to indicate that
+        // all apps' alarm delivery classes should be recalculated.
+        mCurrentSeq++;
+        calculateDeliveryPriorities(triggerList);
         Collections.sort(triggerList, mAlarmDispatchComparator);
 
         if (localLOGV) {
@@ -1423,6 +1487,7 @@
         public long repeatInterval;
         public final AlarmManager.AlarmClockInfo alarmClock;
         public final int userId;
+        public PriorityClass priorityClass;
 
         public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
                 long _interval, PendingIntent _op, WorkSource _ws,
@@ -1676,6 +1741,7 @@
                         rescheduleKernelAlarmsLocked();
                         updateNextAlarmClockLocked();
                         if (mPendingNonWakeupAlarms.size() > 0) {
+                            calculateDeliveryPriorities(mPendingNonWakeupAlarms);
                             triggerList.addAll(mPendingNonWakeupAlarms);
                             Collections.sort(triggerList, mAlarmDispatchComparator);
                             final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
@@ -1889,6 +1955,7 @@
                 if (pkgList != null && (pkgList.length > 0)) {
                     for (String pkg : pkgList) {
                         removeLocked(pkg);
+                        mPriorities.remove(pkg);
                         for (int i=mBroadcastStats.size()-1; i>=0; i--) {
                             ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
                             if (uidStats.remove(pkg) != null) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3dab17f..b29cdf4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4231,6 +4231,7 @@
             NetworkInfo result = new NetworkInfo(
                     networkType, 0, ConnectivityManager.getNetworkTypeName(networkType), "");
             result.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
+            result.setIsAvailable(true);
             return result;
         }
     }
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 5aaeb6a..99a1254 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -134,6 +134,8 @@
 # + check activity_launch_time for Home app
 # Value of "unknown sources" setting at app install time
 3110 unknown_sources_enabled (value|1)
+# Package Manager critical info
+3120 pm_critical_info (msg|3)
 
 
 # ---------------------------
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 50cb5fc..f912fd4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1379,7 +1379,7 @@
 
             // Set flag to monitor and not change apk file paths when
             // scanning install directories.
-            int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
+            final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
 
             final HashSet<String> alreadyDexOpted = new HashSet<String>();
 
@@ -1523,13 +1523,13 @@
                     scanFlags | SCAN_NO_DEX, 0);
 
             // Collected privileged system packages.
-            File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
+            final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
             scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR
                     | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
 
             // Collect ordinary system packages.
-            File systemAppDir = new File(Environment.getRootDirectory(), "app");
+            final File systemAppDir = new File(Environment.getRootDirectory(), "app");
             scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
 
@@ -1544,7 +1544,7 @@
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
 
             // Collect all OEM packages.
-            File oemAppDir = new File(Environment.getOemDirectory(), "app");
+            final File oemAppDir = new File(Environment.getOemDirectory(), "app");
             scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
 
@@ -1579,8 +1579,11 @@
                          * application can be scanned.
                          */
                         if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
-                            Slog.i(TAG, "Expecting better updatd system app for " + ps.name
-                                    + "; removing system app");
+                            logCriticalInfo(Log.WARN, "Expecting better updated system app for "
+                                    + ps.name + "; removing system app.  Last known codePath="
+                                    + ps.codePathString + ", installStatus=" + ps.installStatus
+                                    + ", versionCode=" + ps.versionCode + "; scanned versionCode="
+                                    + scannedPkg.mVersionCode);
                             removePackageLI(ps, true);
                         }
 
@@ -1589,9 +1592,8 @@
 
                     if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
                         psit.remove();
-                        String msg = "System package " + ps.name
-                                + " no longer exists; wiping its data";
-                        reportSettingsProblem(Log.WARN, msg);
+                        logCriticalInfo(Log.WARN, "System package " + ps.name
+                                + " no longer exists; wiping its data");
                         removeDataDirsLI(ps.name);
                     } else {
                         final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
@@ -1648,7 +1650,7 @@
                         PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                         deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
                     }
-                    reportSettingsProblem(Log.WARN, msg);
+                    logCriticalInfo(Log.WARN, msg);
                 }
             }
 
@@ -1792,7 +1794,8 @@
     }
 
     void cleanupInstallFailedPackage(PackageSetting ps) {
-        Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
+        logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + ps.name);
+
         removeDataDirsLI(ps.name);
         if (ps.codePath != null) {
             if (ps.codePath.isDirectory()) {
@@ -4029,7 +4032,7 @@
                 // Delete invalid userdata apps
                 if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                         e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
-                    Slog.w(TAG, "Deleting invalid package at " + file);
+                    logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
                     if (file.isDirectory()) {
                         FileUtils.deleteContents(file);
                     }
@@ -4045,8 +4048,14 @@
         File fname = new File(systemDir, "uiderrors.txt");
         return fname;
     }
-    
+
     static void reportSettingsProblem(int priority, String msg) {
+        logCriticalInfo(priority, msg);
+    }
+
+    static void logCriticalInfo(int priority, String msg) {
+        Slog.println(priority, TAG, msg);
+        EventLogTags.writePmCriticalInfo(msg);
         try {
             File fname = getSettingsProblemFile();
             FileOutputStream out = new FileOutputStream(fname, true);
@@ -4061,7 +4070,6 @@
                     -1, -1);
         } catch (java.io.IOException e) {
         }
-        Slog.println(priority, TAG, msg);
     }
 
     private void collectCertificatesLI(PackageParser pp, PackageSetting ps,
@@ -4155,7 +4163,7 @@
                 if (pkg.mVersionCode < ps.versionCode) {
                     // The system package has been updated and the code path does not match
                     // Ignore entry. Skip it.
-                    Log.i(TAG, "Package " + ps.name + " at " + scanFile
+                    logCriticalInfo(Log.INFO, "Package " + ps.name + " at " + scanFile
                             + " ignored: updated version " + ps.versionCode
                             + " better than this " + pkg.mVersionCode);
                     if (!updatedPkg.codePath.equals(scanFile)) {
@@ -4185,7 +4193,8 @@
                         // Just remove the loaded entries from package lists.
                         mPackages.remove(ps.name);
                     }
-                    Slog.w(TAG, "Package " + ps.name + " at " + scanFile
+
+                    logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
                             + "reverting from " + ps.codePathString
                             + ": new version " + pkg.mVersionCode
                             + " better than installed " + ps.versionCode);
@@ -4232,7 +4241,8 @@
              */
             if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
                     != PackageManager.SIGNATURE_MATCH) {
-                if (DEBUG_INSTALL) Slog.d(TAG, "Signature mismatch!");
+                logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
+                        + " signatures don't match existing userdata copy; removing");
                 deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false);
                 ps = null;
             } else {
@@ -4243,6 +4253,9 @@
                  */
                 if (pkg.mVersionCode < ps.versionCode) {
                     shouldHideSystemApp = true;
+                    logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile
+                            + " but new version " + pkg.mVersionCode + " better than installed "
+                            + ps.versionCode + "; hiding system");
                 } else {
                     /*
                      * The newly found system app is a newer version that the
@@ -4250,9 +4263,9 @@
                      * already-installed application and replace it with our own
                      * while keeping the application data.
                      */
-                    Slog.w(TAG, "Package " + ps.name + " at " + scanFile + "reverting from "
-                            + ps.codePathString + ": new version " + pkg.mVersionCode
-                            + " better than installed " + ps.versionCode);
+                    logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
+                            + " reverting from " + ps.codePathString + ": new version "
+                            + pkg.mVersionCode + " better than installed " + ps.versionCode);
                     InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
                             ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
                             getAppDexInstructionSets(ps));
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 77d3beb..c003fa6 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -4357,13 +4357,15 @@
                         continue;
                     }
 
-                    entriesToAdd[i].value->getPos()
-                            .printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
-                                    SDK_L,
-                                    String8(p->getName()).string(),
-                                    String8(t->getName()).string(),
-                                    String8(entriesToAdd[i].value->getName()).string(),
-                                    entriesToAdd[i].key.toString().string());
+                    if (bundle->getVerbose()) {
+                        entriesToAdd[i].value->getPos()
+                                .printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
+                                        SDK_L,
+                                        String8(p->getName()).string(),
+                                        String8(t->getName()).string(),
+                                        String8(entriesToAdd[i].value->getName()).string(),
+                                        entriesToAdd[i].key.toString().string());
+                    }
 
                     sp<Entry> newEntry = t->getEntry(c->getName(),
                             entriesToAdd[i].value->getPos(),
@@ -4437,13 +4439,15 @@
         resPath.convertToResPath();
 
         // Add a resource table entry.
-        SourcePos(target->getSourceFile(), -1).printf(
-                "using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
-                SDK_L,
-                mAssets->getPackage().string(),
-                newFile->getResourceType().string(),
-                String8(resourceName).string(),
-                newConfig.toString().string());
+        if (bundle->getVerbose()) {
+            SourcePos(target->getSourceFile(), -1).printf(
+                    "using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
+                    SDK_L,
+                    mAssets->getPackage().string(),
+                    newFile->getResourceType().string(),
+                    String8(resourceName).string(),
+                    newConfig.toString().string());
+        }
 
         addEntry(SourcePos(),
                 String16(mAssets->getPackage()),
@@ -4466,12 +4470,14 @@
         sp<XMLNode> node = attrsToRemove[i].key;
         size_t attrIndex = attrsToRemove[i].value;
         const XMLNode::attribute_entry& ae = node->getAttributes()[attrIndex];
-        SourcePos(node->getFilename(), node->getStartLineNumber()).printf(
-                "removing attribute %s%s%s from <%s>",
-                String8(ae.ns).string(),
-                (ae.ns.size() == 0 ? "" : ":"),
-                String8(ae.name).string(),
-                String8(node->getElementName()).string());
+        if (bundle->getVerbose()) {
+            SourcePos(node->getFilename(), node->getStartLineNumber()).printf(
+                    "removing attribute %s%s%s from <%s>",
+                    String8(ae.ns).string(),
+                    (ae.ns.size() == 0 ? "" : ":"),
+                    String8(ae.name).string(),
+                    String8(node->getElementName()).string());
+        }
         node->removeAttribute(attrIndex);
     }
 
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 4a6a434..28a109d 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -159,7 +159,7 @@
             return null;
         }
         // As unfortunate as it is, it's possible to use enums with all attribute formats,
-        // not just integers/enums. So, we need to search the enums always. In case,
+        // not just integers/enums. So, we need to search the enums always. In case
         // enums are used, the returned value is an integer.
         Integer v = resolveEnumAttribute(index);
         return v == null ? mResourceData[index].getValue() : String.valueOf((int) v);
@@ -197,7 +197,7 @@
             }
         } catch (NumberFormatException e) {
             Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
-                    String.format("\"%s\" in attribute \"%2$s\" is not a valid integer",
+                    String.format("\"%1$s\" in attribute \"%2$s\" is not a valid integer",
                             s, mNames[index]),
                     null);
             return defValue;
@@ -221,7 +221,7 @@
             }
         } catch (NumberFormatException e) {
             Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
-                    String.format("\"%s\" in attribute \"%2$s\" cannot be converted to float.",
+                    String.format("\"%1$s\" in attribute \"%2$s\" cannot be converted to float.",
                             s, mNames[index]),
                     null);
         }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 5514798..53756d2 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1072,7 +1072,7 @@
                     sbuf.append(",ipfail=");
                     sbuf.append(result.numIpConfigFailures);
                 }
-                sbuf.append(result.autoJoinStatus).append("} ");
+                sbuf.append(",").append(result.autoJoinStatus).append("} ");
             }
             sbuf.append('\n');
         }