Use public APIs for decoding images for the boot animation
HWUI is restricting access to only a set of stable C APIs. Callers like
boot animation are being converted to either the stable C or NDK APIs.
Test: build and verify animation on reboot
Bug: 150782769
Change-Id: I1fb7c9e0ed2f7bcecec109ddc32b1c5a473f7f3a
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index a1278f3..f08c79a 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -34,6 +34,7 @@
#include <cutils/atomic.h>
#include <cutils/properties.h>
+#include <android/imagedecoder.h>
#include <androidfw/AssetManager.h>
#include <binder/IPCThreadState.h>
#include <utils/Errors.h>
@@ -51,14 +52,6 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-// TODO: Fix Skia.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#include <SkBitmap.h>
-#include <SkImage.h>
-#include <SkStream.h>
-#pragma GCC diagnostic pop
-
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <EGL/eglext.h>
@@ -165,22 +158,51 @@
requestExit();
}
+static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo) {
+ AImageDecoder* decoder = nullptr;
+ AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder);
+ if (!decoder) {
+ return nullptr;
+ }
+
+ const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
+ outInfo->width = AImageDecoderHeaderInfo_getWidth(info);
+ outInfo->height = AImageDecoderHeaderInfo_getHeight(info);
+ outInfo->format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
+ outInfo->stride = AImageDecoder_getMinimumStride(decoder);
+ outInfo->flags = 0;
+
+ const size_t size = outInfo->stride * outInfo->height;
+ void* pixels = malloc(size);
+ int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size);
+ AImageDecoder_delete(decoder);
+
+ if (result != ANDROID_IMAGE_DECODER_SUCCESS) {
+ free(pixels);
+ return nullptr;
+ }
+ return pixels;
+}
+
status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
const char* name) {
Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
if (asset == nullptr)
return NO_INIT;
- SkBitmap bitmap;
- sk_sp<SkData> data = SkData::MakeWithoutCopy(asset->getBuffer(false),
- asset->getLength());
- sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);
- image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode);
+
+ AndroidBitmapInfo bitmapInfo;
+ void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo);
+ auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
+
asset->close();
delete asset;
- const int w = bitmap.width();
- const int h = bitmap.height();
- const void* p = bitmap.getPixels();
+ if (!pixels) {
+ return NO_INIT;
+ }
+
+ const int w = bitmapInfo.width;
+ const int h = bitmapInfo.height;
GLint crop[4] = { 0, h, w, -h };
texture->w = w;
@@ -189,22 +211,22 @@
glGenTextures(1, &texture->name);
glBindTexture(GL_TEXTURE_2D, texture->name);
- switch (bitmap.colorType()) {
- case kAlpha_8_SkColorType:
+ switch (bitmapInfo.format) {
+ case ANDROID_BITMAP_FORMAT_A_8:
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
- GL_UNSIGNED_BYTE, p);
+ GL_UNSIGNED_BYTE, pixels);
break;
- case kARGB_4444_SkColorType:
+ case ANDROID_BITMAP_FORMAT_RGBA_4444:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
- GL_UNSIGNED_SHORT_4_4_4_4, p);
+ GL_UNSIGNED_SHORT_4_4_4_4, pixels);
break;
- case kN32_SkColorType:
+ case ANDROID_BITMAP_FORMAT_RGBA_8888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
- GL_UNSIGNED_BYTE, p);
+ GL_UNSIGNED_BYTE, pixels);
break;
- case kRGB_565_SkColorType:
+ case ANDROID_BITMAP_FORMAT_RGB_565:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
- GL_UNSIGNED_SHORT_5_6_5, p);
+ GL_UNSIGNED_SHORT_5_6_5, pixels);
break;
default:
break;
@@ -221,20 +243,21 @@
status_t BootAnimation::initTexture(FileMap* map, int* width, int* height)
{
- SkBitmap bitmap;
- sk_sp<SkData> data = SkData::MakeWithoutCopy(map->getDataPtr(),
- map->getDataLength());
- sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);
- image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode);
+ AndroidBitmapInfo bitmapInfo;
+ void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo);
+ auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
// FileMap memory is never released until application exit.
// Release it now as the texture is already loaded and the memory used for
// the packed resource can be released.
delete map;
- const int w = bitmap.width();
- const int h = bitmap.height();
- const void* p = bitmap.getPixels();
+ if (!pixels) {
+ return NO_INIT;
+ }
+
+ const int w = bitmapInfo.width;
+ const int h = bitmapInfo.height;
GLint crop[4] = { 0, h, w, -h };
int tw = 1 << (31 - __builtin_clz(w));
@@ -242,28 +265,28 @@
if (tw < w) tw <<= 1;
if (th < h) th <<= 1;
- switch (bitmap.colorType()) {
- case kN32_SkColorType:
+ switch (bitmapInfo.format) {
+ case ANDROID_BITMAP_FORMAT_RGBA_8888:
if (!mUseNpotTextures && (tw != w || th != h)) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
+ 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
- GL_UNSIGNED_BYTE, p);
+ GL_UNSIGNED_BYTE, pixels);
}
break;
- case kRGB_565_SkColorType:
+ case ANDROID_BITMAP_FORMAT_RGB_565:
if (!mUseNpotTextures && (tw != w || th != h)) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
GL_UNSIGNED_SHORT_5_6_5, nullptr);
glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
+ 0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
- GL_UNSIGNED_SHORT_5_6_5, p);
+ GL_UNSIGNED_SHORT_5_6_5, pixels);
}
break;
default: