Merge "Revert "nfc(framework): Split non-updatable portion to a separat..."" into main
diff --git a/Android.bp b/Android.bp
index 68048c6..35e59df 100644
--- a/Android.bp
+++ b/Android.bp
@@ -517,6 +517,50 @@
         ],
     },
     jarjar_prefix: "com.android.internal.hidden_from_bootclasspath",
+
+    jarjar_shards: select(release_flag("RELEASE_USE_SHARDED_JARJAR_ON_FRAMEWORK_MINUS_APEX"), {
+        true: "10",
+        default: "1",
+    }),
+}
+
+// This is identical to "framework-minus-apex" but with "jarjar_shards" hardcodd.
+// (also "stem" is commented out to avoid a conflict with the "framework-minus-apex")
+// TODO(b/383559945) This module is just for local testing / verification. It's not used
+// by anything. Remove it once we roll out RELEASE_USE_SHARDED_JARJAR_ON_FRAMEWORK_MINUS_APEX.
+java_library {
+    name: "framework-minus-apex_jarjar-sharded",
+    defaults: [
+        "framework-minus-apex-with-libs-defaults",
+        "framework-non-updatable-lint-defaults",
+    ],
+    installable: true,
+    // For backwards compatibility.
+    // stem: "framework",
+    apex_available: ["//apex_available:platform"],
+    visibility: [
+        "//frameworks/base",
+        "//frameworks/base/location",
+        // TODO(b/147128803) remove the below lines
+        "//frameworks/base/apex/blobstore/framework",
+        "//frameworks/base/apex/jobscheduler/framework",
+        "//frameworks/base/packages/Tethering/tests/unit",
+        "//packages/modules/Connectivity/Tethering/tests/unit",
+    ],
+    errorprone: {
+        javacflags: [
+            "-Xep:AndroidFrameworkCompatChange:ERROR",
+            "-Xep:AndroidFrameworkUid:ERROR",
+        ],
+    },
+    lint: {
+        baseline_filename: "lint-baseline.xml",
+        warning_checks: [
+            "FlaggedApi",
+        ],
+    },
+    jarjar_prefix: "com.android.internal.hidden_from_bootclasspath",
+    jarjar_shards: "10",
 }
 
 java_library {
diff --git a/boot/preloaded-classes b/boot/preloaded-classes
index afd9984..b83bd4e 100644
--- a/boot/preloaded-classes
+++ b/boot/preloaded-classes
@@ -6583,6 +6583,7 @@
 android.permission.PermissionCheckerManager
 android.permission.PermissionControllerManager$1
 android.permission.PermissionControllerManager
+android.permission.PermissionManager
 android.permission.PermissionManager$1
 android.permission.PermissionManager$2
 android.permission.PermissionManager$OnPermissionsChangeListenerDelegate
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 343de0b..e53c78f 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -6587,6 +6587,7 @@
 android.permission.PermissionCheckerManager
 android.permission.PermissionControllerManager$1
 android.permission.PermissionControllerManager
+android.permission.PermissionManager
 android.permission.PermissionManager$1
 android.permission.PermissionManager$2
 android.permission.PermissionManager$OnPermissionsChangeListenerDelegate
diff --git a/config/preloaded-classes-denylist b/config/preloaded-classes-denylist
index 16f0693..e3e929c 100644
--- a/config/preloaded-classes-denylist
+++ b/config/preloaded-classes-denylist
@@ -3,7 +3,6 @@
 android.net.ConnectivityThread$Singleton
 android.os.FileObserver
 android.os.NullVibrator
-android.permission.PermissionManager
 android.provider.MediaStore
 android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask
 android.view.HdrRenderState
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index bde16c3..696288f 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -234,3 +234,11 @@
     is_fixed_read_only: true
     bug: "377557749"
 }
+
+flag {
+    name: "api_for_backported_fixes"
+    namespace: "media_reliability"
+    description: "Public API app developers use to check if a known issue is fixed on a device."
+    bug: "308461809"
+    is_exported: true
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index e71f607..7935ee5 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -90,7 +90,6 @@
         "android_view_VelocityTracker.cpp",
         "android_view_VerifiedKeyEvent.cpp",
         "android_view_VerifiedMotionEvent.cpp",
-        "com_android_internal_util_ArrayUtils.cpp",
         "com_android_internal_util_VirtualRefBasePtr.cpp",
         "core_jni_helpers.cpp",
         ":deviceproductinfoconstants_aidl",
@@ -271,6 +270,7 @@
                 "com_android_internal_os_ZygoteCommandBuffer.cpp",
                 "com_android_internal_os_ZygoteInit.cpp",
                 "com_android_internal_security_VerityUtils.cpp",
+                "com_android_internal_util_ArrayUtils.cpp",
                 "hwbinder/EphemeralStorage.cpp",
                 "fd_utils.cpp",
                 "android_hardware_input_InputWindowHandle.cpp",
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index d6fe6825..486063e 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -180,6 +180,15 @@
      *     a semi-planar format, the Cb plane can also be treated as an interleaved Cb/Cr plane.
      *   </td>
      * </tr>
+     * <tr>
+     *   <td>{@link android.graphics.ImageFormat#YCBCR_P210 YCBCR_P210}</td>
+     *   <td>3</td>
+     *   <td>P210 is a 4:2:2 YCbCr semiplanar format comprised of a WxH Y plane
+     *     followed by a WxH Cb and Cr planes. Each sample is represented by a 16-bit
+     *     little-endian value, with the lower 6 bits set to zero. Since this is guaranteed to be
+     *     a semi-planar format, the Cb plane can also be treated as an interleaved Cb/Cr plane.
+     *   </td>
+     * </tr>
      * </table>
      *
      * @see android.graphics.ImageFormat
diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java
index f4caad7..83b056f 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/media/java/android/media/ImageUtils.java
@@ -49,6 +49,7 @@
             case ImageFormat.YUV_420_888:
             case ImageFormat.NV21:
             case ImageFormat.YCBCR_P010:
+            case ImageFormat.YCBCR_P210:
                 return 3;
             case ImageFormat.NV16:
                 return 2;
@@ -88,6 +89,7 @@
         switch(hardwareBufferFormat) {
             case HardwareBuffer.YCBCR_420_888:
             case HardwareBuffer.YCBCR_P010:
+            case HardwareBuffer.YCBCR_P210:
                 return 3;
             case HardwareBuffer.RGBA_8888:
             case HardwareBuffer.RGBX_8888:
@@ -269,6 +271,7 @@
             case PixelFormat.RGBA_8888:
             case PixelFormat.RGBX_8888:
             case PixelFormat.RGBA_1010102:
+            case ImageFormat.YCBCR_P210:
                 estimatedBytePerPixel = 4.0;
                 break;
             default:
@@ -318,6 +321,12 @@
                 return new Size(image.getWidth(), image.getHeight());
             case ImageFormat.PRIVATE:
                 return new Size(0, 0);
+            case ImageFormat.YCBCR_P210:
+                if (planeIdx == 0) {
+                    return new Size(image.getWidth(), image.getHeight());
+                } else {
+                    return new Size(image.getWidth() / 2, image.getHeight());
+                }
             default:
                 if (Log.isLoggable(IMAGEUTILS_LOG_TAG, Log.VERBOSE)) {
                     Log.v(IMAGEUTILS_LOG_TAG, "getEffectivePlaneSizeForImage() uses"
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 82e9503..36f62da 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -6158,11 +6158,14 @@
                     buffer.limit(buffer.position() + Utils.divUp(bitDepth, 8)
                             + (mHeight / vert - 1) * rowInc + (mWidth / horiz - 1) * colInc);
                     mPlanes[ix] = new MediaPlane(buffer.slice(), rowInc, colInc);
-                    if ((mFormat == ImageFormat.YUV_420_888 || mFormat == ImageFormat.YCBCR_P010)
+                    if ((mFormat == ImageFormat.YUV_420_888 || mFormat == ImageFormat.YCBCR_P010
+                                || mFormat == ImageFormat.YCBCR_P210)
                             && ix == 1) {
                         cbPlaneOffset = planeOffset;
                     } else if ((mFormat == ImageFormat.YUV_420_888
-                            || mFormat == ImageFormat.YCBCR_P010) && ix == 2) {
+                                       || mFormat == ImageFormat.YCBCR_P010
+                                       || mFormat == ImageFormat.YCBCR_P210)
+                            && ix == 2) {
                         crPlaneOffset = planeOffset;
                     }
                 }
@@ -6172,7 +6175,7 @@
             }
 
             // Validate chroma semiplanerness.
-            if (mFormat == ImageFormat.YCBCR_P010) {
+            if (mFormat == ImageFormat.YCBCR_P010 || mFormat == ImageFormat.YCBCR_P210) {
                 if (crPlaneOffset != cbPlaneOffset + planeOffsetInc) {
                     throw new UnsupportedOperationException("Invalid plane offsets"
                     + " cbPlaneOffset: " + cbPlaneOffset + " crPlaneOffset: " + crPlaneOffset);
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index fbebbdc..e8f8644 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -17,13 +17,14 @@
 // #define LOG_NDEBUG 0
 #define LOG_TAG "AndroidMediaUtils"
 
+#include "android_media_Utils.h"
+
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
 #include <ui/GraphicBufferMapper.h>
 #include <ui/GraphicTypes.h>
 #include <utils/Log.h>
 
-#include "android_media_Utils.h"
-
 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
 
 // Must be in sync with the value in HeicCompositeStream.cpp
@@ -33,6 +34,8 @@
 
 // -----------Utility functions used by ImageReader/Writer JNI-----------------
 
+using AidlPixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
+
 enum {
     IMAGE_MAX_NUM_PLANES = 3,
 };
@@ -74,6 +77,7 @@
         case HAL_PIXEL_FORMAT_BLOB:
         case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
         case HAL_PIXEL_FORMAT_YCBCR_P010:
+        case static_cast<int>(AidlPixelFormat::YCBCR_P210):
             return false;
 
         case HAL_PIXEL_FORMAT_YV12:
@@ -105,6 +109,7 @@
             return false;
 
         case HAL_PIXEL_FORMAT_YCBCR_P010:
+        case static_cast<int>(AidlPixelFormat::YCBCR_P210):
         default:
             return true;
     }
@@ -340,6 +345,47 @@
             cb = buffer->data + ySize;
             cr = cb + 2;
 
+            pData = (idx == 0) ? buffer->data : (idx == 1) ? cb : cr;
+            dataSize = (idx == 0) ? ySize : cSize;
+            rStride = buffer->stride * 2;
+            break;
+        case static_cast<int>(AidlPixelFormat::YCBCR_P210):
+            if (buffer->height % 2 != 0) {
+                ALOGE("YCBCR_P210: height (%d) should be a multiple of 2", buffer->height);
+                return BAD_VALUE;
+            }
+
+            if (buffer->width <= 0) {
+                ALOGE("YCBCR_P210: width (%d) should be a > 0", buffer->width);
+                return BAD_VALUE;
+            }
+
+            if (buffer->height <= 0) {
+                ALOGE("YCBCR_210: height (%d) should be a > 0", buffer->height);
+                return BAD_VALUE;
+            }
+            if (buffer->dataCb && buffer->dataCr) {
+                pData = (idx == 0) ? buffer->data : (idx == 1) ? buffer->dataCb : buffer->dataCr;
+                // only map until last pixel
+                if (idx == 0) {
+                    pStride = 2;
+                    rStride = buffer->stride;
+                    dataSize = buffer->stride * (buffer->height - 1) + buffer->width * 2;
+                } else {
+                    pStride = buffer->chromaStep;
+                    rStride = buffer->chromaStride;
+                    dataSize = buffer->chromaStride * (buffer->height - 1) +
+                            buffer->chromaStep * (buffer->width / 2);
+                }
+                break;
+            }
+
+            ySize = (buffer->stride * 2) * buffer->height;
+            cSize = ySize;
+            pStride = (idx == 0) ? 2 : 4;
+            cb = buffer->data + ySize;
+            cr = cb + 2;
+
             pData = (idx == 0) ?  buffer->data : (idx == 1) ?  cb : cr;
             dataSize = (idx == 0) ? ySize : cSize;
             rStride = buffer->stride * 2;
@@ -544,6 +590,80 @@
     return OK;
 }
 
+static status_t extractP210Gralloc4PlaneLayout(sp<GraphicBuffer> buffer, void *pData, int format,
+                                               LockedImage *outputImage) {
+    using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+    using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+
+    GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+    std::vector<ui::PlaneLayout> planeLayouts;
+    status_t res = mapper.getPlaneLayouts(buffer->handle, &planeLayouts);
+    if (res != OK) {
+        return res;
+    }
+    constexpr int64_t Y_PLANE_COMPONENTS = int64_t(PlaneLayoutComponentType::Y);
+    constexpr int64_t CBCR_PLANE_COMPONENTS =
+            int64_t(PlaneLayoutComponentType::CB) | int64_t(PlaneLayoutComponentType::CR);
+    uint8_t *dataY = nullptr;
+    uint8_t *dataCb = nullptr;
+    uint8_t *dataCr = nullptr;
+    uint32_t strideY = 0;
+    uint32_t strideCbCr = 0;
+    for (const ui::PlaneLayout &layout : planeLayouts) {
+        ALOGV("gralloc4 plane: %s", layout.toString().c_str());
+        int64_t components = 0;
+        for (const PlaneLayoutComponent &component : layout.components) {
+            if (component.sizeInBits != 10) {
+                return BAD_VALUE;
+            }
+            components |= component.type.value;
+        }
+        if (components == Y_PLANE_COMPONENTS) {
+            if (layout.sampleIncrementInBits != 16) {
+                return BAD_VALUE;
+            }
+            if (layout.components[0].offsetInBits != 6) {
+                return BAD_VALUE;
+            }
+            dataY = (uint8_t *)pData + layout.offsetInBytes;
+            strideY = layout.strideInBytes;
+        } else if (components == CBCR_PLANE_COMPONENTS) {
+            if (layout.sampleIncrementInBits != 32) {
+                return BAD_VALUE;
+            }
+            for (const PlaneLayoutComponent &component : layout.components) {
+                if (component.type.value == int64_t(PlaneLayoutComponentType::CB) &&
+                    component.offsetInBits != 6) {
+                    return BAD_VALUE;
+                }
+                if (component.type.value == int64_t(PlaneLayoutComponentType::CR) &&
+                    component.offsetInBits != 22) {
+                    return BAD_VALUE;
+                }
+            }
+            dataCb = (uint8_t *)pData + layout.offsetInBytes;
+            dataCr = (uint8_t *)pData + layout.offsetInBytes + 2;
+            strideCbCr = layout.strideInBytes;
+        } else {
+            return BAD_VALUE;
+        }
+    }
+
+    outputImage->data = dataY;
+    outputImage->width = buffer->getWidth();
+    outputImage->height = buffer->getHeight();
+    outputImage->format = format;
+    outputImage->flexFormat =
+            static_cast<int>(AidlPixelFormat::YCBCR_P210);
+    outputImage->stride = strideY;
+
+    outputImage->dataCb = dataCb;
+    outputImage->dataCr = dataCr;
+    outputImage->chromaStride = strideCbCr;
+    outputImage->chromaStep = 4;
+    return OK;
+}
+
 status_t lockImageFromBuffer(sp<GraphicBuffer> buffer, uint32_t inUsage,
         const Rect& rect, int fenceFd, LockedImage* outputImage) {
     ALOGV("%s: Try to lock the GraphicBuffer", __FUNCTION__);
@@ -581,10 +701,17 @@
             ALOGE("Lock buffer failed!");
             return res;
         }
-        if (isPossibly10BitYUV(format)
-                && OK == extractP010Gralloc4PlaneLayout(buffer, pData, format, outputImage)) {
-            ALOGV("%s: Successfully locked the P010 image", __FUNCTION__);
-            return OK;
+        if (isPossibly10BitYUV(format)) {
+            if (format == HAL_PIXEL_FORMAT_YCBCR_P010 &&
+                OK == extractP010Gralloc4PlaneLayout(buffer, pData, format, outputImage)) {
+                ALOGV("%s: Successfully locked the P010 image", __FUNCTION__);
+                return OK;
+            } else if ((format ==
+                        static_cast<int>(AidlPixelFormat::YCBCR_P210)) &&
+                       OK == extractP210Gralloc4PlaneLayout(buffer, pData, format, outputImage)) {
+                ALOGV("%s: Successfully locked the P210 image", __FUNCTION__);
+                return OK;
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 4c5f652..ac0892b 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1960,6 +1960,10 @@
     public void onUserAdded(int userId) {
         // If the user is restricted tie them to the parent user's VPN
         UserInfo user = mUserManager.getUserInfo(userId);
+        if (user == null) {
+            Log.e(TAG, "Can not retrieve UserInfo for userId=" + userId);
+            return;
+        }
         if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
             synchronized(Vpn.this) {
                 final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
@@ -1989,6 +1993,14 @@
     public void onUserRemoved(int userId) {
         // clean up if restricted
         UserInfo user = mUserManager.getUserInfo(userId);
+        // TODO: Retrieving UserInfo upon receiving the USER_REMOVED intent is not guaranteed.
+        //  This could prevent the removal of associated ranges. To ensure proper range removal,
+        //  store the user info when adding ranges. This allows using the user ID in the
+        //  USER_REMOVED intent to handle the removal process.
+        if (user == null) {
+            Log.e(TAG, "Can not retrieve UserInfo for userId=" + userId);
+            return;
+        }
         if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
             synchronized(Vpn.this) {
                 final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
diff --git a/services/core/java/com/android/server/servicewatcher/ServiceWatcher.java b/services/core/java/com/android/server/servicewatcher/ServiceWatcher.java
index 5636718..50a2b98 100644
--- a/services/core/java/com/android/server/servicewatcher/ServiceWatcher.java
+++ b/services/core/java/com/android/server/servicewatcher/ServiceWatcher.java
@@ -193,11 +193,7 @@
 
         @Override
         public String toString() {
-            if (mComponentName == null) {
-                return "none";
-            } else {
-                return mUid + "/" + mComponentName.flattenToShortString();
-            }
+            return mUid + "/" + mComponentName.flattenToShortString();
         }
     }
 
diff --git a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
index 5db6a8f..9117cc8 100644
--- a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
+++ b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
@@ -918,6 +918,30 @@
     }
 
     @Test
+    public void testOnUserAddedAndRemoved_nullUserInfo() throws Exception {
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        final Set<Range<Integer>> initialRange = rangeSet(PRIMARY_USER_RANGE);
+        // Note since mVpnProfile is a Ikev2VpnProfile, this starts an IkeV2VpnRunner.
+        startLegacyVpn(vpn, mVpnProfile);
+        // Set an initial Uid range and mock the network agent
+        vpn.mNetworkCapabilities.setUids(initialRange);
+        vpn.mNetworkAgent = mMockNetworkAgent;
+
+        // Add the restricted user and then remove it immediately. So the getUserInfo() will return
+        // null for the given restricted user id.
+        setMockedUsers(PRIMARY_USER, RESTRICTED_PROFILE_A);
+        doReturn(null).when(mUserManager).getUserInfo(RESTRICTED_PROFILE_A.id);
+        vpn.onUserAdded(RESTRICTED_PROFILE_A.id);
+        // Expect no range change to the NetworkCapabilities.
+        assertEquals(initialRange, vpn.mNetworkCapabilities.getUids());
+
+        // Remove the restricted user
+        vpn.onUserRemoved(RESTRICTED_PROFILE_A.id);
+        // Expect no range change to the NetworkCapabilities.
+        assertEquals(initialRange, vpn.mNetworkCapabilities.getUids());
+    }
+
+    @Test
     public void testPrepare_throwSecurityExceptionWhenGivenPackageDoesNotBelongToTheCaller()
             throws Exception {
         mTestDeps.mIgnoreCallingUidChecks = false;