summaryrefslogtreecommitdiff
path: root/native
diff options
context:
space:
mode:
Diffstat (limited to 'native')
-rw-r--r--native/android/Android.bp22
-rw-r--r--native/android/choreographer.cpp225
-rw-r--r--native/android/libandroid.map.txt8
-rw-r--r--native/android/surface_control.cpp30
-rw-r--r--native/android/surface_texture.cpp76
-rw-r--r--native/android/system_fonts.cpp61
-rw-r--r--native/android/thermal.cpp261
-rw-r--r--native/graphics/jni/Android.bp13
-rw-r--r--native/graphics/jni/aassetstreamadaptor.cpp117
-rw-r--r--native/graphics/jni/aassetstreamadaptor.h50
-rw-r--r--native/graphics/jni/bitmap.cpp65
-rw-r--r--native/graphics/jni/imagedecoder.cpp348
-rw-r--r--native/graphics/jni/libjnigraphics.map.txt22
-rw-r--r--native/webview/plat_support/Android.bp4
-rw-r--r--native/webview/plat_support/graphics_utils.cpp4
15 files changed, 957 insertions, 349 deletions
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 9f52d856ea75..ccc89f01955b 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -25,6 +25,7 @@ cc_defaults {
cflags: [
"-Wall",
"-Werror",
+ "-Wextra",
"-Wunused",
"-Wunreachable-code",
],
@@ -36,7 +37,6 @@ cc_library_shared {
srcs: [
"asset_manager.cpp",
- "choreographer.cpp",
"configuration.cpp",
"hardware_buffer_jni.cpp",
"input.cpp",
@@ -48,10 +48,10 @@ cc_library_shared {
"sensor.cpp",
"sharedmem.cpp",
"storage_manager.cpp",
- "surface_texture.cpp",
"surface_control.cpp",
"system_fonts.cpp",
"trace.cpp",
+ "thermal.cpp"
],
shared_libs: [
@@ -71,6 +71,9 @@ cc_library_shared {
"libnetd_client",
"libhwui",
"libxml2",
+ "libEGL",
+ "libGLESv2",
+ "libpowermanager",
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
],
@@ -80,7 +83,9 @@ cc_library_shared {
"libarect",
],
- whole_static_libs: ["libnativewindow"],
+ header_libs: [ "libhwui_internal_headers" ],
+
+ whole_static_libs: ["libnativedisplay", "libnativewindow"],
export_static_lib_headers: ["libarect"],
@@ -123,11 +128,16 @@ llndk_library {
// Aidl library for platform compat.
cc_library_shared {
name: "lib-platform-compat-native-api",
- defaults: ["libandroid_defaults"],
-
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-variable",
+ "-Wunused-parameter",
+ ],
shared_libs: [
"libbinder",
- "libutils",
+ "libutils",
],
aidl: {
local_include_dirs: ["aidl"],
diff --git a/native/android/choreographer.cpp b/native/android/choreographer.cpp
deleted file mode 100644
index 63e073405fe0..000000000000
--- a/native/android/choreographer.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#define LOG_TAG "Choreographer"
-//#define LOG_NDEBUG 0
-
-#include <cinttypes>
-#include <queue>
-#include <thread>
-
-#include <android/choreographer.h>
-#include <androidfw/DisplayEventDispatcher.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/SurfaceComposerClient.h>
-#include <utils/Looper.h>
-#include <utils/Mutex.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-static inline const char* toString(bool value) {
- return value ? "true" : "false";
-}
-
-struct FrameCallback {
- AChoreographer_frameCallback callback;
- AChoreographer_frameCallback64 callback64;
- void* data;
- nsecs_t dueTime;
-
- inline bool operator<(const FrameCallback& rhs) const {
- // Note that this is intentionally flipped because we want callbacks due sooner to be at
- // the head of the queue
- return dueTime > rhs.dueTime;
- }
-};
-
-
-class Choreographer : public DisplayEventDispatcher, public MessageHandler {
-public:
- void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
- AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
-
- enum {
- MSG_SCHEDULE_CALLBACKS = 0,
- MSG_SCHEDULE_VSYNC = 1
- };
- virtual void handleMessage(const Message& message) override;
-
- static Choreographer* getForThread();
-
-protected:
- virtual ~Choreographer() = default;
-
-private:
- explicit Choreographer(const sp<Looper>& looper);
- Choreographer(const Choreographer&) = delete;
-
- void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
- void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
- void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
- int32_t configId) override;
-
- void scheduleCallbacks();
-
- // Protected by mLock
- std::priority_queue<FrameCallback> mCallbacks;
-
- mutable Mutex mLock;
-
- const sp<Looper> mLooper;
- const std::thread::id mThreadId;
-};
-
-
-static thread_local Choreographer* gChoreographer;
-Choreographer* Choreographer::getForThread() {
- if (gChoreographer == nullptr) {
- sp<Looper> looper = Looper::getForThread();
- if (!looper.get()) {
- ALOGW("No looper prepared for thread");
- return nullptr;
- }
- gChoreographer = new Choreographer(looper);
- status_t result = gChoreographer->initialize();
- if (result != OK) {
- ALOGW("Failed to initialize");
- return nullptr;
- }
- }
- return gChoreographer;
-}
-
-Choreographer::Choreographer(const sp<Looper>& looper) :
- DisplayEventDispatcher(looper), mLooper(looper), mThreadId(std::this_thread::get_id()) {
-}
-
-void Choreographer::postFrameCallbackDelayed(
- AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- FrameCallback callback{cb, cb64, data, now + delay};
- {
- AutoMutex _l{mLock};
- mCallbacks.push(callback);
- }
- if (callback.dueTime <= now) {
- if (std::this_thread::get_id() != mThreadId) {
- Message m{MSG_SCHEDULE_VSYNC};
- mLooper->sendMessage(this, m);
- } else {
- scheduleVsync();
- }
- } else {
- Message m{MSG_SCHEDULE_CALLBACKS};
- mLooper->sendMessageDelayed(delay, this, m);
- }
-}
-
-void Choreographer::scheduleCallbacks() {
- AutoMutex _{mLock};
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- if (mCallbacks.top().dueTime <= now) {
- ALOGV("choreographer %p ~ scheduling vsync", this);
- scheduleVsync();
- return;
- }
-}
-
-// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
-// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
-// the internal display implicitly.
-void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) {
- std::vector<FrameCallback> callbacks{};
- {
- AutoMutex _l{mLock};
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- while (!mCallbacks.empty() && mCallbacks.top().dueTime < now) {
- callbacks.push_back(mCallbacks.top());
- mCallbacks.pop();
- }
- }
- for (const auto& cb : callbacks) {
- if (cb.callback64 != nullptr) {
- cb.callback64(timestamp, cb.data);
- } else if (cb.callback != nullptr) {
- cb.callback(timestamp, cb.data);
- }
- }
-}
-
-void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
- ALOGV("choreographer %p ~ received hotplug event (displayId=%"
- ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", connected=%s), ignoring.",
- this, displayId, toString(connected));
-}
-
-void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId,
- int32_t configId) {
- ALOGV("choreographer %p ~ received config changed event (displayId=%"
- ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%s), ignoring.",
- this, displayId, toString(configId));
-}
-
-void Choreographer::handleMessage(const Message& message) {
- switch (message.what) {
- case MSG_SCHEDULE_CALLBACKS:
- scheduleCallbacks();
- break;
- case MSG_SCHEDULE_VSYNC:
- scheduleVsync();
- break;
- }
-}
-
-}
-
-/* Glue for the NDK interface */
-
-using android::Choreographer;
-
-static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
- return reinterpret_cast<Choreographer*>(choreographer);
-}
-
-static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
- return reinterpret_cast<AChoreographer*>(choreographer);
-}
-
-AChoreographer* AChoreographer_getInstance() {
- return Choreographer_to_AChoreographer(Choreographer::getForThread());
-}
-
-void AChoreographer_postFrameCallback(AChoreographer* choreographer,
- AChoreographer_frameCallback callback, void* data) {
- AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
- callback, nullptr, data, 0);
-}
-void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
- AChoreographer_frameCallback callback, void* data, long delayMillis) {
- AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
- callback, nullptr, data, ms2ns(delayMillis));
-}
-void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
- AChoreographer_frameCallback64 callback, void* data) {
- AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
- nullptr, callback, data, 0);
-}
-void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
- AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) {
- AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
- nullptr, callback, data, ms2ns(delayMillis));
-}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 203adfc749d2..d56aa86ae6fa 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -23,6 +23,8 @@ LIBANDROID {
AChoreographer_postFrameCallbackDelayed; # introduced=24
AChoreographer_postFrameCallback64; # introduced=29
AChoreographer_postFrameCallbackDelayed64; # introduced=29
+ AChoreographer_registerRefreshRateCallback; # introduced=30
+ AChoreographer_unregisterRefreshRateCallback; # introduced=30
AConfiguration_copy;
AConfiguration_delete;
AConfiguration_diff;
@@ -240,6 +242,7 @@ LIBANDROID {
ASurfaceTransaction_setColor; # introduced=29
ASurfaceTransaction_setDamageRegion; # introduced=29
ASurfaceTransaction_setDesiredPresentTime; # introduced=29
+ ASurfaceTransaction_setFrameRate; # introduced=30
ASurfaceTransaction_setGeometry; # introduced=29
ASurfaceTransaction_setHdrMetadata_cta861_3; # introduced=29
ASurfaceTransaction_setHdrMetadata_smpte2086; # introduced=29
@@ -277,6 +280,11 @@ LIBANDROID {
android_res_nquery; # introduced=29
android_res_nresult; # introduced=29
android_res_nsend; # introduced=29
+ AThermal_acquireManager; # introduced=30
+ AThermal_releaseManager; # introduced=30
+ AThermal_getCurrentThermalStatus; # introduced=30
+ AThermal_registerThermalStatusListener; # introduced=30
+ AThermal_unregisterThermalStatusListener; # introduced=30
local:
*;
};
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 8fe4fecceeb5..0af6cbf3cb40 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -100,7 +100,11 @@ static bool isDataSpaceValid(const sp<SurfaceControl>& surfaceControl, ADataSpac
return getWideColorSupport(surfaceControl);
// These data space need HDR support.
case HAL_DATASPACE_BT2020_PQ:
- return getHdrSupport(surfaceControl);
+ if (!getHdrSupport(surfaceControl)) {
+ ALOGE("Invalid dataspace - device does not support hdr");
+ return false;
+ }
+ return true;
default:
return false;
}
@@ -290,7 +294,7 @@ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* aSurfaceTransaction,
auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats;
- for (const auto& [surfaceControl, acquireTime, previousReleaseFence] : surfaceControlStats) {
+ for (const auto& [surfaceControl, latchTime, acquireTime, presentFence, previousReleaseFence, transformHint, frameEvents] : surfaceControlStats) {
ASurfaceControl* aSurfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
aSurfaceControlStats[aSurfaceControl].acquireTime = acquireTime;
aSurfaceControlStats[aSurfaceControl].previousReleaseFence = previousReleaseFence;
@@ -458,10 +462,11 @@ void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* aSurfaceTransac
CHECK_NOT_NULL(aSurfaceControl);
sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
- LOG_ALWAYS_FATAL_IF(!isDataSpaceValid(surfaceControl, aDataSpace), "invalid dataspace");
-
+ if (!isDataSpaceValid(surfaceControl, aDataSpace)) {
+ ALOGE("Failed to set buffer dataspace - invalid dataspace");
+ return;
+ }
Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
-
transaction->setDataspace(surfaceControl, static_cast<ui::Dataspace>(aDataSpace));
}
@@ -527,7 +532,10 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction,
CHECK_NOT_NULL(aSurfaceControl);
sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
- LOG_ALWAYS_FATAL_IF(!isDataSpaceValid(surfaceControl, dataspace), "invalid dataspace");
+ if (!isDataSpaceValid(surfaceControl, dataspace)) {
+ ALOGE("Failed to set buffer dataspace - invalid dataspace");
+ return;
+ }
Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
half3 color;
@@ -537,3 +545,13 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction,
transaction->setBackgroundColor(surfaceControl, color, alpha, static_cast<ui::Dataspace>(dataspace));
}
+
+void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* aSurfaceTransaction,
+ ASurfaceControl* aSurfaceControl, float frameRate,
+ int8_t compatibility) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ transaction->setFrameRate(surfaceControl, frameRate, compatibility);
+}
diff --git a/native/android/surface_texture.cpp b/native/android/surface_texture.cpp
deleted file mode 100644
index ced2792775d4..000000000000
--- a/native/android/surface_texture.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.
- */
-
-#include <android/surface_texture.h>
-#include <android/surface_texture_jni.h>
-
-#define LOG_TAG "ASurfaceTexture"
-
-#include <utils/Log.h>
-
-#include <gui/Surface.h>
-
-#include <android_runtime/android_graphics_SurfaceTexture.h>
-
-#include "surfacetexture/SurfaceTexture.h"
-
-using namespace android;
-
-struct ASurfaceTexture {
- sp<SurfaceTexture> consumer;
- sp<IGraphicBufferProducer> producer;
-};
-
-ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) {
- if (!surfacetexture || !android_SurfaceTexture_isInstanceOf(env, surfacetexture)) {
- return nullptr;
- }
- ASurfaceTexture* ast = new ASurfaceTexture;
- ast->consumer = SurfaceTexture_getSurfaceTexture(env, surfacetexture);
- ast->producer = SurfaceTexture_getProducer(env, surfacetexture);
- return ast;
-}
-
-ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) {
- sp<Surface> surface = new Surface(st->producer);
- ANativeWindow* win(surface.get());
- ANativeWindow_acquire(win);
- return win;
-}
-
-void ASurfaceTexture_release(ASurfaceTexture* st) {
- delete st;
-}
-
-int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t tex) {
- return st->consumer->attachToContext(tex);
-}
-
-int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) {
- return st->consumer->detachFromContext();
-}
-
-int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) {
- return st->consumer->updateTexImage();
-}
-
-void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) {
- st->consumer->getTransformMatrix(mtx);
-}
-
-int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) {
- return st->consumer->getTimestamp();
-}
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
index 9791da63359b..45f42f1b5dc6 100644
--- a/native/android/system_fonts.cpp
+++ b/native/android/system_fonts.cpp
@@ -16,6 +16,8 @@
#include <jni.h>
+#define LOG_TAG "SystemFont"
+
#include <android/font.h>
#include <android/font_matcher.h>
#include <android/system_fonts.h>
@@ -47,9 +49,14 @@ struct XmlDocDeleter {
using XmlCharUniquePtr = std::unique_ptr<xmlChar, XmlCharDeleter>;
using XmlDocUniquePtr = std::unique_ptr<xmlDoc, XmlDocDeleter>;
+struct ParserState {
+ xmlNode* mFontNode = nullptr;
+ XmlCharUniquePtr mLocale;
+};
+
struct ASystemFontIterator {
XmlDocUniquePtr mXmlDoc;
- xmlNode* mFontNode;
+ ParserState state;
// The OEM customization XML.
XmlDocUniquePtr mCustomizationXmlDoc;
@@ -97,6 +104,7 @@ std::string xmlTrim(const std::string& in) {
const xmlChar* FAMILY_TAG = BAD_CAST("family");
const xmlChar* FONT_TAG = BAD_CAST("font");
+const xmlChar* LOCALE_ATTR_NAME = BAD_CAST("lang");
xmlNode* firstElement(xmlNode* node, const xmlChar* tag) {
for (xmlNode* child = node->children; child; child = child->next) {
@@ -116,9 +124,9 @@ xmlNode* nextSibling(xmlNode* node, const xmlChar* tag) {
return nullptr;
}
-void copyFont(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode, AFont* out,
+void copyFont(const XmlDocUniquePtr& xmlDoc, const ParserState& state, AFont* out,
const std::string& pathPrefix) {
- const xmlChar* LOCALE_ATTR_NAME = BAD_CAST("lang");
+ xmlNode* fontNode = state.mFontNode;
XmlCharUniquePtr filePathStr(
xmlNodeListGetString(xmlDoc.get(), fontNode->xmlChildrenNode, 1));
out->mFilePath = pathPrefix + xmlTrim(
@@ -139,9 +147,10 @@ void copyFont(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode, AFont* out,
out->mCollectionIndex = indexStr ?
strtol(reinterpret_cast<const char*>(indexStr.get()), nullptr, 10) : 0;
- XmlCharUniquePtr localeStr(xmlGetProp(xmlDoc->parent, LOCALE_ATTR_NAME));
out->mLocale.reset(
- localeStr ? new std::string(reinterpret_cast<const char*>(localeStr.get())) : nullptr);
+ state.mLocale ?
+ new std::string(reinterpret_cast<const char*>(state.mLocale.get()))
+ : nullptr);
const xmlChar* TAG_ATTR_NAME = BAD_CAST("tag");
const xmlChar* STYLEVALUE_ATTR_NAME = BAD_CAST("stylevalue");
@@ -178,25 +187,27 @@ bool isFontFileAvailable(const std::string& filePath) {
return S_ISREG(st.st_mode);
}
-xmlNode* findFirstFontNode(const XmlDocUniquePtr& doc) {
+bool findFirstFontNode(const XmlDocUniquePtr& doc, ParserState* state) {
xmlNode* familySet = xmlDocGetRootElement(doc.get());
if (familySet == nullptr) {
- return nullptr;
+ return false;
}
xmlNode* family = firstElement(familySet, FAMILY_TAG);
if (family == nullptr) {
- return nullptr;
+ return false;
}
+ state->mLocale.reset(xmlGetProp(family, LOCALE_ATTR_NAME));
xmlNode* font = firstElement(family, FONT_TAG);
while (font == nullptr) {
family = nextSibling(family, FAMILY_TAG);
if (family == nullptr) {
- return nullptr;
+ return false;
}
font = firstElement(family, FONT_TAG);
}
- return font;
+ state->mFontNode = font;
+ return font != nullptr;
}
} // namespace
@@ -272,38 +283,38 @@ AFont* _Nonnull AFontMatcher_match(
return result.release();
}
-xmlNode* findNextFontNode(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode) {
- if (fontNode == nullptr) {
+bool findNextFontNode(const XmlDocUniquePtr& xmlDoc, ParserState* state) {
+ if (state->mFontNode == nullptr) {
if (!xmlDoc) {
- return nullptr; // Already at the end.
+ return false; // Already at the end.
} else {
// First time to query font.
- return findFirstFontNode(xmlDoc);
+ return findFirstFontNode(xmlDoc, state);
}
} else {
- xmlNode* nextNode = nextSibling(fontNode, FONT_TAG);
+ xmlNode* nextNode = nextSibling(state->mFontNode, FONT_TAG);
while (nextNode == nullptr) {
- xmlNode* family = nextSibling(fontNode->parent, FAMILY_TAG);
+ xmlNode* family = nextSibling(state->mFontNode->parent, FAMILY_TAG);
if (family == nullptr) {
break;
}
+ state->mLocale.reset(xmlGetProp(family, LOCALE_ATTR_NAME));
nextNode = firstElement(family, FONT_TAG);
}
- return nextNode;
+ state->mFontNode = nextNode;
+ return nextNode != nullptr;
}
}
AFont* ASystemFontIterator_next(ASystemFontIterator* ite) {
LOG_ALWAYS_FATAL_IF(ite == nullptr, "nullptr has passed as iterator argument");
if (ite->mXmlDoc) {
- ite->mFontNode = findNextFontNode(ite->mXmlDoc, ite->mFontNode);
- if (ite->mFontNode == nullptr) {
+ if (!findNextFontNode(ite->mXmlDoc, &ite->state)) {
// Reached end of the XML file. Continue OEM customization.
ite->mXmlDoc.reset();
- ite->mFontNode = nullptr;
} else {
std::unique_ptr<AFont> font = std::make_unique<AFont>();
- copyFont(ite->mXmlDoc, ite->mFontNode, font.get(), "/system/fonts/");
+ copyFont(ite->mXmlDoc, ite->state, font.get(), "/system/fonts/");
if (!isFontFileAvailable(font->mFilePath)) {
return ASystemFontIterator_next(ite);
}
@@ -312,15 +323,13 @@ AFont* ASystemFontIterator_next(ASystemFontIterator* ite) {
}
if (ite->mCustomizationXmlDoc) {
// TODO: Filter only customizationType="new-named-family"
- ite->mFontNode = findNextFontNode(ite->mCustomizationXmlDoc, ite->mFontNode);
- if (ite->mFontNode == nullptr) {
+ if (!findNextFontNode(ite->mCustomizationXmlDoc, &ite->state)) {
// Reached end of the XML file. Finishing
ite->mCustomizationXmlDoc.reset();
- ite->mFontNode = nullptr;
return nullptr;
} else {
std::unique_ptr<AFont> font = std::make_unique<AFont>();
- copyFont(ite->mCustomizationXmlDoc, ite->mFontNode, font.get(), "/product/fonts/");
+ copyFont(ite->mCustomizationXmlDoc, ite->state, font.get(), "/product/fonts/");
if (!isFontFileAvailable(font->mFilePath)) {
return ASystemFontIterator_next(ite);
}
@@ -351,7 +360,7 @@ bool AFont_isItalic(const AFont* font) {
const char* AFont_getLocale(const AFont* font) {
LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
- return font->mLocale ? nullptr : font->mLocale->c_str();
+ return font->mLocale ? font->mLocale->c_str() : nullptr;
}
size_t AFont_getCollectionIndex(const AFont* font) {
diff --git a/native/android/thermal.cpp b/native/android/thermal.cpp
new file mode 100644
index 000000000000..545c423908a0
--- /dev/null
+++ b/native/android/thermal.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "thermal"
+
+#include <cerrno>
+#include <thread>
+
+#include <android/thermal.h>
+#include <android/os/BnThermalStatusListener.h>
+#include <android/os/IThermalService.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+using android::sp;
+
+using namespace android;
+using namespace android::os;
+
+struct ThermalServiceListener : public BnThermalStatusListener {
+ public:
+ virtual binder::Status onStatusChange(int32_t status) override;
+ ThermalServiceListener(AThermalManager *manager) {mMgr = manager;}
+ private:
+ AThermalManager *mMgr;
+};
+
+struct ListenerCallback {
+ AThermal_StatusCallback callback;
+ void* data;
+};
+
+struct AThermalManager {
+ public:
+ static AThermalManager* createAThermalManager();
+ AThermalManager() = delete;
+ ~AThermalManager();
+ status_t notifyStateChange(int32_t status);
+ status_t getCurrentThermalStatus(int32_t *status);
+ status_t addListener(AThermal_StatusCallback, void *data);
+ status_t removeListener(AThermal_StatusCallback, void *data);
+ private:
+ AThermalManager(sp<IThermalService> service);
+ sp<IThermalService> mThermalSvc;
+ sp<ThermalServiceListener> mServiceListener;
+ std::vector<ListenerCallback> mListeners;
+ std::mutex mMutex;
+};
+
+binder::Status ThermalServiceListener::onStatusChange(int32_t status) {
+ if (mMgr != nullptr) {
+ mMgr->notifyStateChange(status);
+ }
+ return binder::Status::ok();
+}
+
+AThermalManager* AThermalManager::createAThermalManager() {
+ sp<IBinder> binder =
+ defaultServiceManager()->checkService(String16("thermalservice"));
+
+ if (binder == nullptr) {
+ ALOGE("%s: Thermal service is not ready ", __FUNCTION__);
+ return nullptr;
+ }
+ return new AThermalManager(interface_cast<IThermalService>(binder));
+}
+
+AThermalManager::AThermalManager(sp<IThermalService> service)
+ : mThermalSvc(service),
+ mServiceListener(nullptr) {
+}
+
+AThermalManager::~AThermalManager() {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ mListeners.clear();
+ if (mServiceListener != nullptr) {
+ bool success = false;
+ mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
+ mServiceListener = nullptr;
+ }
+}
+
+status_t AThermalManager::notifyStateChange(int32_t status) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
+
+ for (auto listener : mListeners) {
+ listener.callback(listener.data, thermalStatus);
+ }
+ return OK;
+}
+
+status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ if (callback == nullptr) {
+ // Callback can not be nullptr
+ return EINVAL;
+ }
+ for (const auto& cb : mListeners) {
+ // Don't re-add callbacks.
+ if (callback == cb.callback && data == cb.data) {
+ return EINVAL;
+ }
+ }
+ mListeners.emplace_back(ListenerCallback{callback, data});
+
+ if (mServiceListener != nullptr) {
+ return OK;
+ }
+ bool success = false;
+ mServiceListener = new ThermalServiceListener(this);
+ if (mServiceListener == nullptr) {
+ return ENOMEM;
+ }
+ auto ret = mThermalSvc->registerThermalStatusListener(mServiceListener, &success);
+ if (!success || !ret.isOk()) {
+ ALOGE("Failed in registerThermalStatusListener %d", success);
+ if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
+ return EPERM;
+ }
+ return EPIPE;
+ }
+ return OK;
+}
+
+status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ auto it = std::remove_if(mListeners.begin(),
+ mListeners.end(),
+ [&](const ListenerCallback& cb) {
+ return callback == cb.callback &&
+ data == cb.data;
+ });
+ if (it == mListeners.end()) {
+ // If the listener and data pointer were not previously added.
+ return EINVAL;
+ }
+ mListeners.erase(it, mListeners.end());
+
+ if (!mListeners.empty()) {
+ return OK;
+ }
+ if (mServiceListener == nullptr) {
+ return OK;
+ }
+ bool success = false;
+ auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
+ if (!success || !ret.isOk()) {
+ ALOGE("Failed in unregisterThermalStatusListener %d", success);
+ if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
+ return EPERM;
+ }
+ return EPIPE;
+ }
+ mServiceListener = nullptr;
+ return OK;
+}
+
+status_t AThermalManager::getCurrentThermalStatus(int32_t *status) {
+ binder::Status ret = mThermalSvc->getCurrentThermalStatus(status);
+
+ if (!ret.isOk()) {
+ if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
+ return EPERM;
+ }
+ return EPIPE;
+ }
+ return OK;
+}
+
+/**
+ * Acquire an instance of the thermal manager. This must be freed using
+ * {@link AThermal_releaseManager}.
+ *
+ * @return manager instance on success, nullptr on failure.
+ */
+AThermalManager* AThermal_acquireManager() {
+ auto manager = AThermalManager::createAThermalManager();
+
+ return manager;
+}
+
+/**
+ * Release the thermal manager pointer acquired by
+ * {@link AThermal_acquireManager}.
+ *
+ * @param manager The manager to be released.
+ *
+ */
+void AThermal_releaseManager(AThermalManager *manager) {
+ delete manager;
+}
+
+/**
+ * Gets the current thermal status.
+ *
+ * @param manager The manager instance to use to query the thermal status,
+ * acquired by {@link AThermal_acquireManager}.
+ *
+ * @return current thermal status, ATHERMAL_STATUS_ERROR on failure.
+*/
+AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) {
+ int32_t status = 0;
+ status_t ret = manager->getCurrentThermalStatus(&status);
+ if (ret != OK) {
+ return AThermalStatus::ATHERMAL_STATUS_ERROR;
+ }
+ return static_cast<AThermalStatus>(status);
+}
+
+/**
+ * Register the thermal status listener for thermal status change.
+ *
+ * @param manager The manager instance to use to register.
+ * acquired by {@link AThermal_acquireManager}.
+ * @param callback The callback function to be called when thermal status updated.
+ * @param data The data pointer to be passed when callback is called.
+ *
+ * @return 0 on success
+ * EINVAL if the listener and data pointer were previously added and not removed.
+ * EPERM if the required permission is not held.
+ * EPIPE if communication with the system service has failed.
+ */
+int AThermal_registerThermalStatusListener(AThermalManager *manager,
+ AThermal_StatusCallback callback, void *data) {
+ return manager->addListener(callback, data);
+}
+
+/**
+ * Unregister the thermal status listener previously resgistered.
+ *
+ * @param manager The manager instance to use to unregister.
+ * acquired by {@link AThermal_acquireManager}.
+ * @param callback The callback function to be called when thermal status updated.
+ * @param data The data pointer to be passed when callback is called.
+ *
+ * @return 0 on success
+ * EINVAL if the listener and data pointer were not previously added.
+ * EPERM if the required permission is not held.
+ * EPIPE if communication with the system service has failed.
+ */
+int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
+ AThermal_StatusCallback callback, void *data) {
+ return manager->removeListener(callback, data);
+}
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index 942eafdbc48d..15b473c2a6ab 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -24,12 +24,23 @@ cc_library_shared {
// our source files
//
- srcs: ["bitmap.cpp"],
+ srcs: [
+ "aassetstreamadaptor.cpp",
+ "bitmap.cpp",
+ "imagedecoder.cpp",
+ ],
shared_libs: [
+ "libandroid",
"libandroid_runtime",
+ "libhwui",
+ "liblog",
],
+ header_libs: [ "libhwui_internal_headers" ],
+
+ static_libs: ["libarect"],
+
arch: {
arm: {
// TODO: This is to work around b/24465209. Remove after root cause is fixed
diff --git a/native/graphics/jni/aassetstreamadaptor.cpp b/native/graphics/jni/aassetstreamadaptor.cpp
new file mode 100644
index 000000000000..016008bfce00
--- /dev/null
+++ b/native/graphics/jni/aassetstreamadaptor.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#include "aassetstreamadaptor.h"
+
+#include <log/log.h>
+
+AAssetStreamAdaptor::AAssetStreamAdaptor(AAsset* asset)
+ : mAAsset(asset)
+{
+}
+
+bool AAssetStreamAdaptor::rewind() {
+ off64_t pos = AAsset_seek64(mAAsset, 0, SEEK_SET);
+ if (pos == (off64_t)-1) {
+ ALOGE("rewind failed!");
+ return false;
+ }
+ return true;
+}
+
+size_t AAssetStreamAdaptor::getLength() const {
+ return AAsset_getLength64(mAAsset);
+}
+
+bool AAssetStreamAdaptor::isAtEnd() const {
+ return AAsset_getRemainingLength64(mAAsset) == 0;
+}
+
+SkStreamRewindable* AAssetStreamAdaptor::onDuplicate() const {
+ // Cannot sensibly create a duplicate, since each AAssetStreamAdaptor
+ // would be modifying the same AAsset.
+ //return new AAssetStreamAdaptor(mAAsset);
+ return nullptr;
+}
+
+bool AAssetStreamAdaptor::hasPosition() const {
+ return AAsset_seek64(mAAsset, 0, SEEK_CUR) != -1;
+}
+
+size_t AAssetStreamAdaptor::getPosition() const {
+ const off64_t offset = AAsset_seek64(mAAsset, 0, SEEK_CUR);
+ if (offset == -1) {
+ ALOGE("getPosition failed!");
+ return 0;
+ }
+
+ return offset;
+}
+
+bool AAssetStreamAdaptor::seek(size_t position) {
+ if (AAsset_seek64(mAAsset, position, SEEK_SET) == -1) {
+ ALOGE("seek failed!");
+ return false;
+ }
+
+ return true;
+}
+
+bool AAssetStreamAdaptor::move(long offset) {
+ if (AAsset_seek64(mAAsset, offset, SEEK_CUR) == -1) {
+ ALOGE("move failed!");
+ return false;
+ }
+
+ return true;
+}
+
+size_t AAssetStreamAdaptor::read(void* buffer, size_t size) {
+ ssize_t amount;
+
+ if (!buffer) {
+ if (!size) {
+ return 0;
+ }
+
+ // asset->seek returns new total offset
+ // we want to return amount that was skipped
+ const off64_t oldOffset = AAsset_seek64(mAAsset, 0, SEEK_CUR);
+ if (oldOffset == -1) {
+ ALOGE("seek(oldOffset) failed!");
+ return 0;
+ }
+
+ const off64_t newOffset = AAsset_seek64(mAAsset, size, SEEK_CUR);
+ if (-1 == newOffset) {
+ ALOGE("seek(%zu) failed!", size);
+ return 0;
+ }
+ amount = newOffset - oldOffset;
+ } else {
+ amount = AAsset_read(mAAsset, buffer, size);
+ }
+
+ if (amount < 0) {
+ amount = 0;
+ }
+ return amount;
+}
+
+const void* AAssetStreamAdaptor::getMemoryBase() {
+ return AAsset_getBuffer(mAAsset);
+}
+
diff --git a/native/graphics/jni/aassetstreamadaptor.h b/native/graphics/jni/aassetstreamadaptor.h
new file mode 100644
index 000000000000..c1fddb01344d
--- /dev/null
+++ b/native/graphics/jni/aassetstreamadaptor.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "SkStream.h"
+
+#include <android/asset_manager.h>
+
+// Like AssetStreamAdaptor, but operates on AAsset, a public NDK API.
+class AAssetStreamAdaptor : public SkStreamRewindable {
+public:
+ /**
+ * Create an SkStream that reads from an AAsset.
+ *
+ * The AAsset must remain open for the lifetime of the Adaptor. The Adaptor
+ * does *not* close the AAsset.
+ */
+ explicit AAssetStreamAdaptor(AAsset*);
+
+ bool rewind() override;
+ size_t read(void* buffer, size_t size) override;
+ bool hasLength() const override { return true; }
+ size_t getLength() const override;
+ bool hasPosition() const override;
+ size_t getPosition() const override;
+ bool seek(size_t position) override;
+ bool move(long offset) override;
+ bool isAtEnd() const override;
+ const void* getMemoryBase() override;
+protected:
+ SkStreamRewindable* onDuplicate() const override;
+
+private:
+ AAsset* mAAsset;
+};
+
diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp
index ff14832a2f0f..b8eb543ff835 100644
--- a/native/graphics/jni/bitmap.cpp
+++ b/native/graphics/jni/bitmap.cpp
@@ -15,7 +15,9 @@
*/
#include <android/bitmap.h>
-#include <android/graphics/Bitmap.h>
+#include <android/data_space.h>
+#include <android/graphics/bitmap.h>
+#include <android/data_space.h>
int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
AndroidBitmapInfo* info) {
@@ -24,21 +26,38 @@ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
}
if (info) {
- android::bitmap::imageInfo(env, jbitmap, info);
+ *info = ABitmap_getInfoFromJava(env, jbitmap);
}
return ANDROID_BITMAP_RESULT_SUCCESS;
}
+int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap) {
+ if (NULL == env || NULL == jbitmap) {
+ return ADATASPACE_UNKNOWN;
+ }
+
+ android::graphics::Bitmap bitmap(env, jbitmap);
+ if (!bitmap.isValid()) {
+ return ADATASPACE_UNKNOWN;
+ }
+
+ return bitmap.getDataSpace();
+}
+
int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) {
if (NULL == env || NULL == jbitmap) {
return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
}
- void* addr = android::bitmap::lockPixels(env, jbitmap);
+ android::graphics::Bitmap bitmap(env, jbitmap);
+ void* addr = bitmap.isValid() ? bitmap.getPixels() : nullptr;
+
if (!addr) {
return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
}
+ ABitmap_acquireRef(bitmap.get());
+
if (addrPtr) {
*addrPtr = addr;
}
@@ -50,9 +69,45 @@ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) {
return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
}
- bool unlocked = android::bitmap::unlockPixels(env, jbitmap);
- if (!unlocked) {
+ android::graphics::Bitmap bitmap(env, jbitmap);
+
+ if (!bitmap.isValid()) {
return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
}
+
+ bitmap.notifyPixelsChanged();
+ ABitmap_releaseRef(bitmap.get());
return ANDROID_BITMAP_RESULT_SUCCESS;
}
+
+int AndroidBitmap_getHardwareBuffer(JNIEnv* env, jobject jbitmap, AHardwareBuffer** outBuffer) {
+ if (NULL == env || NULL == jbitmap || NULL == outBuffer) {
+ return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+ }
+
+ android::graphics::Bitmap bitmap(env, jbitmap);
+
+ if (!bitmap.isValid()) {
+ return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
+ }
+
+ *outBuffer = bitmap.getHardwareBuffer();
+ return *outBuffer == NULL ? ANDROID_BITMAP_RESULT_BAD_PARAMETER : ANDROID_BITMAP_RESULT_SUCCESS;
+}
+
+int AndroidBitmap_compress(const AndroidBitmapInfo* info,
+ int32_t dataSpace,
+ const void* pixels,
+ int32_t format, int32_t quality,
+ void* userContext,
+ AndroidBitmap_CompressWriteFunc fn) {
+ if (NULL == info || NULL == pixels || NULL == fn) {
+ return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+ }
+ if (quality < 0 || quality > 100) {
+ return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+ }
+
+ return ABitmap_compress(info, (ADataSpace) dataSpace, pixels,
+ (AndroidBitmapCompressFormat) format, quality, userContext, fn);
+}
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
new file mode 100644
index 000000000000..56f390698eb2
--- /dev/null
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#include "aassetstreamadaptor.h"
+
+#include <android/asset_manager.h>
+#include <android/bitmap.h>
+#include <android/data_space.h>
+#include <android/imagedecoder.h>
+#include <MimeType.h>
+#include <android/rect.h>
+#include <hwui/ImageDecoder.h>
+#include <log/log.h>
+#include <SkAndroidCodec.h>
+#include <utils/Color.h>
+
+#include <fcntl.h>
+#include <limits>
+#include <optional>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+using namespace android;
+
+int ResultToErrorCode(SkCodec::Result result) {
+ switch (result) {
+ case SkCodec::kIncompleteInput:
+ return ANDROID_IMAGE_DECODER_INCOMPLETE;
+ case SkCodec::kErrorInInput:
+ return ANDROID_IMAGE_DECODER_ERROR;
+ case SkCodec::kInvalidInput:
+ return ANDROID_IMAGE_DECODER_INVALID_INPUT;
+ case SkCodec::kCouldNotRewind:
+ return ANDROID_IMAGE_DECODER_SEEK_ERROR;
+ case SkCodec::kUnimplemented:
+ return ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT;
+ case SkCodec::kInvalidConversion:
+ return ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
+ case SkCodec::kInvalidParameters:
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ case SkCodec::kSuccess:
+ return ANDROID_IMAGE_DECODER_SUCCESS;
+ case SkCodec::kInvalidScale:
+ return ANDROID_IMAGE_DECODER_INVALID_SCALE;
+ case SkCodec::kInternalError:
+ return ANDROID_IMAGE_DECODER_INTERNAL_ERROR;
+ }
+}
+
+static int createFromStream(std::unique_ptr<SkStreamRewindable> stream, AImageDecoder** outDecoder) {
+ SkCodec::Result result;
+ auto codec = SkCodec::MakeFromStream(std::move(stream), &result, nullptr,
+ SkCodec::SelectionPolicy::kPreferAnimation);
+ auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec),
+ SkAndroidCodec::ExifOrientationBehavior::kRespect);
+ if (!androidCodec) {
+ return ResultToErrorCode(result);
+ }
+
+ // AImageDecoderHeaderInfo_getWidth/Height return an int32_t. Ensure that
+ // the conversion is safe.
+ const auto& info = androidCodec->getInfo();
+ if (info.width() > std::numeric_limits<int32_t>::max()
+ || info.height() > std::numeric_limits<int32_t>::max()) {
+ return ANDROID_IMAGE_DECODER_INVALID_INPUT;
+ }
+
+ *outDecoder = reinterpret_cast<AImageDecoder*>(new ImageDecoder(std::move(androidCodec)));
+ return ANDROID_IMAGE_DECODER_SUCCESS;
+}
+
+int AImageDecoder_createFromAAsset(AAsset* asset, AImageDecoder** outDecoder) {
+ if (!asset || !outDecoder) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+ *outDecoder = nullptr;
+
+ auto stream = std::make_unique<AAssetStreamAdaptor>(asset);
+ return createFromStream(std::move(stream), outDecoder);
+}
+
+static bool isSeekable(int descriptor) {
+ return ::lseek64(descriptor, 0, SEEK_CUR) != -1;
+}
+
+int AImageDecoder_createFromFd(int fd, AImageDecoder** outDecoder) {
+ if (fd <= 0 || !outDecoder) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ struct stat fdStat;
+ if (fstat(fd, &fdStat) == -1) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ if (!isSeekable(fd)) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ // SkFILEStream will close its descriptor. Duplicate it so the client will
+ // still be responsible for closing the original.
+ int dupDescriptor = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+ FILE* file = fdopen(dupDescriptor, "r");
+ if (!file) {
+ close(dupDescriptor);
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ auto stream = std::unique_ptr<SkStreamRewindable>(new SkFILEStream(file));
+ return createFromStream(std::move(stream), outDecoder);
+}
+
+int AImageDecoder_createFromBuffer(const void* buffer, size_t length,
+ AImageDecoder** outDecoder) {
+ if (!buffer || !length || !outDecoder) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+ *outDecoder = nullptr;
+
+ // The client is expected to keep the buffer alive as long as the
+ // AImageDecoder, so we do not need to copy the buffer.
+ auto stream = std::unique_ptr<SkStreamRewindable>(
+ new SkMemoryStream(buffer, length, false /* copyData */));
+ return createFromStream(std::move(stream), outDecoder);
+}
+
+static ImageDecoder* toDecoder(AImageDecoder* d) {
+ return reinterpret_cast<ImageDecoder*>(d);
+}
+
+static const ImageDecoder* toDecoder(const AImageDecoder* d) {
+ return reinterpret_cast<const ImageDecoder*>(d);
+}
+
+// Note: This differs from the version in android_bitmap.cpp in that this
+// version returns kGray_8_SkColorType for ANDROID_BITMAP_FORMAT_A_8. SkCodec
+// allows decoding single channel images to gray, which Android then treats
+// as A_8/ALPHA_8.
+static SkColorType getColorType(AndroidBitmapFormat format) {
+ switch (format) {
+ case ANDROID_BITMAP_FORMAT_RGBA_8888:
+ return kN32_SkColorType;
+ case ANDROID_BITMAP_FORMAT_RGB_565:
+ return kRGB_565_SkColorType;
+ case ANDROID_BITMAP_FORMAT_RGBA_4444:
+ return kARGB_4444_SkColorType;
+ case ANDROID_BITMAP_FORMAT_A_8:
+ return kGray_8_SkColorType;
+ case ANDROID_BITMAP_FORMAT_RGBA_F16:
+ return kRGBA_F16_SkColorType;
+ default:
+ return kUnknown_SkColorType;
+ }
+}
+
+int AImageDecoder_setAndroidBitmapFormat(AImageDecoder* decoder, int32_t format) {
+ if (!decoder || format < ANDROID_BITMAP_FORMAT_NONE
+ || format > ANDROID_BITMAP_FORMAT_RGBA_F16) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+ return toDecoder(decoder)->setOutColorType(getColorType((AndroidBitmapFormat) format))
+ ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
+}
+
+int AImageDecoder_setDataSpace(AImageDecoder* decoder, int32_t dataspace) {
+ sk_sp<SkColorSpace> cs = uirenderer::DataSpaceToColorSpace((android_dataspace)dataspace);
+ // 0 is ADATASPACE_UNKNOWN. We need an explicit request for an ADataSpace.
+ if (!decoder || !dataspace || !cs) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ ImageDecoder* imageDecoder = toDecoder(decoder);
+ imageDecoder->setOutColorSpace(std::move(cs));
+ return ANDROID_IMAGE_DECODER_SUCCESS;
+}
+
+const AImageDecoderHeaderInfo* AImageDecoder_getHeaderInfo(const AImageDecoder* decoder) {
+ return reinterpret_cast<const AImageDecoderHeaderInfo*>(decoder);
+}
+
+static const ImageDecoder* toDecoder(const AImageDecoderHeaderInfo* info) {
+ return reinterpret_cast<const ImageDecoder*>(info);
+}
+
+int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo* info) {
+ if (!info) {
+ return 0;
+ }
+ return toDecoder(info)->mCodec->getInfo().width();
+}
+
+int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo* info) {
+ if (!info) {
+ return 0;
+ }
+ return toDecoder(info)->mCodec->getInfo().height();
+}
+
+const char* AImageDecoderHeaderInfo_getMimeType(const AImageDecoderHeaderInfo* info) {
+ if (!info) {
+ return nullptr;
+ }
+ return getMimeType(toDecoder(info)->mCodec->getEncodedFormat());
+}
+
+int32_t AImageDecoderHeaderInfo_getDataSpace(const AImageDecoderHeaderInfo* info) {
+ if (!info) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ // Note: This recomputes the color type because it's possible the client has
+ // changed the output color type, so we cannot rely on it. Alternatively,
+ // we could store the ADataSpace in the ImageDecoder.
+ const ImageDecoder* imageDecoder = toDecoder(info);
+ SkColorType colorType = imageDecoder->mCodec->computeOutputColorType(kN32_SkColorType);
+ sk_sp<SkColorSpace> colorSpace = imageDecoder->getDefaultColorSpace();
+ return uirenderer::ColorSpaceToADataSpace(colorSpace.get(), colorType);
+}
+
+// FIXME: Share with getFormat in android_bitmap.cpp?
+static AndroidBitmapFormat getFormat(SkColorType colorType) {
+ switch (colorType) {
+ case kN32_SkColorType:
+ return ANDROID_BITMAP_FORMAT_RGBA_8888;
+ case kRGB_565_SkColorType:
+ return ANDROID_BITMAP_FORMAT_RGB_565;
+ case kARGB_4444_SkColorType:
+ return ANDROID_BITMAP_FORMAT_RGBA_4444;
+ case kAlpha_8_SkColorType:
+ return ANDROID_BITMAP_FORMAT_A_8;
+ case kRGBA_F16_SkColorType:
+ return ANDROID_BITMAP_FORMAT_RGBA_F16;
+ default:
+ return ANDROID_BITMAP_FORMAT_NONE;
+ }
+}
+
+int32_t AImageDecoderHeaderInfo_getAndroidBitmapFormat(const AImageDecoderHeaderInfo* info) {
+ if (!info) {
+ return ANDROID_BITMAP_FORMAT_NONE;
+ }
+ return getFormat(toDecoder(info)->mCodec->computeOutputColorType(kN32_SkColorType));
+}
+
+int AImageDecoderHeaderInfo_getAlphaFlags(const AImageDecoderHeaderInfo* info) {
+ if (!info) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+ switch (toDecoder(info)->mCodec->getInfo().alphaType()) {
+ case kUnknown_SkAlphaType:
+ LOG_ALWAYS_FATAL("Invalid alpha type");
+ return ANDROID_IMAGE_DECODER_INTERNAL_ERROR;
+ case kUnpremul_SkAlphaType:
+ // fall through. premul is the default.
+ case kPremul_SkAlphaType:
+ return ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
+ case kOpaque_SkAlphaType:
+ return ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE;
+ }
+}
+
+int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* decoder, bool required) {
+ if (!decoder) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ return toDecoder(decoder)->setUnpremultipliedRequired(required)
+ ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
+}
+
+int AImageDecoder_setTargetSize(AImageDecoder* decoder, int32_t width, int32_t height) {
+ if (!decoder) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ return toDecoder(decoder)->setTargetSize(width, height)
+ ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_SCALE;
+}
+
+int AImageDecoder_computeSampledSize(const AImageDecoder* decoder, int sampleSize,
+ int32_t* width, int32_t* height) {
+ if (!decoder || !width || !height || sampleSize < 1) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ SkISize size = toDecoder(decoder)->mCodec->getSampledDimensions(sampleSize);
+ *width = size.width();
+ *height = size.height();
+ return ANDROID_IMAGE_DECODER_SUCCESS;
+}
+
+int AImageDecoder_setCrop(AImageDecoder* decoder, ARect crop) {
+ if (!decoder) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ SkIRect cropIRect;
+ cropIRect.setLTRB(crop.left, crop.top, crop.right, crop.bottom);
+ SkIRect* cropPtr = cropIRect == SkIRect::MakeEmpty() ? nullptr : &cropIRect;
+ return toDecoder(decoder)->setCropRect(cropPtr)
+ ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+}
+
+
+size_t AImageDecoder_getMinimumStride(AImageDecoder* decoder) {
+ if (!decoder) {
+ return 0;
+ }
+
+ SkImageInfo info = toDecoder(decoder)->getOutputInfo();
+ return info.minRowBytes();
+}
+
+int AImageDecoder_decodeImage(AImageDecoder* decoder,
+ void* pixels, size_t stride,
+ size_t size) {
+ if (!decoder || !pixels || !stride) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ ImageDecoder* imageDecoder = toDecoder(decoder);
+
+ SkImageInfo info = imageDecoder->getOutputInfo();
+ size_t minSize = info.computeByteSize(stride);
+ if (SkImageInfo::ByteSizeOverflowed(minSize) || size < minSize || !info.validRowBytes(stride)) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ return ResultToErrorCode(imageDecoder->decode(pixels, stride));
+}
+
+void AImageDecoder_delete(AImageDecoder* decoder) {
+ delete toDecoder(decoder);
+}
diff --git a/native/graphics/jni/libjnigraphics.map.txt b/native/graphics/jni/libjnigraphics.map.txt
index a601d8af2830..01c14770bebd 100644
--- a/native/graphics/jni/libjnigraphics.map.txt
+++ b/native/graphics/jni/libjnigraphics.map.txt
@@ -1,8 +1,30 @@
LIBJNIGRAPHICS {
global:
+ AImageDecoder_createFromAAsset; # introduced=30
+ AImageDecoder_createFromFd; # introduced=30
+ AImageDecoder_createFromBuffer; # introduced=30
+ AImageDecoder_delete; # introduced=30
+ AImageDecoder_setAndroidBitmapFormat; # introduced=30
+ AImageDecoder_setUnpremultipliedRequired; # introduced=30
+ AImageDecoder_setDataSpace; # introduced=30
+ AImageDecoder_getHeaderInfo; # introduced=30
+ AImageDecoder_getMinimumStride; # introduced=30
+ AImageDecoder_decodeImage; # introduced=30
+ AImageDecoder_setTargetSize; # introduced=30
+ AImageDecoder_computeSampledSize; # introduced=30
+ AImageDecoder_setCrop; # introduced=30
+ AImageDecoderHeaderInfo_getWidth; # introduced=30
+ AImageDecoderHeaderInfo_getHeight; # introduced=30
+ AImageDecoderHeaderInfo_getMimeType; # introduced=30
+ AImageDecoderHeaderInfo_getAlphaFlags; # introduced=30
+ AImageDecoderHeaderInfo_getAndroidBitmapFormat; # introduced=30
+ AImageDecoderHeaderInfo_getDataSpace; # introduced=30
AndroidBitmap_getInfo;
+ AndroidBitmap_getDataSpace;
AndroidBitmap_lockPixels;
AndroidBitmap_unlockPixels;
+ AndroidBitmap_compress; # introduced=30
+ AndroidBitmap_getHardwareBuffer; #introduced=30
local:
*;
};
diff --git a/native/webview/plat_support/Android.bp b/native/webview/plat_support/Android.bp
index 88decc86c387..1a3b36d046e1 100644
--- a/native/webview/plat_support/Android.bp
+++ b/native/webview/plat_support/Android.bp
@@ -30,12 +30,14 @@ cc_library_shared {
"graphic_buffer_impl.cpp",
],
+ header_libs: [ "libhwui_internal_headers" ],
+
shared_libs: [
"libandroidfw",
- "libandroid_runtime",
"libcutils",
"libhwui",
"liblog",
+ "libnativehelper",
"libui",
"libutils",
"libvulkan",
diff --git a/native/webview/plat_support/graphics_utils.cpp b/native/webview/plat_support/graphics_utils.cpp
index 56825cee4520..8d7a59e46e72 100644
--- a/native/webview/plat_support/graphics_utils.cpp
+++ b/native/webview/plat_support/graphics_utils.cpp
@@ -25,11 +25,9 @@
#include <cstdlib>
#include <jni.h>
#include <utils/Log.h>
-#include "android/graphics/GraphicsJNI.h"
+#include "GraphicsJNI.h"
#include "graphic_buffer_impl.h"
#include "SkCanvasStateUtils.h"
-#include "SkGraphics.h"
-#include "SkPicture.h"
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))