Merge "create setChargingPolicy" into main
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index 8ea4632..746c280 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -111,6 +111,7 @@
"allocator_may_return_null = 1",
],
},
+ dictionary: "fuzz/imagedecoder_fuzzer.dict",
host_supported: true,
}
diff --git a/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp b/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp
index 838bf3f..6743997 100644
--- a/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp
+++ b/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp
@@ -15,32 +15,15 @@
*/
#include <android/imagedecoder.h>
-
#include <binder/IPCThreadState.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <cstdlib>
-#include <memory>
+#include <fuzzer/FuzzedDataProvider.h>
#ifdef PNG_MUTATOR_DEFINE_LIBFUZZER_CUSTOM_MUTATOR
#include <fuzz/png_mutator.h>
#endif
-struct DecoderDeleter {
- void operator()(AImageDecoder* decoder) const { AImageDecoder_delete(decoder); }
-};
-
-using DecoderPointer = std::unique_ptr<AImageDecoder, DecoderDeleter>;
-
-static DecoderPointer makeDecoder(const uint8_t* data, size_t size) {
- AImageDecoder* decoder = nullptr;
- int result = AImageDecoder_createFromBuffer(data, size, &decoder);
- if (result != ANDROID_IMAGE_DECODER_SUCCESS) {
- // This was not a valid image.
- return nullptr;
- }
- return DecoderPointer(decoder);
-}
+constexpr int32_t kMaxDimension = 5000;
+constexpr int32_t kMinDimension = 0;
struct PixelFreer {
void operator()(void* pixels) const { std::free(pixels); }
@@ -48,41 +31,113 @@
using PixelPointer = std::unique_ptr<void, PixelFreer>;
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- // Without this call, decoding HEIF may time out on binder IPC calls.
- android::ProcessState::self()->startThreadPool();
+AImageDecoder* init(const uint8_t* data, size_t size, bool useFileDescriptor) {
+ AImageDecoder* decoder = nullptr;
+ if (useFileDescriptor) {
+ constexpr char testFd[] = "tempFd";
+ int32_t fileDesc = open(testFd, O_RDWR | O_CREAT | O_TRUNC);
+ write(fileDesc, data, size);
+ AImageDecoder_createFromFd(fileDesc, &decoder);
+ close(fileDesc);
+ } else {
+ AImageDecoder_createFromBuffer(data, size, &decoder);
+ }
+ return decoder;
+}
- DecoderPointer decoder = makeDecoder(data, size);
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider dataProvider = FuzzedDataProvider(data, size);
+ /**
+ * Use maximum of 80% of buffer for creating decoder and save at least
+ * 20% buffer for fuzzing other APIs
+ */
+ const int32_t dataSize = dataProvider.ConsumeIntegralInRange<int32_t>(0, (size * 80) / 100);
+ std::vector<uint8_t> inputBuffer = dataProvider.ConsumeBytes<uint8_t>(dataSize);
+ AImageDecoder* decoder =
+ init(inputBuffer.data(), inputBuffer.size(), dataProvider.ConsumeBool());
if (!decoder) {
return 0;
}
-
- const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder.get());
- int32_t width = AImageDecoderHeaderInfo_getWidth(info);
- int32_t height = AImageDecoderHeaderInfo_getHeight(info);
-
- // Set an arbitrary limit on the size of an image. The fuzzer runs with a
- // limited amount of memory, and keeping this allocation small allows the
- // fuzzer to continue running to try to find more serious problems. This
- // size is large enough to hold a photo taken by a current gen phone.
- constexpr int32_t kMaxDimension = 5000;
- if (width > kMaxDimension || height > kMaxDimension) {
- return 0;
+ const AImageDecoderHeaderInfo* headerInfo = AImageDecoder_getHeaderInfo(decoder);
+ AImageDecoderFrameInfo* frameInfo = AImageDecoderFrameInfo_create();
+ int32_t height = AImageDecoderHeaderInfo_getHeight(headerInfo);
+ int32_t width = AImageDecoderHeaderInfo_getWidth(headerInfo);
+ while (dataProvider.remaining_bytes()) {
+ auto invokeImageApi = dataProvider.PickValueInArray<const std::function<void()>>({
+ [&]() {
+ int32_t testHeight =
+ dataProvider.ConsumeIntegralInRange<int32_t>(kMinDimension,
+ kMaxDimension);
+ int32_t testWidth = dataProvider.ConsumeIntegralInRange<int32_t>(kMinDimension,
+ kMaxDimension);
+ int32_t result = AImageDecoder_setTargetSize(decoder, testHeight, testWidth);
+ if (result == ANDROID_IMAGE_DECODER_SUCCESS) {
+ height = testHeight;
+ width = testWidth;
+ }
+ },
+ [&]() {
+ const bool required = dataProvider.ConsumeBool();
+ AImageDecoder_setUnpremultipliedRequired(decoder, required);
+ },
+ [&]() {
+ AImageDecoder_setAndroidBitmapFormat(
+ decoder,
+ dataProvider.ConsumeIntegralInRange<
+ int32_t>(ANDROID_BITMAP_FORMAT_NONE,
+ ANDROID_BITMAP_FORMAT_RGBA_1010102) /* format */);
+ },
+ [&]() {
+ AImageDecoder_setDataSpace(decoder,
+ dataProvider
+ .ConsumeIntegral<int32_t>() /* dataspace */);
+ },
+ [&]() {
+ ARect rect{dataProvider.ConsumeIntegral<int32_t>() /* left */,
+ dataProvider.ConsumeIntegral<int32_t>() /* top */,
+ dataProvider.ConsumeIntegral<int32_t>() /* right */,
+ dataProvider.ConsumeIntegral<int32_t>() /* bottom */};
+ AImageDecoder_setCrop(decoder, rect);
+ },
+ [&]() { AImageDecoderHeaderInfo_getWidth(headerInfo); },
+ [&]() { AImageDecoderHeaderInfo_getMimeType(headerInfo); },
+ [&]() { AImageDecoderHeaderInfo_getAlphaFlags(headerInfo); },
+ [&]() { AImageDecoderHeaderInfo_getAndroidBitmapFormat(headerInfo); },
+ [&]() {
+ int32_t tempHeight;
+ int32_t tempWidth;
+ AImageDecoder_computeSampledSize(decoder,
+ dataProvider.ConsumeIntegral<
+ int>() /* sampleSize */,
+ &tempWidth, &tempHeight);
+ },
+ [&]() { AImageDecoderHeaderInfo_getDataSpace(headerInfo); },
+ [&]() { AImageDecoder_getRepeatCount(decoder); },
+ [&]() { AImageDecoder_getFrameInfo(decoder, frameInfo); },
+ [&]() { AImageDecoderFrameInfo_getDuration(frameInfo); },
+ [&]() { AImageDecoderFrameInfo_hasAlphaWithinBounds(frameInfo); },
+ [&]() { AImageDecoderFrameInfo_getDisposeOp(frameInfo); },
+ [&]() { AImageDecoderFrameInfo_getBlendOp(frameInfo); },
+ [&]() {
+ AImageDecoder_setInternallyHandleDisposePrevious(
+ decoder, dataProvider.ConsumeBool() /* handle */);
+ },
+ [&]() { AImageDecoder_rewind(decoder); },
+ [&]() { AImageDecoder_advanceFrame(decoder); },
+ [&]() {
+ size_t stride = AImageDecoder_getMinimumStride(decoder);
+ size_t pixelSize = height * stride;
+ auto pixels = PixelPointer(std::malloc(pixelSize));
+ if (!pixels.get()) {
+ return;
+ }
+ AImageDecoder_decodeImage(decoder, pixels.get(), stride, pixelSize);
+ },
+ });
+ invokeImageApi();
}
- size_t stride = AImageDecoder_getMinimumStride(decoder.get());
- size_t pixelSize = height * stride;
- auto pixels = PixelPointer(std::malloc(pixelSize));
- if (!pixels.get()) {
- return 0;
- }
-
- while (true) {
- int result = AImageDecoder_decodeImage(decoder.get(), pixels.get(), stride, pixelSize);
- if (result != ANDROID_IMAGE_DECODER_SUCCESS) break;
-
- result = AImageDecoder_advanceFrame(decoder.get());
- if (result != ANDROID_IMAGE_DECODER_SUCCESS) break;
- }
+ AImageDecoderFrameInfo_delete(frameInfo);
+ AImageDecoder_delete(decoder);
return 0;
}
diff --git a/native/graphics/jni/fuzz/imagedecoder_fuzzer.dict b/native/graphics/jni/fuzz/imagedecoder_fuzzer.dict
new file mode 100644
index 0000000..5b54a0e
--- /dev/null
+++ b/native/graphics/jni/fuzz/imagedecoder_fuzzer.dict
@@ -0,0 +1,7 @@
+kw1="\x89\x50\x4E\x47"
+kw2="\xff\xD8\xFF"
+kw4="\x52\x49\x46\x46"
+kw5="\x00\x00\x01\x00"
+kw6="\x47\x49\x46\x08"
+kw7="ftyp"
+kw8="\x04\x00\x00\x00"
diff --git a/tools/localedata/extract_icu_data.py b/tools/localedata/extract_icu_data.py
index 81ac897..8f67fa8 100755
--- a/tools/localedata/extract_icu_data.py
+++ b/tools/localedata/extract_icu_data.py
@@ -22,6 +22,8 @@
import os.path
import sys
+import xml.etree.ElementTree as ElementTree
+
def get_locale_parts(locale):
"""Split a locale into three parts, for langauge, script, and region."""
@@ -40,42 +42,43 @@
def read_likely_subtags(input_file_name):
"""Read and parse ICU's likelySubtags.txt."""
- with open(input_file_name) as input_file:
- likely_script_dict = {
- # Android's additions for pseudo-locales. These internal codes make
- # sure that the pseudo-locales would not match other English or
- # Arabic locales. (We can't use private-use ISO 15924 codes, since
- # they may be used by apps for other purposes.)
- "en_XA": "~~~A",
- "ar_XB": "~~~B",
- # Removed data from later versions of ICU
- "ji": "Hebr", # Old code for Yiddish, still used in Java and Android
- }
- representative_locales = {
- # Android's additions
- "en_Latn_GB", # representative for en_Latn_001
- "es_Latn_MX", # representative for es_Latn_419
- "es_Latn_US", # representative for es_Latn_419 (not the best idea,
- # but Android has been shipping with it for quite a
- # while. Fortunately, MX < US, so if both exist, MX
- # would be chosen.)
- }
- for line in input_file:
- line = line.strip(u' \n\uFEFF')
- if line.startswith('//'):
- continue
- if '{' in line and '}' in line:
- from_locale = line[:line.index('{')]
- to_locale = line[line.index('"')+1:line.rindex('"')]
- from_lang, from_scr, from_region = get_locale_parts(from_locale)
- _, to_scr, to_region = get_locale_parts(to_locale)
- if from_lang == 'und':
- continue # not very useful for our purposes
- if from_region is None and to_region not in ['001', 'ZZ']:
- representative_locales.add(to_locale)
- if from_scr is None:
- likely_script_dict[from_locale] = to_scr
- return likely_script_dict, frozenset(representative_locales)
+ likely_script_dict = {
+ # Android's additions for pseudo-locales. These internal codes make
+ # sure that the pseudo-locales would not match other English or
+ # Arabic locales. (We can't use private-use ISO 15924 codes, since
+ # they may be used by apps for other purposes.)
+ "en_XA": "~~~A",
+ "ar_XB": "~~~B",
+ # Removed data from later versions of ICU
+ "ji": "Hebr", # Old code for Yiddish, still used in Java and Android
+ }
+ representative_locales = {
+ # Android's additions
+ "en_Latn_GB", # representative for en_Latn_001
+ "es_Latn_MX", # representative for es_Latn_419
+ "es_Latn_US", # representative for es_Latn_419 (not the best idea,
+ # but Android has been shipping with it for quite a
+ # while. Fortunately, MX < US, so if both exist, MX
+ # would be chosen.)
+ }
+ xml_tree = ElementTree.parse(input_file_name)
+ likely_subtags = xml_tree.find('likelySubtags')
+ for child in likely_subtags:
+ from_locale = child.get('from')
+ to_locale = child.get('to')
+ # print(f'from: {from_locale} to: {to_locale}')
+ from_lang, from_scr, from_region = get_locale_parts(from_locale)
+ _, to_scr, to_region = get_locale_parts(to_locale)
+ if to_locale == "FAIL":
+ continue # "FAIL" cases are not useful here.
+ if from_lang == 'und':
+ continue # not very useful for our purposes
+ if from_region is None and to_region not in ['001', 'ZZ']:
+ representative_locales.add(to_locale)
+ if from_scr is None:
+ likely_script_dict[from_locale] = to_scr
+
+ return likely_script_dict, frozenset(representative_locales)
# From packLanguageOrRegion() in ResourceTypes.cpp
@@ -86,7 +89,7 @@
elif len(inp) == 2:
return ord(inp[0]), ord(inp[1])
else:
- assert len(inp) == 3
+ assert len(inp) == 3, f'Expects a 3-character string, but "{inp}" '
base = ord(base)
first = ord(inp[0]) - base
second = ord(inp[1]) - base
@@ -161,9 +164,10 @@
print('});')
-def read_and_dump_likely_data(icu_data_dir):
+def read_and_dump_likely_data(cldr_source_dir):
"""Read and dump the likely-script data."""
- likely_subtags_txt = os.path.join(icu_data_dir, 'misc', 'likelySubtags.txt')
+ likely_subtags_txt = os.path.join(cldr_source_dir,
+ 'common', 'supplemental', 'likelySubtags.xml')
likely_script_dict, representative_locales = read_likely_subtags(
likely_subtags_txt)
@@ -280,10 +284,11 @@
icu_data_dir = os.path.join(
source_root,
'external', 'icu', 'icu4c', 'source', 'data')
+ cldr_source_dir = os.path.join(source_root, 'external', 'cldr')
print('// Auto-generated by %s' % sys.argv[0])
print()
- likely_script_dict = read_and_dump_likely_data(icu_data_dir)
+ likely_script_dict = read_and_dump_likely_data(cldr_source_dir)
read_and_dump_parent_data(icu_data_dir, likely_script_dict)