Merge cherrypicks of [4741663, 4741664, 4741665, 4741666, 4743080, 4743081, 4743082, 4743083, 4741262, 4741263, 4741264, 4741265, 4741266, 4741667, 4743084, 4741242, 4741243, 4741741, 4741742, 4741743, 4741744, 4741822, 4743085, 4741668, 4741338, 4743055, 4743056, 4743070, 4743073, 4743075, 4743076, 4743078, 4743079, 4743161, 4743162, 4743164, 4743165, 4743167, 4743168, 4743169, 4743170, 4741681, 4741682, 4741683, 4741684, 4741685, 4741686, 4741687, 4741688, 4741689, 4741690, 4741691, 4741692, 4741693, 4741694, 4741695, 4741696, 4741697, 4741698, 4741699, 4743240, 4743241, 4743242, 4743243, 4741745, 4741823, 4741824, 4741825, 4741267, 4741268, 4743244, 4743280, 4743281, 4743224, 4743203, 4743204, 4743205, 4741746, 4741747, 4743245, 4741826, 4741827, 4741828, 4741829, 4741748, 4741749, 4741750, 4743233, 4743282, 4741244, 4741245, 4741246, 4741247, 4743206, 4743207, 4743208, 4743209, 4743210, 4743211, 4743212, 4743213, 4743214, 4743215, 4743216, 4743217, 4743218, 4743219, 4743360, 4743361, 4743362, 4743363, 4743364, 4743365, 4743366, 4743367, 4743368, 4743369, 4743370, 4743371, 4743372, 4743373, 4743374, 4743375, 4743376, 4743377, 4743283, 4743284, 4741830, 4742501, 4743246, 4743086, 4743087, 4743378, 4743379, 4741751] into sparse-4749909-L04200000199131547

Change-Id: I1492186998ee5230a67cd2efaf8c68d8b008cb7e
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 7a1931718..037aeb0 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -35,23 +35,23 @@
 
     void setServiceInfo(in AccessibilityServiceInfo info);
 
-    boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
+    String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
         long accessibilityNodeId, int interactionId,
         IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
         in Bundle arguments);
 
-    boolean findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
+    String[] findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
         String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
         long threadId);
 
-    boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
+    String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
         long accessibilityNodeId, String viewId, int interactionId,
         IAccessibilityInteractionConnectionCallback callback, long threadId);
 
-    boolean findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
+    String[] findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
         int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
 
-    boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
+    String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
         int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
 
     boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2c04f8f..8dc558c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5872,6 +5872,16 @@
     }
 
     /**
+     * Temporary method on O-MR1 only.
+     *
+     * @hide
+     */
+    @Override
+    public ComponentName getComponentNameForAutofill() {
+        return mComponent;
+    }
+
+    /**
      * Retrieve a {@link SharedPreferences} object for accessing preferences
      * that are private to this activity.  This simply calls the underlying
      * {@link #getSharedPreferences(String, int)} method by passing in this activity's
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index c8d9839..9dceb7f 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -268,4 +268,9 @@
      * @param token The IApplicationToken for the activity
      */
     public abstract void setFocusedActivity(IBinder token);
+
+    /**
+     * Returns {@code true} if {@code uid} is running an activity from {@code packageName}.
+     */
+    public abstract boolean hasRunningActivity(int uid, @Nullable String packageName);
 }
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 93836263..bf715c3 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -2058,6 +2058,16 @@
         return mActivityComponent;
     }
 
+    /**
+     * Called by Autofill server when app forged a different value.
+     *
+     * @hide
+     */
+    public void setActivityComponent(ComponentName componentName) {
+        ensureData();
+        mActivityComponent = componentName;
+    }
+
     /** @hide */
     public int getFlags() {
         return mFlags;
diff --git a/core/java/android/appwidget/AppWidgetManagerInternal.java b/core/java/android/appwidget/AppWidgetManagerInternal.java
new file mode 100644
index 0000000..5562c55
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetManagerInternal.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appwidget;
+
+import android.annotation.Nullable;
+import android.util.ArraySet;
+
+/**
+ * App widget manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class AppWidgetManagerInternal {
+
+    /**
+     * Gets the packages from which the uid hosts widgets.
+     *
+     * @param uid The potential host UID.
+     * @return Whether the UID hosts widgets from the package.
+     */
+    public abstract @Nullable ArraySet<String> getHostedWidgetPackages(int uid);
+}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 98cd319..9498f12 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -808,7 +808,11 @@
             return null;
         }
         try {
-            return service.getRemoteName(this);
+            String name = service.getRemoteName(this);
+            if (name != null) {
+                return name.replaceAll("[\\t\\n\\r]+", " ");
+            }
+            return null;
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
         }
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 11830c2..84b7794 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -42,6 +42,9 @@
  */
 public class PackageItemInfo {
     private static final float MAX_LABEL_SIZE_PX = 500f;
+    /** The maximum length of a safe label, in characters */
+    private static final int MAX_SAFE_LABEL_LENGTH = 50000;
+
     /**
      * Public name of this item. From the "android:name" attribute.
      */
@@ -169,7 +172,8 @@
         // If the label contains new line characters it may push the UI
         // down to hide a part of it. Labels shouldn't have new line
         // characters, so just truncate at the first time one is seen.
-        final int labelLength = labelStr.length();
+        final int labelLength = Math.min(labelStr.length(), MAX_SAFE_LABEL_LENGTH);
+        final StringBuffer sb = new StringBuffer(labelLength);
         int offset = 0;
         while (offset < labelLength) {
             final int codePoint = labelStr.codePointAt(offset);
@@ -181,14 +185,19 @@
                 break;
             }
             // replace all non-break space to " " in order to be trimmed
+            final int charCount = Character.charCount(codePoint);
             if (type == Character.SPACE_SEPARATOR) {
-                labelStr = labelStr.substring(0, offset) + " " + labelStr.substring(offset +
-                        Character.charCount(codePoint));
+                sb.append(' ');
+            } else {
+                sb.append(labelStr.charAt(offset));
+                if (charCount == 2) {
+                    sb.append(labelStr.charAt(offset + 1));
+                }
             }
-            offset += Character.charCount(codePoint);
+            offset += charCount;
         }
 
-        labelStr = labelStr.trim();
+        labelStr = sb.toString().trim();
         if (labelStr.isEmpty()) {
             return packageName;
         }
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index bf35a3d..c440949 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -83,7 +83,7 @@
         mAppId = in.readLong();
         mAppVersion = in.readInt();
         mVersionRestrictionMask = in.readInt();
-        mAppIdVendorMask = in.readInt();
+        mAppIdVendorMask = in.readLong();
     }
 
     public int describeContents() {
@@ -91,7 +91,6 @@
     }
 
     public void writeToParcel(Parcel out, int flags) {
-
         out.writeLong(mAppId);
         out.writeInt(mAppVersion);
         out.writeInt(mVersionRestrictionMask);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index d7ecc81..467eb9b 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2505,6 +2505,28 @@
     }
 
     /**
+     * Returns if the active data network for the given UID is metered. A network
+     * is classified as metered when the user is sensitive to heavy data usage on
+     * that connection due to monetary costs, data limitations or
+     * battery/performance issues. You should check this before doing large
+     * data transfers, and warn the user or delay the operation until another
+     * network is available.
+     *
+     * @return {@code true} if large transfers should be avoided, otherwise
+     *        {@code false}.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+    public boolean isActiveNetworkMeteredForUid(int uid) {
+        try {
+            return mService.isActiveNetworkMeteredForUid(uid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * If the LockdownVpn mechanism is enabled, updates the vpn
      * with a reload of its profile.
      *
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index a6fe738..f11372c2 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -66,6 +66,7 @@
 
     NetworkQuotaInfo getActiveNetworkQuotaInfo();
     boolean isActiveNetworkMetered();
+    boolean isActiveNetworkMeteredForUid(int uid);
 
     boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress);
 
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index fae9d53..c6d3860 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1340,6 +1340,13 @@
      * @see Parcelable
      */
     public final <T extends Parcelable> void writeTypedList(List<T> val) {
+        writeTypedList(val, 0);
+    }
+
+    /**
+     * @hide
+     */
+    public <T extends Parcelable> void writeTypedList(List<T> val, int parcelableFlags) {
         if (val == null) {
             writeInt(-1);
             return;
@@ -1348,13 +1355,7 @@
         int i=0;
         writeInt(N);
         while (i < N) {
-            T item = val.get(i);
-            if (item != null) {
-                writeInt(1);
-                item.writeToParcel(this, 0);
-            } else {
-                writeInt(0);
-            }
+            writeTypedObject(val.get(i), parcelableFlags);
             i++;
         }
     }
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 13e1e26..ff4f358 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -694,8 +694,8 @@
             // Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo);
             // If the magic is non-zero, we simply return thumbnail if it does exist.
             // querying MediaProvider and simply return thumbnail.
-            MiniThumbFile thumbFile = new MiniThumbFile(isVideo ? Video.Media.EXTERNAL_CONTENT_URI
-                    : Images.Media.EXTERNAL_CONTENT_URI);
+            MiniThumbFile thumbFile = MiniThumbFile.instance(
+                    isVideo ? Video.Media.EXTERNAL_CONTENT_URI : Images.Media.EXTERNAL_CONTENT_URI);
             Cursor c = null;
             try {
                 long magic = thumbFile.getMagic(origId);
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index 65b0efc..21a3df8 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -316,8 +316,8 @@
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeParcelable(mPresentation, flags);
-        parcel.writeTypedArrayList(mFieldIds, flags);
-        parcel.writeTypedArrayList(mFieldValues, flags);
+        parcel.writeTypedList(mFieldIds, flags);
+        parcel.writeTypedList(mFieldValues, flags);
         parcel.writeParcelableList(mFieldPresentations, flags);
         parcel.writeParcelable(mAuthentication, flags);
         parcel.writeString(mId);
@@ -333,8 +333,9 @@
             final Builder builder = (presentation == null)
                     ? new Builder()
                     : new Builder(presentation);
-            final ArrayList<AutofillId> ids = parcel.readTypedArrayList(null);
-            final ArrayList<AutofillValue> values = parcel.readTypedArrayList(null);
+            final ArrayList<AutofillId> ids = parcel.createTypedArrayList(AutofillId.CREATOR);
+            final ArrayList<AutofillValue> values =
+                    parcel.createTypedArrayList(AutofillValue.CREATOR);
             final ArrayList<RemoteViews> presentations = new ArrayList<>();
             parcel.readParcelableList(presentations, null);
             final int idCount = (ids != null) ? ids.size() : 0;
diff --git a/core/java/android/service/autofill/SaveRequest.java b/core/java/android/service/autofill/SaveRequest.java
index 9de9315..fc4272dd 100644
--- a/core/java/android/service/autofill/SaveRequest.java
+++ b/core/java/android/service/autofill/SaveRequest.java
@@ -19,9 +19,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Bundle;
-import android.os.CancellationSignal;
 import android.os.Parcel;
 import android.os.Parcelable;
+
 import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
@@ -45,7 +45,7 @@
     }
 
     private SaveRequest(@NonNull Parcel parcel) {
-        this(parcel.readTypedArrayList(null), parcel.readBundle());
+        this(parcel.createTypedArrayList(FillContext.CREATOR), parcel.readBundle());
     }
 
     /**
@@ -57,7 +57,7 @@
 
     /**
      * Gets the extra client state returned from the last {@link
-     * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)}
+     * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
      * fill request}.
      *
      * @return The client state.
@@ -73,7 +73,7 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeTypedArrayList(mFillContexts, flags);
+        parcel.writeTypedList(mFillContexts, flags);
         parcel.writeBundle(mClientState);
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8f250a9..3f1ea34c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -7733,6 +7733,7 @@
             if (!registered) {
                 mAttachInfo.mAccessibilityWindowId =
                         mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
+                                mContext.getPackageName(),
                                 new AccessibilityInteractionConnection(ViewRootImpl.this));
             }
         }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index c4ffb4c..235e61a 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -611,6 +611,11 @@
         void notifyKeyguardTrustedChanged();
 
         /**
+         * The keyguard showing state has changed
+         */
+        void onKeyguardShowingAndNotOccludedChanged();
+
+        /**
          * Notifies the window manager that screen is being turned off.
          *
          * @param listener callback to call when display can be turned off
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 19213ca..980a2c9 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -28,6 +28,8 @@
 import android.util.LongSparseArray;
 import android.util.SparseArray;
 
+import com.android.internal.util.ArrayUtils;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -283,14 +285,19 @@
                 }
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
-                        accessibilityWindowId, accessibilityNodeId, interactionId, this,
-                        prefetchFlags, Thread.currentThread().getId(), arguments);
-                Binder.restoreCallingIdentity(identityToken);
-                if (success) {
+                final String[] packageNames;
+                try {
+                    packageNames = connection.findAccessibilityNodeInfoByAccessibilityId(
+                            accessibilityWindowId, accessibilityNodeId, interactionId, this,
+                            prefetchFlags, Thread.currentThread().getId(), arguments);
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+                if (packageNames != null) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
-                    finalizeAndCacheAccessibilityNodeInfos(infos, connectionId);
+                    finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+                            bypassCache, packageNames);
                     if (infos != null && !infos.isEmpty()) {
                         for (int i = 1; i < infos.size(); i++) {
                             infos.get(i).recycle();
@@ -333,15 +340,21 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findAccessibilityNodeInfosByViewId(
-                        accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
-                if (success) {
+                final String[] packageNames;
+                try {
+                    packageNames = connection.findAccessibilityNodeInfosByViewId(
+                            accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
+                if (packageNames != null) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
                     if (infos != null) {
-                        finalizeAndCacheAccessibilityNodeInfos(infos, connectionId);
+                        finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+                                false, packageNames);
                         return infos;
                     }
                 }
@@ -381,15 +394,21 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findAccessibilityNodeInfosByText(
-                        accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
-                if (success) {
+                final String[] packageNames;
+                try {
+                    packageNames = connection.findAccessibilityNodeInfosByText(
+                            accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
+                if (packageNames != null) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
                     if (infos != null) {
-                        finalizeAndCacheAccessibilityNodeInfos(infos, connectionId);
+                        finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+                                false, packageNames);
                         return infos;
                     }
                 }
@@ -428,14 +447,19 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findFocus(accessibilityWindowId,
-                        accessibilityNodeId, focusType, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
-                if (success) {
+                final String[] packageNames;
+                try {
+                    packageNames = connection.findFocus(accessibilityWindowId,
+                            accessibilityNodeId, focusType, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
+                if (packageNames != null) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
                             interactionId);
-                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId);
+                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames);
                     return info;
                 }
             } else {
@@ -472,14 +496,19 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.focusSearch(accessibilityWindowId,
-                        accessibilityNodeId, direction, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
-                if (success) {
+                final String[] packageNames;
+                try {
+                    packageNames = connection.focusSearch(accessibilityWindowId,
+                            accessibilityNodeId, direction, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
+                if (packageNames != null) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
                             interactionId);
-                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId);
+                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames);
                     return info;
                 }
             } else {
@@ -580,7 +609,7 @@
                 int interactionId) {
         synchronized (mInstanceLock) {
             final boolean success = waitForResultTimedLocked(interactionId);
-            List<AccessibilityNodeInfo> result = null;
+            final List<AccessibilityNodeInfo> result;
             if (success) {
                 result = mFindAccessibilityNodeInfosResult;
             } else {
@@ -696,13 +725,28 @@
      *
      * @param info The info.
      * @param connectionId The id of the connection to the system.
+     * @param bypassCache Whether or not to bypass the cache. The node is added to the cache if
+     *                    this value is {@code false}
+     * @param packageNames The valid package names a node can come from.
      */
     private void finalizeAndCacheAccessibilityNodeInfo(AccessibilityNodeInfo info,
-            int connectionId) {
+            int connectionId, boolean bypassCache, String[] packageNames) {
         if (info != null) {
             info.setConnectionId(connectionId);
+            // Empty array means any package name is Okay
+            if (!ArrayUtils.isEmpty(packageNames)) {
+                CharSequence packageName = info.getPackageName();
+                if (packageName == null
+                        || !ArrayUtils.contains(packageNames, packageName.toString())) {
+                    // If the node package not one of the valid ones, pick the top one - this
+                    // is one of the packages running in the introspected UID.
+                    info.setPackageName(packageNames[0]);
+                }
+            }
             info.setSealed(true);
-            sAccessibilityCache.add(info);
+            if (!bypassCache) {
+                sAccessibilityCache.add(info);
+            }
         }
     }
 
@@ -711,14 +755,18 @@
      *
      * @param infos The {@link AccessibilityNodeInfo}s.
      * @param connectionId The id of the connection to the system.
+     * @param bypassCache Whether or not to bypass the cache. The nodes are added to the cache if
+     *                    this value is {@code false}
+     * @param packageNames The valid package names a node can come from.
      */
     private void finalizeAndCacheAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos,
-            int connectionId) {
+            int connectionId, boolean bypassCache, String[] packageNames) {
         if (infos != null) {
             final int infosCount = infos.size();
             for (int i = 0; i < infosCount; i++) {
                 AccessibilityNodeInfo info = infos.get(i);
-                finalizeAndCacheAccessibilityNodeInfo(info, connectionId);
+                finalizeAndCacheAccessibilityNodeInfo(info, connectionId,
+                        bypassCache, packageNames);
             }
         }
     }
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 0b9bc57..2478281e 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -885,7 +885,7 @@
      * @hide
      */
     public int addAccessibilityInteractionConnection(IWindow windowToken,
-            IAccessibilityInteractionConnection connection) {
+            String packageName, IAccessibilityInteractionConnection connection) {
         final IAccessibilityManager service;
         final int userId;
         synchronized (mLock) {
@@ -896,7 +896,8 @@
             userId = mUserId;
         }
         try {
-            return service.addAccessibilityInteractionConnection(windowToken, connection, userId);
+            return service.addAccessibilityInteractionConnection(windowToken, connection,
+                    packageName, userId);
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error while adding an accessibility interaction connection. ", re);
         }
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 3f499ab..6329c11 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -45,7 +45,7 @@
     List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId);
 
     int addAccessibilityInteractionConnection(IWindow windowToken,
-            in IAccessibilityInteractionConnection connection, int userId);
+            in IAccessibilityInteractionConnection connection, String packageName, int userId);
 
     void removeAccessibilityInteractionConnection(IWindow windowToken);
 
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 4fb2a99..fb9534b 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -24,6 +24,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -44,6 +45,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.Preconditions;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -384,13 +386,20 @@
          * Runs the specified action on the UI thread.
          */
         void runOnUiThread(Runnable action);
+
+        /**
+         * Gets the complete component name of this client.
+         *
+         * <p>Temporary method on O-MR1 only.
+         */
+        ComponentName getComponentNameForAutofill();
     }
 
     /**
      * @hide
      */
     public AutofillManager(Context context, IAutoFillManager service) {
-        mContext = context;
+        mContext = Preconditions.checkNotNull(context, "context cannot be null");
         mService = service;
     }
 
@@ -940,6 +949,10 @@
         return mContext.getAutofillClient();
     }
 
+    private ComponentName getComponentNameFromContext(AutofillClient client) {
+        return client == null ? null : client.getComponentNameForAutofill();
+    }
+
     /** @hide */
     public void onAuthenticationResult(int authenticationId, Intent data) {
         if (!hasAutofillFeature()) {
@@ -990,13 +1003,18 @@
             return;
         }
         try {
+            final AutofillClient client = getClientLocked();
+            final ComponentName componentName = getComponentNameFromContext(client);
+            if (componentName == null) {
+                Log.w(TAG, "startSessionLocked(): context is not activity: " + mContext);
+                return;
+            }
             mSessionId = mService.startSession(mContext.getActivityToken(),
                     mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
-                    mCallback != null, flags, mContext.getOpPackageName());
+                    mCallback != null, flags, componentName);
             if (mSessionId != NO_SESSION) {
                 mState = STATE_ACTIVE;
             }
-            final AutofillClient client = getClientLocked();
             if (client != null) {
                 client.autofillCallbackResetableStateAvailable();
             }
@@ -1050,14 +1068,19 @@
 
         try {
             if (restartIfNecessary) {
+                final AutofillClient client = getClientLocked();
+                final ComponentName componentName = getComponentNameFromContext(client);
+                if (componentName == null) {
+                    Log.w(TAG, "startSessionLocked(): context is not activity: " + mContext);
+                    return;
+                }
                 final int newId = mService.updateOrRestartSession(mContext.getActivityToken(),
                         mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
-                        mCallback != null, flags, mContext.getOpPackageName(), mSessionId, action);
+                        mCallback != null, flags, componentName, mSessionId, action);
                 if (newId != mSessionId) {
                     if (sDebug) Log.d(TAG, "Session restarted: " + mSessionId + "=>" + newId);
                     mSessionId = newId;
                     mState = (mSessionId == NO_SESSION) ? STATE_UNKNOWN : STATE_ACTIVE;
-                    final AutofillClient client = getClientLocked();
                     if (client != null) {
                         client.autofillCallbackResetableStateAvailable();
                     }
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 6bd9bec..9329c4d 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -16,6 +16,7 @@
 
 package android.view.autofill;
 
+import android.content.ComponentName;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -34,14 +35,15 @@
     int addClient(in IAutoFillManagerClient client, int userId);
     int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
             in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
-            String packageName);
+            in ComponentName componentName);
     FillEventHistory getFillEventHistory();
     boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback);
     void updateSession(int sessionId, in AutofillId id, in Rect bounds,
             in AutofillValue value, int action, int flags, int userId);
     int updateOrRestartSession(IBinder activityToken, in IBinder appCallback,
             in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
-            boolean hasCallback, int flags, String packageName, int sessionId, int action);
+            boolean hasCallback, int flags, in ComponentName componentName, int sessionId,
+            int action);
     void finishSession(int sessionId, int userId);
     void cancelSession(int sessionId, int userId);
     void setAuthenticationResult(in Bundle data, int sessionId, int authenticationId, int userId);
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 733ffb1..4813b4c 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -457,6 +457,22 @@
 
     uninit();
 
+    // The chunk must be at least the size of the string pool header.
+    if (size < sizeof(ResStringPool_header)) {
+        ALOGW("Bad string block: data size %zu is too small to be a string block", size);
+        return (mError=BAD_TYPE);
+    }
+
+    // The data is at least as big as a ResChunk_header, so we can safely validate the other
+    // header fields.
+    // `data + size` is safe because the source of `size` comes from the kernel/filesystem.
+    if (validate_chunk(reinterpret_cast<const ResChunk_header*>(data), sizeof(ResStringPool_header),
+                       reinterpret_cast<const uint8_t*>(data) + size,
+                       "ResStringPool_header") != NO_ERROR) {
+        ALOGW("Bad string block: malformed block dimensions");
+        return (mError=BAD_TYPE);
+    }
+
     const bool notDeviceEndian = htods(0xf0) != 0xf0;
 
     if (copyData || notDeviceEndian) {
@@ -468,6 +484,8 @@
         data = mOwnedData;
     }
 
+    // The size has been checked, so it is safe to read the data in the ResStringPool_header
+    // data structure.
     mHeader = (const ResStringPool_header*)data;
 
     if (notDeviceEndian) {
@@ -6558,8 +6576,16 @@
             }
 
         } else if (ctype == RES_TABLE_LIBRARY_TYPE) {
+
             if (group->dynamicRefTable.entries().size() == 0) {
-                status_t err = group->dynamicRefTable.load((const ResTable_lib_header*) chunk);
+                const ResTable_lib_header* lib = (const ResTable_lib_header*) chunk;
+                status_t err = validate_chunk(&lib->header, sizeof(*lib),
+                                              endPos, "ResTable_lib_header");
+                if (err != NO_ERROR) {
+                    return (mError=err);
+                }
+
+                err = group->dynamicRefTable.load(lib);
                 if (err != NO_ERROR) {
                     return (mError=err);
                 }
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 0d99473..f384ea5 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2363,10 +2363,10 @@
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mTrackType);
+            dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
             dest.writeString(getLanguage());
 
             if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
-                dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index cb4e46f..e66945b 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -323,7 +323,6 @@
     private final Uri mAudioUri;
     private final Uri mVideoUri;
     private final Uri mImagesUri;
-    private final Uri mThumbsUri;
     private final Uri mPlaylistsUri;
     private final Uri mFilesUri;
     private final Uri mFilesUriNoNotify;
@@ -419,7 +418,6 @@
         mAudioUri = Audio.Media.getContentUri(volumeName);
         mVideoUri = Video.Media.getContentUri(volumeName);
         mImagesUri = Images.Media.getContentUri(volumeName);
-        mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
         mFilesUri = Files.getContentUri(volumeName);
         mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
 
@@ -1283,53 +1281,6 @@
         }
     }
 
-    private void pruneDeadThumbnailFiles() {
-        HashSet<String> existingFiles = new HashSet<String>();
-        String directory = "/sdcard/DCIM/.thumbnails";
-        String [] files = (new File(directory)).list();
-        Cursor c = null;
-        if (files == null)
-            files = new String[0];
-
-        for (int i = 0; i < files.length; i++) {
-            String fullPathString = directory + "/" + files[i];
-            existingFiles.add(fullPathString);
-        }
-
-        try {
-            c = mMediaProvider.query(
-                    mThumbsUri,
-                    new String [] { "_data" },
-                    null,
-                    null,
-                    null, null);
-            Log.v(TAG, "pruneDeadThumbnailFiles... " + c);
-            if (c != null && c.moveToFirst()) {
-                do {
-                    String fullPathString = c.getString(0);
-                    existingFiles.remove(fullPathString);
-                } while (c.moveToNext());
-            }
-
-            for (String fileToDelete : existingFiles) {
-                if (false)
-                    Log.v(TAG, "fileToDelete is " + fileToDelete);
-                try {
-                    (new File(fileToDelete)).delete();
-                } catch (SecurityException ex) {
-                }
-            }
-
-            Log.v(TAG, "/pruneDeadThumbnailFiles... " + c);
-        } catch (RemoteException e) {
-            // We will soon be killed...
-        } finally {
-            if (c != null) {
-                c.close();
-            }
-        }
-    }
-
     static class MediaBulkDeleter {
         StringBuilder whereClause = new StringBuilder();
         ArrayList<String> whereArgs = new ArrayList<String>(100);
@@ -1373,9 +1324,6 @@
             processPlayLists();
         }
 
-        if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external")))
-            pruneDeadThumbnailFiles();
-
         // allow GC to clean up
         mPlayLists.clear();
     }
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index 664308c..9899367 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -44,13 +44,14 @@
  */
 public class MiniThumbFile {
     private static final String TAG = "MiniThumbFile";
-    private static final int MINI_THUMB_DATA_FILE_VERSION = 3;
+    private static final int MINI_THUMB_DATA_FILE_VERSION = 4;
     public static final int BYTES_PER_MINTHUMB = 10000;
     private static final int HEADER_SIZE = 1 + 8 + 4;
     private Uri mUri;
     private RandomAccessFile mMiniThumbFile;
     private FileChannel mChannel;
     private ByteBuffer mBuffer;
+    private ByteBuffer mEmptyBuffer;
     private static final Hashtable<String, MiniThumbFile> sThumbFiles =
         new Hashtable<String, MiniThumbFile>();
 
@@ -127,9 +128,10 @@
         return mMiniThumbFile;
     }
 
-    public MiniThumbFile(Uri uri) {
+    private MiniThumbFile(Uri uri) {
         mUri = uri;
         mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
+        mEmptyBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
     }
 
     public synchronized void deactivate() {
@@ -184,6 +186,54 @@
         return 0;
     }
 
+    public synchronized void eraseMiniThumb(long id) {
+        RandomAccessFile r = miniThumbDataFile();
+        if (r != null) {
+            long pos = id * BYTES_PER_MINTHUMB;
+            FileLock lock = null;
+            try {
+                mBuffer.clear();
+                mBuffer.limit(1 + 8);
+
+                lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false);
+                // check that we can read the following 9 bytes
+                // (1 for the "status" and 8 for the long)
+                if (mChannel.read(mBuffer, pos) == 9) {
+                    mBuffer.position(0);
+                    if (mBuffer.get() == 1) {
+                        long currentMagic = mBuffer.getLong();
+                        if (currentMagic == 0) {
+                            // there is no thumbnail stored here
+                            Log.i(TAG, "no thumbnail for id " + id);
+                            return;
+                        }
+                        // zero out the thumbnail slot
+                        // Log.v(TAG, "clearing slot " + id + ", magic " + currentMagic
+                        //         + " at offset " + pos);
+                        mChannel.write(mEmptyBuffer, pos);
+                    }
+                } else {
+                    // Log.v(TAG, "No slot");
+                }
+            } catch (IOException ex) {
+                Log.v(TAG, "Got exception checking file magic: ", ex);
+            } catch (RuntimeException ex) {
+                // Other NIO related exception like disk full, read only channel..etc
+                Log.e(TAG, "Got exception when reading magic, id = " + id +
+                        ", disk full or mount read-only? " + ex.getClass());
+            } finally {
+                try {
+                    if (lock != null) lock.release();
+                }
+                catch (IOException ex) {
+                    // ignore it.
+                }
+            }
+        } else {
+            // Log.v(TAG, "No data file");
+        }
+    }
+
     public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic)
             throws IOException {
         RandomAccessFile r = miniThumbDataFile();
diff --git a/packages/Osu/src/com/android/hotspot2/flow/OSUInfo.java b/packages/Osu/src/com/android/hotspot2/flow/OSUInfo.java
index 401eccb..ae47ddd 100644
--- a/packages/Osu/src/com/android/hotspot2/flow/OSUInfo.java
+++ b/packages/Osu/src/com/android/hotspot2/flow/OSUInfo.java
@@ -42,6 +42,7 @@
     private HSIconFileElement mIconFileElement;
     private String mIconFileName;
     private IconInfo mIconInfo;
+    private int mIconIndex;
 
     public OSUInfo(ScanResult scanResult, OSUProvider osuProvider, int osuID) {
         mOsuID = osuID;
@@ -50,6 +51,7 @@
         mAnqpDomID = scanResult.anqpDomainId;
         mAdvertisingSSID = scanResult.SSID;
         mOSUProvider = osuProvider;
+        mIconIndex = -1;
     }
 
     public long getOSUBssid() {
@@ -157,12 +159,15 @@
     public void setIconFileElement(HSIconFileElement iconFileElement, String fileName) {
         synchronized (mOSUProvider) {
             mIconFileElement = iconFileElement;
+            int index = 0;
             for (IconInfo iconInfo : mOSUProvider.getIcons()) {
                 if (iconInfo.getFileName().equals(fileName)) {
                     mIconInfo = iconInfo;
                     mIconFileName = fileName;
+                    mIconIndex = index;
                     break;
                 }
+                index++;
             }
             mIconStatus = IconStatus.Available;
         }
@@ -285,9 +290,9 @@
             return;
         }
         mIconFileElement = new HSIconFileElement(in);
-        int iconIndex = in.readInt();
-        mIconInfo = iconIndex >= 0 && iconIndex < mOSUProvider.getIcons().size()
-                ? mOSUProvider.getIcons().get(iconIndex) : null;
+        mIconIndex = in.readInt();
+        mIconInfo = mIconIndex >= 0 && mIconIndex < mOSUProvider.getIcons().size()
+                ? mOSUProvider.getIcons().get(mIconIndex) : null;
     }
 
     public static final Parcelable.Creator<OSUInfo> CREATOR = new Parcelable.Creator<OSUInfo>() {
@@ -317,5 +322,6 @@
         dest.writeInt(mIconStatus.ordinal());
         mOSUProvider.writeParcel(dest);
         mIconFileElement.writeParcel(dest);
+        dest.writeInt(mIconIndex);
     }
 }
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index a27515c..3cadff2 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4006,6 +4006,19 @@
     // OS: O
     FIELD_NOTIFICATION_GROUP_SUMMARY = 947;
 
+    // An app attempted to forge a different component name in the AssisStructure that would be
+    // passed to the autofill service.
+    // OS: O (security patch)
+    // Package: Real package of the app being autofilled
+    // Tag FIELD_AUTOFILL_SERVICE: Package of the autofill service that processed the request
+    // TAG FIELD_AUTOFILL_FORGED_COMPONENT_NAME: Component name being forged
+    AUTOFILL_FORGED_COMPONENT_ATTEMPT = 948;
+
+    // FIELD - The component that an app tried tro forged.
+    // Type: string
+    // OS: O (security patch)
+    FIELD_AUTOFILL_FORGED_COMPONENT_NAME = 949;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // OPEN: Settings > System > Languages & input > Advanced > Lift to open camera
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 83dfccb..8b4076a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -34,6 +34,7 @@
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
 import android.app.UiAutomation;
+import android.appwidget.AppWidgetManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -82,6 +83,7 @@
 import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.ArraySet;
 import android.view.Display;
 import android.view.IWindow;
 import android.view.InputDevice;
@@ -110,10 +112,11 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IntPair;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 import com.android.server.policy.AccessibilityShortcutController;
 import com.android.server.statusbar.StatusBarManagerInternal;
-
+import libcore.util.EmptyArray;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.FileDescriptor;
@@ -199,6 +202,8 @@
 
     private final WindowManagerInternal mWindowManagerService;
 
+    private AppWidgetManagerInternal mAppWidgetService;
+
     private final SecurityPolicy mSecurityPolicy;
 
     private final MainHandler mMainHandler;
@@ -229,10 +234,10 @@
     private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
             new RemoteCallbackList<>();
 
-    private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
+    private final SparseArray<RemoteAccessibilityConnection> mGlobalInteractionConnections =
             new SparseArray<>();
 
-    private AccessibilityConnectionWrapper mPictureInPictureActionReplacingConnection;
+    private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection;
 
     private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<>();
 
@@ -501,6 +506,11 @@
             // performs the current profile parent resolution..
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+            // Make sure the reported package is one the caller has access to.
+            event.setPackageName(mSecurityPolicy.resolveValidReportedPackageLocked(
+                    event.getPackageName(), UserHandle.getCallingAppId(), resolvedUserId));
+
             // This method does nothing for a background user.
             if (resolvedUserId == mCurrentUserId) {
                 if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
@@ -627,30 +637,38 @@
 
     @Override
     public int addAccessibilityInteractionConnection(IWindow windowToken,
-            IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
+            IAccessibilityInteractionConnection connection, String packageName,
+            int userId) throws RemoteException {
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
             // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+            final int resolvedUid = UserHandle.getUid(resolvedUserId, UserHandle.getCallingAppId());
+
+            // Make sure the reported package is one the caller has access to.
+            packageName = mSecurityPolicy.resolveValidReportedPackageLocked(
+                    packageName, UserHandle.getCallingAppId(), resolvedUserId);
+
             final int windowId = sNextWindowId++;
             // If the window is from a process that runs across users such as
             // the system UI or the system we add it to the global state that
             // is shared across users.
             if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
-                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
-                        windowId, connection, UserHandle.USER_ALL);
+                RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
+                        windowId, connection, packageName, resolvedUid, UserHandle.USER_ALL);
                 wrapper.linkToDeath();
                 mGlobalInteractionConnections.put(windowId, wrapper);
                 mGlobalWindowTokens.put(windowId, windowToken.asBinder());
                 if (DEBUG) {
                     Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid()
-                            + " with windowId: " + windowId + " and  token: " + windowToken.asBinder());
+                            + " with windowId: " + windowId + " and  token: "
+                            + windowToken.asBinder());
                 }
             } else {
-                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
-                        windowId, connection, resolvedUserId);
+                RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
+                        windowId, connection, packageName, resolvedUid, resolvedUserId);
                 wrapper.linkToDeath();
                 UserState userState = getUserStateLocked(resolvedUserId);
                 userState.mInteractionConnections.put(windowId, wrapper);
@@ -679,7 +697,8 @@
             if (removedWindowId >= 0) {
                 if (DEBUG) {
                     Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid()
-                            + " with windowId: " + removedWindowId + " and token: " + window.asBinder());
+                            + " with windowId: " + removedWindowId + " and token: "
+                            + window.asBinder());
                 }
                 return;
             }
@@ -703,13 +722,13 @@
 
     private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken,
             SparseArray<IBinder> windowTokens,
-            SparseArray<AccessibilityConnectionWrapper> interactionConnections) {
+            SparseArray<RemoteAccessibilityConnection> interactionConnections) {
         final int count = windowTokens.size();
         for (int i = 0; i < count; i++) {
             if (windowTokens.valueAt(i) == windowToken) {
                 final int windowId = windowTokens.keyAt(i);
                 windowTokens.removeAt(i);
-                AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId);
+                RemoteAccessibilityConnection wrapper = interactionConnections.get(windowId);
                 wrapper.unlinkToDeath();
                 interactionConnections.remove(windowId);
                 return windowId;
@@ -729,9 +748,9 @@
                 mPictureInPictureActionReplacingConnection = null;
             }
             if (connection != null) {
-                AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
+                RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
                         AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID,
-                        connection, UserHandle.USER_ALL);
+                        connection, "foo.bar.baz", Process.SYSTEM_UID, UserHandle.USER_ALL);
                 mPictureInPictureActionReplacingConnection = wrapper;
                 wrapper.linkToDeath();
             }
@@ -2023,7 +2042,8 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                        Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null, userState.mUserId);
+                        Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null,
+                        userState.mUserId);
 
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
                         Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId);
@@ -2354,18 +2374,35 @@
         }
     }
 
-    private class AccessibilityConnectionWrapper implements DeathRecipient {
+    class RemoteAccessibilityConnection implements DeathRecipient {
+        private final int mUid;
+        private final String mPackageName;
         private final int mWindowId;
         private final int mUserId;
         private final IAccessibilityInteractionConnection mConnection;
 
-        public AccessibilityConnectionWrapper(int windowId,
-                IAccessibilityInteractionConnection connection, int userId) {
+        RemoteAccessibilityConnection(int windowId,
+                IAccessibilityInteractionConnection connection,
+                String packageName, int uid, int userId) {
             mWindowId = windowId;
+            mPackageName = packageName;
+            mUid = uid;
             mUserId = userId;
             mConnection = connection;
         }
 
+        public int getUid() {
+            return  mUid;
+        }
+
+        public String getPackageName() {
+            return mPackageName;
+        }
+
+        public IAccessibilityInteractionConnection getRemote() {
+            return mConnection;
+        }
+
         public void linkToDeath() throws RemoteException {
             mConnection.asBinder().linkToDeath(this, 0);
         }
@@ -3041,28 +3078,28 @@
         }
 
         @Override
-        public boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
+        public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
                 long accessibilityNodeId, String viewIdResName, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
             final int resolvedWindowId;
-            IAccessibilityInteractionConnection connection = null;
+            RemoteAccessibilityConnection connection = null;
             Region partialInteractiveRegion = Region.obtain();
             MagnificationSpec spec;
             synchronized (mLock) {
                 mUsesAccessibilityCache = true;
                 if (!isCalledForCurrentUserLocked()) {
-                    return false;
+                    return null;
                 }
                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
                 final boolean permissionGranted =
                         mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
-                    return false;
+                    return null;
                 } else {
                     connection = getConnectionLocked(resolvedWindowId);
                     if (connection == null) {
-                        return false;
+                        return null;
                     }
                 }
                 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -3075,12 +3112,14 @@
             final int interrogatingPid = Binder.getCallingPid();
             callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                     interrogatingPid, interrogatingTid);
+            final int callingUid = Binder.getCallingUid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId, viewIdResName,
-                        partialInteractiveRegion, interactionId, callback, mFetchFlags,
-                        interrogatingPid, interrogatingTid, spec);
-                return true;
+                connection.getRemote().findAccessibilityNodeInfosByViewId(accessibilityNodeId,
+                        viewIdResName, partialInteractiveRegion, interactionId, callback,
+                        mFetchFlags, interrogatingPid, interrogatingTid, spec);
+                return mSecurityPolicy.computeValidReportedPackages(callingUid,
+                        connection.getPackageName(), connection.getUid());
             } catch (RemoteException re) {
                 if (DEBUG) {
                     Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
@@ -3088,36 +3127,36 @@
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
                 // Recycle if passed to another process.
-                if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+                if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
                     partialInteractiveRegion.recycle();
                 }
             }
-            return false;
+            return null;
         }
 
         @Override
-        public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId,
+        public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId,
                 long accessibilityNodeId, String text, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
             final int resolvedWindowId;
-            IAccessibilityInteractionConnection connection = null;
+            RemoteAccessibilityConnection connection = null;
             Region partialInteractiveRegion = Region.obtain();
             MagnificationSpec spec;
             synchronized (mLock) {
                 mUsesAccessibilityCache = true;
                 if (!isCalledForCurrentUserLocked()) {
-                    return false;
+                    return null;
                 }
                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
-                    return false;
+                    return null;
                 } else {
                     connection = getConnectionLocked(resolvedWindowId);
                     if (connection == null) {
-                        return false;
+                        return null;
                     }
                 }
                 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -3130,12 +3169,14 @@
             final int interrogatingPid = Binder.getCallingPid();
             callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                     interrogatingPid, interrogatingTid);
+            final int callingUid = Binder.getCallingUid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
+                connection.getRemote().findAccessibilityNodeInfosByText(accessibilityNodeId, text,
                         partialInteractiveRegion, interactionId, callback, mFetchFlags,
                         interrogatingPid, interrogatingTid, spec);
-                return true;
+                return mSecurityPolicy.computeValidReportedPackages(callingUid,
+                        connection.getPackageName(), connection.getUid());
             } catch (RemoteException re) {
                 if (DEBUG) {
                     Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
@@ -3143,36 +3184,36 @@
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
                 // Recycle if passed to another process.
-                if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+                if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
                     partialInteractiveRegion.recycle();
                 }
             }
-            return false;
+            return null;
         }
 
         @Override
-        public boolean findAccessibilityNodeInfoByAccessibilityId(
+        public String[] findAccessibilityNodeInfoByAccessibilityId(
                 int accessibilityWindowId, long accessibilityNodeId, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
                 long interrogatingTid, Bundle arguments) throws RemoteException {
             final int resolvedWindowId;
-            IAccessibilityInteractionConnection connection = null;
+            RemoteAccessibilityConnection connection = null;
             Region partialInteractiveRegion = Region.obtain();
             MagnificationSpec spec;
             synchronized (mLock) {
                 mUsesAccessibilityCache = true;
                 if (!isCalledForCurrentUserLocked()) {
-                    return false;
+                    return null;
                 }
                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
-                    return false;
+                    return null;
                 } else {
                     connection = getConnectionLocked(resolvedWindowId);
                     if (connection == null) {
-                        return false;
+                        return null;
                     }
                 }
                 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -3185,12 +3226,14 @@
             final int interrogatingPid = Binder.getCallingPid();
             callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                     interrogatingPid, interrogatingTid);
+            final int callingUid = Binder.getCallingUid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
-                        partialInteractiveRegion, interactionId, callback, mFetchFlags | flags,
-                        interrogatingPid, interrogatingTid, spec, arguments);
-                return true;
+                connection.getRemote().findAccessibilityNodeInfoByAccessibilityId(
+                        accessibilityNodeId, partialInteractiveRegion, interactionId, callback,
+                        mFetchFlags | flags, interrogatingPid, interrogatingTid, spec, arguments);
+                return mSecurityPolicy.computeValidReportedPackages(callingUid,
+                        connection.getPackageName(), connection.getUid());
             } catch (RemoteException re) {
                 if (DEBUG) {
                     Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
@@ -3198,36 +3241,36 @@
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
                 // Recycle if passed to another process.
-                if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+                if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
                     partialInteractiveRegion.recycle();
                 }
             }
-            return false;
+            return null;
         }
 
         @Override
-        public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId,
+        public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId,
                 int focusType, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
             final int resolvedWindowId;
-            IAccessibilityInteractionConnection connection = null;
+            RemoteAccessibilityConnection connection = null;
             Region partialInteractiveRegion = Region.obtain();
             MagnificationSpec spec;
             synchronized (mLock) {
                 if (!isCalledForCurrentUserLocked()) {
-                    return false;
+                    return null;
                 }
                 resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
                         accessibilityWindowId, focusType);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
-                    return false;
+                    return null;
                 } else {
                     connection = getConnectionLocked(resolvedWindowId);
                     if (connection == null) {
-                        return false;
+                        return null;
                     }
                 }
                 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -3240,12 +3283,14 @@
             final int interrogatingPid = Binder.getCallingPid();
             callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                     interrogatingPid, interrogatingTid);
+            final int callingUid = Binder.getCallingUid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                connection.findFocus(accessibilityNodeId, focusType, partialInteractiveRegion,
-                        interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
-                        spec);
-                return true;
+                connection.getRemote().findFocus(accessibilityNodeId, focusType,
+                        partialInteractiveRegion, interactionId, callback, mFetchFlags,
+                        interrogatingPid, interrogatingTid, spec);
+                return mSecurityPolicy.computeValidReportedPackages(callingUid,
+                        connection.getPackageName(), connection.getUid());
             } catch (RemoteException re) {
                 if (DEBUG) {
                     Slog.e(LOG_TAG, "Error calling findFocus()");
@@ -3253,35 +3298,35 @@
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
                 // Recycle if passed to another process.
-                if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+                if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
                     partialInteractiveRegion.recycle();
                 }
             }
-            return false;
+            return null;
         }
 
         @Override
-        public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId,
+        public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId,
                 int direction, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
             final int resolvedWindowId;
-            IAccessibilityInteractionConnection connection = null;
+            RemoteAccessibilityConnection connection = null;
             Region partialInteractiveRegion = Region.obtain();
             MagnificationSpec spec;
             synchronized (mLock) {
                 if (!isCalledForCurrentUserLocked()) {
-                    return false;
+                    return null;
                 }
                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
-                    return false;
+                    return null;
                 } else {
                     connection = getConnectionLocked(resolvedWindowId);
                     if (connection == null) {
-                        return false;
+                        return null;
                     }
                 }
                 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
@@ -3294,12 +3339,14 @@
             final int interrogatingPid = Binder.getCallingPid();
             callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                     interrogatingPid, interrogatingTid);
+            final int callingUid = Binder.getCallingUid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                connection.focusSearch(accessibilityNodeId, direction, partialInteractiveRegion,
-                        interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
-                        spec);
-                return true;
+                connection.getRemote().focusSearch(accessibilityNodeId, direction,
+                        partialInteractiveRegion, interactionId, callback, mFetchFlags,
+                        interrogatingPid, interrogatingTid, spec);
+                return mSecurityPolicy.computeValidReportedPackages(callingUid,
+                        connection.getPackageName(), connection.getUid());
             } catch (RemoteException re) {
                 if (DEBUG) {
                     Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
@@ -3307,11 +3354,11 @@
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
                 // Recycle if passed to another process.
-                if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+                if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
                     partialInteractiveRegion.recycle();
                 }
             }
-            return false;
+            return null;
         }
 
         @Override
@@ -3351,8 +3398,8 @@
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
             final int resolvedWindowId;
-            IAccessibilityInteractionConnection connection = null;
             IBinder activityToken = null;
+            RemoteAccessibilityConnection connection;
             synchronized (mLock) {
                 if (!isCalledForCurrentUserLocked()) {
                     return false;
@@ -3375,7 +3422,7 @@
                 if ((a11yWindowInfo != null) && a11yWindowInfo.inPictureInPicture()) {
                     if ((mPictureInPictureActionReplacingConnection != null)
                             && !isA11yFocusAction) {
-                        connection = mPictureInPictureActionReplacingConnection.mConnection;
+                        connection = mPictureInPictureActionReplacingConnection;
                     }
                 }
             }
@@ -3391,8 +3438,9 @@
                     LocalServices.getService(ActivityManagerInternal.class)
                             .setFocusedActivity(activityToken);
                 }
-                connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
-                        interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid);
+                connection.mConnection.performAccessibilityAction(accessibilityNodeId, action,
+                        arguments, interactionId, callback, mFetchFlags, interrogatingPid,
+                        interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
                     Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
@@ -4072,16 +4120,16 @@
             LocalServices.getService(StatusBarManagerInternal.class).toggleSplitScreen();
         }
 
-        private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
+        private RemoteAccessibilityConnection getConnectionLocked(int windowId) {
             if (DEBUG) {
                 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
             }
-            AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId);
+            RemoteAccessibilityConnection wrapper = mGlobalInteractionConnections.get(windowId);
             if (wrapper == null) {
                 wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
             }
             if (wrapper != null && wrapper.mConnection != null) {
-                return wrapper.mConnection;
+                return wrapper;
             }
             if (DEBUG) {
                 Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
@@ -4230,6 +4278,16 @@
         }
     }
 
+    private AppWidgetManagerInternal getAppWidgetManager() {
+        synchronized (mLock) {
+            if (mAppWidgetService == null
+                    && mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
+                mAppWidgetService = LocalServices.getService(AppWidgetManagerInternal.class);
+            }
+            return mAppWidgetService;
+        }
+    }
+
     final class WindowsForAccessibilityCallback implements
             WindowManagerInternal.WindowsForAccessibilityCallback {
 
@@ -4507,6 +4565,81 @@
             }
         }
 
+        private boolean isValidPackageForUid(String packageName, int uid) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return uid == mPackageManager.getPackageUid(
+                        packageName, UserHandle.getUserId(uid));
+            } catch (PackageManager.NameNotFoundException e) {
+                return false;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        String resolveValidReportedPackageLocked(CharSequence packageName, int appId, int userId) {
+            // Okay to pass no package
+            if (packageName == null) {
+                return null;
+            }
+            // The system gets to pass any package
+            if (appId == Process.SYSTEM_UID) {
+                return packageName.toString();
+            }
+            // Passing a package in your UID is fine
+            final String packageNameStr = packageName.toString();
+            final int resolvedUid = UserHandle.getUid(userId, appId);
+            if (isValidPackageForUid(packageNameStr, resolvedUid)) {
+                return packageName.toString();
+            }
+            // Appwidget hosts get to pass packages for widgets they host
+            final AppWidgetManagerInternal appWidgetManager = getAppWidgetManager();
+            if (appWidgetManager != null && ArrayUtils.contains(appWidgetManager
+                            .getHostedWidgetPackages(resolvedUid), packageNameStr)) {
+                return packageName.toString();
+            }
+            // Otherwise, set the package to the first one in the UID
+            final String[] packageNames = mPackageManager.getPackagesForUid(resolvedUid);
+            if (ArrayUtils.isEmpty(packageNames)) {
+                return null;
+            }
+            // Okay, the caller reported a package it does not have access to.
+            // Instead of crashing the caller for better backwards compatibility
+            // we report the first package in the UID. Since most of the time apps
+            // don't use shared user id, this will yield correct results and for
+            // the edge case of using a shared user id we may report the wrong
+            // package but this is fine since first, this is a cheating app and
+            // second there is no way to get the correct package anyway.
+            return packageNames[0];
+        }
+
+        String[] computeValidReportedPackages(int callingUid,
+                String targetPackage, int targetUid) {
+            if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
+                // Empty array means any package is Okay
+                return EmptyArray.STRING;
+            }
+            // IMPORTANT: The target package is already vetted to be in the target UID
+            String[] uidPackages = new String[]{targetPackage};
+            // Appwidget hosts get to pass packages for widgets they host
+            final AppWidgetManagerInternal appWidgetManager = getAppWidgetManager();
+            if (appWidgetManager != null) {
+                final ArraySet<String> widgetPackages = appWidgetManager
+                        .getHostedWidgetPackages(targetUid);
+                if (widgetPackages != null && !widgetPackages.isEmpty()) {
+                    final String[] validPackages = new String[uidPackages.length
+                            + widgetPackages.size()];
+                    System.arraycopy(uidPackages, 0, validPackages, 0, uidPackages.length);
+                    final int widgetPackageCount = widgetPackages.size();
+                    for (int i = 0; i < widgetPackageCount; i++) {
+                        validPackages[uidPackages.length + i] = widgetPackages.valueAt(i);
+                    }
+                    return validPackages;
+                }
+            }
+            return uidPackages;
+        }
+
         public void clearWindowsLocked() {
             List<WindowInfo> windows = Collections.emptyList();
             final int activeWindowId = mActiveWindowId;
@@ -4932,7 +5065,7 @@
         public final RemoteCallbackList<IAccessibilityManagerClient> mUserClients =
             new RemoteCallbackList<>();
 
-        public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections =
+        public final SparseArray<RemoteAccessibilityConnection> mInteractionConnections =
                 new SparseArray<>();
 
         public final SparseArray<IBinder> mWindowTokens = new SparseArray<>();
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 80b5477..a57010b 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -29,6 +29,7 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
 import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetManagerInternal;
 import android.appwidget.AppWidgetProviderInfo;
 import android.appwidget.PendingHostUpdate;
 import android.content.BroadcastReceiver;
@@ -99,6 +100,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.widget.IRemoteViewsAdapterConnection;
 import com.android.internal.widget.IRemoteViewsFactory;
@@ -107,6 +109,7 @@
 import com.android.server.policy.IconUtilities;
 
 import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -256,6 +259,8 @@
         computeMaximumWidgetBitmapMemory();
         registerBroadcastReceiver();
         registerOnCrossProfileProvidersChangedListener();
+
+        LocalServices.addService(AppWidgetManagerInternal.class, new AppWidgetManagerLocal());
     }
 
     private void computeMaximumWidgetBitmapMemory() {
@@ -4709,4 +4714,24 @@
             }
         }
     }
+
+    private class AppWidgetManagerLocal extends AppWidgetManagerInternal {
+        @Override
+        public ArraySet<String> getHostedWidgetPackages(int uid) {
+            synchronized (mLock) {
+                ArraySet<String> widgetPackages = null;
+                final int widgetCount = mWidgets.size();
+                for (int i = 0; i < widgetCount; i++) {
+                    final Widget widget = mWidgets.get(i);
+                    if  (widget.host.id.uid == uid) {
+                        if (widgetPackages == null) {
+                            widgetPackages = new ArraySet<>();
+                        }
+                        widgetPackages.add(widget.provider.id.componentName.getPackageName());
+                    }
+                }
+                return widgetPackages;
+            }
+        }
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 1f4161ac..ffc778a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -533,25 +533,26 @@
         @Override
         public int startSession(IBinder activityToken, IBinder appCallback, AutofillId autofillId,
                 Rect bounds, AutofillValue value, int userId, boolean hasCallback, int flags,
-                String packageName) {
+                ComponentName componentName) {
 
             activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
             appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
             autofillId = Preconditions.checkNotNull(autofillId, "autoFillId");
-            packageName = Preconditions.checkNotNull(packageName, "packageName");
+            componentName = Preconditions.checkNotNull(componentName, "componentName");
+            final String packageName = Preconditions.checkNotNull(componentName.getPackageName());
 
             Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId");
 
             try {
                 mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId);
             } catch (PackageManager.NameNotFoundException e) {
-                throw new IllegalArgumentException(packageName + " is not a valid package", e);
+                throw new IllegalArgumentException(componentName + " is not a valid package", e);
             }
 
             synchronized (mLock) {
                 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
                 return service.startSessionLocked(activityToken, getCallingUid(), appCallback,
-                        autofillId, bounds, value, hasCallback, flags, packageName);
+                        autofillId, bounds, value, hasCallback, flags, componentName);
             }
         }
 
@@ -603,7 +604,8 @@
         @Override
         public int updateOrRestartSession(IBinder activityToken, IBinder appCallback,
                 AutofillId autoFillId, Rect bounds, AutofillValue value, int userId,
-                boolean hasCallback, int flags, String packageName, int sessionId, int action) {
+                boolean hasCallback, int flags, ComponentName componentName, int sessionId,
+                int action) {
             boolean restart = false;
             synchronized (mLock) {
                 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
@@ -614,7 +616,7 @@
             }
             if (restart) {
                 return startSession(activityToken, appCallback, autoFillId, bounds, value, userId,
-                        hasCallback, flags, packageName);
+                        hasCallback, flags, componentName);
             }
 
             // Nothing changed...
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 3a3b570..6d3398e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -26,12 +26,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ServiceInfo;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -43,6 +45,7 @@
 import android.os.Looper;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.service.autofill.AutofillService;
@@ -67,6 +70,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.os.HandlerCaller;
+import com.android.server.LocalServices;
 import com.android.server.autofill.ui.AutoFillUI;
 
 import java.io.PrintWriter;
@@ -279,7 +283,7 @@
     int startSessionLocked(@NonNull IBinder activityToken, int uid,
             @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
             @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
-            int flags, @NonNull String packageName) {
+            int flags, @NonNull ComponentName componentName) {
         if (!isEnabled()) {
             return 0;
         }
@@ -289,7 +293,7 @@
         pruneAbandonedSessionsLocked();
 
         final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
-                hasCallback, packageName);
+                hasCallback, componentName);
         if (newSession == null) {
             return NO_SESSION;
         }
@@ -386,7 +390,8 @@
     }
 
     private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
-            @NonNull IBinder appCallbackToken, boolean hasCallback, @NonNull String packageName) {
+            @NonNull IBinder appCallbackToken, boolean hasCallback,
+            @NonNull ComponentName componentName) {
         // use random ids so that one app cannot know that another app creates sessions
         int sessionId;
         int tries = 0;
@@ -400,15 +405,45 @@
             sessionId = sRandom.nextInt();
         } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0);
 
+        assertCallerLocked(componentName);
+
         final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
                 sessionId, uid, activityToken, appCallbackToken, hasCallback,
-                mUiLatencyHistory, mInfo.getServiceInfo().getComponentName(), packageName);
+                mUiLatencyHistory, mInfo.getServiceInfo().getComponentName(), componentName);
         mSessions.put(newSession.id, newSession);
 
         return newSession;
     }
 
     /**
+     * Asserts the component is owned by the caller.
+     */
+    private void assertCallerLocked(@NonNull ComponentName componentName) {
+        final String packageName = componentName.getPackageName();
+        final PackageManager pm = mContext.getPackageManager();
+        final int callingUid = Binder.getCallingUid();
+        final int packageUid;
+        try {
+            packageUid = pm.getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
+        } catch (NameNotFoundException e) {
+            throw new SecurityException("Could not verify UID for " + componentName);
+        }
+        if (callingUid != packageUid && !LocalServices.getService(ActivityManagerInternal.class)
+                .hasRunningActivity(callingUid, packageName)) {
+            final String[] packages = pm.getPackagesForUid(callingUid);
+            final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid;
+            Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid
+                    + ") passed component (" + componentName + ") owned by UID " + packageUid);
+            mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT)
+                    .setPackageName(callingPackage)
+                    .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
+                    .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME,
+                            componentName == null ? "null" : componentName.flattenToShortString()));
+            throw new SecurityException("Invalid component: " + componentName);
+        }
+    }
+
+    /**
      * Restores a session after an activity was temporarily destroyed.
      *
      * @param sessionId The id of the session to restore
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index de2950d..1f0e51c 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -126,8 +126,8 @@
     @GuardedBy("mLock")
     @NonNull private IBinder mActivityToken;
 
-    /** Package name of the app that is auto-filled */
-    @NonNull private final String mPackageName;
+    /** Component that's being auto-filled */
+    @NonNull private final ComponentName mComponentName;
 
     @GuardedBy("mLock")
     private final ArrayMap<AutofillId, ViewState> mViewStates = new ArrayMap<>();
@@ -227,6 +227,16 @@
                 structure.ensureData();
 
                 // Sanitize structure before it's sent to service.
+                final ComponentName componentNameFromApp = structure.getActivityComponent();
+                if (!mComponentName.equals(componentNameFromApp)) {
+                    Slog.w(TAG, "Activity " + mComponentName + " forged different component on "
+                            + "AssistStructure: " + componentNameFromApp);
+                    structure.setActivityComponent(mComponentName);
+                    mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT)
+                            .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME,
+                                            componentNameFromApp == null ? "null"
+                                                    : componentNameFromApp.flattenToShortString()));
+                }
                 structure.sanitizeForParceling(true);
 
                 // Flags used to start the session.
@@ -415,7 +425,7 @@
             @NonNull Context context, @NonNull HandlerCaller handlerCaller, int userId,
             @NonNull Object lock, int sessionId, int uid, @NonNull IBinder activityToken,
             @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
-            @NonNull ComponentName componentName, @NonNull String packageName) {
+            @NonNull ComponentName serviceComponentName, @NonNull ComponentName appComponentName) {
         id = sessionId;
         this.uid = uid;
         mStartTime = SystemClock.elapsedRealtime();
@@ -423,11 +433,11 @@
         mLock = lock;
         mUi = ui;
         mHandlerCaller = handlerCaller;
-        mRemoteFillService = new RemoteFillService(context, componentName, userId, this);
+        mRemoteFillService = new RemoteFillService(context, serviceComponentName, userId, this);
         mActivityToken = activityToken;
         mHasCallback = hasCallback;
         mUiLatencyHistory = uiLatencyHistory;
-        mPackageName = packageName;
+        mComponentName = appComponentName;
         mClient = IAutoFillManagerClient.Stub.asInterface(client);
 
         writeLog(MetricsEvent.AUTOFILL_SESSION_STARTED);
@@ -1008,8 +1018,8 @@
                 final IAutoFillManagerClient client = getClient();
                 mPendingSaveUi = new PendingUi(mActivityToken, id, client);
                 getUiForShowing().showSaveUi(mService.getServiceLabel(), mService.getServiceIcon(),
-                        mService.getServicePackageName(), saveInfo, valueFinder, mPackageName, this,
-                        mPendingSaveUi);
+                        mService.getServicePackageName(), saveInfo, valueFinder,
+                        mComponentName.getPackageName(), this, mPendingSaveUi);
                 if (client != null) {
                     try {
                         client.setSaveUiState(id, true);
@@ -1365,7 +1375,7 @@
         }
 
         getUiForShowing().showFillUi(filledId, response, filterText,
-                mService.getServicePackageName(), mPackageName, this);
+                mService.getServicePackageName(), mComponentName.getPackageName(), this);
 
         synchronized (mLock) {
             if (mUiShownTime == 0) {
@@ -1690,14 +1700,14 @@
 
     @Override
     public String toString() {
-        return "Session: [id=" + id + ", pkg=" + mPackageName + "]";
+        return "Session: [id=" + id + ", pkg=" + mComponentName.getPackageName() + "]";
     }
 
     void dumpLocked(String prefix, PrintWriter pw) {
         final String prefix2 = prefix + "  ";
         pw.print(prefix); pw.print("id: "); pw.println(id);
         pw.print(prefix); pw.print("uid: "); pw.println(uid);
-        pw.print(prefix); pw.print("mPackagename: "); pw.println(mPackageName);
+        pw.print(prefix); pw.print("mComponentName: "); pw.println(mComponentName);
         pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
         pw.print(prefix); pw.print("mStartTime: "); pw.println(mStartTime);
         pw.print(prefix); pw.print("Time to show UI: ");
@@ -1920,7 +1930,7 @@
     }
 
     private LogMaker newLogMaker(int category, String servicePackageName) {
-        return Helper.newLogMaker(category, mPackageName, servicePackageName);
+        return Helper.newLogMaker(category, mComponentName.getPackageName(), servicePackageName);
     }
 
     private void writeLog(int category) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c1801b8..6e8c0d4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -969,7 +969,7 @@
         if (!mLockdownEnabled) {
             int user = UserHandle.getUserId(uid);
             synchronized (mVpns) {
-                Vpn vpn = mVpns.get(user);
+                Vpn vpn = getVpn(user);
                 if (vpn != null && vpn.appliesToUid(uid)) {
                     return vpn.getUnderlyingNetworks();
                 }
@@ -1017,7 +1017,7 @@
             return false;
         }
         synchronized (mVpns) {
-            final Vpn vpn = mVpns.get(UserHandle.getUserId(uid));
+            final Vpn vpn = getVpn(UserHandle.getUserId(uid));
             if (vpn != null && vpn.isBlockingUid(uid)) {
                 return true;
             }
@@ -1094,7 +1094,7 @@
         final int user = UserHandle.getUserId(uid);
         int vpnNetId = NETID_UNSET;
         synchronized (mVpns) {
-            final Vpn vpn = mVpns.get(user);
+            final Vpn vpn = getVpn(user);
             if (vpn != null && vpn.appliesToUid(uid)) vpnNetId = vpn.getNetId();
         }
         NetworkAgentInfo nai;
@@ -1224,7 +1224,7 @@
 
         if (!mLockdownEnabled) {
             synchronized (mVpns) {
-                Vpn vpn = mVpns.get(userId);
+                Vpn vpn = getVpn(userId);
                 if (vpn != null) {
                     Network[] networks = vpn.getUnderlyingNetworks();
                     if (networks != null) {
@@ -1339,7 +1339,17 @@
     public boolean isActiveNetworkMetered() {
         enforceAccessPermission();
 
-        final int uid = Binder.getCallingUid();
+        return isActiveNetworkMeteredCommon(Binder.getCallingUid());
+    }
+
+    @Override
+    public boolean isActiveNetworkMeteredForUid(int uid) {
+        enforceConnectivityInternalPermission();
+
+        return isActiveNetworkMeteredCommon(uid);
+    }
+
+    private boolean isActiveNetworkMeteredCommon(int uid) {
         final NetworkCapabilities caps = getUnfilteredActiveNetworkState(uid).networkCapabilities;
         if (caps != null) {
             return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
@@ -3414,7 +3424,7 @@
         throwIfLockdownEnabled();
 
         synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
+            Vpn vpn = getVpn(userId);
             if (vpn != null) {
                 return vpn.prepare(oldPackage, newPackage);
             } else {
@@ -3441,7 +3451,7 @@
         enforceCrossUserPermission(userId);
 
         synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
+            Vpn vpn = getVpn(userId);
             if (vpn != null) {
                 vpn.setPackageAuthorization(packageName, authorized);
             }
@@ -3460,7 +3470,7 @@
         throwIfLockdownEnabled();
         int user = UserHandle.getUserId(Binder.getCallingUid());
         synchronized (mVpns) {
-            return mVpns.get(user).establish(config);
+            return getVpn(user).establish(config);
         }
     }
 
@@ -3477,7 +3487,7 @@
         }
         int user = UserHandle.getUserId(Binder.getCallingUid());
         synchronized (mVpns) {
-            mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress);
+            getVpn(user).startLegacyVpn(profile, mKeyStore, egress);
         }
     }
 
@@ -3491,7 +3501,7 @@
         enforceCrossUserPermission(userId);
 
         synchronized (mVpns) {
-            return mVpns.get(userId).getLegacyVpnInfo();
+            return getVpn(userId).getLegacyVpnInfo();
         }
     }
 
@@ -3555,7 +3565,7 @@
     public VpnConfig getVpnConfig(int userId) {
         enforceCrossUserPermission(userId);
         synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
+            Vpn vpn = getVpn(userId);
             if (vpn != null) {
                 return vpn.getVpnConfig();
             } else {
@@ -3589,7 +3599,7 @@
             }
             int user = UserHandle.getUserId(Binder.getCallingUid());
             synchronized (mVpns) {
-                Vpn vpn = mVpns.get(user);
+                Vpn vpn = getVpn(user);
                 if (vpn == null) {
                     Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
                     return false;
@@ -3636,7 +3646,7 @@
      */
     private boolean startAlwaysOnVpn(int userId) {
         synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
+            Vpn vpn = getVpn(userId);
             if (vpn == null) {
                 // Shouldn't happen as all codepaths that point here should have checked the Vpn
                 // exists already.
@@ -3654,7 +3664,7 @@
         enforceCrossUserPermission(userId);
 
         synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
+            Vpn vpn = getVpn(userId);
             if (vpn == null) {
                 Slog.w(TAG, "User " + userId + " has no Vpn configuration");
                 return false;
@@ -3674,7 +3684,7 @@
         }
 
         synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
+            Vpn vpn = getVpn(userId);
             if (vpn == null) {
                 Slog.w(TAG, "User " + userId + " has no Vpn configuration");
                 return false;
@@ -3696,7 +3706,7 @@
         enforceCrossUserPermission(userId);
 
         synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
+            Vpn vpn = getVpn(userId);
             if (vpn == null) {
                 Slog.w(TAG, "User " + userId + " has no Vpn configuration");
                 return null;
@@ -3842,22 +3852,38 @@
 
     private void onUserStart(int userId) {
         synchronized (mVpns) {
-            Vpn userVpn = mVpns.get(userId);
+            Vpn userVpn = getVpn(userId);
             if (userVpn != null) {
                 loge("Starting user already has a VPN");
                 return;
             }
             userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId);
-            mVpns.put(userId, userVpn);
+            setVpn(userId, userVpn);
         }
         if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
             updateLockdownVpn();
         }
     }
 
+    /** @hide */
+    @VisibleForTesting
+    Vpn getVpn(int userId) {
+        synchronized (mVpns) {
+            return mVpns.get(userId);
+        }
+    }
+
+    /** @hide */
+    @VisibleForTesting
+    void setVpn(int userId, Vpn userVpn) {
+        synchronized (mVpns) {
+            mVpns.put(userId, userVpn);
+        }
+    }
+
     private void onUserStop(int userId) {
         synchronized (mVpns) {
-            Vpn userVpn = mVpns.get(userId);
+            Vpn userVpn = getVpn(userId);
             if (userVpn == null) {
                 loge("Stopped user has no VPN");
                 return;
@@ -5429,7 +5455,7 @@
         throwIfLockdownEnabled();
         int user = UserHandle.getUserId(Binder.getCallingUid());
         synchronized (mVpns) {
-            return mVpns.get(user).addAddress(address, prefixLength);
+            return getVpn(user).addAddress(address, prefixLength);
         }
     }
 
@@ -5438,7 +5464,7 @@
         throwIfLockdownEnabled();
         int user = UserHandle.getUserId(Binder.getCallingUid());
         synchronized (mVpns) {
-            return mVpns.get(user).removeAddress(address, prefixLength);
+            return getVpn(user).removeAddress(address, prefixLength);
         }
     }
 
@@ -5448,7 +5474,7 @@
         int user = UserHandle.getUserId(Binder.getCallingUid());
         boolean success;
         synchronized (mVpns) {
-            success = mVpns.get(user).setUnderlyingNetworks(networks);
+            success = getVpn(user).setUnderlyingNetworks(networks);
         }
         if (success) {
             notifyIfacesChangedForNetworkStats();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1520b96..4a2d9c9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -24248,6 +24248,26 @@
                 }
             }
         }
+
+        @Override
+        public boolean hasRunningActivity(int uid, @Nullable String packageName) {
+            if (packageName == null) return false;
+
+            synchronized (ActivityManagerService.this) {
+                for (int i = 0; i < mLruProcesses.size(); i++) {
+                    final ProcessRecord processRecord = mLruProcesses.get(i);
+                    if (processRecord.uid == uid) {
+                        for (int j = 0; j < processRecord.activities.size(); j++) {
+                            final ActivityRecord activityRecord = processRecord.activities.get(j);
+                            if (packageName.equals(activityRecord.packageName)) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+            return false;
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 56cff7c..d51e1f7 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -94,8 +94,6 @@
 import com.android.server.LocalServices;
 import com.android.server.net.BaseNetworkObserver;
 
-import libcore.io.IoUtils;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -114,6 +112,8 @@
 import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import libcore.io.IoUtils;
+
 /**
  * @hide
  */
@@ -1184,6 +1184,18 @@
                     /* allowedApplications */ null,
                     /* disallowedApplications */ exemptedPackages);
 
+            // The UID range of the first user (0-99999) would block the IPSec traffic, which comes
+            // directly from the kernel and is marked as uid=0. So we adjust the range to allow
+            // it through (b/69873852).
+            for (UidRange range : addedRanges) {
+                if (range.start == 0) {
+                    addedRanges.remove(range);
+                    if (range.stop != 0) {
+                        addedRanges.add(new UidRange(1, range.stop));
+                    }
+                }
+            }
+
             removedRanges.removeAll(addedRanges);
             addedRanges.removeAll(mBlockedUsers);
         }
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 78367fe..4d5a920 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -112,10 +112,8 @@
         final boolean connected = (info != null) && info.isConnected();
         final boolean connectionUsable = connected && validated;
 
-        final boolean metered = connected && (capabilities != null)
-                && !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
-        final boolean unmetered = connected && (capabilities != null)
-                && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+        final boolean metered = connected && mConnManager.isActiveNetworkMeteredForUid(jobUid);
+        final boolean unmetered = connected && !mConnManager.isActiveNetworkMeteredForUid(jobUid);
         final boolean notRoaming = connected && (info != null)
                 && !info.isRoaming();
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 06600bf..d6b5728 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -184,6 +184,7 @@
 import android.graphics.Bitmap;
 import android.hardware.display.DisplayManager;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -5850,6 +5851,83 @@
     }
 
     /**
+     * We might auto-grant permissions if any permission of the group is already granted. Hence if
+     * the group of a granted permission changes we need to revoke it to avoid having permissions of
+     * the new group auto-granted.
+     *
+     * @param newPackage The new package that was installed
+     * @param oldPackage The old package that was updated
+     * @param allPackageNames All package names
+     */
+    private void revokeRuntimePermissionsIfGroupChanged(
+            PackageParser.Package newPackage,
+            PackageParser.Package oldPackage,
+            ArrayList<String> allPackageNames) {
+        final int numOldPackagePermissions = oldPackage.permissions.size();
+        final ArrayMap<String, String> oldPermissionNameToGroupName
+                = new ArrayMap<>(numOldPackagePermissions);
+
+        for (int i = 0; i < numOldPackagePermissions; i++) {
+            final PackageParser.Permission permission = oldPackage.permissions.get(i);
+
+            if (permission.group != null) {
+                oldPermissionNameToGroupName.put(permission.info.name,
+                        permission.group.info.name);
+            }
+        }
+
+        final int numNewPackagePermissions = newPackage.permissions.size();
+        for (int newPermissionNum = 0; newPermissionNum < numNewPackagePermissions;
+                newPermissionNum++) {
+            final PackageParser.Permission newPermission =
+                    newPackage.permissions.get(newPermissionNum);
+            final int newProtection = newPermission.info.protectionLevel;
+
+            if ((newProtection & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
+                final String permissionName = newPermission.info.name;
+                final String newPermissionGroupName =
+                        newPermission.group == null ? null : newPermission.group.info.name;
+                final String oldPermissionGroupName = oldPermissionNameToGroupName.get(
+                        permissionName);
+
+                if (newPermissionGroupName != null
+                        && !newPermissionGroupName.equals(oldPermissionGroupName)) {
+                    final List<UserInfo> users = mContext.getSystemService(UserManager.class)
+                            .getUsers();
+
+                    final int numUsers = users.size();
+                    for (int userNum = 0; userNum < numUsers; userNum++) {
+                        final int userId = users.get(userNum).id;
+                        final int numPackages = allPackageNames.size();
+
+                        for (int packageNum = 0; packageNum < numPackages; packageNum++) {
+                            final String packageName = allPackageNames.get(packageNum);
+
+                            if (checkPermission(permissionName, packageName, userId)
+                                    == PackageManager.PERMISSION_GRANTED) {
+                                EventLog.writeEvent(0x534e4554, "72710897",
+                                        newPackage.applicationInfo.uid,
+                                        "Revoking permission", permissionName, "from package",
+                                        packageName, "as the group changed from",
+                                        oldPermissionGroupName, "to", newPermissionGroupName);
+
+                                try {
+                                    revokeRuntimePermission(packageName, permissionName, userId,
+                                           false);
+                                } catch (IllegalArgumentException e) {
+                                    Slog.e(TAG, "Could not revoke " + permissionName + " from "
+                                            + packageName, e);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
      * Get the first event id for the permission.
      *
      * <p>There are four events for each permission: <ul>
@@ -10743,6 +10821,8 @@
         String primaryCpuAbiFromSettings = null;
         String secondaryCpuAbiFromSettings = null;
 
+        final PackageParser.Package oldPkg;
+
         // writer
         synchronized (mPackages) {
             if (pkg.mSharedUserId != null) {
@@ -10843,6 +10923,12 @@
             final PackageSetting disabledPkgSetting =
                     mSettings.getDisabledSystemPkgLPr(pkg.packageName);
 
+            if (oldPkgSetting == null) {
+                oldPkg = null;
+            } else {
+                oldPkg = oldPkgSetting.pkg;
+            }
+
             String[] usesStaticLibraries = null;
             if (pkg.usesStaticLibraries != null) {
                 usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
@@ -11175,6 +11261,25 @@
                 mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
             }
         }
+
+        if (oldPkg != null) {
+            // We need to call revokeRuntimePermissionsIfGroupChanged async as permission
+            // revokation from this method might need to kill apps which need the
+            // mPackages lock on a different thread. This would dead lock.
+            //
+            // Hence create a copy of all package names and pass it into
+            // revokeRuntimePermissionsIfGroupChanged. Only for those permissions might get
+            // revoked. If a new package is added before the async code runs the permission
+            // won't be granted yet, hence new packages are no problem.
+            final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());
+
+            AsyncTask.execute(new Runnable() {
+                public void run() {
+                    revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg, allPackageNames);
+                }
+            });
+        }
+
         return pkg;
     }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 15d2071..83b8175 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -131,6 +131,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -1534,6 +1535,24 @@
                 "Ephemeral apps can't use ShortcutManager");
     }
 
+    private void verifyShortcutInfoPackage(String callerPackage, ShortcutInfo si) {
+        if (si == null) {
+            return;
+        }
+        if (!Objects.equals(callerPackage, si.getPackage())) {
+            android.util.EventLog.writeEvent(0x534e4554, "109824443", -1, "");
+            throw new SecurityException("Shortcut package name mismatch");
+        }
+    }
+
+    private void verifyShortcutInfoPackages(
+            String callerPackage, List<ShortcutInfo> list) {
+        final int size = list.size();
+        for (int i = 0; i < size; i++) {
+            verifyShortcutInfoPackage(callerPackage, list.get(i));
+        }
+    }
+
     // Overridden in unit tests to execute r synchronously.
     void injectPostToHandler(Runnable r) {
         mHandler.post(r);
@@ -1681,6 +1700,7 @@
         verifyCaller(packageName, userId);
 
         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
+        verifyShortcutInfoPackages(packageName, newShortcuts);
         final int size = newShortcuts.size();
 
         synchronized (mLock) {
@@ -1732,6 +1752,7 @@
         verifyCaller(packageName, userId);
 
         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
+        verifyShortcutInfoPackages(packageName, newShortcuts);
         final int size = newShortcuts.size();
 
         synchronized (mLock) {
@@ -1812,6 +1833,7 @@
         verifyCaller(packageName, userId);
 
         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
+        verifyShortcutInfoPackages(packageName, newShortcuts);
         final int size = newShortcuts.size();
 
         synchronized (mLock) {
@@ -1871,6 +1893,7 @@
         Preconditions.checkNotNull(shortcut);
         Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
         verifyCaller(packageName, userId);
+        verifyShortcutInfoPackage(packageName, shortcut);
 
         final Intent ret;
         synchronized (mLock) {
@@ -1892,6 +1915,7 @@
     private boolean requestPinItem(String packageName, int userId, ShortcutInfo shortcut,
             AppWidgetProviderInfo appWidget, Bundle extras, IntentSender resultIntent) {
         verifyCaller(packageName, userId);
+        verifyShortcutInfoPackage(packageName, shortcut);
 
         final boolean ret;
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index da14c36..d3469c2 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2150,6 +2150,11 @@
                     public void onTrustedChanged() {
                         mWindowManagerFuncs.notifyKeyguardTrustedChanged();
                     }
+
+                    @Override
+                    public void onShowingChanged() {
+                        mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged();
+                    }
                 });
     }
 
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 941cd44..fd34c51 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -86,6 +86,8 @@
     @Override // Binder interface
     public void onShowingStateChanged(boolean showing) {
         mIsShowing = showing;
+
+        mCallback.onShowingChanged();
     }
 
     @Override // Binder interface
@@ -119,6 +121,7 @@
 
     public interface StateCallback {
         void onTrustedChanged();
+        void onShowingChanged();
     }
 
     public void dump(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index a9e56f3..5a75262 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -165,10 +165,18 @@
     }
 
     WindowState computeFocusedWindow() {
+        // While the keyguard is showing, we must focus anything besides the main display.
+        // Otherwise we risk input not going to the keyguard when the user expects it to.
+        final boolean forceDefaultDisplay = mService.mPolicy.isKeyguardShowingAndNotOccluded();
+
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final DisplayContent dc = mChildren.get(i);
             final WindowState win = dc.findFocusedWindow();
             if (win != null) {
+                if (forceDefaultDisplay && !dc.isDefaultDisplay) {
+                    EventLog.writeEvent(0x534e4554, "71786287", win.mOwnerUid, "");
+                    continue;
+                }
                 return win;
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f5cc43b..d378fa3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2929,6 +2929,11 @@
     }
 
     @Override
+    public void onKeyguardShowingAndNotOccludedChanged() {
+        mH.sendEmptyMessage(H.RECOMPUTE_FOCUS);
+    }
+
+    @Override
     public void screenTurningOff(ScreenOffListener listener) {
         mTaskSnapshotController.screenTurningOff(listener);
     }
@@ -4897,6 +4902,7 @@
         public static final int NOTIFY_KEYGUARD_FLAGS_CHANGED = 56;
         public static final int NOTIFY_KEYGUARD_TRUSTED_CHANGED = 57;
         public static final int SET_HAS_OVERLAY_UI = 58;
+        public static final int RECOMPUTE_FOCUS = 61;
 
         /**
          * Used to denote that an integer field in a message will not be used.
@@ -5363,6 +5369,13 @@
                     mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1);
                 }
                 break;
+                case RECOMPUTE_FOCUS: {
+                    synchronized (mWindowMap) {
+                        updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+                                true /* updateInputWindows */);
+                    }
+                }
+                break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG_WM, "handleMessage: exit");
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 10d2413..a6cada7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -313,6 +313,25 @@
         assertEquals(window1, sWm.mRoot.computeFocusedWindow());
     }
 
+    @Test
+    public void testKeyguard_preventsSecondaryDisplayFocus() throws Exception {
+        final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR,
+                sWm.getDefaultDisplayContentLocked(), "keyguard");
+        assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
+
+        // Add a window to a second display, and it should be focused
+        final DisplayContent dc = createNewDisplay();
+        final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
+        assertEquals(win, sWm.mRoot.computeFocusedWindow());
+
+        ((TestWindowManagerPolicy)sWm.mPolicy).keyguardShowingAndNotOccluded = true;
+        try {
+            assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
+        } finally {
+            ((TestWindowManagerPolicy)sWm.mPolicy).keyguardShowingAndNotOccluded = false;
+        }
+    }
+
     /**
      * This tests setting the maximum ui width on a display.
      */
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index eca27ee..27ea325 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -63,6 +63,7 @@
     private static WindowManagerService sWm = null;
 
     int rotationToReport = 0;
+    boolean keyguardShowingAndNotOccluded = false;
 
     private Runnable mRunnableWhenAddingSplashScreen;
 
@@ -420,7 +421,7 @@
 
     @Override
     public boolean isKeyguardLocked() {
-        return false;
+        return keyguardShowingAndNotOccluded;
     }
 
     @Override
@@ -440,7 +441,7 @@
 
     @Override
     public boolean isKeyguardShowingAndNotOccluded() {
-        return false;
+        return keyguardShowingAndNotOccluded;
     }
 
     @Override
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c9afb9f..d4a8066 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4605,7 +4605,7 @@
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return null;
-            return telephony.getForbiddenPlmns(subId, appType);
+            return telephony.getForbiddenPlmns(subId, appType, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 9262ec5..235b5ee 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1352,12 +1352,12 @@
      * Returns null if the query fails.
      *
      *
-     * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
+     * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE
      *
      * @param subId subscription ID used for authentication
      * @param appType the icc application type, like {@link #APPTYPE_USIM}
      */
-    String[] getForbiddenPlmns(int subId, int appType);
+    String[] getForbiddenPlmns(int subId, int appType, String callingPackage);
 
     /**
      * Check if phone is in emergency callback mode
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 6674f20..504a2db 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -22,6 +22,7 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
 import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
 import static android.net.ConnectivityManager.TYPE_NONE;
+import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.NetworkCapabilities.*;
@@ -102,6 +103,7 @@
 import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult;
+import com.android.server.connectivity.Vpn;
 import com.android.server.net.NetworkPinner;
 import com.android.server.net.NetworkPolicyManagerInternal;
 
@@ -333,6 +335,9 @@
                 case TRANSPORT_WIFI_AWARE:
                     mScore = 20;
                     break;
+                case TRANSPORT_VPN:
+                    mScore = 0;
+                    break;
                 default:
                     throw new UnsupportedOperationException("unimplemented network type");
             }
@@ -868,6 +873,8 @@
                 return TYPE_WIFI;
             case TRANSPORT_CELLULAR:
                 return TYPE_MOBILE;
+            case TRANSPORT_VPN:
+                return TYPE_VPN;
             default:
                 return TYPE_NONE;
         }
@@ -3447,4 +3454,84 @@
             return;
         }
     }
+
+    @SmallTest
+    public void testVpnNetworkMetered() {
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(callback);
+
+        final NetworkRequest cellRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR).build();
+        final TestNetworkCallback cellCallback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(cellRequest, cellCallback);
+
+        // Setup cellular
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+        callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        cellCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        verifyActiveNetwork(TRANSPORT_CELLULAR);
+
+        // Verify meteredness of cellular
+        assertTrue(mCm.isActiveNetworkMetered());
+
+        // Setup Wifi
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+        callback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+        cellCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+        verifyActiveNetwork(TRANSPORT_WIFI);
+
+        // Verify meteredness of WiFi
+        assertTrue(mCm.isActiveNetworkMetered());
+
+        // Verify that setting unmetered on Wifi changes ActiveNetworkMetered
+        mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
+        callback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
+        assertFalse(mCm.isActiveNetworkMetered());
+
+        // Setup VPN
+        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        vpnNetworkAgent.connect(true);
+
+        Vpn mockVpn = mock(Vpn.class);
+        when(mockVpn.appliesToUid(anyInt())).thenReturn(true);
+        when(mockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId);
+
+        Vpn oldVpn = mService.getVpn(UserHandle.myUserId());
+        mService.setVpn(UserHandle.myUserId(), mockVpn);
+        assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+
+        // Verify meteredness of VPN on default network
+        when(mockVpn.getUnderlyingNetworks()).thenReturn(null);
+        assertFalse(mCm.isActiveNetworkMetered());
+        assertFalse(mCm.isActiveNetworkMeteredForUid(Process.myUid()));
+
+        // Verify meteredness of VPN on unmetered wifi
+        when(mockVpn.getUnderlyingNetworks())
+                .thenReturn(new Network[] {mWiFiNetworkAgent.getNetwork()});
+        assertFalse(mCm.isActiveNetworkMetered());
+        assertFalse(mCm.isActiveNetworkMeteredForUid(Process.myUid()));
+
+        // Set WiFi as metered, then check to see that it has been updated on the VPN
+        mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
+        callback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
+        assertTrue(mCm.isActiveNetworkMetered());
+        assertTrue(mCm.isActiveNetworkMeteredForUid(Process.myUid()));
+
+        // Switch to cellular
+        when(mockVpn.getUnderlyingNetworks())
+                .thenReturn(new Network[] {mCellNetworkAgent.getNetwork()});
+        assertTrue(mCm.isActiveNetworkMetered());
+        assertTrue(mCm.isActiveNetworkMeteredForUid(Process.myUid()));
+
+        // Test unmetered cellular
+        mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
+        cellCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
+        assertFalse(mCm.isActiveNetworkMetered());
+        assertFalse(mCm.isActiveNetworkMeteredForUid(Process.myUid()));
+
+        mService.setVpn(UserHandle.myUserId(), oldVpn);
+        mCm.unregisterNetworkCallback(callback);
+    }
 }