Merge "Notify WifiManager of interface state changes" into oc-dev
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 0ad790b..3353530 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -64,6 +64,7 @@
 
     ComponentName mActivityComponent;
     private boolean mIsHomeActivity;
+    private int mFlags;
 
     final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
 
@@ -186,6 +187,7 @@
             mSanitizeOnWrite = as.mSanitizeOnWrite;
             mWriteStructure = as.waitForReady();
             ComponentName.writeToParcel(as.mActivityComponent, out);
+            out.writeInt(as.mFlags);
             out.writeLong(as.mAcquisitionStartTime);
             out.writeLong(as.mAcquisitionEndTime);
             mNumWindows = as.mWindowNodes.size();
@@ -340,6 +342,7 @@
         void go() {
             fetchData();
             mActivityComponent = ComponentName.readFromParcel(mCurParcel);
+            mFlags = mCurParcel.readInt();
             mAcquisitionStartTime = mCurParcel.readLong();
             mAcquisitionEndTime = mCurParcel.readLong();
             final int N = mCurParcel.readInt();
@@ -1876,6 +1879,7 @@
     public AssistStructure(Activity activity, boolean forAutoFill, int flags) {
         mHaveData = true;
         mActivityComponent = activity.getComponentName();
+        mFlags = flags;
         ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
                 activity.getActivityToken());
         for (int i=0; i<views.size(); i++) {
@@ -1887,6 +1891,7 @@
     public AssistStructure() {
         mHaveData = true;
         mActivityComponent = null;
+        mFlags = 0;
     }
 
     /** @hide */
@@ -1913,6 +1918,7 @@
         }
         Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
         Log.i(TAG, "Sanitize on write: " + mSanitizeOnWrite);
+        Log.i(TAG, "Flags: " + mFlags);
         final int N = getWindowNodeCount();
         for (int i=0; i<N; i++) {
             WindowNode node = getWindowNodeAt(i);
@@ -2025,6 +2031,11 @@
         return mActivityComponent;
     }
 
+    /** @hide */
+    public int getFlags() {
+        return mFlags;
+    }
+
     /**
      * Returns whether the activity associated with this AssistStructure was the home activity
      * (Launcher) at the time the assist data was acquired.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e4db0f0..a05f11b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -547,6 +547,8 @@
      */
     public interface Callback {
         boolean hasFeature(String feature);
+        String[] getOverlayPaths(String targetPackageName, String targetPath);
+        String[] getOverlayApks(String targetPackageName);
     }
 
     /**
@@ -563,6 +565,14 @@
         @Override public boolean hasFeature(String feature) {
             return mPm.hasSystemFeature(feature);
         }
+
+        @Override public String[] getOverlayPaths(String targetPackageName, String targetPath) {
+            return null;
+        }
+
+        @Override public String[] getOverlayApks(String targetPackageName) {
+            return null;
+        }
     }
 
     /**
@@ -1054,7 +1064,19 @@
 
         try {
             final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
-            return fromCacheEntry(bytes);
+            Package p = fromCacheEntry(bytes);
+            if (mCallback != null) {
+                String[] overlayApks = mCallback.getOverlayApks(p.packageName);
+                if (overlayApks != null && overlayApks.length > 0) {
+                    for (String overlayApk : overlayApks) {
+                        // If a static RRO is updated, return null.
+                        if (!isCacheUpToDate(new File(overlayApk), cacheFile)) {
+                            return null;
+                        }
+                    }
+                }
+            }
+            return p;
         } catch (Exception e) {
             Slog.w(TAG, "Error reading package cache: ", e);
 
@@ -1238,7 +1260,7 @@
             parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
 
             final String[] outError = new String[1];
-            final Package pkg = parseBaseApk(res, parser, flags, outError);
+            final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
             if (pkg == null) {
                 throw new PackageParserException(mParseError,
                         apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
@@ -1938,6 +1960,7 @@
      * need to consider whether they should be supported by split APKs and child
      * packages.
      *
+     * @param apkPath The package apk file path
      * @param res The resources from which to resolve values
      * @param parser The manifest parser
      * @param flags Flags how to parse
@@ -1947,7 +1970,7 @@
      * @throws XmlPullParserException
      * @throws IOException
      */
-    private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
+    private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
             String[] outError) throws XmlPullParserException, IOException {
         final String splitName;
         final String pkgName;
@@ -1967,6 +1990,15 @@
             return null;
         }
 
+        if (mCallback != null) {
+            String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath);
+            if (overlayPaths != null && overlayPaths.length > 0) {
+                for (String overlayPath : overlayPaths) {
+                    res.getAssets().addOverlayPath(overlayPath);
+                }
+            }
+        }
+
         final Package pkg = new Package(pkgName);
 
         TypedArray sa = res.obtainAttributes(parser,
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index 8a28c45..e482c78 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -74,11 +74,9 @@
 
     @Override
     public String toString() {
-        if (!DEBUG) {
-            return super.toString();
-        } else {
-            return "FillContext [mRequestId=" + mRequestId + "]";
-        }
+        if (!DEBUG)  return super.toString();
+
+        return "FillContext [reqId=" + mRequestId + "]";
     }
 
     @Override
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 2c8e43e..b1c9d69 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -107,11 +107,10 @@
     @Deprecated
     public static final int FLAG_MANUAL_REQUEST = 0x1;
 
-    // TODO(b/37563972): start from 0x1 once FLAG_MANUAL_REQUEST is gone
-    /** @hide */ public static final int FLAG_START_SESSION = 0x80000000;
-    /** @hide */ public static final int FLAG_VIEW_ENTERED =  0x40000000;
-    /** @hide */ public static final int FLAG_VIEW_EXITED =   0x20000000;
-    /** @hide */ public static final int FLAG_VALUE_CHANGED = 0x10000000;
+    /** @hide */ public static final int ACTION_START_SESSION = 1;
+    /** @hide */ public static final int ACTION_VIEW_ENTERED =  2;
+    /** @hide */ public static final int ACTION_VIEW_EXITED = 3;
+    /** @hide */ public static final int ACTION_VALUE_CHANGED = 4;
 
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
@@ -404,7 +403,7 @@
                     startSessionLocked(id, view.getWindowToken(), null, value, flags);
                 } else {
                     // Update focus on existing session.
-                    updateSessionLocked(id, null, value, FLAG_VIEW_ENTERED);
+                    updateSessionLocked(id, null, value, ACTION_VIEW_ENTERED, flags);
                 }
             }
         }
@@ -430,7 +429,7 @@
                 final AutofillId id = getAutofillId(view);
 
                 // Update focus on existing session.
-                updateSessionLocked(id, null, null, FLAG_VIEW_EXITED);
+                updateSessionLocked(id, null, null, ACTION_VIEW_EXITED, 0);
             }
         }
     }
@@ -482,7 +481,7 @@
                     startSessionLocked(id, view.getWindowToken(), bounds, null, flags);
                 } else {
                     // Update focus on existing session.
-                    updateSessionLocked(id, bounds, null, FLAG_VIEW_ENTERED);
+                    updateSessionLocked(id, bounds, null, ACTION_VIEW_ENTERED, flags);
                 }
             }
         }
@@ -510,7 +509,7 @@
                 final AutofillId id = getAutofillId(view, childId);
 
                 // Update focus on existing session.
-                updateSessionLocked(id, null, null, FLAG_VIEW_EXITED);
+                updateSessionLocked(id, null, null, ACTION_VIEW_EXITED, 0);
             }
         }
     }
@@ -562,7 +561,7 @@
                 value = view.getAutofillValue();
             }
 
-            updateSessionLocked(id, null, value, FLAG_VALUE_CHANGED);
+            updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, 0);
         }
     }
 
@@ -583,7 +582,7 @@
             }
 
             final AutofillId id = getAutofillId(view, childId);
-            updateSessionLocked(id, null, value, FLAG_VALUE_CHANGED);
+            updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, 0);
         }
     }
 
@@ -726,7 +725,7 @@
             mSessionId = mService.startSession(mContext.getActivityToken(), windowToken,
                     mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
                     mCallback != null, flags, mContext.getOpPackageName());
-            AutofillClient client = getClientLocked();
+            final AutofillClient client = getClientLocked();
             if (client != null) {
                 client.autofillCallbackResetableStateAvailable();
             }
@@ -769,16 +768,18 @@
         mTrackedViews = null;
     }
 
-    private void updateSessionLocked(AutofillId id, Rect bounds, AutofillValue value, int flags) {
+    private void updateSessionLocked(AutofillId id, Rect bounds, AutofillValue value, int action,
+            int flags) {
         if (DEBUG) {
-            if (VERBOSE || (flags & FLAG_VIEW_EXITED) != 0) {
+            if (VERBOSE || action != ACTION_VIEW_EXITED) {
                 Log.d(TAG, "updateSessionLocked(): id=" + id + ", bounds=" + bounds
-                        + ", value=" + value + ", flags=" + flags);
+                        + ", value=" + value + ", action=" + action + ", flags=" + flags);
             }
         }
 
         try {
-            mService.updateSession(mSessionId, id, bounds, value, flags, mContext.getUserId());
+            mService.updateSession(mSessionId, id, bounds, value, action, flags,
+                    mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 9417bd0..6e121ac 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -38,7 +38,7 @@
     boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback);
     void setWindow(int sessionId, in IBinder windowToken);
     void updateSession(int sessionId, in AutofillId id, in Rect bounds,
-            in AutofillValue value, int flags, int userId);
+            in AutofillValue value, int action, int flags, int userId);
     void finishSession(int sessionId, int userId);
     void cancelSession(int sessionId, int userId);
     void setAuthenticationResult(in Bundle data, int sessionId, int userId);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 8a20c85..8d65ded 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -509,12 +509,12 @@
 
         @Override
         public void updateSession(int sessionId, AutofillId id, Rect bounds,
-                AutofillValue value, int flags, int userId) {
+                AutofillValue value, int action, int flags, int userId) {
             synchronized (mLock) {
                 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
                 if (service != null) {
                     service.updateSessionLocked(sessionId, getCallingUid(), id, bounds, value,
-                            flags);
+                            action, flags);
                 }
             }
         }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 44a296e..500ddb2 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -16,7 +16,7 @@
 
 package com.android.server.autofill;
 
-import static android.view.autofill.AutofillManager.FLAG_START_SESSION;
+import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
 import static android.view.autofill.AutofillManager.NO_SESSION;
 
 import static com.android.server.autofill.Helper.DEBUG;
@@ -271,14 +271,14 @@
         }
 
         final String historyItem =
-                "id=" + newSession.getId() + " uid=" + uid + " s=" + mInfo.getServiceInfo().packageName
+                "id=" + newSession.id + " uid=" + uid + " s=" + mInfo.getServiceInfo().packageName
                         + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds + " hc=" +
                         hasCallback + " f=" + flags;
         mRequestsHistory.log(historyItem);
 
-        newSession.updateLocked(autofillId, virtualBounds, value, FLAG_START_SESSION);
+        newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags);
 
-        return newSession.getId();
+        return newSession.id;
     }
 
     void finishSessionLocked(int sessionId, int uid) {
@@ -350,9 +350,9 @@
         } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0);
 
         final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
-                sessionId, uid, activityToken, windowToken, appCallbackToken, hasCallback, flags,
+                sessionId, uid, activityToken, windowToken, appCallbackToken, hasCallback,
                 mInfo.getServiceInfo().getComponentName(), packageName);
-        mSessions.put(newSession.getId(), newSession);
+        mSessions.put(newSession.id, newSession);
 
         return newSession;
     }
@@ -396,7 +396,7 @@
     }
 
     void updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
-            AutofillValue value, int flags) {
+            AutofillValue value, int action, int flags) {
         final Session session = mSessions.get(sessionId);
         if (session == null || session.uid != uid) {
             if (VERBOSE) {
@@ -406,7 +406,7 @@
             return;
         }
 
-        session.updateLocked(autofillId, virtualBounds, value, flags);
+        session.updateLocked(autofillId, virtualBounds, value, action, flags);
     }
 
     void removeSessionLocked(int sessionId) {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 2aeb07e..f6831b2 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -89,7 +89,7 @@
     private PendingRequest mPendingRequest;
 
     public interface FillServiceCallbacks {
-        void onFillRequestSuccess(@Nullable FillResponse response, int serviceUid,
+        void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response, int serviceUid,
                 @NonNull String servicePackageName);
         void onFillRequestFailure(@Nullable CharSequence message,
                 @NonNull String servicePackageName);
@@ -281,10 +281,10 @@
     }
 
     private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest,
-            int callingUid, FillResponse response) {
+            int callingUid, int requestFlags, FillResponse response) {
         mHandler.getHandler().post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onFillRequestSuccess(response, callingUid,
+                mCallbacks.onFillRequestSuccess(requestFlags, response, callingUid,
                         mComponentName.getPackageName());
             }
         });
@@ -452,8 +452,8 @@
                 public void onSuccess(FillResponse response) {
                     RemoteFillService remoteService = mWeakService.get();
                     if (remoteService != null) {
-                        remoteService.dispatchOnFillRequestSuccess(
-                                PendingFillRequest.this, getCallingUid(), response);
+                        remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
+                                getCallingUid(), request.getFlags(), response);
                     }
                 }
 
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5a32274..eb95684 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -20,10 +20,10 @@
 import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
 import static android.service.voice.VoiceInteractionSession.KEY_RECEIVER_EXTRAS;
 import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
-import static android.view.autofill.AutofillManager.FLAG_START_SESSION;
-import static android.view.autofill.AutofillManager.FLAG_VALUE_CHANGED;
-import static android.view.autofill.AutofillManager.FLAG_VIEW_ENTERED;
-import static android.view.autofill.AutofillManager.FLAG_VIEW_EXITED;
+import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
+import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED;
+import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED;
+import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
 
 import static com.android.server.autofill.Helper.DEBUG;
 import static com.android.server.autofill.Helper.VERBOSE;
@@ -108,7 +108,7 @@
     private static AtomicInteger sIdCounter = new AtomicInteger();
 
     /** Id of the session */
-    private final int mId;
+    public final int id;
 
     /** uid the session is for */
     public final int uid;
@@ -174,23 +174,14 @@
     private boolean mDestroyed;
 
     /**
-     * Flags used to start the session.
-     */
-    private final int mFlags;
-
-    /**
      * Receiver of assist data from the app's {@link Activity}.
      */
     private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
         @Override
         public void send(int resultCode, Bundle resultData) throws RemoteException {
-            if (VERBOSE) {
-                Slog.v(TAG, "resultCode on mAssistReceiver: " + resultCode);
-            }
-
             final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
             if (structure == null) {
-                Slog.wtf(TAG, "no assist structure for id " + resultCode);
+                Slog.wtf(TAG, "no assist structure");
                 return;
             }
 
@@ -218,6 +209,9 @@
                 // Sanitize structure before it's sent to service.
                 structure.sanitizeForParceling(true);
 
+                // Flags used to start the session.
+                final int flags = structure.getFlags();
+
                 if (mContexts == null) {
                     mContexts = new ArrayList<>(1);
                 }
@@ -230,7 +224,7 @@
                     fillStructureWithAllowedValues(mContexts.get(i).getStructure());
                 }
 
-                request = new FillRequest(requestId, mContexts, mClientState, mFlags);
+                request = new FillRequest(requestId, mContexts, mClientState, flags);
             }
 
             mRemoteFillService.onFillRequest(request);
@@ -295,7 +289,7 @@
     /**
      * Reads a new structure and then request a new fill response from the fill service.
      */
-    private void requestNewFillResponseLocked() {
+    private void requestNewFillResponseLocked(int flags) {
         int requestId;
 
         do {
@@ -303,7 +297,7 @@
         } while (requestId == INVALID_REQUEST_ID);
 
         if (DEBUG) {
-            Slog.d(TAG, "Requesting structure for requestId " + requestId);
+            Slog.d(TAG, "Requesting structure for requestId=" + requestId + ", flags=" + flags);
         }
 
         // If the focus changes very quickly before the first request is returned each focus change
@@ -319,7 +313,7 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 if (!ActivityManager.getService().requestAutofillData(mAssistReceiver,
-                        receiverExtras, mActivityToken, mFlags)) {
+                        receiverExtras, mActivityToken, flags)) {
                     Slog.w(TAG, "failed to request autofill data for " + mActivityToken);
                 }
             } finally {
@@ -334,8 +328,8 @@
             @NonNull Context context, @NonNull HandlerCaller handlerCaller, int userId,
             @NonNull Object lock, int sessionId, int uid, @NonNull IBinder activityToken,
             @Nullable IBinder windowToken, @NonNull IBinder client, boolean hasCallback,
-            int flags, @NonNull ComponentName componentName, @NonNull String packageName) {
-        mId = sessionId;
+            @NonNull ComponentName componentName, @NonNull String packageName) {
+        id = sessionId;
         this.uid = uid;
         mService = service;
         mLock = lock;
@@ -346,7 +340,6 @@
         mWindowToken = windowToken;
         mHasCallback = hasCallback;
         mPackageName = packageName;
-        mFlags = flags;
         mClient = IAutoFillManagerClient.Stub.asInterface(client);
 
         mMetricsLogger.action(MetricsEvent.AUTOFILL_SESSION_STARTED, mPackageName);
@@ -371,7 +364,7 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#switchWindow() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
             mWindowToken = newWindow;
@@ -388,7 +381,7 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#switchActivity() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
             mActivityToken = newActivity;
@@ -401,17 +394,17 @@
 
     // FillServiceCallbacks
     @Override
-    public void onFillRequestSuccess(@Nullable FillResponse response, int serviceUid,
-            @NonNull String servicePackageName) {
+    public void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
+            int serviceUid, @NonNull String servicePackageName) {
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
         }
         if (response == null) {
-            if ((mFlags & FLAG_MANUAL_REQUEST) != 0) {
+            if ((requestFlags & FLAG_MANUAL_REQUEST) != 0) {
                 getUiForShowing().showError(R.string.autofill_error_cannot_autofill);
             }
             // Nothing to be done, but need to notify client.
@@ -452,7 +445,7 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onFillRequestFailure() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
         }
@@ -472,7 +465,7 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onSaveRequestSuccess() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
         }
@@ -494,7 +487,7 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onSaveRequestFailure() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
         }
@@ -541,7 +534,7 @@
             synchronized (mLock) {
                 if (mDestroyed) {
                     Slog.w(TAG, "Call to Session#authenticate() rejected - session: "
-                            + mId + " destroyed");
+                            + id + " destroyed");
                     return;
                 }
             }
@@ -566,7 +559,7 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#fill() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
         }
@@ -579,12 +572,12 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#save() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
         }
         mHandlerCaller.getHandler()
-                .obtainMessage(AutofillManagerServiceImpl.MSG_SERVICE_SAVE, mId, 0)
+                .obtainMessage(AutofillManagerServiceImpl.MSG_SERVICE_SAVE, id, 0)
                 .sendToTarget();
     }
 
@@ -594,7 +587,7 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#cancelSave() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
         }
@@ -608,13 +601,13 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#requestShowFillUi() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
             if (id.equals(mCurrentViewId)) {
                 try {
                     final ViewState view = mViewStates.get(id);
-                    mClient.requestShowFillUi(mId, mWindowToken, id, width, height,
+                    mClient.requestShowFillUi(this.id, mWindowToken, id, width, height,
                             view.getVirtualBounds(), presenter);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Error requesting to show fill UI", e);
@@ -635,7 +628,7 @@
             // NOTE: We allow this call in a destroyed state as the UI is
             // asked to go away after we get destroyed, so let it do that.
             try {
-                mClient.requestHideFillUi(mId, mWindowToken, id);
+                mClient.requestHideFillUi(this.id, mWindowToken, id);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error requesting to hide fill UI", e);
             }
@@ -648,7 +641,7 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#startIntentSender() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
             removeSelfLocked();
@@ -667,7 +660,7 @@
     void setAuthenticationResultLocked(Bundle data) {
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#setAuthenticationResultLocked() rejected - session: "
-                    + mId + " destroyed");
+                    + id + " destroyed");
             return;
         }
         if ((mResponseWaitingAuth == null && mDatasetWaitingAuth == null) || data == null) {
@@ -707,7 +700,7 @@
     void setHasCallbackLocked(boolean hasIt) {
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#setHasCallbackLocked() rejected - session: "
-                    + mId + " destroyed");
+                    + id + " destroyed");
             return;
         }
         mHasCallback = hasIt;
@@ -721,7 +714,7 @@
     public boolean showSaveLocked() {
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#showSaveLocked() rejected - session: "
-                    + mId + " destroyed");
+                    + id + " destroyed");
             return false;
         }
         if (mContexts == null) {
@@ -845,7 +838,7 @@
     void callSaveLocked() {
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#callSaveLocked() rejected - session: "
-                    + mId + " destroyed");
+                    + id + " destroyed");
             return;
         }
 
@@ -932,7 +925,7 @@
                 final int numDatasets = datasets.size();
 
                 for (int dataSetNum = 0; dataSetNum < numDatasets; dataSetNum++) {
-                    final ArrayList fields = datasets.get(dataSetNum).getFieldIds();
+                    final ArrayList<AutofillId> fields = datasets.get(dataSetNum).getFieldIds();
 
                     if (fields != null && fields.contains(id)) {
                         return false;
@@ -944,96 +937,92 @@
         return true;
     }
 
-    void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int flags) {
+    void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int action,
+            int flags) {
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#updateLocked() rejected - session: "
-                    + mId + " destroyed");
+                    + id + " destroyed");
             return;
         }
         ViewState viewState = mViewStates.get(id);
 
         if (viewState == null) {
-            if ((flags & (FLAG_START_SESSION | FLAG_VALUE_CHANGED | FLAG_VIEW_ENTERED)) != 0) {
+            if (action == ACTION_START_SESSION || action == ACTION_VALUE_CHANGED
+                    || action == ACTION_VIEW_ENTERED) {
                 if (DEBUG) {
-                    Slog.d(TAG, "Creating viewState for " + id + " on " + getFlagAsString(flags));
+                    Slog.d(TAG,
+                            "Creating viewState for " + id + " on " + getActionAsString(action));
                 }
                 viewState = new ViewState(this, id, value, this, ViewState.STATE_INITIAL);
                 mViewStates.put(id, viewState);
             } else {
-                if (VERBOSE) Slog.v(TAG, "Ignored " + getFlagAsString(flags) + " for " + id);
+                if (VERBOSE) Slog.v(TAG, "Ignored " + getActionAsString(action) + " for " + id);
                 return;
             }
         }
 
-        if ((flags & FLAG_START_SESSION) != 0) {
-            // View is triggering autofill.
-            mCurrentViewId = viewState.id;
-            viewState.update(value, virtualBounds);
-            viewState.setState(ViewState.STATE_STARTED_SESSION);
-            requestNewFillResponseLocked();
-            return;
-        }
-
-        if ((flags & FLAG_VALUE_CHANGED) != 0) {
-            if (value != null && !value.equals(viewState.getCurrentValue())) {
-                // Always update the internal state.
-                viewState.setCurrentValue(value);
-
-                // Must check if this update was caused by autofilling the view, in which
-                // case we just update the value, but not the UI.
-                final AutofillValue filledValue = viewState.getAutofilledValue();
-                if (value.equals(filledValue)) {
-                    return;
-                }
-                // Update the internal state...
-                viewState.setState(ViewState.STATE_CHANGED);
-
-                //..and the UI
-                if (value.isText()) {
-                    getUiForShowing().filterFillUi(value.getTextValue().toString());
-                } else {
-                    getUiForShowing().filterFillUi(null);
-                }
-            }
-
-            return;
-        }
-
-        if ((flags & FLAG_VIEW_ENTERED) != 0) {
-            if (shouldStartNewPartitionLocked(id)) {
-                // TODO(b/37424539): proper implementation
-                if (mResponseWaitingAuth != null && ((flags & FLAG_START_SESSION) == 0)) {
-                    viewState.setState(ViewState.STATE_WAITING_RESPONSE_AUTH);
-                } else if ((flags & FLAG_START_SESSION) == 0){
-                    if (DEBUG) {
-                        Slog.d(TAG, "Starting partition for view id " + viewState.id);
-                    }
-                    viewState.setState(ViewState.STATE_STARTED_PARTITION);
-                    requestNewFillResponseLocked();
-                }
-            }
-
-            // Remove the UI if the ViewState has changed.
-            if (mCurrentViewId != viewState.id) {
-                mUi.hideFillUi(mCurrentViewId != null ? mCurrentViewId : null);
+        switch(action) {
+            case ACTION_START_SESSION:
+                // View is triggering autofill.
                 mCurrentViewId = viewState.id;
-            }
+                viewState.update(value, virtualBounds);
+                viewState.setState(ViewState.STATE_STARTED_SESSION);
+                requestNewFillResponseLocked(flags);
+                break;
+            case ACTION_VALUE_CHANGED:
+                if (value != null && !value.equals(viewState.getCurrentValue())) {
+                    // Always update the internal state.
+                    viewState.setCurrentValue(value);
 
-            // If the ViewState is ready to be displayed, onReady() will be called.
-            viewState.update(value, virtualBounds);
+                    // Must check if this update was caused by autofilling the view, in which
+                    // case we just update the value, but not the UI.
+                    final AutofillValue filledValue = viewState.getAutofilledValue();
+                    if (value.equals(filledValue)) {
+                        return;
+                    }
+                    // Update the internal state...
+                    viewState.setState(ViewState.STATE_CHANGED);
 
-            return;
+                    //..and the UI
+                    if (value.isText()) {
+                        getUiForShowing().filterFillUi(value.getTextValue().toString());
+                    } else {
+                        getUiForShowing().filterFillUi(null);
+                    }
+                }
+                break;
+            case ACTION_VIEW_ENTERED:
+                if (shouldStartNewPartitionLocked(id)) {
+                    // TODO(b/37424539): proper implementation
+                    if (mResponseWaitingAuth != null) {
+                        viewState.setState(ViewState.STATE_WAITING_RESPONSE_AUTH);
+                    } else {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Starting partition for view id " + viewState.id);
+                        }
+                        viewState.setState(ViewState.STATE_STARTED_PARTITION);
+                        requestNewFillResponseLocked(flags);
+                    }
+                }
+
+                // Remove the UI if the ViewState has changed.
+                if (mCurrentViewId != viewState.id) {
+                    mUi.hideFillUi(mCurrentViewId != null ? mCurrentViewId : null);
+                    mCurrentViewId = viewState.id;
+                }
+
+                // If the ViewState is ready to be displayed, onReady() will be called.
+                viewState.update(value, virtualBounds);
+                break;
+            case ACTION_VIEW_EXITED:
+                if (mCurrentViewId == viewState.id) {
+                    mUi.hideFillUi(viewState.id);
+                    mCurrentViewId = null;
+                }
+                break;
+            default:
+                Slog.w(TAG, "updateLocked(): unknown action: " + action);
         }
-
-        if ((flags & FLAG_VIEW_EXITED) != 0) {
-            if (mCurrentViewId == viewState.id) {
-                mUi.hideFillUi(viewState.id);
-                mCurrentViewId = null;
-            }
-            return;
-        }
-
-        Slog.w(TAG, "updateLocked(): unknown flags " + flags + ": " + getFlagAsString(flags));
     }
 
     @Override
@@ -1042,7 +1031,7 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onFillReady() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
         }
@@ -1055,12 +1044,8 @@
         getUiForShowing().showFillUi(filledId, response, filterText, mPackageName);
     }
 
-    static String getFlagAsString(int flag) {
-        return DebugUtils.flagsToString(AutofillManager.class, "FLAG_", flag);
-    }
-
-    int getId() {
-        return mId;
+    String getActionAsString(int flag) {
+        return DebugUtils.flagsToString(AutofillManager.class, "ACTION_", flag);
     }
 
     boolean isDestroyed() {
@@ -1079,7 +1064,7 @@
         synchronized (mLock) {
             if (!mHasCallback) return;
             try {
-                mClient.notifyNoFillUi(mId, mWindowToken, mCurrentViewId);
+                mClient.notifyNoFillUi(id, mWindowToken, mCurrentViewId);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error notifying client no fill UI: windowToken=" + mWindowToken
                         + " id=" + mCurrentViewId, e);
@@ -1114,7 +1099,7 @@
         }
 
         try {
-            mClient.setTrackedViews(mId, trackedViews, saveOnAllViewsInvisible);
+            mClient.setTrackedViews(id, trackedViews, saveOnAllViewsInvisible);
         } catch (RemoteException e) {
             Slog.w(TAG, "Cannot set tracked ids", e);
         }
@@ -1128,7 +1113,8 @@
         if (mResponses == null) {
             mResponses = new SparseArray<>(4);
         }
-        mResponses.put(response.getRequestId(), response);
+        final int requestId = response.getRequestId();
+        mResponses.put(requestId, response);
         mClientState = response.getClientState();
 
         setViewStatesLocked(response, ViewState.STATE_FILLABLE);
@@ -1138,13 +1124,18 @@
             return;
         }
 
-        if ((mFlags & FLAG_MANUAL_REQUEST) != 0 && response.getDatasets() != null
-                && response.getDatasets().size() == 1) {
-            Slog.d(TAG, "autofilling manual request directly");
-            autoFill(response.getRequestId(), response.getDatasets().get(0));
-            return;
-        }
+        final ArrayList<Dataset> datasets = response.getDatasets();
 
+        if (datasets != null && datasets.size() == 1) {
+            // Check if it its a single response for a manual request, in which case it should
+            // be automatically filled
+            final FillContext context = getFillContextByRequestIdLocked(requestId);
+            if (context != null && (context.getStructure().getFlags() & FLAG_MANUAL_REQUEST) != 0) {
+                Slog.d(TAG, "autofilling manual request directly");
+                autoFill(requestId, datasets.get(0));
+                return;
+            }
+        }
         // Updates the UI, if necessary.
         final ViewState currentView = mViewStates.get(mCurrentViewId);
         currentView.maybeCallOnFillReady();
@@ -1199,7 +1190,7 @@
         }
     }
 
-    private ViewState createOrUpdateViewStateLocked(AutofillId id, int state,AutofillValue value) {
+    private ViewState createOrUpdateViewStateLocked(AutofillId id, int state, AutofillValue value) {
         ViewState viewState = mViewStates.get(id);
         if (viewState != null)  {
             viewState.setState(state);
@@ -1234,7 +1225,7 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#autoFill() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
             // Autofill it directly...
@@ -1280,7 +1271,7 @@
     private void startAuthentication(IntentSender intent, Intent fillInIntent) {
         try {
             synchronized (mLock) {
-                mClient.authenticate(mId, intent, fillInIntent);
+                mClient.authenticate(id, intent, fillInIntent);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "Error launching auth intent", e);
@@ -1288,10 +1279,9 @@
     }
 
     void dumpLocked(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("id: "); pw.println(mId);
+        pw.print(prefix); pw.print("id: "); pw.println(id);
         pw.print(prefix); pw.print("uid: "); pw.println(uid);
         pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
-        pw.print(prefix); pw.print("mFlags: "); pw.println(mFlags);
         pw.print(prefix); pw.print("mResponses: "); pw.println(mResponses);
         pw.print(prefix); pw.print("mResponseWaitingAuth: "); pw.println(mResponseWaitingAuth);
         pw.print(prefix); pw.print("mDatasetWaitingAuth: "); pw.println(mDatasetWaitingAuth);
@@ -1332,14 +1322,14 @@
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#autoFillApp() rejected - session: "
-                        + mId + " destroyed");
+                        + id + " destroyed");
                 return;
             }
             try {
                 if (DEBUG) {
                     Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
                 }
-                mClient.autofill(mId, mWindowToken, dataset.getFieldIds(),
+                mClient.autofill(id, mWindowToken, dataset.getFieldIds(),
                         dataset.getFieldValues());
                 setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED);
             } catch (RemoteException e) {
@@ -1378,11 +1368,11 @@
         }
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#removeSelfLocked() rejected - session: "
-                    + mId + " destroyed");
+                    + id + " destroyed");
             return;
         }
         destroyLocked();
-        mService.removeSessionLocked(mId);
+        mService.removeSessionLocked(id);
     }
 
     private int getLastResponseIndex() {
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 3967f59..d98ee9d 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -65,15 +65,15 @@
     public static final int STATE_WAITING_RESPONSE_AUTH = 0x80;
 
     public final AutofillId id;
+
     private final Listener mListener;
     private final Session mSession;
-    private FillResponse mResponse;
 
+    private FillResponse mResponse;
     private AutofillValue mInitialValue;
     private AutofillValue mCurrentValue;
     private AutofillValue mAutofilledValue;
     private Rect mVirtualBounds;
-
     private int mState;
 
     ViewState(Session session, AutofillId id, AutofillValue value, Listener listener, int state) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 772cdcd..cabaebd4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12912,11 +12912,6 @@
     @Override
     public boolean requestAutofillData(IResultReceiver receiver, Bundle receiverExtras,
             IBinder activityToken, int flags) {
-        // NOTE: we could always use ActivityManager.ASSIST_CONTEXT_FULL and let ActivityThread
-        // rely on the flags to decide whether the handleRequestAssistContextExtras() is for
-        // autofill, but it's safer to explicitly use new AutoFill types, in case the Assist
-        // requests use flags in the future as well (since their flags value might collide with the
-        // autofill flag values).
         return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_AUTOFILL, null, null,
                 receiver, receiverExtras, activityToken, true, true, UserHandle.getCallingUserId(),
                 null, PENDING_AUTOFILL_ASSIST_STRUCTURE_TIMEOUT, flags) != null;
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index ba72dcf..d6bfb35 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -751,6 +751,26 @@
         mAppsNotReportingCrashes.add(proc.info.packageName);
     }
 
+    static boolean isInterestingForBackgroundTraces(ProcessRecord app) {
+        // The system_server is always considered interesting.
+        if (app.pid == MY_PID) {
+            return true;
+        }
+
+        // A package is considered interesting if any of the following is true :
+        //
+        // - It's displaying an activity.
+        // - It's the SystemUI.
+        // - It has an overlay or a top UI visible.
+        //
+        // NOTE: The check whether a given ProcessRecord belongs to the systemui
+        // process is a bit of a kludge, but the same pattern seems repeated at
+        // several places in the system server.
+        return app.isInterestingToUserLocked() ||
+            (app.info != null && "com.android.systemui".equals(app.info.packageName)) ||
+            (app.hasTopUi || app.hasOverlayUi);
+    }
+
     final void appNotResponding(ProcessRecord app, ActivityRecord activity,
             ActivityRecord parent, boolean aboveSystem, final String annotation) {
         ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
@@ -812,7 +832,7 @@
             firstPids.add(app.pid);
 
             // Don't dump other PIDs if it's a background ANR
-            isSilentANR = !showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID;
+            isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app);
             if (!isSilentANR) {
                 int parentPid = app.pid;
                 if (parent != null && parent.app != null && parent.app.pid > 0) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 3c5c5fd..b025385 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -520,6 +520,14 @@
                 return true;
             }
         }
+
+        final int servicesSize = services.size();
+        for (int i = 0; i < servicesSize; i++) {
+            ServiceRecord r = services.valueAt(i);
+            if (r.isForeground) {
+                return true;
+            }
+        }
         return false;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a14c273..15df545 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -739,12 +739,123 @@
     @GuardedBy("mPackages")
     final SparseArray<Map<String, Integer>> mChangedPackagesSequenceNumbers = new SparseArray<>();
 
-    final PackageParser.Callback mPackageParserCallback = new PackageParser.Callback() {
-        @Override public boolean hasFeature(String feature) {
+    class PackageParserCallback implements PackageParser.Callback {
+        @Override public final boolean hasFeature(String feature) {
             return PackageManagerService.this.hasSystemFeature(feature, 0);
         }
+
+        final List<PackageParser.Package> getStaticOverlayPackagesLocked(
+                Collection<PackageParser.Package> allPackages, String targetPackageName) {
+            List<PackageParser.Package> overlayPackages = null;
+            for (PackageParser.Package p : allPackages) {
+                if (targetPackageName.equals(p.mOverlayTarget) && p.mIsStaticOverlay) {
+                    if (overlayPackages == null) {
+                        overlayPackages = new ArrayList<PackageParser.Package>();
+                    }
+                    overlayPackages.add(p);
+                }
+            }
+            if (overlayPackages != null) {
+                Comparator<PackageParser.Package> cmp = new Comparator<PackageParser.Package>() {
+                    public int compare(PackageParser.Package p1, PackageParser.Package p2) {
+                        return p1.mOverlayPriority - p2.mOverlayPriority;
+                    }
+                };
+                Collections.sort(overlayPackages, cmp);
+            }
+            return overlayPackages;
+        }
+
+        final String[] getStaticOverlayPathsLocked(Collection<PackageParser.Package> allPackages,
+                String targetPackageName, String targetPath) {
+            if ("android".equals(targetPackageName)) {
+                // Static RROs targeting to "android", ie framework-res.apk, are already applied by
+                // native AssetManager.
+                return null;
+            }
+            List<PackageParser.Package> overlayPackages =
+                    getStaticOverlayPackagesLocked(allPackages, targetPackageName);
+            if (overlayPackages == null || overlayPackages.isEmpty()) {
+                return null;
+            }
+            List<String> overlayPathList = null;
+            for (PackageParser.Package overlayPackage : overlayPackages) {
+                if (targetPath == null) {
+                    if (overlayPathList == null) {
+                        overlayPathList = new ArrayList<String>();
+                    }
+                    overlayPathList.add(overlayPackage.baseCodePath);
+                    continue;
+                }
+
+                try {
+                    // Creates idmaps for system to parse correctly the Android manifest of the
+                    // target package.
+                    //
+                    // OverlayManagerService will update each of them with a correct gid from its
+                    // target package app id.
+                    mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
+                            UserHandle.getSharedAppGid(
+                                    UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
+                    if (overlayPathList == null) {
+                        overlayPathList = new ArrayList<String>();
+                    }
+                    overlayPathList.add(overlayPackage.baseCodePath);
+                } catch (InstallerException e) {
+                    Slog.e(TAG, "Failed to generate idmap for " + targetPath + " and " +
+                            overlayPackage.baseCodePath);
+                }
+            }
+            return overlayPathList == null ? null : overlayPathList.toArray(new String[0]);
+        }
+
+        String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
+            synchronized (mPackages) {
+                return getStaticOverlayPathsLocked(
+                        mPackages.values(), targetPackageName, targetPath);
+            }
+        }
+
+        @Override public final String[] getOverlayApks(String targetPackageName) {
+            return getStaticOverlayPaths(targetPackageName, null);
+        }
+
+        @Override public final String[] getOverlayPaths(String targetPackageName,
+                String targetPath) {
+            return getStaticOverlayPaths(targetPackageName, targetPath);
+        }
     };
 
+    class ParallelPackageParserCallback extends PackageParserCallback {
+        List<PackageParser.Package> mOverlayPackages = null;
+
+        void findStaticOverlayPackages() {
+            synchronized (mPackages) {
+                for (PackageParser.Package p : mPackages.values()) {
+                    if (p.mIsStaticOverlay) {
+                        if (mOverlayPackages == null) {
+                            mOverlayPackages = new ArrayList<PackageParser.Package>();
+                        }
+                        mOverlayPackages.add(p);
+                    }
+                }
+            }
+        }
+
+        @Override
+        synchronized String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
+            // We can trust mOverlayPackages without holding mPackages because package uninstall
+            // can't happen while running parallel parsing.
+            // Moreover holding mPackages on each parsing thread causes dead-lock.
+            return mOverlayPackages == null ? null :
+                    getStaticOverlayPathsLocked(mOverlayPackages, targetPackageName, targetPath);
+        }
+    }
+
+    final PackageParser.Callback mPackageParserCallback = new PackageParserCallback();
+    final ParallelPackageParserCallback mParallelPackageParserCallback =
+            new ParallelPackageParserCallback();
+
     public static final class SharedLibraryEntry {
         public final String path;
         public final String apk;
@@ -2453,6 +2564,8 @@
                     | PackageParser.PARSE_IS_SYSTEM_DIR
                     | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
 
+            mParallelPackageParserCallback.findStaticOverlayPackages();
+
             // Find base frameworks (resource packages without code).
             scanDirTracedLI(frameworkDir, mDefParseFlags
                     | PackageParser.PARSE_IS_SYSTEM
@@ -7856,7 +7969,8 @@
                     + " flags=0x" + Integer.toHexString(parseFlags));
         }
         ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
-                mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, mPackageParserCallback);
+                mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
+                mParallelPackageParserCallback);
 
         // Submit files for parsing in parallel
         int fileCount = 0;