diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 525cd5f64c2ad..380110f53f3b4 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -791,7 +791,7 @@ Landroid/graphics/BitmapFactory;->nativeDecodeByteArray([BIILandroid/graphics/Bi Landroid/graphics/BitmapFactory;->nativeDecodeFileDescriptor(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap; Landroid/graphics/BitmapFactory;->nativeDecodeStream(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap; Landroid/graphics/Bitmap;->getDefaultDensity()I -Landroid/graphics/Bitmap;->(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V +Landroid/graphics/Bitmap;->(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;)V Landroid/graphics/Bitmap;->mNativePtr:J Landroid/graphics/Bitmap;->mNinePatchChunk:[B Landroid/graphics/Bitmap;->mNinePatchInsets:Landroid/graphics/NinePatch$InsetStruct; diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 5a74a2473b320..735232424c554 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -205,9 +205,12 @@ jobject createBitmap(JNIEnv* env, Bitmap* bitmap, // native SkBitmap stays in sync with the Java Bitmap. assert_premultiplied(bitmap->info(), isPremultiplied); BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap); + if (!isMutable) { + bitmapWrapper->bitmap().setImmutable(); + } jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID, reinterpret_cast(bitmapWrapper), bitmap->width(), bitmap->height(), density, - isMutable, isPremultiplied, ninePatchChunk, ninePatchInsets); + isPremultiplied, ninePatchChunk, ninePatchInsets); if (env->ExceptionCheck() != 0) { ALOGE("*** Uncaught exception returned from Java call!\n"); @@ -1571,6 +1574,20 @@ static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlon dstBitmapHandle->bitmap().setColorSpace(srcBitmapHandle->bitmap().info().refColorSpace()); } +static jboolean Bitmap_isImmutable(jlong bitmapHandle) { + LocalScopedBitmap bitmapHolder(bitmapHandle); + if (!bitmapHolder.valid()) return JNI_FALSE; + + return bitmapHolder->bitmap().isImmutable() ? JNI_TRUE : JNI_FALSE; +} + +static void Bitmap_setImmutable(JNIEnv* env, jobject, jlong bitmapHandle) { + LocalScopedBitmap bitmapHolder(bitmapHandle); + if (!bitmapHolder.valid()) return; + + return bitmapHolder->bitmap().setImmutable(); +} + /////////////////////////////////////////////////////////////////////////////// static const JNINativeMethod gBitmapMethods[] = { @@ -1626,13 +1643,18 @@ static const JNINativeMethod gBitmapMethods[] = { { "nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear}, { "nativeCopyColorSpace", "(JJ)V", (void*)Bitmap_copyColorSpace }, + { "nativeSetImmutable", "(J)V", (void*)Bitmap_setImmutable}, + + // ------------ @CriticalNative ---------------- + { "nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable} + }; int register_android_graphics_Bitmap(JNIEnv* env) { gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap")); gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J"); - gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); + gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V"); gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I"); return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index e8ede94f62bb7..d6c119fbdd201 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -33,6 +33,8 @@ import android.view.DisplayListCanvas; import android.view.RenderNode; import android.view.ThreadedRenderer; +import dalvik.annotation.optimization.CriticalNative; + import libcore.util.NativeAllocationRegistry; import java.io.OutputStream; @@ -59,8 +61,6 @@ public final class Bitmap implements Parcelable { // Convenience for JNI access private final long mNativePtr; - private final boolean mIsMutable; - /** * Represents whether the Bitmap's content is requested to be pre-multiplied. * Note that isPremultiplied() does not directly return this value, because @@ -117,8 +117,7 @@ public final class Bitmap implements Parcelable { * int (pointer). */ // called from JNI - Bitmap(long nativeBitmap, int width, int height, int density, - boolean isMutable, boolean requestPremultiplied, + Bitmap(long nativeBitmap, int width, int height, int density, boolean requestPremultiplied, byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) { if (nativeBitmap == 0) { throw new RuntimeException("internal error: native bitmap is 0"); @@ -126,7 +125,6 @@ public final class Bitmap implements Parcelable { mWidth = width; mHeight = height; - mIsMutable = isMutable; mRequestPremultiplied = requestPremultiplied; mNinePatchChunk = ninePatchChunk; @@ -742,7 +740,7 @@ public final class Bitmap implements Parcelable { } /** - * Returns an immutable bitmap from the source bitmap. The new bitmap may + * Returns a bitmap from the source bitmap. The new bitmap may * be the same object as source, or a copy may have been made. It is * initialized with the same density and color space as the original bitmap. */ @@ -751,7 +749,7 @@ public final class Bitmap implements Parcelable { } /** - * Returns an immutable bitmap from the specified subset of the source + * Returns a bitmap from the specified subset of the source * bitmap. The new bitmap may be the same object as source, or a copy may * have been made. It is initialized with the same density and color space * as the original bitmap. @@ -771,7 +769,7 @@ public final class Bitmap implements Parcelable { } /** - * Returns an immutable bitmap from subset of the source bitmap, + * Returns a bitmap from subset of the source bitmap, * transformed by the optional matrix. The new bitmap may be the * same object as source, or a copy may have been made. It is * initialized with the same density and color space as the original @@ -781,6 +779,12 @@ public final class Bitmap implements Parcelable { * same as the source bitmap itself, then the source bitmap is * returned and no new bitmap is created. * + * The returned bitmap will always be mutable except in the following scenarios: + * (1) In situations where the source bitmap is returned and the source bitmap is immutable + * + * (2) The source bitmap is a hardware bitmap. That is {@link #getConfig()} is equivalent to + * {@link Config#HARDWARE} + * * @param source The bitmap we are subsetting * @param x The x coordinate of the first pixel in source * @param y The y coordinate of the first pixel in source @@ -1218,11 +1222,9 @@ public final class Bitmap implements Parcelable { * scaled to match if necessary. * @param height The height of the bitmap to create. The picture's height will be * scaled to match if necessary. - * @param config The {@link Config} of the created bitmap. If this is null then - * the bitmap will be {@link Config#HARDWARE}. + * @param config The {@link Config} of the created bitmap. * - * @return An immutable bitmap with a HARDWARE config whose contents are created - * from the recorded drawing commands in the Picture source. + * @return An immutable bitmap with a configuration specified by the config parameter */ public static @NonNull Bitmap createBitmap(@NonNull Picture source, int width, int height, @NonNull Config config) { @@ -1260,7 +1262,7 @@ public final class Bitmap implements Parcelable { } canvas.drawPicture(source); canvas.setBitmap(null); - bitmap.makeImmutable(); + bitmap.setImmutable(); return bitmap; } } @@ -1351,13 +1353,22 @@ public final class Bitmap implements Parcelable { * Returns true if the bitmap is marked as mutable (i.e. can be drawn into) */ public final boolean isMutable() { - return mIsMutable; + return !nativeIsImmutable(mNativePtr); } - /** @hide */ - public final void makeImmutable() { - // todo mIsMutable = false; - // todo nMakeImmutable(); + /** + * Marks the Bitmap as immutable. Further modifications to this Bitmap are disallowed. + * After this method is called, this Bitmap cannot be made mutable again and subsequent calls + * to {@link #reconfigure(int, int, Config)}, {@link #setPixel(int, int, int)}, + * {@link #setPixels(int[], int, int, int, int, int, int)} and {@link #eraseColor(int)} will + * fail and throw an IllegalStateException. + * + * @hide + */ + public void setImmutable() { + if (isMutable()) { + nativeSetImmutable(mNativePtr); + } } /** @@ -1923,7 +1934,7 @@ public final class Bitmap implements Parcelable { public void writeToParcel(Parcel p, int flags) { checkRecycled("Can't parcel a recycled bitmap"); noteHardwareBitmapSlowCall(); - if (!nativeWriteToParcel(mNativePtr, mIsMutable, mDensity, p)) { + if (!nativeWriteToParcel(mNativePtr, isMutable(), mDensity, p)) { throw new RuntimeException("native writeToParcel failed"); } } @@ -2096,4 +2107,11 @@ public final class Bitmap implements Parcelable { private static native boolean nativeIsSRGB(long nativePtr); private static native boolean nativeIsSRGBLinear(long nativePtr); private static native void nativeCopyColorSpace(long srcBitmap, long dstBitmap); + + private static native void nativeSetImmutable(long nativePtr); + + // ---------------- @CriticalNative ------------------- + + @CriticalNative + private static native boolean nativeIsImmutable(long nativePtr); }