Merge "Don't crash systemui"
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 966f902..d21f76d 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -30,6 +30,7 @@
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
@@ -270,7 +271,7 @@
         ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
         intent.setComponent(comp);
         if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
-                mContext.getUser())) {
+                UserHandle.CURRENT_OR_SELF)) {
             Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
             return false;
         }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 83e287a..b7a5352 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -615,6 +615,13 @@
     public static final int PRIVATE_FLAG_PRODUCT = 1 << 19;
 
     /**
+     * Value for {@link #privateFlags}: whether this app is pre-installed on the
+     * google partition of the system image.
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_PRODUCT_SERVICES = 1 << 21;
+
+    /**
      * Value for {@link #privateFlags}: whether this app is signed with the
      * platform key.
      * @hide
@@ -639,6 +646,7 @@
             PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE,
             PRIVATE_FLAG_PRIVILEGED,
             PRIVATE_FLAG_PRODUCT,
+            PRIVATE_FLAG_PRODUCT_SERVICES,
             PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER,
             PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY,
             PRIVATE_FLAG_STATIC_SHARED_LIBRARY,
@@ -1888,6 +1896,11 @@
         return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
     }
 
+    /** @hide */
+    public boolean isProductServices() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0;
+    }
+
     /**
      * Returns whether or not this application was installed as a virtual preload.
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 876cf2b..83757c4 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6785,6 +6785,11 @@
         }
 
         /** @hide */
+        public boolean isProductServices() {
+            return applicationInfo.isProductServices();
+        }
+
+        /** @hide */
         public boolean isPrivileged() {
             return applicationInfo.isPrivilegedApp();
         }
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index e32ed9d..347f60f 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -45,6 +45,7 @@
     private static final String ENV_ODM_ROOT = "ODM_ROOT";
     private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
     private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT";
+    private static final String ENV_PRODUCT_SERVICES_ROOT = "PRODUCT_SERVICES_ROOT";
 
     /** {@hide} */
     public static final String DIR_ANDROID = "Android";
@@ -67,6 +68,8 @@
     private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm");
     private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
     private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product");
+    private static final File DIR_PRODUCT_SERVICES_ROOT = getDirectory(ENV_PRODUCT_SERVICES_ROOT,
+                                                           "/product_services");
 
     private static UserEnvironment sCurrentUser;
     private static boolean sUserRequired;
@@ -196,6 +199,16 @@
     }
 
     /**
+     * Return root directory of the "product_services" partition holding middleware
+     * services if any. If present, the partition is mounted read-only.
+     *
+     * @hide
+     */
+    public static File getProductServicesDirectory() {
+        return DIR_PRODUCT_SERVICES_ROOT;
+    }
+
+    /**
      * Return the system directory for a user. This is for use by system
      * services to store files relating to the user. This directory will be
      * automatically deleted when the user is removed.
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index dba74b1..f88a4e2 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
@@ -502,6 +503,7 @@
                 || mCurrentDate.get(Calendar.DAY_OF_MONTH) != dayOfMonth);
     }
 
+    @UnsupportedAppUsage
     private void setDate(int year, int month, int dayOfMonth) {
         mCurrentDate.set(year, month, dayOfMonth);
         resetAutofilledValue();
@@ -512,6 +514,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     private void updateSpinners() {
         // set the spinner ranges respecting the min and max dates
         if (mCurrentDate.equals(mMinDate)) {
@@ -564,6 +567,7 @@
     /**
      * Updates the calendar view with the current date.
      */
+    @UnsupportedAppUsage
     private void updateCalendarView() {
         mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false);
     }
@@ -572,6 +576,7 @@
     /**
      * Notifies the listener, if such, for a change in the selected date.
      */
+    @UnsupportedAppUsage
     private void notifyDateChanged() {
         mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
         if (mOnDateChangedListener != null) {
@@ -627,6 +632,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     private void updateInputState() {
         // Make sure that if the user changes the value and the IME is active
         // for one of the inputs if this widget, the IME is closed. If the user
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 1b3faf5..119f30d 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -33,6 +33,7 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
+import android.annotation.UnsupportedAppUsage;
 import android.app.ActionBar;
 import android.app.Activity;
 import android.app.Dialog;
@@ -79,6 +80,7 @@
     private ActionBarOverlayLayout mOverlayLayout;
     private ActionBarContainer mContainerView;
     private DecorToolbar mDecorToolbar;
+    @UnsupportedAppUsage
     private ActionBarContextView mContextView;
     private ActionBarContainer mSplitView;
     private View mContentView;
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index c5be8e4..0a787b9 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -169,6 +169,10 @@
     final ArrayMap<String, ArraySet<String>> mProductPrivAppPermissions = new ArrayMap<>();
     final ArrayMap<String, ArraySet<String>> mProductPrivAppDenyPermissions = new ArrayMap<>();
 
+    final ArrayMap<String, ArraySet<String>> mProductServicesPrivAppPermissions = new ArrayMap<>();
+    final ArrayMap<String, ArraySet<String>> mProductServicesPrivAppDenyPermissions =
+            new ArrayMap<>();
+
     final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
 
     public static SystemConfig getInstance() {
@@ -276,6 +280,14 @@
         return mProductPrivAppDenyPermissions.get(packageName);
     }
 
+    public ArraySet<String> getProductServicesPrivAppPermissions(String packageName) {
+        return mProductServicesPrivAppPermissions.get(packageName);
+    }
+
+    public ArraySet<String> getProductServicesPrivAppDenyPermissions(String packageName) {
+        return mProductServicesPrivAppDenyPermissions.get(packageName);
+    }
+
     public Map<String, Boolean> getOemPermissions(String packageName) {
         final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName);
         if (oemPermissions != null) {
@@ -326,6 +338,17 @@
                 Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag);
         readPermissions(Environment.buildPath(
                 Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag);
+
+        // Allow /product_services to customize system configs around libs, features, permissions
+        // and apps.
+        int productServicesPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
+                ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
+        readPermissions(Environment.buildPath(
+                Environment.getProductServicesDirectory(), "etc", "sysconfig"),
+                productServicesPermissionFlag);
+        readPermissions(Environment.buildPath(
+                Environment.getProductServicesDirectory(), "etc", "permissions"),
+                productServicesPermissionFlag);
     }
 
     void readPermissions(File libraryDir, int permissionFlag) {
@@ -659,22 +682,27 @@
                     }
                     XmlUtils.skipCurrentTag(parser);
                 } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
-                    // privapp permissions from system, vendor and product partitions are stored
-                    // separately. This is to prevent xml files in the vendor partition from
-                    // granting permissions to priv apps in the system partition and vice
-                    // versa.
+                    // privapp permissions from system, vendor, product and product_services
+                    // partitions are stored separately. This is to prevent xml files in the vendor
+                    // partition from granting permissions to priv apps in the system partition and
+                    // vice versa.
                     boolean vendor = permFile.toPath().startsWith(
-                            Environment.getVendorDirectory().toPath())
+                            Environment.getVendorDirectory().toPath() + "/")
                             || permFile.toPath().startsWith(
-                                Environment.getOdmDirectory().toPath());
+                                Environment.getOdmDirectory().toPath() + "/");
                     boolean product = permFile.toPath().startsWith(
-                            Environment.getProductDirectory().toPath());
+                            Environment.getProductDirectory().toPath() + "/");
+                    boolean productServices = permFile.toPath().startsWith(
+                            Environment.getProductServicesDirectory().toPath() + "/");
                     if (vendor) {
                         readPrivAppPermissions(parser, mVendorPrivAppPermissions,
                                 mVendorPrivAppDenyPermissions);
                     } else if (product) {
                         readPrivAppPermissions(parser, mProductPrivAppPermissions,
                                 mProductPrivAppDenyPermissions);
+                    } else if (productServices) {
+                        readPrivAppPermissions(parser, mProductServicesPrivAppPermissions,
+                                mProductServicesPrivAppDenyPermissions);
                     } else {
                         readPrivAppPermissions(parser, mPrivAppPermissions,
                                 mPrivAppDenyPermissions);
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 02076bd..8083a6a 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -310,180 +310,17 @@
 using namespace android;
 using namespace android::bitmap;
 
-///////////////////////////////////////////////////////////////////////////////
-// Conversions to/from SkColor, for get/setPixels, and the create method, which
-// is basically like setPixels
-
-typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
-                              int x, int y);
-
-static void FromColor_F16(void* dst, const SkColor src[], int width,
-                          int, int) {
-    uint64_t* d = (uint64_t*)dst;
-
-    for (int i = 0; i < width; i++) {
-        *d++ = SkColor4f::FromColor(*src++).premul().toF16();
-    }
-}
-
-static void FromColor_F16_Raw(void* dst, const SkColor src[], int width,
-                          int, int) {
-    uint64_t* d = (uint64_t*)dst;
-
-    for (int i = 0; i < width; i++) {
-        const SkColor4f color = SkColor4f::FromColor(*src++);
-        uint16_t* scratch = reinterpret_cast<uint16_t*>(d++);
-        scratch[0] = SkFloatToHalf(color.fR);
-        scratch[1] = SkFloatToHalf(color.fG);
-        scratch[2] = SkFloatToHalf(color.fB);
-        scratch[3] = SkFloatToHalf(color.fA);
-    }
-}
-
-static void FromColor_D32(void* dst, const SkColor src[], int width,
-                          int, int) {
-    SkPMColor* d = (SkPMColor*)dst;
-
-    for (int i = 0; i < width; i++) {
-        *d++ = SkPreMultiplyColor(*src++);
-    }
-}
-
-static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
-                          int, int) {
-    // Needed to thwart the unreachable code detection from clang.
-    static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER;
-
-    // SkColor's ordering may be different from SkPMColor
-    if (sk_color_ne_zero) {
-        memcpy(dst, src, width * sizeof(SkColor));
-        return;
-    }
-
-    // order isn't same, repack each pixel manually
-    SkPMColor* d = (SkPMColor*)dst;
-    for (int i = 0; i < width; i++) {
-        SkColor c = *src++;
-        *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
-                                   SkColorGetG(c), SkColorGetB(c));
-    }
-}
-
-static void FromColor_D565(void* dst, const SkColor src[], int width,
-                           int x, int y) {
-    uint16_t* d = (uint16_t*)dst;
-
-    DITHER_565_SCAN(y);
-    for (int stop = x + width; x < stop; x++) {
-        SkColor c = *src++;
-        *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
-                                DITHER_VALUE(x));
-    }
-}
-
-static void FromColor_D4444(void* dst, const SkColor src[], int width,
-                            int x, int y) {
-    SkPMColor16* d = (SkPMColor16*)dst;
-
-    DITHER_4444_SCAN(y);
-    for (int stop = x + width; x < stop; x++) {
-        SkPMColor pmc = SkPreMultiplyColor(*src++);
-        *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
-//        *d++ = SkPixel32ToPixel4444(pmc);
-    }
-}
-
-static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
-                            int x, int y) {
-    SkPMColor16* d = (SkPMColor16*)dst;
-
-    DITHER_4444_SCAN(y);
-    for (int stop = x + width; x < stop; x++) {
-        SkColor c = *src++;
-
-        // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
-        SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
-                                            SkColorGetG(c), SkColorGetB(c));
-        *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
-//        *d++ = SkPixel32ToPixel4444(pmc);
-    }
-}
-
-static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) {
-    uint8_t* d = (uint8_t*)dst;
-
-    for (int stop = x + width; x < stop; x++) {
-        *d++ = SkColorGetA(*src++);
-    }
-}
-
-// can return NULL
-static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
-    switch (bitmap.colorType()) {
-        case kN32_SkColorType:
-            return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw;
-        case kARGB_4444_SkColorType:
-            return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 :
-                    FromColor_D4444_Raw;
-        case kRGB_565_SkColorType:
-            return FromColor_D565;
-        case kAlpha_8_SkColorType:
-            return FromColor_DA8;
-        case kRGBA_F16_SkColorType:
-            return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_F16 : FromColor_F16_Raw;
-        default:
-            break;
-    }
-    return NULL;
-}
-
-static bool IsColorSpaceSRGB(SkColorSpace* colorSpace) {
-    return colorSpace == nullptr || colorSpace->isSRGB();
-}
-
 bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
-        int x, int y, int width, int height, const SkBitmap& dstBitmap) {
-    void* dst = dstBitmap.getPixels();
-    FromColorProc proc = ChooseFromColorProc(dstBitmap);
-
-    if (NULL == dst || NULL == proc) {
-        return false;
-    }
-
+        int x, int y, int width, int height, SkBitmap* dstBitmap) {
     const jint* array = env->GetIntArrayElements(srcColors, NULL);
     const SkColor* src = (const SkColor*)array + srcOffset;
 
-    // reset to to actual choice from caller
-    dst = dstBitmap.getAddr(x, y);
+    auto sRGB = SkColorSpace::MakeSRGB();
+    SkImageInfo srcInfo = SkImageInfo::Make(
+            width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
+    SkPixmap srcPM(srcInfo, src, srcStride * 4);
 
-    SkColorSpace* colorSpace = dstBitmap.colorSpace();
-    if (dstBitmap.colorType() == kRGBA_F16_SkColorType || IsColorSpaceSRGB(colorSpace)) {
-        // now copy/convert each scanline
-        for (int y = 0; y < height; y++) {
-            proc(dst, src, width, x, y);
-            src += srcStride;
-            dst = (char*)dst + dstBitmap.rowBytes();
-        }
-    } else {
-        auto sRGB = SkColorSpace::MakeSRGB();
-        auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace);
-
-        std::unique_ptr<SkColor[]> row(new SkColor[width]);
-
-        // now copy/convert each scanline
-        for (int y = 0; y < height; y++) {
-            memcpy(row.get(), src, sizeof(SkColor) * width);
-            xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, row.get(),
-                    SkColorSpaceXform::kBGRA_8888_ColorFormat, row.get(), width,
-                    SkAlphaType::kUnpremul_SkAlphaType);
-
-            proc(dst, row.get(), width, x, y);
-            src += srcStride;
-            dst = (char*)dst + dstBitmap.rowBytes();
-        }
-    }
-
-    dstBitmap.notifyPixelsChanged();
+    dstBitmap->writePixels(srcPM, x, y);
 
     env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT);
     return true;
@@ -491,90 +328,6 @@
 
 //////////////////// ToColor procs
 
-typedef void (*ToColorProc)(SkColor dst[], const void* src, int width);
-
-static void ToColor_F16_Alpha(SkColor dst[], const void* src, int width) {
-    SkASSERT(width > 0);
-    uint64_t* s = (uint64_t*)src;
-    do {
-        *dst++ = SkPM4f::FromF16((const uint16_t*) s++).unpremul().toSkColor();
-    } while (--width != 0);
-}
-
-static void ToColor_F16_Raw(SkColor dst[], const void* src, int width) {
-    SkASSERT(width > 0);
-    uint64_t* s = (uint64_t*)src;
-    do {
-        *dst++ = Sk4f_toS32(swizzle_rb(SkHalfToFloat_finite_ftz(*s++)));
-    } while (--width != 0);
-}
-
-static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width) {
-    SkASSERT(width > 0);
-    const SkPMColor* s = (const SkPMColor*)src;
-    do {
-        *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
-    } while (--width != 0);
-}
-
-static void ToColor_S32_Raw(SkColor dst[], const void* src, int width) {
-    SkASSERT(width > 0);
-    const SkPMColor* s = (const SkPMColor*)src;
-    do {
-        SkPMColor c = *s++;
-        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
-                                SkGetPackedG32(c), SkGetPackedB32(c));
-    } while (--width != 0);
-}
-
-static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width) {
-    SkASSERT(width > 0);
-    const SkPMColor* s = (const SkPMColor*)src;
-    do {
-        SkPMColor c = *s++;
-        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
-                               SkGetPackedB32(c));
-    } while (--width != 0);
-}
-
-static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width) {
-    SkASSERT(width > 0);
-    const SkPMColor16* s = (const SkPMColor16*)src;
-    do {
-        *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
-    } while (--width != 0);
-}
-
-static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width) {
-    SkASSERT(width > 0);
-    const SkPMColor16* s = (const SkPMColor16*)src;
-    do {
-        SkPMColor c = SkPixel4444ToPixel32(*s++);
-        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
-                                SkGetPackedG32(c), SkGetPackedB32(c));
-    } while (--width != 0);
-}
-
-static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width) {
-    SkASSERT(width > 0);
-    const SkPMColor16* s = (const SkPMColor16*)src;
-    do {
-        SkPMColor c = SkPixel4444ToPixel32(*s++);
-        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
-                               SkGetPackedB32(c));
-    } while (--width != 0);
-}
-
-static void ToColor_S565(SkColor dst[], const void* src, int width) {
-    SkASSERT(width > 0);
-    const uint16_t* s = (const uint16_t*)src;
-    do {
-        uint16_t c = *s++;
-        *dst++ =  SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
-                                SkPacked16ToB32(c));
-    } while (--width != 0);
-}
-
 static void ToColor_SA8(SkColor dst[], const void* src, int width) {
     SkASSERT(width > 0);
     const uint8_t* s = (const uint8_t*)src;
@@ -584,52 +337,6 @@
     } while (--width != 0);
 }
 
-// can return NULL
-static ToColorProc ChooseToColorProc(const SkBitmap& src) {
-    switch (src.colorType()) {
-        case kN32_SkColorType:
-            switch (src.alphaType()) {
-                case kOpaque_SkAlphaType:
-                    return ToColor_S32_Opaque;
-                case kPremul_SkAlphaType:
-                    return ToColor_S32_Alpha;
-                case kUnpremul_SkAlphaType:
-                    return ToColor_S32_Raw;
-                default:
-                    return NULL;
-            }
-        case kARGB_4444_SkColorType:
-            switch (src.alphaType()) {
-                case kOpaque_SkAlphaType:
-                    return ToColor_S4444_Opaque;
-                case kPremul_SkAlphaType:
-                    return ToColor_S4444_Alpha;
-                case kUnpremul_SkAlphaType:
-                    return ToColor_S4444_Raw;
-                default:
-                    return NULL;
-            }
-        case kRGB_565_SkColorType:
-            return ToColor_S565;
-        case kAlpha_8_SkColorType:
-            return ToColor_SA8;
-        case kRGBA_F16_SkColorType:
-            switch (src.alphaType()) {
-                case kOpaque_SkAlphaType:
-                    return ToColor_F16_Raw;
-                case kPremul_SkAlphaType:
-                    return ToColor_F16_Alpha;
-                case kUnpremul_SkAlphaType:
-                    return ToColor_F16_Raw;
-                default:
-                    return NULL;
-            }
-        default:
-            break;
-    }
-    return NULL;
-}
-
 static void ToF16_SA8(void* dst, const void* src, int width) {
     SkASSERT(width > 0);
     uint64_t* d = (uint64_t*)dst;
@@ -694,7 +401,7 @@
     }
 
     if (jColors != NULL) {
-        GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap);
+        GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, &bitmap);
     }
 
     return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
@@ -1271,7 +978,7 @@
     if (!bitmapHolder.valid()) return JNI_TRUE;
 
     SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
-    return IsColorSpaceSRGB(colorSpace);
+    return colorSpace == nullptr || colorSpace->isSRGB();
 }
 
 static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -1330,28 +1037,13 @@
     SkBitmap bitmap;
     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
 
-    ToColorProc proc = ChooseToColorProc(bitmap);
-    if (NULL == proc) {
-        return 0;
-    }
-    const void* src = bitmap.getAddr(x, y);
-    if (NULL == src) {
-        return 0;
-    }
+    auto sRGB = SkColorSpace::MakeSRGB();
+    SkImageInfo dstInfo = SkImageInfo::Make(
+            1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
 
-    SkColor dst[1];
-    proc(dst, src, 1);
-
-    SkColorSpace* colorSpace = bitmap.colorSpace();
-    if (bitmap.colorType() != kRGBA_F16_SkColorType &&  !IsColorSpaceSRGB(colorSpace)) {
-        auto sRGB = SkColorSpace::MakeSRGB();
-        auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get());
-        xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0],
-                SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], 1,
-                SkAlphaType::kUnpremul_SkAlphaType);
-    }
-
-    return static_cast<jint>(dst[0]);
+    SkColor dst;
+    bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
+    return static_cast<jint>(dst);
 }
 
 static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
@@ -1360,41 +1052,12 @@
     SkBitmap bitmap;
     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
 
-    ToColorProc proc = ChooseToColorProc(bitmap);
-    if (NULL == proc) {
-        return;
-    }
-    const void* src = bitmap.getAddr(x, y);
-    if (NULL == src) {
-        return;
-    }
+    auto sRGB = SkColorSpace::MakeSRGB();
+    SkImageInfo dstInfo = SkImageInfo::Make(
+            width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
 
     jint* dst = env->GetIntArrayElements(pixelArray, NULL);
-    SkColor* d = (SkColor*)dst + offset;
-
-    SkColorSpace* colorSpace = bitmap.colorSpace();
-    if (bitmap.colorType() == kRGBA_F16_SkColorType || IsColorSpaceSRGB(colorSpace)) {
-        while (--height >= 0) {
-            proc(d, src, width);
-            d += stride;
-            src = (void*)((const char*)src + bitmap.rowBytes());
-        }
-    } else {
-        auto sRGB = SkColorSpace::MakeSRGB();
-        auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get());
-
-        while (--height >= 0) {
-            proc(d, src, width);
-
-            xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, d,
-                    SkColorSpaceXform::kBGRA_8888_ColorFormat, d, width,
-                    SkAlphaType::kUnpremul_SkAlphaType);
-
-            d += stride;
-            src = (void*)((const char*)src + bitmap.rowBytes());
-        }
-    }
-
+    bitmap.readPixels(dstInfo, dst + offset, stride * 4, x, y);
     env->ReleaseIntArrayElements(pixelArray, dst, 0);
 }
 
@@ -1405,26 +1068,13 @@
     SkBitmap bitmap;
     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
     SkColor color = static_cast<SkColor>(colorHandle);
-    if (NULL == bitmap.getPixels()) {
-        return;
-    }
 
-    FromColorProc proc = ChooseFromColorProc(bitmap);
-    if (NULL == proc) {
-        return;
-    }
+    auto sRGB = SkColorSpace::MakeSRGB();
+    SkImageInfo srcInfo = SkImageInfo::Make(
+            1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
+    SkPixmap srcPM(srcInfo, &color, srcInfo.minRowBytes());
 
-    SkColorSpace* colorSpace = bitmap.colorSpace();
-    if (bitmap.colorType() != kRGBA_F16_SkColorType && !IsColorSpaceSRGB(colorSpace)) {
-        auto sRGB = SkColorSpace::MakeSRGB();
-        auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace);
-        xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &color,
-                SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, 1,
-                SkAlphaType::kUnpremul_SkAlphaType);
-    }
-
-    proc(bitmap.getAddr(x, y), &color, 1, x, y);
-    bitmap.notifyPixelsChanged();
+    bitmap.writePixels(srcPM, x, y);
 }
 
 static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
@@ -1433,7 +1083,7 @@
     SkBitmap bitmap;
     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
     GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
-            x, y, width, height, bitmap);
+            x, y, width, height, &bitmap);
 }
 
 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 9d85cc2..cee3c46 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -102,7 +102,7 @@
     */
     static bool SetPixels(JNIEnv* env, jintArray colors, int srcOffset,
             int srcStride, int x, int y, int width, int height,
-            const SkBitmap& dstBitmap);
+            SkBitmap* dstBitmap);
 
     static SkColorSpaceTransferFn getNativeTransferParameters(JNIEnv* env, jobject transferParams);
     static SkMatrix44 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50);
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index db3bfe6..eba4c50 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -462,7 +462,7 @@
         return;
     }
 
-    if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
+    if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, &bitmap)) {
         return;
     }
 
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index fa9f445..830ca83 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -179,6 +179,10 @@
         argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
       }
 
+      if (stat(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR, &st) == 0) {
+        argv[argc++] = AssetManager::PRODUCT_SERVICES_OVERLAY_DIR;
+      }
+
       // Finally, invoke idmap (if any overlay directory exists)
       if (argc > 5) {
         execv(AssetManager::IDMAP_BIN, (char* const*)argv);
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index c5904e0..f56f7ec 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -87,13 +87,17 @@
   static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/";
   static const char* kSystemProductOverlayDir = "/system/product/overlay/";
   static const char* kProductOverlayDir = "/product/overlay";
+  static const char* kSystemProductServicesOverlayDir = "/system/product_services/overlay/";
+  static const char* kProductServicesOverlayDir = "/product_services/overlay";
   static const char* kApkSuffix = ".apk";
 
   if ((android::base::StartsWith(path, kOverlayDir)
        || android::base::StartsWith(path, kOverlaySubdir)
        || android::base::StartsWith(path, kVendorOverlayDir)
        || android::base::StartsWith(path, kSystemProductOverlayDir)
-       || android::base::StartsWith(path, kProductOverlayDir))
+       || android::base::StartsWith(path, kProductOverlayDir)
+       || android::base::StartsWith(path, kSystemProductServicesOverlayDir)
+       || android::base::StartsWith(path, kProductServicesOverlayDir))
       && android::base::EndsWith(path, kApkSuffix)
       && path.find("/../") == std::string::npos) {
     return true;
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index fc625bb..843c146 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -74,6 +74,7 @@
 const char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
 const char* AssetManager::OVERLAY_DIR = "/vendor/overlay";
 const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay";
+const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay";
 const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme";
 const char* AssetManager::TARGET_PACKAGE_NAME = "android";
 const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h
index 08da731..cdb87bc 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -61,6 +61,7 @@
     static const char* IDMAP_BIN;
     static const char* OVERLAY_DIR;
     static const char* PRODUCT_OVERLAY_DIR;
+    static const char* PRODUCT_SERVICES_OVERLAY_DIR;
     /*
      * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay
      * APKs in OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 4b0379e..d829602 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1227,25 +1227,25 @@
     public boolean getIpForwardingEnabled() throws IllegalStateException{
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        final NativeDaemonEvent event;
         try {
-            event = mConnector.execute("ipfwd", "status");
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            final boolean isEnabled = mNetdService.ipfwdEnabled();
+            return isEnabled;
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
-
-        // 211 Forwarding enabled
-        event.checkCode(IpFwdStatusResult);
-        return event.getMessage().endsWith("enabled");
     }
 
     @Override
     public void setIpForwardingEnabled(boolean enable) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
-            mConnector.execute("ipfwd", enable ? "enable" : "disable", "tethering");
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            if (enable) {
+                mNetdService.ipfwdEnableForwarding("tethering");
+            } else {
+                mNetdService.ipfwdDisableForwarding("tethering");
+            }
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -1371,11 +1371,14 @@
     }
 
     private void modifyInterfaceForward(boolean add, String fromIface, String toIface) {
-        final Command cmd = new Command("ipfwd", add ? "add" : "remove", fromIface, toIface);
         try {
-            mConnector.execute(cmd);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            if (add) {
+                mNetdService.ipfwdAddInterfaceForward(fromIface, toIface);
+            } else {
+                mNetdService.ipfwdRemoveInterfaceForward(fromIface, toIface);
+            }
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 320affb..cf47d4e 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -365,10 +365,12 @@
                 continue;
             }
 
-            // If the path is in /system, /vendor or /product, ignore. It will have been
-            // ota-dexopted into /data/ota and moved into the dalvik-cache already.
-            if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")
-                    || pkg.codePath.startsWith("/product")) {
+            // If the path is in /system, /vendor, /product or /product_services, ignore. It will
+            // have been ota-dexopted into /data/ota and moved into the dalvik-cache already.
+            if (pkg.codePath.startsWith("/system")
+                    || pkg.codePath.startsWith("/vendor")
+                    || pkg.codePath.startsWith("/product")
+                    || pkg.codePath.startsWith("/product_services")) {
                 continue;
             }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3c2b089..fba4be2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -450,26 +450,27 @@
     private static final int SHELL_UID = Process.SHELL_UID;
     private static final int SE_UID = Process.SE_UID;
 
-    static final int SCAN_NO_DEX = 1<<0;
-    static final int SCAN_UPDATE_SIGNATURE = 1<<1;
-    static final int SCAN_NEW_INSTALL = 1<<2;
-    static final int SCAN_UPDATE_TIME = 1<<3;
-    static final int SCAN_BOOTING = 1<<4;
-    static final int SCAN_REQUIRE_KNOWN = 1<<7;
-    static final int SCAN_MOVE = 1<<8;
-    static final int SCAN_INITIAL = 1<<9;
-    static final int SCAN_CHECK_ONLY = 1<<10;
-    static final int SCAN_DONT_KILL_APP = 1<<11;
-    static final int SCAN_IGNORE_FROZEN = 1<<12;
-    static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1<<13;
-    static final int SCAN_AS_INSTANT_APP = 1<<14;
-    static final int SCAN_AS_FULL_APP = 1<<15;
-    static final int SCAN_AS_VIRTUAL_PRELOAD = 1<<16;
-    static final int SCAN_AS_SYSTEM = 1<<17;
-    static final int SCAN_AS_PRIVILEGED = 1<<18;
-    static final int SCAN_AS_OEM = 1<<19;
-    static final int SCAN_AS_VENDOR = 1<<20;
-    static final int SCAN_AS_PRODUCT = 1<<21;
+    static final int SCAN_NO_DEX = 1 << 0;
+    static final int SCAN_UPDATE_SIGNATURE = 1 << 1;
+    static final int SCAN_NEW_INSTALL = 1 << 2;
+    static final int SCAN_UPDATE_TIME = 1 << 3;
+    static final int SCAN_BOOTING = 1 << 4;
+    static final int SCAN_REQUIRE_KNOWN = 1 << 7;
+    static final int SCAN_MOVE = 1 << 8;
+    static final int SCAN_INITIAL = 1 << 9;
+    static final int SCAN_CHECK_ONLY = 1 << 10;
+    static final int SCAN_DONT_KILL_APP = 1 << 11;
+    static final int SCAN_IGNORE_FROZEN = 1 << 12;
+    static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 13;
+    static final int SCAN_AS_INSTANT_APP = 1 << 14;
+    static final int SCAN_AS_FULL_APP = 1 << 15;
+    static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 16;
+    static final int SCAN_AS_SYSTEM = 1 << 17;
+    static final int SCAN_AS_PRIVILEGED = 1 << 18;
+    static final int SCAN_AS_OEM = 1 << 19;
+    static final int SCAN_AS_VENDOR = 1 << 20;
+    static final int SCAN_AS_PRODUCT = 1 << 21;
+    static final int SCAN_AS_PRODUCT_SERVICES = 1 << 22;
 
     @IntDef(flag = true, prefix = { "SCAN_" }, value = {
             SCAN_NO_DEX,
@@ -575,6 +576,8 @@
 
     private static final String PRODUCT_OVERLAY_DIR = "/product/overlay";
 
+    private static final String PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay";
+
     /** Canonical intent used to identify what counts as a "web browser" app */
     private static final Intent sBrowserIntent;
     static {
@@ -2590,9 +2593,10 @@
                 scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
             }
 
-            // Collect vendor/product overlay packages. (Do this before scanning any apps.)
-            // For security and version matching reason, only consider
-            // overlay packages if they reside in the right directory.
+            // Collect vendor/product/product_services overlay packages. (Do this before scanning
+            // any apps.)
+            // For security and version matching reason, only consider overlay packages if they
+            // reside in the right directory.
             scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
                     mDefParseFlags
                     | PackageParser.PARSE_IS_SYSTEM_DIR,
@@ -2607,6 +2611,13 @@
                     | SCAN_AS_SYSTEM
                     | SCAN_AS_PRODUCT,
                     0);
+            scanDirTracedLI(new File(PRODUCT_SERVICES_OVERLAY_DIR),
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_PRODUCT_SERVICES,
+                    0);
 
             mParallelPackageParserCallback.findStaticOverlayPackages();
 
@@ -2718,7 +2729,7 @@
                     | SCAN_AS_OEM,
                     0);
 
-            // Collected privileged product packages.
+            // Collected privileged /product packages.
             File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
             try {
                 privilegedProductAppDir = privilegedProductAppDir.getCanonicalFile();
@@ -2734,7 +2745,7 @@
                     | SCAN_AS_PRIVILEGED,
                     0);
 
-            // Collect ordinary product packages.
+            // Collect ordinary /product packages.
             File productAppDir = new File(Environment.getProductDirectory(), "app");
             try {
                 productAppDir = productAppDir.getCanonicalFile();
@@ -2749,6 +2760,39 @@
                     | SCAN_AS_PRODUCT,
                     0);
 
+            // Collected privileged /product_services packages.
+            File privilegedProductServicesAppDir =
+                    new File(Environment.getProductServicesDirectory(), "priv-app");
+            try {
+                privilegedProductServicesAppDir =
+                        privilegedProductServicesAppDir.getCanonicalFile();
+            } catch (IOException e) {
+                // failed to look up canonical path, continue with original one
+            }
+            scanDirTracedLI(privilegedProductServicesAppDir,
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_PRODUCT_SERVICES
+                    | SCAN_AS_PRIVILEGED,
+                    0);
+
+            // Collect ordinary /product_services packages.
+            File productServicesAppDir = new File(Environment.getProductServicesDirectory(), "app");
+            try {
+                productServicesAppDir = productServicesAppDir.getCanonicalFile();
+            } catch (IOException e) {
+                // failed to look up canonical path, continue with original one
+            }
+            scanDirTracedLI(productServicesAppDir,
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_PRODUCT_SERVICES,
+                    0);
+
             // Prune any system packages that no longer exist.
             final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
             // Stub packages must either be replaced with full versions in the /data
@@ -2953,6 +2997,23 @@
                                     scanFlags
                                     | SCAN_AS_SYSTEM
                                     | SCAN_AS_PRODUCT;
+                        } else if (FileUtils.contains(privilegedProductServicesAppDir, scanFile)) {
+                            reparseFlags =
+                                    mDefParseFlags |
+                                    PackageParser.PARSE_IS_SYSTEM_DIR;
+                            rescanFlags =
+                                    scanFlags
+                                    | SCAN_AS_SYSTEM
+                                    | SCAN_AS_PRODUCT_SERVICES
+                                    | SCAN_AS_PRIVILEGED;
+                        } else if (FileUtils.contains(productServicesAppDir, scanFile)) {
+                            reparseFlags =
+                                    mDefParseFlags |
+                                    PackageParser.PARSE_IS_SYSTEM_DIR;
+                            rescanFlags =
+                                    scanFlags
+                                    | SCAN_AS_SYSTEM
+                                    | SCAN_AS_PRODUCT_SERVICES;
                         } else {
                             Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                             continue;
@@ -10167,6 +10228,7 @@
      * <li>{@link #SCAN_AS_OEM}</li>
      * <li>{@link #SCAN_AS_VENDOR}</li>
      * <li>{@link #SCAN_AS_PRODUCT}</li>
+     * <li>{@link #SCAN_AS_PRODUCT_SERVICES}</li>
      * <li>{@link #SCAN_AS_INSTANT_APP}</li>
      * <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li>
      * </ul>
@@ -10193,6 +10255,10 @@
                     & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0) {
                 scanFlags |= SCAN_AS_PRODUCT;
             }
+            if ((disabledPkgSetting.pkgPrivateFlags
+                    & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0) {
+                scanFlags |= SCAN_AS_PRODUCT_SERVICES;
+            }
         }
         if (pkgSetting != null) {
             final int userId = ((user == null) ? 0 : user.getIdentifier());
@@ -11035,6 +11101,10 @@
             pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT;
         }
 
+        if ((scanFlags & SCAN_AS_PRODUCT_SERVICES) != 0) {
+            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES;
+        }
+
         // Check if the package is signed with the same key as the platform package.
         if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) ||
                 (platformPkg != null && compareSignatures(
@@ -12128,6 +12198,8 @@
             codeRoot = Environment.getOdmDirectory();
         } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
             codeRoot = Environment.getProductDirectory();
+        } else if (FileUtils.contains(Environment.getProductServicesDirectory(), codePath)) {
+            codeRoot = Environment.getProductServicesDirectory();
         } else {
             // Unrecognized code path; take its top real segment as the apk root:
             // e.g. /something/app/blah.apk => /something
@@ -16675,13 +16747,16 @@
             final boolean oem = isOemApp(oldPackage);
             final boolean vendor = isVendorApp(oldPackage);
             final boolean product = isProductApp(oldPackage);
+            final boolean productServices = isProductServicesApp(oldPackage);
+
             final @ParseFlags int systemParseFlags = parseFlags;
             final @ScanFlags int systemScanFlags = scanFlags
                     | SCAN_AS_SYSTEM
                     | (privileged ? SCAN_AS_PRIVILEGED : 0)
                     | (oem ? SCAN_AS_OEM : 0)
                     | (vendor ? SCAN_AS_VENDOR : 0)
-                    | (product ? SCAN_AS_PRODUCT : 0);
+                    | (product ? SCAN_AS_PRODUCT : 0)
+                    | (productServices ? SCAN_AS_PRODUCT_SERVICES : 0);
 
             replaceSystemPackageLIF(oldPackage, pkg, systemParseFlags, systemScanFlags,
                     user, allUsers, installerPackageName, res, installReason);
@@ -17990,6 +18065,11 @@
         return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
     }
 
+    private static boolean isProductServicesApp(PackageParser.Package pkg) {
+        return (pkg.applicationInfo.privateFlags
+                & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0;
+    }
+
     private static boolean hasDomainURLs(PackageParser.Package pkg) {
         return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
     }
@@ -18729,10 +18809,13 @@
             final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
             final File privilegedOdmAppDir = new File(Environment.getOdmDirectory(), "priv-app");
             final File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
+            final File privilegedProductServicesAppDir =
+                    new File(Environment.getProductServicesDirectory(), "priv-app");
             return path.startsWith(privilegedAppDir.getCanonicalPath())
                     || path.startsWith(privilegedVendorAppDir.getCanonicalPath())
                     || path.startsWith(privilegedOdmAppDir.getCanonicalPath())
-                    || path.startsWith(privilegedProductAppDir.getCanonicalPath());
+                    || path.startsWith(privilegedProductAppDir.getCanonicalPath())
+                    || path.startsWith(privilegedProductServicesAppDir.getCanonicalPath());
         } catch (IOException e) {
             Slog.e(TAG, "Unable to access code path " + path);
         }
@@ -18767,6 +18850,15 @@
         return false;
     }
 
+    static boolean locationIsProductServices(String path) {
+        try {
+            return path.startsWith(Environment.getProductServicesDirectory().getCanonicalPath());
+        } catch (IOException e) {
+            Slog.e(TAG, "Unable to access code path " + path);
+        }
+        return false;
+    }
+
     /*
      * Tries to delete system package.
      */
@@ -18894,6 +18986,9 @@
         if (locationIsProduct(codePathString)) {
             scanFlags |= SCAN_AS_PRODUCT;
         }
+        if (locationIsProductServices(codePathString)) {
+            scanFlags |= SCAN_AS_PRODUCT_SERVICES;
+        }
 
         final File codePath = new File(codePathString);
         final PackageParser.Package pkg =
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 3834a88..f2c0395 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -25,7 +25,6 @@
 import android.accounts.IAccountManager;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.Application;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IIntentReceiver;
@@ -67,7 +66,6 @@
 import android.os.IUserManager;
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelFileDescriptor.AutoCloseInputStream;
-import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
@@ -84,11 +82,17 @@
 import android.text.format.DateUtils;
 import android.util.ArraySet;
 import android.util.PrintWriterPrinter;
+
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
+
 import dalvik.system.DexFile;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -96,10 +100,6 @@
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.net.URISyntaxException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.FileAttribute;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -110,10 +110,7 @@
 import java.util.WeakHashMap;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
-import libcore.io.IoUtils;
-import libcore.io.Streams;
 
 class PackageManagerShellCommand extends ShellCommand {
     /** Path for streaming APK content */
@@ -1777,6 +1774,15 @@
         }
     }
 
+    private boolean isProductServicesApp(String pkg) {
+        try {
+            final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+            return info != null && info.applicationInfo.isProductServices();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     private int runGetPrivappPermissions() {
         final String pkg = getNextArg();
         if (pkg == null) {
@@ -1789,6 +1795,9 @@
             privAppPermissions = SystemConfig.getInstance().getVendorPrivAppPermissions(pkg);
         } else if (isProductApp(pkg)) {
             privAppPermissions = SystemConfig.getInstance().getProductPrivAppPermissions(pkg);
+        } else if (isProductServicesApp(pkg)) {
+            privAppPermissions = SystemConfig.getInstance()
+                    .getProductServicesPrivAppPermissions(pkg);
         } else {
             privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
         }
@@ -1810,6 +1819,9 @@
             privAppPermissions = SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg);
         } else if (isProductApp(pkg)) {
             privAppPermissions = SystemConfig.getInstance().getProductPrivAppDenyPermissions(pkg);
+        } else if (isProductServicesApp(pkg)) {
+            privAppPermissions = SystemConfig.getInstance()
+                    .getProductServicesPrivAppDenyPermissions(pkg);
         } else {
             privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
         }
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index ea05b74..727fb15 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -148,6 +148,10 @@
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
     }
 
+    public boolean isProductServices() {
+        return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0;
+    }
+
     public boolean isForwardLocked() {
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
     }
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 7c92045..239dc99 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -63,6 +63,7 @@
                 | ApplicationInfo.PRIVATE_FLAG_OEM
                 | ApplicationInfo.PRIVATE_FLAG_VENDOR
                 | ApplicationInfo.PRIVATE_FLAG_PRODUCT
+                | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES
                 | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK
                 | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
     }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e9cd707..ed56a32 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -850,7 +850,8 @@
         pkgSetting.pkgPrivateFlags &= ~(ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
                 | ApplicationInfo.PRIVATE_FLAG_OEM
                 | ApplicationInfo.PRIVATE_FLAG_VENDOR
-                | ApplicationInfo.PRIVATE_FLAG_PRODUCT);
+                | ApplicationInfo.PRIVATE_FLAG_PRODUCT
+                | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES);
         pkgSetting.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;
         pkgSetting.pkgPrivateFlags |=
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
@@ -860,6 +861,8 @@
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR;
         pkgSetting.pkgPrivateFlags |=
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT;
+        pkgSetting.pkgPrivateFlags |=
+                pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES;
         pkgSetting.primaryCpuAbiString = primaryCpuAbi;
         pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
         if (childPkgNames != null) {
@@ -4445,6 +4448,7 @@
             ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY",
             ApplicationInfo.PRIVATE_FLAG_VENDOR, "VENDOR",
             ApplicationInfo.PRIVATE_FLAG_PRODUCT, "PRODUCT",
+            ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES, "PRODUCT_SERVICES",
             ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD",
     };
 
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 843cd8a..a78cb33 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -25,7 +25,6 @@
 import android.app.DownloadManager;
 import android.app.admin.DevicePolicyManager;
 import android.companion.CompanionDeviceManager;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -54,7 +53,6 @@
 import android.provider.MediaStore;
 import android.provider.Telephony.Sms.Intents;
 import android.security.Credentials;
-import android.service.textclassifier.TextClassifierService;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -1399,6 +1397,11 @@
         if (dir.isDirectory() && dir.canRead()) {
             Collections.addAll(ret, dir.listFiles());
         }
+        dir = new File(Environment.getProductServicesDirectory(),
+                "etc/default-permissions");
+        if (dir.isDirectory() && dir.canRead()) {
+            Collections.addAll(ret, dir.listFiles());
+        }
         // For IoT devices, we check the oem partition for default permissions for each app.
         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED, 0)) {
             dir = new File(Environment.getOemDirectory(), "etc/default-permissions");
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 9dc0b29..c4f90a12 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1097,6 +1097,10 @@
         } else if (pkg.isProduct()) {
             wlPermissions =
                     SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName);
+        } else if (pkg.isProductServices()) {
+            wlPermissions =
+                    SystemConfig.getInstance().getProductServicesPrivAppPermissions(
+                            pkg.packageName);
         } else {
             wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName);
         }
@@ -1129,6 +1133,9 @@
                     } else if (pkg.isProduct()) {
                         deniedPermissions = SystemConfig.getInstance()
                                 .getProductPrivAppDenyPermissions(pkg.packageName);
+                    } else if (pkg.isProductServices()) {
+                        deniedPermissions = SystemConfig.getInstance()
+                                .getProductServicesPrivAppDenyPermissions(pkg.packageName);
                     } else {
                         deniedPermissions = SystemConfig.getInstance()
                                 .getPrivAppDenyPermissions(pkg.packageName);
diff --git a/tests/libs-permissions/Android.mk b/tests/libs-permissions/Android.mk
index eb38623..f4250c8 100644
--- a/tests/libs-permissions/Android.mk
+++ b/tests/libs-permissions/Android.mk
@@ -13,3 +13,17 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions
 LOCAL_SRC_FILES:= product/com.android.test.libs.product.xml
 include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.test.libs.product_services
+LOCAL_PRODUCT_SERVICES_MODULE := true
+LOCAL_SRC_FILES := $(call all-java-files-under, product_services/java)
+LOCAL_REQUIRED_MODULES := com.android.test.libs.product_services.xml
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.test.libs.product_services.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_SERVICES_ETC)/permissions
+LOCAL_SRC_FILES:= product_services/com.android.test.libs.product_services.xml
+include $(BUILD_PREBUILT)
diff --git a/tests/libs-permissions/product_services/com.android.test.libs.product_services.xml b/tests/libs-permissions/product_services/com.android.test.libs.product_services.xml
new file mode 100644
index 0000000..082a9be
--- /dev/null
+++ b/tests/libs-permissions/product_services/com.android.test.libs.product_services.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<permissions>
+    <library name="com.android.test.libs.product_services"
+            file="/product_services/framework/com.android.test.libs.product_services.jar" />
+</permissions>
diff --git a/tests/libs-permissions/product_services/java/com/android/test/libs/product_services/LibsProductServicesTest.java b/tests/libs-permissions/product_services/java/com/android/test/libs/product_services/LibsProductServicesTest.java
new file mode 100644
index 0000000..dcbdae8
--- /dev/null
+++ b/tests/libs-permissions/product_services/java/com/android/test/libs/product_services/LibsProductServicesTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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 com.android.test.libs.product_services;
+
+/**
+ * Test class for product_services libs.
+ */
+public class LibsProductServicesTest {
+
+    /**
+     * Dummy method for testing.
+     */
+    public static void test() {
+    }
+}
diff --git a/tests/privapp-permissions/Android.mk b/tests/privapp-permissions/Android.mk
index 9795188..1149b8a 100644
--- a/tests/privapp-permissions/Android.mk
+++ b/tests/privapp-permissions/Android.mk
@@ -46,3 +46,19 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions
 LOCAL_SRC_FILES:= product/privapp-permissions-test.xml
 include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := ProductServicesPrivAppPermissionTest
+LOCAL_SDK_VERSION := current
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MANIFEST_FILE := product_services/AndroidManifest.xml
+LOCAL_PRODUCT_SERVICES_MODULE := true
+LOCAL_REQUIRED_MODULES := product_servicesprivapp-permissions-test.xml
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := product_servicesprivapp-permissions-test.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_SERVICES_ETC)/permissions
+LOCAL_SRC_FILES:= product_services/privapp-permissions-test.xml
+include $(BUILD_PREBUILT)
diff --git a/tests/privapp-permissions/product_services/AndroidManifest.xml b/tests/privapp-permissions/product_services/AndroidManifest.xml
new file mode 100644
index 0000000..511ddee
--- /dev/null
+++ b/tests/privapp-permissions/product_services/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.framework.permission.privapp.tests.product_services">
+
+    <!-- MANAGE_USB is signature|privileged -->
+    <uses-permission android:name="android.permission.MANAGE_USB"/>
+</manifest>
diff --git a/tests/privapp-permissions/product_services/privapp-permissions-test.xml b/tests/privapp-permissions/product_services/privapp-permissions-test.xml
new file mode 100644
index 0000000..43baebb
--- /dev/null
+++ b/tests/privapp-permissions/product_services/privapp-permissions-test.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+    <privapp-permissions package="com.android.framework.permission.privapp.tests.product_services">
+        <permission name="android.permission.MANAGE_USB"/>
+    </privapp-permissions>
+</permissions>