From ed61179b528847721dad674e0c933964117bdaa0 Mon Sep 17 00:00:00 2001 From: "Alam, SahibeX" Date: Thu, 5 Oct 2023 11:44:50 +0530 Subject: [PATCH] ASB - Security Patch integration October 2023 Integrating Security Patches Test done: STS TCs Passed Tracked-On: OAM-112412 Signed-off-by: Alam, SahibeX --- ...4-Update-security_patch_level-string.patch | 2 +- ...read-after-xmlRegGetCounter.bulletin.patch | 126 ++ ...pdate-to-v1-2-0-8-g20ceff7e.bulletin.patch | 533 ++++++ ...kgroundProcesses-can-kill-c.bulletin.patch | 112 ++ ...supported-v1-and-v2-signers.bulletin.patch | 87 + ...REMOTE_INPUT_HISTORY_ITEMS-.bulletin.patch | 104 ++ ...ssions-for-notification-shortcutIcon.patch | 157 ++ ...tions-DO-NOT-MERGE-ANYWHERE.bulletin.patch | 1122 +++++++++++++ ...ssions-for-EXTRA_REMOTE_INP.bulletin.patch | 88 + ...REMOTE_INPUT_HISTORY_ITEMS-.bulletin.patch | 101 ++ ...ey-mappings-with-JNI-object.bulletin.patch | 50 + ...ons-in-Autofill-RemoteViews.bulletin.patch | 154 ++ ...from-content-URI-to-PipMenu.bulletin.patch | 56 + ...ct-malformed-UTF-16-strings.bulletin.patch | 62 + ...-exclude-secure_frp_mode-fr.bulletin.patch | 138 ++ ...nore-small-source-rect-hint.bulletin.patch | 86 + ...er-when-media-control-title-is-blank.patch | 181 ++ ...fter-free-in-GPUService-cpp.bulletin.patch | 209 +++ ...Restrict-ApnEditor-settings.bulletin.patch | 132 ++ ...ons-from-setLockCredential-.bulletin.patch | 68 + ...re-share-key-check-for-wapi.bulletin.patch | 121 ++ ...ate-password-check-for-WAPI.bulletin.patch | 99 ++ ...rabilities-in-MediaProvider.bulletin.patch | 248 +++ ...-in-CallRedirectionService-.bulletin.patch | 51 + ...low-in-build_read_multi_rsp.bulletin.patch | 84 + ...supported-v1-and-v2-signers.bulletin.patch | 1474 +++++++++++++++++ 26 files changed, 5644 insertions(+), 1 deletion(-) create mode 100644 aosp_diff/preliminary/external/libxml2/0001-malloc-fail-Fix-OOB-read-after-xmlRegGetCounter.bulletin.patch create mode 100644 aosp_diff/preliminary/external/webp/0001-update-to-v1-2-0-8-g20ceff7e.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0188-DO-NOT-MERGE-ActivityManager-killBackgroundProcesses-can-kill-c.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0189-Limit-the-number-of-supported-v1-and-v2-signers.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0190-Verify-URI-permissions-for-EXTRA_REMOTE_INPUT_HISTORY_ITEMS-.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0191-Verify-URI-permissions-for-notification-shortcutIcon.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0192-Import-translations-DO-NOT-MERGE-ANYWHERE.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0193-DO-NOT-MERGE-Revert-Verify-URI-permissions-for-EXTRA_REMOTE_INP.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0194-Verify-URI-permissions-for-EXTRA_REMOTE_INPUT_HISTORY_ITEMS-.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0195-Do-not-share-key-mappings-with-JNI-object.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0196-DO-NOT-MERGE-Verify-URI-Permissions-in-Autofill-RemoteViews.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0197-Disallow-loading-icon-from-content-URI-to-PipMenu.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0198-Fixing-DatabaseUtils-to-detect-malformed-UTF-16-strings.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0200-RESTRICT-AUTOMERGE-SettingsProvider-exclude-secure_frp_mode-fr.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0201--RESTRICT-AUTOMERGE-Ignore-small-source-rect-hint.bulletin.patch create mode 100644 aosp_diff/preliminary/frameworks/base/99_0202-Add-placeholder-when-media-control-title-is-blank.patch create mode 100644 aosp_diff/preliminary/frameworks/native/19_0019-Fix-for-heap-use-after-free-in-GPUService-cpp.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/apps/Settings/35_0035--RESTRICT-AUTOMERGE-Restrict-ApnEditor-settings.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/apps/Settings/36_0036-RESTRICT-AUTOMERGE-Catch-exceptions-from-setLockCredential-.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/modules/Wifi/0009-Add-pre-share-key-check-for-wapi.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/modules/Wifi/0010-Update-password-check-for-WAPI.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/providers/MediaProvider/08_0008-Fix-path-traversal-vulnerabilities-in-MediaProvider.bulletin.patch create mode 100644 aosp_diff/preliminary/packages/services/Telecomm/12_0012-Fix-vulnerability-in-CallRedirectionService-.bulletin.patch create mode 100644 aosp_diff/preliminary/system/bt/39_0039-Fix-an-integer-underflow-in-build_read_multi_rsp.bulletin.patch create mode 100644 aosp_diff/preliminary/tools/apksig/0001-Limit-the-number-of-supported-v1-and-v2-signers.bulletin.patch diff --git a/aosp_diff/preliminary/build/make/04_0004-Update-security_patch_level-string.patch b/aosp_diff/preliminary/build/make/04_0004-Update-security_patch_level-string.patch index 21af7a1a99..40ceb7d09c 100644 --- a/aosp_diff/preliminary/build/make/04_0004-Update-security_patch_level-string.patch +++ b/aosp_diff/preliminary/build/make/04_0004-Update-security_patch_level-string.patch @@ -20,7 +20,7 @@ index 47bb92c142..2d0ac256a4 100644 # It must match one of the Android Security Patch Level strings of the Public Security Bulletins. # If there is no $PLATFORM_SECURITY_PATCH set, keep it empty. - PLATFORM_SECURITY_PATCH := 2022-02-05 -+ PLATFORM_SECURITY_PATCH := 2023-09-01 ++ PLATFORM_SECURITY_PATCH := 2023-10-01 endif .KATI_READONLY := PLATFORM_SECURITY_PATCH diff --git a/aosp_diff/preliminary/external/libxml2/0001-malloc-fail-Fix-OOB-read-after-xmlRegGetCounter.bulletin.patch b/aosp_diff/preliminary/external/libxml2/0001-malloc-fail-Fix-OOB-read-after-xmlRegGetCounter.bulletin.patch new file mode 100644 index 0000000000..dd06b989d6 --- /dev/null +++ b/aosp_diff/preliminary/external/libxml2/0001-malloc-fail-Fix-OOB-read-after-xmlRegGetCounter.bulletin.patch @@ -0,0 +1,126 @@ +From f8016cd3e5e5ddef29a97122382fbd863813f9d3 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Fri, 17 Feb 2023 15:53:07 +0100 +Subject: [PATCH] malloc-fail: Fix OOB read after xmlRegGetCounter + +Found with libFuzzer, see #344. + +(cherry picked from commit 1743c4c3fc58cf38ecce68db9de51d0f3651e033) + +I also copied the error label from +e64653c0e7975594e27d7de2ed4be062c1e4ad03 to fix the build failure. + +Bug: http://b/274231102 +Test: TreeHugger +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:761198eaee09f721452adfefa92b9a6c9b875f24) +Merged-In: I3bad3e03092e17a761cb6e299aff848ebd35b6f4 +Change-Id: I3bad3e03092e17a761cb6e299aff848ebd35b6f4 +--- + xmlregexp.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/xmlregexp.c b/xmlregexp.c +index 40dabb20..0395219a 100644 +--- a/xmlregexp.c ++++ b/xmlregexp.c +@@ -1673,6 +1673,8 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, + return(-1); + inter = ctxt->state; + counter = xmlRegGetCounter(ctxt); ++ if (counter < 0) ++ return(-1); + ctxt->counters[counter].min = atom->min - 1; + ctxt->counters[counter].max = atom->max - 1; + /* count the number of times we see it again */ +@@ -1691,6 +1693,8 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, + * epsilon transition. + */ + counter = xmlRegGetCounter(ctxt); ++ if (counter < 0) ++ return(-1); + ctxt->counters[counter].min = atom->min - 1; + ctxt->counters[counter].max = atom->max - 1; + /* count the number of times we see it again */ +@@ -6008,6 +6012,8 @@ xmlAutomataNewCountTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, + * associate a counter to the transition. + */ + counter = xmlRegGetCounter(am); ++ if (counter < 0) ++ goto error; + am->counters[counter].min = min; + am->counters[counter].max = max; + +@@ -6027,6 +6033,10 @@ xmlAutomataNewCountTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, + if (min == 0) + xmlFAGenerateEpsilonTransition(am, from, to); + return(to); ++ ++error: ++ xmlRegFreeAtom(atom); ++ return(NULL); + } + + /** +@@ -6074,6 +6084,8 @@ xmlAutomataNewCountTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, + * associate a counter to the transition. + */ + counter = xmlRegGetCounter(am); ++ if (counter < 0) ++ goto error; + am->counters[counter].min = min; + am->counters[counter].max = max; + +@@ -6093,6 +6105,10 @@ xmlAutomataNewCountTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, + if (min == 0) + xmlFAGenerateEpsilonTransition(am, from, to); + return(to); ++ ++error: ++ xmlRegFreeAtom(atom); ++ return(NULL); + } + + /** +@@ -6160,6 +6176,8 @@ xmlAutomataNewOnceTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, + * associate a counter to the transition. + */ + counter = xmlRegGetCounter(am); ++ if (counter < 0) ++ goto error; + am->counters[counter].min = 1; + am->counters[counter].max = 1; + +@@ -6172,6 +6190,10 @@ xmlAutomataNewOnceTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlRegAtomPush(am, atom); + am->state = to; + return(to); ++ ++error: ++ xmlRegFreeAtom(atom); ++ return(NULL); + } + + +@@ -6219,6 +6241,8 @@ xmlAutomataNewOnceTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, + * associate a counter to the transition. + */ + counter = xmlRegGetCounter(am); ++ if (counter < 0) ++ goto error; + am->counters[counter].min = 1; + am->counters[counter].max = 1; + +@@ -6231,6 +6255,10 @@ xmlAutomataNewOnceTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlRegAtomPush(am, atom); + am->state = to; + return(to); ++ ++error: ++ xmlRegFreeAtom(atom); ++ return(NULL); + } + + /** +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/external/webp/0001-update-to-v1-2-0-8-g20ceff7e.bulletin.patch b/aosp_diff/preliminary/external/webp/0001-update-to-v1-2-0-8-g20ceff7e.bulletin.patch new file mode 100644 index 0000000000..b4e1a459ce --- /dev/null +++ b/aosp_diff/preliminary/external/webp/0001-update-to-v1-2-0-8-g20ceff7e.bulletin.patch @@ -0,0 +1,533 @@ +From d4e9e78f941d250a70ec1b5ba9f759da43225295 Mon Sep 17 00:00:00 2001 +From: James Zern +Date: Sat, 9 Sep 2023 13:46:56 -0700 +Subject: [PATCH] update to v1.2.0-8-g20ceff7e + +https://chromium.googlesource.com/webm/libwebp/+log/v1.2.0..v1.2.0-8-g20ceff7e + +20ceff7e Fix OOB write in BuildHuffmanTable. +258f74e8 GetBackwardReferences: fail on alloc error +d21fa8d4 BackwardReferencesHashChainDistanceOnly: fix segfault on OOM +34ddf5b2 VP8LEncodeStream: fix segfault on OOM +17674ecf alpha_processing_neon.c: fix 0x01... typo +7dfde712 alpha_processing_neon.c: fix Dispatch/ExtractAlpha_NEON +059d4a59 Fix lossless encoding for MIPS. +113968ca pngdec: check version before using png_get_chunk_malloc_max + +Bug: 299477569 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:210681f7f5d24c73fc55e7147e870c1351c31400) +Merged-In: I627bc9605c25ff01db2c12d53833fb2c8cb74fc1 +Change-Id: I627bc9605c25ff01db2c12d53833fb2c8cb74fc1 +--- + README.android | 2 +- + README.version | 4 +- + src/dec/vp8l_dec.c | 46 ++++++------ + src/dec/vp8li_dec.h | 2 +- + src/dsp/alpha_processing_neon.c | 6 +- + src/dsp/lossless_enc_mips32.c | 8 +-- + src/enc/backward_references_cost_enc.c | 2 +- + src/enc/backward_references_enc.c | 19 ++--- + src/enc/vp8l_enc.c | 11 ++- + src/utils/huffman_utils.c | 97 +++++++++++++++++++++----- + src/utils/huffman_utils.h | 27 ++++++- + 11 files changed, 159 insertions(+), 65 deletions(-) + +diff --git a/README.android b/README.android +index eb8a65e..e8a0e6b 100644 +--- a/README.android ++++ b/README.android +@@ -1,5 +1,5 @@ + URL: https://chromium.googlesource.com/webm/libwebp +-Version: v1.2.0 ++Version: v1.2.0-8-g20ceff7e + License: Google BSD like + + Local modifications: +diff --git a/README.version b/README.version +index fa87b87..f1613d7 100644 +--- a/README.version ++++ b/README.version +@@ -1,3 +1,3 @@ +-URL: https://chromium.googlesource.com/webm/libwebp/+archive/v1.2.0.tar.gz +-Version: v1.2.0 ++URL: https://chromium.googlesource.com/webm/libwebp/+archive/v1.2.0-8-g20ceff7e.tar.gz ++Version: v1.2.0-8-g20ceff7e + BugComponent: 20174 +diff --git a/src/dec/vp8l_dec.c b/src/dec/vp8l_dec.c +index 2d603b4..09a0eec 100644 +--- a/src/dec/vp8l_dec.c ++++ b/src/dec/vp8l_dec.c +@@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths( + int symbol; + int max_symbol; + int prev_code_len = DEFAULT_CODE_LENGTH; +- HuffmanCode table[1 << LENGTHS_TABLE_BITS]; ++ HuffmanTables tables; + +- if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS, +- code_length_code_lengths, +- NUM_CODE_LENGTH_CODES)) { ++ if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) || ++ !VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS, ++ code_length_code_lengths, NUM_CODE_LENGTH_CODES)) { + goto End; + } + +@@ -277,7 +277,7 @@ static int ReadHuffmanCodeLengths( + int code_len; + if (max_symbol-- == 0) break; + VP8LFillBitWindow(br); +- p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK]; ++ p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK]; + VP8LSetBitPos(br, br->bit_pos_ + p->bits); + code_len = p->value; + if (code_len < kCodeLengthLiterals) { +@@ -300,6 +300,7 @@ static int ReadHuffmanCodeLengths( + ok = 1; + + End: ++ VP8LHuffmanTablesDeallocate(&tables); + if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR; + return ok; + } +@@ -307,7 +308,8 @@ static int ReadHuffmanCodeLengths( + // 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman + // tree. + static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec, +- int* const code_lengths, HuffmanCode* const table) { ++ int* const code_lengths, ++ HuffmanTables* const table) { + int ok = 0; + int size = 0; + VP8LBitReader* const br = &dec->br_; +@@ -362,8 +364,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, + VP8LMetadata* const hdr = &dec->hdr_; + uint32_t* huffman_image = NULL; + HTreeGroup* htree_groups = NULL; +- HuffmanCode* huffman_tables = NULL; +- HuffmanCode* huffman_table = NULL; ++ HuffmanTables* huffman_tables = &hdr->huffman_tables_; + int num_htree_groups = 1; + int num_htree_groups_max = 1; + int max_alphabet_size = 0; +@@ -372,6 +373,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, + int* mapping = NULL; + int ok = 0; + ++ // Check the table has been 0 initialized (through InitMetadata). ++ assert(huffman_tables->root.start == NULL); ++ assert(huffman_tables->curr_segment == NULL); ++ + if (allow_recursion && VP8LReadBits(br, 1)) { + // use meta Huffman codes. + const int huffman_precision = VP8LReadBits(br, 3) + 2; +@@ -434,16 +439,15 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, + + code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size, + sizeof(*code_lengths)); +- huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size, +- sizeof(*huffman_tables)); + htree_groups = VP8LHtreeGroupsNew(num_htree_groups); + +- if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) { ++ if (htree_groups == NULL || code_lengths == NULL || ++ !VP8LHuffmanTablesAllocate(num_htree_groups * table_size, ++ huffman_tables)) { + dec->status_ = VP8_STATUS_OUT_OF_MEMORY; + goto Error; + } + +- huffman_table = huffman_tables; + for (i = 0; i < num_htree_groups_max; ++i) { + // If the index "i" is unused in the Huffman image, just make sure the + // coefficients are valid but do not store them. +@@ -468,19 +472,20 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, + int max_bits = 0; + for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { + int alphabet_size = kAlphabetSize[j]; +- htrees[j] = huffman_table; + if (j == 0 && color_cache_bits > 0) { + alphabet_size += (1 << color_cache_bits); + } +- size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table); ++ size = ++ ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables); ++ htrees[j] = huffman_tables->curr_segment->curr_table; + if (size == 0) { + goto Error; + } + if (is_trivial_literal && kLiteralMap[j] == 1) { +- is_trivial_literal = (huffman_table->bits == 0); ++ is_trivial_literal = (htrees[j]->bits == 0); + } +- total_size += huffman_table->bits; +- huffman_table += size; ++ total_size += htrees[j]->bits; ++ huffman_tables->curr_segment->curr_table += size; + if (j <= ALPHA) { + int local_max_bits = code_lengths[0]; + int k; +@@ -515,14 +520,13 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, + hdr->huffman_image_ = huffman_image; + hdr->num_htree_groups_ = num_htree_groups; + hdr->htree_groups_ = htree_groups; +- hdr->huffman_tables_ = huffman_tables; + + Error: + WebPSafeFree(code_lengths); + WebPSafeFree(mapping); + if (!ok) { + WebPSafeFree(huffman_image); +- WebPSafeFree(huffman_tables); ++ VP8LHuffmanTablesDeallocate(huffman_tables); + VP8LHtreeGroupsFree(htree_groups); + } + return ok; +@@ -1353,7 +1357,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) { + assert(hdr != NULL); + + WebPSafeFree(hdr->huffman_image_); +- WebPSafeFree(hdr->huffman_tables_); ++ VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_); + VP8LHtreeGroupsFree(hdr->htree_groups_); + VP8LColorCacheClear(&hdr->color_cache_); + VP8LColorCacheClear(&hdr->saved_color_cache_); +@@ -1669,7 +1673,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) { + // Sanity checks. + if (dec == NULL) return 0; + +- assert(dec->hdr_.huffman_tables_ != NULL); ++ assert(dec->hdr_.huffman_tables_.root.start != NULL); + assert(dec->hdr_.htree_groups_ != NULL); + assert(dec->hdr_.num_htree_groups_ > 0); + +diff --git a/src/dec/vp8li_dec.h b/src/dec/vp8li_dec.h +index 72b2e86..32540a4 100644 +--- a/src/dec/vp8li_dec.h ++++ b/src/dec/vp8li_dec.h +@@ -51,7 +51,7 @@ typedef struct { + uint32_t* huffman_image_; + int num_htree_groups_; + HTreeGroup* htree_groups_; +- HuffmanCode* huffman_tables_; ++ HuffmanTables huffman_tables_; + } VP8LMetadata; + + typedef struct VP8LDecoder VP8LDecoder; +diff --git a/src/dsp/alpha_processing_neon.c b/src/dsp/alpha_processing_neon.c +index 9d55421..27d7175 100644 +--- a/src/dsp/alpha_processing_neon.c ++++ b/src/dsp/alpha_processing_neon.c +@@ -83,7 +83,7 @@ static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first, + static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride, + int width, int height, + uint8_t* dst, int dst_stride) { +- uint32_t alpha_mask = 0xffffffffu; ++ uint32_t alpha_mask = 0xffu; + uint8x8_t mask8 = vdup_n_u8(0xff); + uint32_t tmp[2]; + int i, j; +@@ -107,6 +107,7 @@ static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride, + dst += dst_stride; + } + vst1_u8((uint8_t*)tmp, mask8); ++ alpha_mask *= 0x01010101; + alpha_mask &= tmp[0]; + alpha_mask &= tmp[1]; + return (alpha_mask != 0xffffffffu); +@@ -134,7 +135,7 @@ static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride, + static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride, + int width, int height, + uint8_t* alpha, int alpha_stride) { +- uint32_t alpha_mask = 0xffffffffu; ++ uint32_t alpha_mask = 0xffu; + uint8x8_t mask8 = vdup_n_u8(0xff); + uint32_t tmp[2]; + int i, j; +@@ -156,6 +157,7 @@ static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride, + alpha += alpha_stride; + } + vst1_u8((uint8_t*)tmp, mask8); ++ alpha_mask *= 0x01010101; + alpha_mask &= tmp[0]; + alpha_mask &= tmp[1]; + return (alpha_mask == 0xffffffffu); +diff --git a/src/dsp/lossless_enc_mips32.c b/src/dsp/lossless_enc_mips32.c +index 0412a09..9963051 100644 +--- a/src/dsp/lossless_enc_mips32.c ++++ b/src/dsp/lossless_enc_mips32.c +@@ -347,24 +347,24 @@ static void GetCombinedEntropyUnrefined_MIPS32(const uint32_t X[], + static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb, + uint32_t* pout, int size) { + uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; +- const uint32_t end = ((size) / 4) * 4; ++ const int end = ((size) / 4) * 4; + const uint32_t* const LoopEnd = pa + end; + int i; + ASM_START + ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout) + ASM_END_0 +- for (i = end; i < size; ++i) pout[i] = pa[i] + pb[i]; ++ for (i = 0; i < size - end; ++i) pout[i] = pa[i] + pb[i]; + } + + static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) { + uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; +- const uint32_t end = ((size) / 4) * 4; ++ const int end = ((size) / 4) * 4; + const uint32_t* const LoopEnd = pa + end; + int i; + ASM_START + ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout) + ASM_END_1 +- for (i = end; i < size; ++i) pout[i] += pa[i]; ++ for (i = 0; i < size - end; ++i) pout[i] += pa[i]; + } + + #undef ASM_END_1 +diff --git a/src/enc/backward_references_cost_enc.c b/src/enc/backward_references_cost_enc.c +index 516abd7..5eb24d4 100644 +--- a/src/enc/backward_references_cost_enc.c ++++ b/src/enc/backward_references_cost_enc.c +@@ -577,7 +577,7 @@ static int BackwardReferencesHashChainDistanceOnly( + (CostModel*)WebPSafeCalloc(1ULL, cost_model_size); + VP8LColorCache hashers; + CostManager* cost_manager = +- (CostManager*)WebPSafeMalloc(1ULL, sizeof(*cost_manager)); ++ (CostManager*)WebPSafeCalloc(1ULL, sizeof(*cost_manager)); + int offset_prev = -1, len_prev = -1; + double offset_cost = -1; + int first_offset_is_constant = -1; // initialized with 'impossible' value +diff --git a/src/enc/backward_references_enc.c b/src/enc/backward_references_enc.c +index 519b36a..d5e931e 100644 +--- a/src/enc/backward_references_enc.c ++++ b/src/enc/backward_references_enc.c +@@ -976,15 +976,16 @@ static int GetBackwardReferences(int width, int height, + const VP8LHashChain* const hash_chain_tmp = + (lz77_types_best[i] == kLZ77Standard) ? hash_chain : &hash_chain_box; + const int cache_bits = (i == 1) ? 0 : *cache_bits_best; +- if (VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits, +- hash_chain_tmp, &refs[i], +- refs_tmp)) { +- double bit_cost_trace; +- VP8LHistogramCreate(histo, refs_tmp, cache_bits); +- bit_cost_trace = VP8LHistogramEstimateBits(histo); +- if (bit_cost_trace < bit_costs_best[i]) { +- BackwardRefsSwap(refs_tmp, &refs[i]); +- } ++ double bit_cost_trace; ++ if (!VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits, ++ hash_chain_tmp, &refs[i], ++ refs_tmp)) { ++ goto Error; ++ } ++ VP8LHistogramCreate(histo, refs_tmp, cache_bits); ++ bit_cost_trace = VP8LHistogramEstimateBits(histo); ++ if (bit_cost_trace < bit_costs_best[i]) { ++ BackwardRefsSwap(refs_tmp, &refs[i]); + } + } + +diff --git a/src/enc/vp8l_enc.c b/src/enc/vp8l_enc.c +index 0b44ebe..1875e53 100644 +--- a/src/enc/vp8l_enc.c ++++ b/src/enc/vp8l_enc.c +@@ -1706,11 +1706,16 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, + const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface(); + int ok_main; + ++ if (enc_main == NULL || !VP8LBitWriterInit(&bw_side, 0)) { ++ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); ++ VP8LEncoderDelete(enc_main); ++ return 0; ++ } ++ + // Analyze image (entropy, num_palettes etc) +- if (enc_main == NULL || +- !EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main, ++ if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main, + &red_and_blue_always_zero) || +- !EncoderInit(enc_main) || !VP8LBitWriterInit(&bw_side, 0)) { ++ !EncoderInit(enc_main)) { + err = VP8_ENC_ERROR_OUT_OF_MEMORY; + goto Error; + } +diff --git a/src/utils/huffman_utils.c b/src/utils/huffman_utils.c +index 0cba0fb..9efd628 100644 +--- a/src/utils/huffman_utils.c ++++ b/src/utils/huffman_utils.c +@@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits, + if (num_open < 0) { + return 0; + } +- if (root_table == NULL) continue; + for (; count[len] > 0; --count[len]) { + HuffmanCode code; + if ((key & mask) != low) { +- table += table_size; ++ if (root_table != NULL) table += table_size; + table_bits = NextTableBitSize(count, len, root_bits); + table_size = 1 << table_bits; + total_size += table_size; + low = key & mask; +- root_table[low].bits = (uint8_t)(table_bits + root_bits); +- root_table[low].value = (uint16_t)((table - root_table) - low); ++ if (root_table != NULL) { ++ root_table[low].bits = (uint8_t)(table_bits + root_bits); ++ root_table[low].value = (uint16_t)((table - root_table) - low); ++ } ++ } ++ if (root_table != NULL) { ++ code.bits = (uint8_t)(len - root_bits); ++ code.value = (uint16_t)sorted[symbol++]; ++ ReplicateValue(&table[key >> root_bits], step, table_size, code); + } +- code.bits = (uint8_t)(len - root_bits); +- code.value = (uint16_t)sorted[symbol++]; +- ReplicateValue(&table[key >> root_bits], step, table_size, code); + key = GetNextKey(key, len); + } + } +@@ -211,25 +214,83 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits, + ((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES) + // Cut-off value for switching between heap and stack allocation. + #define SORTED_SIZE_CUTOFF 512 +-int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, ++int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits, + const int code_lengths[], int code_lengths_size) { +- int total_size; ++ const int total_size = ++ BuildHuffmanTable(NULL, root_bits, code_lengths, code_lengths_size, NULL); + assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE); +- if (root_table == NULL) { +- total_size = BuildHuffmanTable(NULL, root_bits, +- code_lengths, code_lengths_size, NULL); +- } else if (code_lengths_size <= SORTED_SIZE_CUTOFF) { ++ if (total_size == 0 || root_table == NULL) return total_size; ++ ++ if (root_table->curr_segment->curr_table + total_size >= ++ root_table->curr_segment->start + root_table->curr_segment->size) { ++ // If 'root_table' does not have enough memory, allocate a new segment. ++ // The available part of root_table->curr_segment is left unused because we ++ // need a contiguous buffer. ++ const int segment_size = root_table->curr_segment->size; ++ struct HuffmanTablesSegment* next = ++ (HuffmanTablesSegment*)WebPSafeMalloc(1, sizeof(*next)); ++ if (next == NULL) return 0; ++ // Fill the new segment. ++ // We need at least 'total_size' but if that value is small, it is better to ++ // allocate a big chunk to prevent more allocations later. 'segment_size' is ++ // therefore chosen (any other arbitrary value could be chosen). ++ next->size = total_size > segment_size ? total_size : segment_size; ++ next->start = ++ (HuffmanCode*)WebPSafeMalloc(next->size, sizeof(*next->start)); ++ if (next->start == NULL) { ++ WebPSafeFree(next); ++ return 0; ++ } ++ next->curr_table = next->start; ++ next->next = NULL; ++ // Point to the new segment. ++ root_table->curr_segment->next = next; ++ root_table->curr_segment = next; ++ } ++ if (code_lengths_size <= SORTED_SIZE_CUTOFF) { + // use local stack-allocated array. + uint16_t sorted[SORTED_SIZE_CUTOFF]; +- total_size = BuildHuffmanTable(root_table, root_bits, +- code_lengths, code_lengths_size, sorted); +- } else { // rare case. Use heap allocation. ++ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits, ++ code_lengths, code_lengths_size, sorted); ++ } else { // rare case. Use heap allocation. + uint16_t* const sorted = + (uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted)); + if (sorted == NULL) return 0; +- total_size = BuildHuffmanTable(root_table, root_bits, +- code_lengths, code_lengths_size, sorted); ++ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits, ++ code_lengths, code_lengths_size, sorted); + WebPSafeFree(sorted); + } + return total_size; + } ++ ++int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) { ++ // Have 'segment' point to the first segment for now, 'root'. ++ HuffmanTablesSegment* const root = &huffman_tables->root; ++ huffman_tables->curr_segment = root; ++ // Allocate root. ++ root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start)); ++ if (root->start == NULL) return 0; ++ root->curr_table = root->start; ++ root->next = NULL; ++ root->size = size; ++ return 1; ++} ++ ++void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables) { ++ HuffmanTablesSegment *current, *next; ++ if (huffman_tables == NULL) return; ++ // Free the root node. ++ current = &huffman_tables->root; ++ next = current->next; ++ WebPSafeFree(current->start); ++ current->start = NULL; ++ current->next = NULL; ++ current = next; ++ // Free the following nodes. ++ while (current != NULL) { ++ next = current->next; ++ WebPSafeFree(current->start); ++ WebPSafeFree(current); ++ current = next; ++ } ++} +diff --git a/src/utils/huffman_utils.h b/src/utils/huffman_utils.h +index 13b7ad1..98415c5 100644 +--- a/src/utils/huffman_utils.h ++++ b/src/utils/huffman_utils.h +@@ -43,6 +43,29 @@ typedef struct { + // or non-literal symbol otherwise + } HuffmanCode32; + ++// Contiguous memory segment of HuffmanCodes. ++typedef struct HuffmanTablesSegment { ++ HuffmanCode* start; ++ // Pointer to where we are writing into the segment. Starts at 'start' and ++ // cannot go beyond 'start' + 'size'. ++ HuffmanCode* curr_table; ++ // Pointer to the next segment in the chain. ++ struct HuffmanTablesSegment* next; ++ int size; ++} HuffmanTablesSegment; ++ ++// Chained memory segments of HuffmanCodes. ++typedef struct HuffmanTables { ++ HuffmanTablesSegment root; ++ // Currently processed segment. At first, this is 'root'. ++ HuffmanTablesSegment* curr_segment; ++} HuffmanTables; ++ ++// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on ++// memory allocation error, 1 otherwise. ++int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables); ++void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables); ++ + #define HUFFMAN_PACKED_BITS 6 + #define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS) + +@@ -78,9 +101,7 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups); + // the huffman table. + // Returns built table size or 0 in case of error (invalid tree or + // memory error). +-// If root_table is NULL, it returns 0 if a lookup cannot be built, something +-// > 0 otherwise (but not the table size). +-int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, ++int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits, + const int code_lengths[], int code_lengths_size); + + #ifdef __cplusplus +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0188-DO-NOT-MERGE-ActivityManager-killBackgroundProcesses-can-kill-c.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0188-DO-NOT-MERGE-ActivityManager-killBackgroundProcesses-can-kill-c.bulletin.patch new file mode 100644 index 0000000000..157c292e4b --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0188-DO-NOT-MERGE-ActivityManager-killBackgroundProcesses-can-kill-c.bulletin.patch @@ -0,0 +1,112 @@ +From 5f446d2ce101e9072a46603d4e1ab66a336e35fa Mon Sep 17 00:00:00 2001 +From: Jing Ji +Date: Tue, 25 Oct 2022 22:39:52 -0700 +Subject: [PATCH] DO NOT MERGE: ActivityManager#killBackgroundProcesses can + kill caller's own app only + +unless it's a system app. + +Bug: 239423414 +Bug: 223376078 +Test: atest CtsAppTestCases:ActivityManagerTest +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d1c95670b248df945784b0f2830acf83b5682de3) +Merged-In: Iac6baa889965b8ffecd9a43179a4c96632ad1d02 +Change-Id: Iac6baa889965b8ffecd9a43179a4c96632ad1d02 +--- + core/java/android/app/ActivityManager.java | 3 ++ + core/res/AndroidManifest.xml | 6 +++- + .../server/am/ActivityManagerService.java | 32 +++++++++++++++++-- + 3 files changed, 38 insertions(+), 3 deletions(-) + +diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java +index 644a87d850df..18ac45fc0ff8 100644 +--- a/core/java/android/app/ActivityManager.java ++++ b/core/java/android/app/ActivityManager.java +@@ -3661,6 +3661,9 @@ public class ActivityManager { + * processes to reclaim memory; the system will take care of restarting + * these processes in the future as needed. + * ++ *

Third party applications can only use this API to kill their own processes. ++ *

++ * + * @param packageName The name of the package whose processes are to + * be killed. + */ +diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml +index 0c50e0d5bfa4..cb9160d89617 100644 +--- a/core/res/AndroidManifest.xml ++++ b/core/res/AndroidManifest.xml +@@ -2812,7 +2812,11 @@ + android:protectionLevel="normal" /> + + + = FIRST_APPLICATION_UID ++ && (proc == null || !proc.info.isSystemApp())) { ++ final String msg = "Permission Denial: killAllBackgroundProcesses() from pid=" ++ + callingPid + ", uid=" + callingUid + " is not allowed"; ++ Slog.w(TAG, msg); ++ // Silently return to avoid existing apps from crashing. ++ return; ++ } ++ + final long callingId = Binder.clearCallingIdentity(); + try { + synchronized (this) { +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0189-Limit-the-number-of-supported-v1-and-v2-signers.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0189-Limit-the-number-of-supported-v1-and-v2-signers.bulletin.patch new file mode 100644 index 0000000000..0887c21b44 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0189-Limit-the-number-of-supported-v1-and-v2-signers.bulletin.patch @@ -0,0 +1,87 @@ +From b8fc2998ebdf43cb11b8dc69e5976c88d853b055 Mon Sep 17 00:00:00 2001 +From: Michael Groover +Date: Fri, 31 Mar 2023 21:31:22 +0000 +Subject: [PATCH] Limit the number of supported v1 and v2 signers + +The v1 and v2 APK Signature Schemes support multiple signers; this +was intended to allow multiple entities to sign an APK. Previously, +the platform had no limits placed on the number of signers supported +in an APK, but this commit sets a hard limit of 10 supported signers +for these signature schemes to ensure a large number of signers +does not place undue burden on the platform. + +Bug: 266580022 +Test: Manually verified the platform only allowed an APK with the + maximum number of supported signers. +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:6f6ee8a55f37c2b8c0df041b2bd53ec928764597) +Merged-In: I6aa86b615b203cdc69d58a593ccf8f18474ca091 +Change-Id: I6aa86b615b203cdc69d58a593ccf8f18474ca091 +--- + .../util/apk/ApkSignatureSchemeV2Verifier.java | 10 ++++++++++ + core/java/android/util/jar/StrictJarVerifier.java | 11 +++++++++++ + 2 files changed, 21 insertions(+) + +diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +index f74990a82327..0f1ab7fd1c34 100644 +--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java ++++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +@@ -74,6 +74,11 @@ public class ApkSignatureSchemeV2Verifier { + + private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a; + ++ /** ++ * The maximum number of signers supported by the v2 APK signature scheme. ++ */ ++ private static final int MAX_V2_SIGNERS = 10; ++ + /** + * Returns {@code true} if the provided APK contains an APK Signature Scheme V2 signature. + * +@@ -182,6 +187,11 @@ public class ApkSignatureSchemeV2Verifier { + } + while (signers.hasRemaining()) { + signerCount++; ++ if (signerCount > MAX_V2_SIGNERS) { ++ throw new SecurityException( ++ "APK Signature Scheme v2 only supports a maximum of " + MAX_V2_SIGNERS ++ + " signers"); ++ } + try { + ByteBuffer signer = getLengthPrefixedSlice(signers); + X509Certificate[] certs = verifySigner(signer, contentDigests, certFactory); +diff --git a/core/java/android/util/jar/StrictJarVerifier.java b/core/java/android/util/jar/StrictJarVerifier.java +index 45254908c5c9..a6aca330d323 100644 +--- a/core/java/android/util/jar/StrictJarVerifier.java ++++ b/core/java/android/util/jar/StrictJarVerifier.java +@@ -78,6 +78,11 @@ class StrictJarVerifier { + "SHA1", + }; + ++ /** ++ * The maximum number of signers supported by the JAR signature scheme. ++ */ ++ private static final int MAX_JAR_SIGNERS = 10; ++ + private final String jarName; + private final StrictJarManifest manifest; + private final HashMap metaEntries; +@@ -293,10 +298,16 @@ class StrictJarVerifier { + return false; + } + ++ int signerCount = 0; + Iterator it = metaEntries.keySet().iterator(); + while (it.hasNext()) { + String key = it.next(); + if (key.endsWith(".DSA") || key.endsWith(".RSA") || key.endsWith(".EC")) { ++ if (++signerCount > MAX_JAR_SIGNERS) { ++ throw new SecurityException( ++ "APK Signature Scheme v1 only supports a maximum of " + MAX_JAR_SIGNERS ++ + " signers"); ++ } + verifyCertificate(key); + it.remove(); + } +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0190-Verify-URI-permissions-for-EXTRA_REMOTE_INPUT_HISTORY_ITEMS-.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0190-Verify-URI-permissions-for-EXTRA_REMOTE_INPUT_HISTORY_ITEMS-.bulletin.patch new file mode 100644 index 0000000000..c9e3684126 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0190-Verify-URI-permissions-for-EXTRA_REMOTE_INPUT_HISTORY_ITEMS-.bulletin.patch @@ -0,0 +1,104 @@ +From f2d7a8dfcaa1843be1d9dc1eefb7fac92e3653c9 Mon Sep 17 00:00:00 2001 +From: Ioana Alexandru +Date: Fri, 21 Apr 2023 15:39:22 +0000 +Subject: [PATCH] Verify URI permissions for EXTRA_REMOTE_INPUT_HISTORY_ITEMS. + +Also added the person URIs in the test, since they weren't being +checked. + +Test: atest NotificationManagerServiceTest & tested with POC from bug +Bug: 276729064 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:43b1711332763788c7abf05c3baa931296c45bbb) +Merged-In: I848545f7aee202495c515f47a32871a2cb6ae707 +Change-Id: I848545f7aee202495c515f47a32871a2cb6ae707 +--- + core/java/android/app/Notification.java | 11 +++++++ + .../NotificationManagerServiceTest.java | 32 +++++++++++++++++++ + 2 files changed, 43 insertions(+) + +diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java +index 228e5a363547..90a4c304c399 100644 +--- a/core/java/android/app/Notification.java ++++ b/core/java/android/app/Notification.java +@@ -2799,6 +2799,17 @@ public class Notification implements Parcelable + if (person != null) { + visitor.accept(person.getIconUri()); + } ++ ++ final RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[]) ++ extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS); ++ if (history != null) { ++ for (int i = 0; i < history.length; i++) { ++ RemoteInputHistoryItem item = history[i]; ++ if (item.getUri() != null) { ++ visitor.accept(item.getUri()); ++ } ++ } ++ } + } + + if (isStyle(MessagingStyle.class) && extras != null) { +diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +index fba2f95027a4..4e8a1b4823f0 100755 +--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java ++++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +@@ -116,6 +116,7 @@ import android.app.NotificationManager; + import android.app.PendingIntent; + import android.app.Person; + import android.app.RemoteInput; ++import android.app.RemoteInputHistoryItem; + import android.app.StatsManager; + import android.app.admin.DevicePolicyManagerInternal; + import android.app.usage.UsageStatsManagerInternal; +@@ -4318,10 +4319,36 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + public void testVisitUris() throws Exception { + final Uri audioContents = Uri.parse("content://com.example/audio"); + final Uri backgroundImage = Uri.parse("content://com.example/background"); ++ final Icon personIcon1 = Icon.createWithContentUri("content://media/person1"); ++ final Icon personIcon2 = Icon.createWithContentUri("content://media/person2"); ++ final Icon personIcon3 = Icon.createWithContentUri("content://media/person3"); ++ final Person person1 = new Person.Builder() ++ .setName("Messaging Person") ++ .setIcon(personIcon1) ++ .build(); ++ final Person person2 = new Person.Builder() ++ .setName("People List Person 1") ++ .setIcon(personIcon2) ++ .build(); ++ final Person person3 = new Person.Builder() ++ .setName("People List Person 2") ++ .setIcon(personIcon3) ++ .build(); ++ final Uri historyUri1 = Uri.parse("content://com.example/history1"); ++ final Uri historyUri2 = Uri.parse("content://com.example/history2"); ++ final RemoteInputHistoryItem historyItem1 = new RemoteInputHistoryItem(null, historyUri1, ++ "a"); ++ final RemoteInputHistoryItem historyItem2 = new RemoteInputHistoryItem(null, historyUri2, ++ "b"); + + Bundle extras = new Bundle(); + extras.putParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents); + extras.putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, backgroundImage.toString()); ++ extras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person1); ++ extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, ++ new ArrayList<>(Arrays.asList(person2, person3))); ++ extras.putParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS, ++ new RemoteInputHistoryItem[]{historyItem1, historyItem2}); + + Notification n = new Notification.Builder(mContext, "a") + .setContentTitle("notification with uris") +@@ -4333,6 +4360,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + n.visitUris(visitor); + verify(visitor, times(1)).accept(eq(audioContents)); + verify(visitor, times(1)).accept(eq(backgroundImage)); ++ verify(visitor, times(1)).accept(eq(personIcon1.getUri())); ++ verify(visitor, times(1)).accept(eq(personIcon2.getUri())); ++ verify(visitor, times(1)).accept(eq(personIcon3.getUri())); ++ verify(visitor, times(1)).accept(eq(historyUri1)); ++ verify(visitor, times(1)).accept(eq(historyUri2)); + } + + @Test +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0191-Verify-URI-permissions-for-notification-shortcutIcon.patch b/aosp_diff/preliminary/frameworks/base/99_0191-Verify-URI-permissions-for-notification-shortcutIcon.patch new file mode 100644 index 0000000000..fa97af9a8b --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0191-Verify-URI-permissions-for-notification-shortcutIcon.patch @@ -0,0 +1,157 @@ +From cbd83296ef90a8ee392005de65a0f5ea3dcfda10 Mon Sep 17 00:00:00 2001 +From: Ioana Alexandru +Date: Thu, 27 Apr 2023 14:55:28 +0000 +Subject: [PATCH] Verify URI permissions for notification shortcutIcon. + +Bug: 277593270 +Test: atest NotificationManagerServiceTest +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:beb185c5cd60edc68f4ef386c4407eba9c02c698) +Merged-In: Iaf2a9a82f18e018e60e6cdc020da6ebf7267e8b1 +Change-Id: Iaf2a9a82f18e018e60e6cdc020da6ebf7267e8b1 +--- + core/java/android/app/Notification.java | 2 + + .../NotificationManagerServiceTest.java | 87 +++++++++++++++---- + 2 files changed, 70 insertions(+), 19 deletions(-) + +diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java +index df124a447d72..e9ba212a9812 100644 +--- a/core/java/android/app/Notification.java ++++ b/core/java/android/app/Notification.java +@@ -2850,6 +2850,8 @@ public class Notification implements Parcelable + } + } + } ++ ++ visitIconUri(visitor, extras.getParcelable(EXTRA_CONVERSATION_ICON)); + } + + if (isStyle(CallStyle.class) & extras != null) { +diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +index ee9435722be5..179ec997f681 100755 +--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java ++++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +@@ -4454,6 +4454,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + public void testVisitUris() throws Exception { + final Uri audioContents = Uri.parse("content://com.example/audio"); + final Uri backgroundImage = Uri.parse("content://com.example/background"); ++ final Icon smallIcon = Icon.createWithContentUri("content://media/small/icon"); ++ final Icon largeIcon = Icon.createWithContentUri("content://media/large/icon"); + final Icon personIcon1 = Icon.createWithContentUri("content://media/person1"); + final Icon personIcon2 = Icon.createWithContentUri("content://media/person2"); + final Icon personIcon3 = Icon.createWithContentUri("content://media/person3"); +@@ -4487,7 +4489,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + + Notification n = new Notification.Builder(mContext, "a") + .setContentTitle("notification with uris") +- .setSmallIcon(android.R.drawable.sym_def_app_icon) ++ .setSmallIcon(smallIcon) ++ .setLargeIcon(largeIcon) + .addExtras(extras) + .build(); + +@@ -4495,6 +4498,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + n.visitUris(visitor); + verify(visitor, times(1)).accept(eq(audioContents)); + verify(visitor, times(1)).accept(eq(backgroundImage)); ++ verify(visitor, times(1)).accept(eq(smallIcon.getUri())); ++ verify(visitor, times(1)).accept(eq(largeIcon.getUri())); + verify(visitor, times(1)).accept(eq(personIcon1.getUri())); + verify(visitor, times(1)).accept(eq(personIcon2.getUri())); + verify(visitor, times(1)).accept(eq(personIcon3.getUri())); +@@ -4502,6 +4507,68 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + verify(visitor, times(1)).accept(eq(historyUri2)); + } + ++ @Test ++ public void testVisitUris_audioContentsString() throws Exception { ++ final Uri audioContents = Uri.parse("content://com.example/audio"); ++ ++ Bundle extras = new Bundle(); ++ extras.putString(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents.toString()); ++ ++ Notification n = new Notification.Builder(mContext, "a") ++ .setContentTitle("notification with uris") ++ .setSmallIcon(android.R.drawable.sym_def_app_icon) ++ .addExtras(extras) ++ .build(); ++ ++ Consumer visitor = (Consumer) spy(Consumer.class); ++ n.visitUris(visitor); ++ verify(visitor, times(1)).accept(eq(audioContents)); ++ } ++ ++ @Test ++ public void testVisitUris_messagingStyle() { ++ final Icon personIcon1 = Icon.createWithContentUri("content://media/person1"); ++ final Icon personIcon2 = Icon.createWithContentUri("content://media/person2"); ++ final Icon personIcon3 = Icon.createWithContentUri("content://media/person3"); ++ final Person person1 = new Person.Builder() ++ .setName("Messaging Person 1") ++ .setIcon(personIcon1) ++ .build(); ++ final Person person2 = new Person.Builder() ++ .setName("Messaging Person 2") ++ .setIcon(personIcon2) ++ .build(); ++ final Person person3 = new Person.Builder() ++ .setName("Messaging Person 3") ++ .setIcon(personIcon3) ++ .build(); ++ Icon shortcutIcon = Icon.createWithContentUri("content://media/shortcut"); ++ ++ Notification.Builder builder = new Notification.Builder(mContext, "a") ++ .setCategory(Notification.CATEGORY_MESSAGE) ++ .setContentTitle("new message!") ++ .setContentText("Conversation Notification") ++ .setSmallIcon(android.R.drawable.sym_def_app_icon); ++ Notification.MessagingStyle.Message message1 = new Notification.MessagingStyle.Message( ++ "Marco?", System.currentTimeMillis(), person2); ++ Notification.MessagingStyle.Message message2 = new Notification.MessagingStyle.Message( ++ "Polo!", System.currentTimeMillis(), person3); ++ Notification.MessagingStyle style = new Notification.MessagingStyle(person1) ++ .addMessage(message1) ++ .addMessage(message2) ++ .setShortcutIcon(shortcutIcon); ++ builder.setStyle(style); ++ Notification n = builder.build(); ++ ++ Consumer visitor = (Consumer) spy(Consumer.class); ++ n.visitUris(visitor); ++ ++ verify(visitor, times(1)).accept(eq(shortcutIcon.getUri())); ++ verify(visitor, times(1)).accept(eq(personIcon1.getUri())); ++ verify(visitor, times(1)).accept(eq(personIcon2.getUri())); ++ verify(visitor, times(1)).accept(eq(personIcon3.getUri())); ++ } ++ + @Test + public void testVisitUris_callStyle() { + Icon personIcon = Icon.createWithContentUri("content://media/person"); +@@ -4545,24 +4612,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + verify(visitor, times(1)).accept(eq(largeIconPrivate.getUri())); + } + +- @Test +- public void testVisitUris_audioContentsString() throws Exception { +- final Uri audioContents = Uri.parse("content://com.example/audio"); +- +- Bundle extras = new Bundle(); +- extras.putString(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents.toString()); +- +- Notification n = new Notification.Builder(mContext, "a") +- .setContentTitle("notification with uris") +- .setSmallIcon(android.R.drawable.sym_def_app_icon) +- .addExtras(extras) +- .build(); +- +- Consumer visitor = (Consumer) spy(Consumer.class); +- n.visitUris(visitor); +- verify(visitor, times(1)).accept(eq(audioContents)); +- } +- + @Test + public void testSetNotificationPolicy_preP_setOldFields() { + ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); +-- +2.17.1 + diff --git a/aosp_diff/preliminary/frameworks/base/99_0192-Import-translations-DO-NOT-MERGE-ANYWHERE.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0192-Import-translations-DO-NOT-MERGE-ANYWHERE.bulletin.patch new file mode 100644 index 0000000000..bdf6f76f83 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0192-Import-translations-DO-NOT-MERGE-ANYWHERE.bulletin.patch @@ -0,0 +1,1122 @@ +From d5470c988cd65e1d7a8a640c7665bfa9796b82d8 Mon Sep 17 00:00:00 2001 +From: Bill Yi +Date: Wed, 21 Jun 2023 13:29:29 -0700 +Subject: [PATCH] Import translations. DO NOT MERGE ANYWHERE + +BUG:286996125 + +Auto-generated-cl: translation import +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:204ea4a673cc47f154cbff66d664618f1942b6b9) +Merged-In: I88f32886c5748d119bf37745060403a0e31d829d +Change-Id: I88f32886c5748d119bf37745060403a0e31d829d +--- + packages/SystemUI/res/values-af/strings.xml | 1 + + packages/SystemUI/res/values-am/strings.xml | 1 + + packages/SystemUI/res/values-ar/strings.xml | 1 + + packages/SystemUI/res/values-as/strings.xml | 1 + + packages/SystemUI/res/values-az/strings.xml | 1 + + packages/SystemUI/res/values-b+sr+Latn/strings.xml | 1 + + packages/SystemUI/res/values-be/strings.xml | 1 + + packages/SystemUI/res/values-bg/strings.xml | 1 + + packages/SystemUI/res/values-bn/strings.xml | 1 + + packages/SystemUI/res/values-bs/strings.xml | 1 + + packages/SystemUI/res/values-ca/strings.xml | 1 + + packages/SystemUI/res/values-cs/strings.xml | 1 + + packages/SystemUI/res/values-da/strings.xml | 1 + + packages/SystemUI/res/values-de/strings.xml | 1 + + packages/SystemUI/res/values-el/strings.xml | 1 + + packages/SystemUI/res/values-en-rAU/strings.xml | 1 + + packages/SystemUI/res/values-en-rCA/strings.xml | 1 + + packages/SystemUI/res/values-en-rGB/strings.xml | 1 + + packages/SystemUI/res/values-en-rIN/strings.xml | 1 + + packages/SystemUI/res/values-en-rXC/strings.xml | 1 + + packages/SystemUI/res/values-es-rUS/strings.xml | 1 + + packages/SystemUI/res/values-es/strings.xml | 1 + + packages/SystemUI/res/values-et/strings.xml | 1 + + packages/SystemUI/res/values-eu/strings.xml | 1 + + packages/SystemUI/res/values-fa/strings.xml | 1 + + packages/SystemUI/res/values-fi/strings.xml | 1 + + packages/SystemUI/res/values-fr-rCA/strings.xml | 1 + + packages/SystemUI/res/values-fr/strings.xml | 1 + + packages/SystemUI/res/values-gl/strings.xml | 1 + + packages/SystemUI/res/values-gu/strings.xml | 1 + + packages/SystemUI/res/values-hi/strings.xml | 1 + + packages/SystemUI/res/values-hr/strings.xml | 1 + + packages/SystemUI/res/values-hu/strings.xml | 1 + + packages/SystemUI/res/values-hy/strings.xml | 1 + + packages/SystemUI/res/values-in/strings.xml | 1 + + packages/SystemUI/res/values-is/strings.xml | 1 + + packages/SystemUI/res/values-it/strings.xml | 1 + + packages/SystemUI/res/values-iw/strings.xml | 1 + + packages/SystemUI/res/values-ja/strings.xml | 1 + + packages/SystemUI/res/values-ka/strings.xml | 1 + + packages/SystemUI/res/values-kk/strings.xml | 1 + + packages/SystemUI/res/values-km/strings.xml | 1 + + packages/SystemUI/res/values-kn/strings.xml | 1 + + packages/SystemUI/res/values-ko/strings.xml | 1 + + packages/SystemUI/res/values-ky/strings.xml | 1 + + packages/SystemUI/res/values-lo/strings.xml | 1 + + packages/SystemUI/res/values-lt/strings.xml | 1 + + packages/SystemUI/res/values-lv/strings.xml | 1 + + packages/SystemUI/res/values-mk/strings.xml | 1 + + packages/SystemUI/res/values-ml/strings.xml | 1 + + packages/SystemUI/res/values-mn/strings.xml | 1 + + packages/SystemUI/res/values-mr/strings.xml | 1 + + packages/SystemUI/res/values-ms/strings.xml | 1 + + packages/SystemUI/res/values-my/strings.xml | 1 + + packages/SystemUI/res/values-nb/strings.xml | 1 + + packages/SystemUI/res/values-ne/strings.xml | 1 + + packages/SystemUI/res/values-nl/strings.xml | 1 + + packages/SystemUI/res/values-or/strings.xml | 1 + + packages/SystemUI/res/values-pa/strings.xml | 1 + + packages/SystemUI/res/values-pl/strings.xml | 1 + + packages/SystemUI/res/values-pt-rBR/strings.xml | 1 + + packages/SystemUI/res/values-pt-rPT/strings.xml | 1 + + packages/SystemUI/res/values-pt/strings.xml | 1 + + packages/SystemUI/res/values-ro/strings.xml | 1 + + packages/SystemUI/res/values-ru/strings.xml | 1 + + packages/SystemUI/res/values-si/strings.xml | 1 + + packages/SystemUI/res/values-sk/strings.xml | 1 + + packages/SystemUI/res/values-sl/strings.xml | 1 + + packages/SystemUI/res/values-sq/strings.xml | 1 + + packages/SystemUI/res/values-sr/strings.xml | 1 + + packages/SystemUI/res/values-sv/strings.xml | 1 + + packages/SystemUI/res/values-sw/strings.xml | 1 + + packages/SystemUI/res/values-ta/strings.xml | 1 + + packages/SystemUI/res/values-te/strings.xml | 1 + + packages/SystemUI/res/values-th/strings.xml | 1 + + packages/SystemUI/res/values-tl/strings.xml | 1 + + packages/SystemUI/res/values-tr/strings.xml | 1 + + packages/SystemUI/res/values-uk/strings.xml | 1 + + packages/SystemUI/res/values-ur/strings.xml | 1 + + packages/SystemUI/res/values-uz/strings.xml | 1 + + packages/SystemUI/res/values-vi/strings.xml | 1 + + packages/SystemUI/res/values-zh-rCN/strings.xml | 1 + + packages/SystemUI/res/values-zh-rHK/strings.xml | 1 + + packages/SystemUI/res/values-zh-rTW/strings.xml | 1 + + packages/SystemUI/res/values-zu/strings.xml | 1 + + 85 files changed, 85 insertions(+) + +diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml +index 8229661fbc24..c6c08c94ee4b 100644 +--- a/packages/SystemUI/res/values-af/strings.xml ++++ b/packages/SystemUI/res/values-af/strings.xml +@@ -1093,6 +1093,7 @@ + "Maak %1$s oop" + "Speel %1$s deur %2$s vanaf %3$s" + "Speel %1$s vanaf %2$s" ++ "%1$s loop tans" + "Onaktief, gaan program na" + "Fout, probeer tans weer …" + "Nie gekry nie" +diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml +index 7f101d73b925..11edb63bfe03 100644 +--- a/packages/SystemUI/res/values-am/strings.xml ++++ b/packages/SystemUI/res/values-am/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s ክፈት" + "%1$s%2$s%3$s ያጫውቱ" + "%1$s%2$s ያጫውቱ" ++ "%1$s እያሄደ ነው" + "ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ" + "ስህተት፣ እንደገና በመሞከር ላይ…" + "አልተገኘም" +diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml +index 8f230246a70e..94271b1e7a6e 100644 +--- a/packages/SystemUI/res/values-ar/strings.xml ++++ b/packages/SystemUI/res/values-ar/strings.xml +@@ -1117,6 +1117,7 @@ + "فتح %1$s" + "تشغيل %1$s للفنان %2$s من تطبيق %3$s" + "تشغيل %1$s من تطبيق %2$s" ++ "\"%1$s\" قيد التشغيل" + "غير نشط، تحقّق من التطبيق." + "حدث خطأ، جارٍ إعادة المحاولة…" + "لم يتم العثور عليه." +diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml +index c4438fca51e3..fcbefc4d24cb 100644 +--- a/packages/SystemUI/res/values-as/strings.xml ++++ b/packages/SystemUI/res/values-as/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s খোলক" + "%3$s%2$s%1$s গীতটো প্লে’ কৰক" + "%2$s%1$s গীতটো প্লে’ কৰক" ++ "%1$s চলি আছে" + "সক্ৰিয় নহয়, এপ্‌টো পৰীক্ষা কৰক" + "আসোঁৱাহ, পুনৰ চেষ্টা কৰি আছে…" + "বিচাৰি পোৱা নগ’ল" +diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml +index 7e50b194000a..ac6b69767896 100644 +--- a/packages/SystemUI/res/values-az/strings.xml ++++ b/packages/SystemUI/res/values-az/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s tətbiqini açın" + "%2$s tərəfindən %1$s mahnısını %3$s tətbiqindən oxudun" + "%1$s mahnısını %2$s tətbiqindən oxudun" ++ "%1$s işləyir" + "Aktiv deyil, tətbiqi yoxlayın" + "Xəta, yenidən cəhd edilir…" + "Tapılmadı" +diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml +index 701765f4036c..136ba652d248 100644 +--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml ++++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml +@@ -1099,6 +1099,7 @@ + "Otvorite %1$s" + "Pustite %1$s izvođača %2$s iz aplikacije %3$s" + "Pustite %1$s iz aplikacije %2$s" ++ "Aplikacija %1$s je pokrenuta" + "Neaktivno. Vidite aplikaciju" + "Greška, pokušava se ponovo…" + "Nije pronađeno" +diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml +index 5da6cf8b9c35..7a783f52bedd 100644 +--- a/packages/SystemUI/res/values-be/strings.xml ++++ b/packages/SystemUI/res/values-be/strings.xml +@@ -1105,6 +1105,7 @@ + "Адкрыйце праграму \"%1$s\"" + "Прайграйце кампазіцыю \"%1$s\" (выканаўца – %2$s) з дапамогай праграмы \"%3$s\"" + "Прайграйце кампазіцыю \"%1$s\" з дапамогай праграмы \"%2$s\"" ++ "%1$s працуе" + "Неактыўна, праверце праграму" + "Памылка, паўторная спроба…" + "Не знойдзена" +diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml +index 742de25d539c..0165b9d62138 100644 +--- a/packages/SystemUI/res/values-bg/strings.xml ++++ b/packages/SystemUI/res/values-bg/strings.xml +@@ -1093,6 +1093,7 @@ + "Отваряне на %1$s" + "Пускане на %1$s на %2$s от %3$s" + "Пускане на %1$s от %2$s" ++ "%1$s се изпълнява" + "Неактивно, проверете прилож." + "Грешка. Извършва се нов опит…" + "Не е намерено" +diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml +index b35ae1f1efde..d9badc2da8a0 100644 +--- a/packages/SystemUI/res/values-bn/strings.xml ++++ b/packages/SystemUI/res/values-bn/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s অ্যাপ খুলুন" + "%2$s-এর %1$s গানটি %3$s অ্যাপে চালান" + "%1$s গানটি %2$s অ্যাপে চালান" ++ "%1$s চলছে" + "বন্ধ আছে, অ্যাপ চেক করুন" + "সমস্যা, আবার চেষ্টা করা হচ্ছে…" + "খুঁজে পাওয়া যায়নি" +diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml +index b87739732e4b..e5189cac783e 100644 +--- a/packages/SystemUI/res/values-bs/strings.xml ++++ b/packages/SystemUI/res/values-bs/strings.xml +@@ -1099,6 +1099,7 @@ + "Otvorite aplikaciju %1$s" + "Reproducirajte pjesmu %1$s izvođača %2$s pomoću aplikacije %3$s" + "Reproducirajte pjesmu %1$s pomoću aplikacije %2$s" ++ "Aplikacija %1$s je pokrenuta" + "Neaktivno, vidite aplikaciju" + "Greška, ponovni pokušaj…" + "Nije pronađeno" +diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml +index a5504f02833e..f74ab42dcbff 100644 +--- a/packages/SystemUI/res/values-ca/strings.xml ++++ b/packages/SystemUI/res/values-ca/strings.xml +@@ -1093,6 +1093,7 @@ + "Obre %1$s" + "Reprodueix %1$s (%2$s) des de l\'aplicació %3$s" + "Reprodueix %1$s des de l\'aplicació %2$s" ++ "%1$s s\'està executant" + "Inactiu; comprova l\'aplicació" + "Error. S\'està tornant a provar…" + "No s\'ha trobat" +diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml +index f48c9fb1cd77..30de08b37c52 100644 +--- a/packages/SystemUI/res/values-cs/strings.xml ++++ b/packages/SystemUI/res/values-cs/strings.xml +@@ -1105,6 +1105,7 @@ + "Otevřít aplikaci %1$s" + "Přehrát skladbu %1$s od interpreta %2$s z aplikace %3$s" + "Přehrát skladbu %1$s z aplikace %2$s" ++ "Aplikace %1$s je spuštěna" + "Neaktivní, zkontrolujte aplikaci" + "Chyba. Nový pokus…" + "Nenalezeno" +diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml +index cbef46488c5a..4c7712005330 100644 +--- a/packages/SystemUI/res/values-da/strings.xml ++++ b/packages/SystemUI/res/values-da/strings.xml +@@ -1093,6 +1093,7 @@ + "Åbn %1$s" + "Afspil %1$s af %2$s via %3$s" + "Afspil %1$s via %2$s" ++ "%1$s kører" + "Inaktiv. Tjek appen" + "Fejl. Prøver igen…" + "Ikke fundet" +diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml +index 50fcdfb7032a..a22c7a03405c 100644 +--- a/packages/SystemUI/res/values-de/strings.xml ++++ b/packages/SystemUI/res/values-de/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s öffnen" + "%1$s von %2$s über %3$s wiedergeben" + "%1$s über %2$s wiedergeben" ++ "%1$s wird ausgeführt" + "Inaktiv – sieh in der App nach" + "Fehler. Neuer Versuch…" + "Nicht gefunden" +diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml +index b8d357f3ff95..a50335abfa0f 100644 +--- a/packages/SystemUI/res/values-el/strings.xml ++++ b/packages/SystemUI/res/values-el/strings.xml +@@ -1093,6 +1093,7 @@ + "Άνοιγμα της εφαρμογής %1$s" + "Αναπαραγωγή του %1$s από %2$s στην εφαρμογή %3$s" + "Αναπαραγωγή του %1$s στην εφαρμογή %2$s" ++ "Η εφαρμογή %1$s εκτελείται" + "Ανενεργό, έλεγχος εφαρμογής" + "Προέκυψε σφάλμα. Επανάληψη…" + "Δεν βρέθηκε." +diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml +index d69a95bba878..8ac0feb192dd 100644 +--- a/packages/SystemUI/res/values-en-rAU/strings.xml ++++ b/packages/SystemUI/res/values-en-rAU/strings.xml +@@ -1093,6 +1093,7 @@ + "Open %1$s" + "Play %1$s by %2$s from %3$s" + "Play %1$s from %2$s" ++ "%1$s is running" + "Inactive, check app" + "Error, retrying…" + "Not found" +diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml +index 3666069ee54b..1f6c5c3dc288 100644 +--- a/packages/SystemUI/res/values-en-rCA/strings.xml ++++ b/packages/SystemUI/res/values-en-rCA/strings.xml +@@ -1093,6 +1093,7 @@ + "Open %1$s" + "Play %1$s by %2$s from %3$s" + "Play %1$s from %2$s" ++ "%1$s is running" + "Inactive, check app" + "Error, retrying…" + "Not found" +diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml +index d69a95bba878..8ac0feb192dd 100644 +--- a/packages/SystemUI/res/values-en-rGB/strings.xml ++++ b/packages/SystemUI/res/values-en-rGB/strings.xml +@@ -1093,6 +1093,7 @@ + "Open %1$s" + "Play %1$s by %2$s from %3$s" + "Play %1$s from %2$s" ++ "%1$s is running" + "Inactive, check app" + "Error, retrying…" + "Not found" +diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml +index d69a95bba878..8ac0feb192dd 100644 +--- a/packages/SystemUI/res/values-en-rIN/strings.xml ++++ b/packages/SystemUI/res/values-en-rIN/strings.xml +@@ -1093,6 +1093,7 @@ + "Open %1$s" + "Play %1$s by %2$s from %3$s" + "Play %1$s from %2$s" ++ "%1$s is running" + "Inactive, check app" + "Error, retrying…" + "Not found" +diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml +index 030c5884d3e3..cf843402ce07 100644 +--- a/packages/SystemUI/res/values-en-rXC/strings.xml ++++ b/packages/SystemUI/res/values-en-rXC/strings.xml +@@ -1093,6 +1093,7 @@ + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‎Open ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎Play ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ by ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎ from ‎‏‎‎‏‏‎%3$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‎‏‎‏‎Play ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ from ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" ++ "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ is running‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎Inactive, check app‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‎Error, retrying…‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎Not found‎‏‎‎‏‎" +diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml +index bb43d81596be..ba39498537d8 100644 +--- a/packages/SystemUI/res/values-es-rUS/strings.xml ++++ b/packages/SystemUI/res/values-es-rUS/strings.xml +@@ -1093,6 +1093,7 @@ + "Abre %1$s" + "Reproduce %1$s, de %2$s, en %3$s" + "Reproducir %1$s en %2$s" ++ "%1$s se está ejecutando" + "Inactivo. Verifica la app" + "Hubo un error. Reintentando…" + "No se encontró" +diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml +index 820c708e4fe1..1b8b8ad0ddb2 100644 +--- a/packages/SystemUI/res/values-es/strings.xml ++++ b/packages/SystemUI/res/values-es/strings.xml +@@ -1093,6 +1093,7 @@ + "Abrir %1$s" + "Poner %1$s de %2$s en %3$s" + "Poner %1$s en %2$s" ++ "%1$s se está ejecutando" + "Inactivo, comprobar aplicación" + "Error; reintentando…" + "No se ha encontrado" +diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml +index 6cd609fa6151..98de88b4cc22 100644 +--- a/packages/SystemUI/res/values-et/strings.xml ++++ b/packages/SystemUI/res/values-et/strings.xml +@@ -1093,6 +1093,7 @@ + "Rakenduse %1$s avamine" + "Esita lugu %1$s esitajalt %2$s rakenduses %3$s" + "Esita lugu %1$s rakenduses %2$s" ++ "%1$s töötab" + "Passiivne, vaadake rakendust" + "Viga, proovitakse uuesti …" + "Ei leitud" +diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml +index b6162a830186..39ead203d999 100644 +--- a/packages/SystemUI/res/values-eu/strings.xml ++++ b/packages/SystemUI/res/values-eu/strings.xml +@@ -1093,6 +1093,7 @@ + "Ireki %1$s" + "Erreproduzitu %1$s (%2$s) %3$s bidez" + "Erreproduzitu %1$s %2$s bidez" ++ "%1$s abian da" + "Inaktibo; egiaztatu aplikazioa" + "Errorea. Berriro saiatzen…" + "Ez da aurkitu" +diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml +index d1ddd8c042f4..31920ae82777 100644 +--- a/packages/SystemUI/res/values-fa/strings.xml ++++ b/packages/SystemUI/res/values-fa/strings.xml +@@ -1093,6 +1093,7 @@ + "باز کردن %1$s" + "%1$s از %2$s را ازطریق %3$s پخش کنید" + "%1$s را ازطریق %2$s پخش کنید" ++ "%1$s در حال اجرا است" + "غیرفعال، برنامه را بررسی کنید" + "خطا، درحال تلاش مجدد…" + "پیدا نشد" +diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml +index 652acf7ddd89..0f1184f506f0 100644 +--- a/packages/SystemUI/res/values-fi/strings.xml ++++ b/packages/SystemUI/res/values-fi/strings.xml +@@ -1093,6 +1093,7 @@ + "Avaa %1$s" + "Soita %1$s (%2$s) sovelluksessa %3$s" + "Soita %1$s (%2$s)" ++ "%1$s on käynnissä" + "Epäaktiivinen, tarkista sovellus" + "Virhe, yritetään uudelleen…" + "Ei löydy" +diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml +index 1ec1f9190a22..355caf7903b3 100644 +--- a/packages/SystemUI/res/values-fr-rCA/strings.xml ++++ b/packages/SystemUI/res/values-fr-rCA/strings.xml +@@ -1093,6 +1093,7 @@ + "Ouvrez %1$s" + "Lecture de %1$s par %2$s à partir de %3$s" + "Lecture de %1$s à partir de %2$s" ++ "%1$s en cours d\'exécution" + "Délai expiré, vérifiez l\'appli" + "Erreur, nouvelle tentative…" + "Introuvable" +diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml +index 6a08d8716677..aa22179a7927 100644 +--- a/packages/SystemUI/res/values-fr/strings.xml ++++ b/packages/SystemUI/res/values-fr/strings.xml +@@ -1093,6 +1093,7 @@ + "Ouvre %1$s" + "Mets %1$s par %2$s depuis %3$s" + "Mets %1$s depuis %2$s" ++ "%1$s est en cours d\'exécution" + "Délai expiré, vérifier l\'appli" + "Erreur. Nouvelle tentative…" + "Introuvable" +diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml +index 15678e4cc907..0f4c804882f4 100644 +--- a/packages/SystemUI/res/values-gl/strings.xml ++++ b/packages/SystemUI/res/values-gl/strings.xml +@@ -1093,6 +1093,7 @@ + "Abre %1$s" + "Reproduce %1$s, de %2$s, en %3$s" + "Reproduce %1$s en %2$s" ++ "%1$s estase executando" + "Inactivo. Comproba a app" + "Erro. Tentando de novo…" + "Non se atopou" +diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml +index 9255827aa64e..b43ede6e602b 100644 +--- a/packages/SystemUI/res/values-gu/strings.xml ++++ b/packages/SystemUI/res/values-gu/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s ખોલો" + "%3$s પર %2$sનું %1$s ગીત ચલાવો" + "%2$s પર %1$s ગીત ચલાવો" ++ "%1$s ચાલી રહી છે" + "નિષ્ક્રિય, ઍપને ચેક કરો" + "ભૂલ, ફરી પ્રયાસ કરી રહ્યા છીએ…" + "મળ્યું નથી" +diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml +index 1ebb517dc316..25aa0a7d67fc 100644 +--- a/packages/SystemUI/res/values-hi/strings.xml ++++ b/packages/SystemUI/res/values-hi/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s खोलें" + "%3$s पर, %2$s का %1$s चलाएं" + "%2$s पर, %1$s चलाएं" ++ "%1$s चालू है" + "काम नहीं कर रहा, ऐप जांचें" + "कोई गड़बड़ी हुई, फिर से कोशिश की जा रही है…" + "कंट्रोल नहीं है" +diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml +index 9ec657d8d19d..4716ac550073 100644 +--- a/packages/SystemUI/res/values-hr/strings.xml ++++ b/packages/SystemUI/res/values-hr/strings.xml +@@ -1099,6 +1099,7 @@ + "Otvori %1$s" + "Pustite %1$s, %2$s putem aplikacije %3$s" + "Pustite %1$s putem aplikacije %2$s" ++ "Aplikacija %1$s je pokrenuta" + "Neaktivno, provjerite aplik." + "Pogreška, pokušavamo ponovo…" + "Nije pronađeno" +diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml +index d9d8148938de..075445ac56f1 100644 +--- a/packages/SystemUI/res/values-hu/strings.xml ++++ b/packages/SystemUI/res/values-hu/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s megnyitása" + "%2$s %1$s című számának lejátszása innen: %3$s" + "%1$s lejátszása innen: %2$s" ++ "A(z) %1$s jelenleg fut" + "Inaktív, ellenőrizze az appot" + "Hiba, újrapróbálkozás…" + "Nem található" +diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml +index 1d8094a4f61c..1bbbf443156a 100644 +--- a/packages/SystemUI/res/values-hy/strings.xml ++++ b/packages/SystemUI/res/values-hy/strings.xml +@@ -1093,6 +1093,7 @@ + "Բացեք %1$s հավելվածը" + "Նվագարկել %1$s երգը %2$s-ի կատարմամբ %3$s հավելվածից" + "Նվագարկել %1$s երգը %2$s հավելվածից" ++ "%1$s հավելվածն աշխատում է" + "Ակտիվ չէ, ստուգեք հավելվածը" + "Սխալ. նորից ենք փորձում…" + "Չի գտնվել" +diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml +index 76ee7224933c..5d6b2db52c5f 100644 +--- a/packages/SystemUI/res/values-in/strings.xml ++++ b/packages/SystemUI/res/values-in/strings.xml +@@ -1093,6 +1093,7 @@ + "Buka %1$s" + "Putar %1$s oleh %2$s dari %3$s" + "Putar %1$s dari %2$s" ++ "%1$s sedang berjalan" + "Nonaktif, periksa aplikasi" + "Error, mencoba lagi..." + "Tidak ditemukan" +diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml +index 01905542684d..685c2ebc48be 100644 +--- a/packages/SystemUI/res/values-is/strings.xml ++++ b/packages/SystemUI/res/values-is/strings.xml +@@ -1093,6 +1093,7 @@ + "Opna %1$s" + "Spila %1$s með %2$s í %3$s" + "Spila %1$s í %2$s" ++ "%1$s er í gangi" + "Óvirkt, athugaðu forrit" + "Villa, reynir aftur…" + "Fannst ekki" +diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml +index 0efab5ceb84e..0c654ef86fea 100644 +--- a/packages/SystemUI/res/values-it/strings.xml ++++ b/packages/SystemUI/res/values-it/strings.xml +@@ -1093,6 +1093,7 @@ + "Apri %1$s" + "Riproduci %1$s di %2$s da %3$s" + "Riproduci %1$s da %2$s" ++ "%1$s è in esecuzione" + "Inattivo, controlla l\'app" + "Errore. Nuovo tentativo…" + "Controllo non trovato" +diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml +index 1e4c9d66ed9c..da6871eb7fc2 100644 +--- a/packages/SystemUI/res/values-iw/strings.xml ++++ b/packages/SystemUI/res/values-iw/strings.xml +@@ -1105,6 +1105,7 @@ + "פתיחה של %1$s" + "הפעלת %1$s של %2$s מ-%3$s" + "הפעלת %1$s מ-%2$s" ++ "אפליקציית %1$s פועלת" + "לא פעיל, יש לבדוק את האפליקציה" + "שגיאה, מתבצע ניסיון חוזר…" + "לא נמצא" +diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml +index 27259791f664..e6f7f03cfb47 100644 +--- a/packages/SystemUI/res/values-ja/strings.xml ++++ b/packages/SystemUI/res/values-ja/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s を開く" + "%1$s(アーティスト名: %2$s)を %3$s で再生" + "%1$s%2$s で再生" ++ "%1$s を実行しています" + "無効: アプリをご確認ください" + "エラー。再試行しています…" + "見つかりませんでした" +diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml +index 21e1c52ae136..8b8a4bbab1bf 100644 +--- a/packages/SystemUI/res/values-ka/strings.xml ++++ b/packages/SystemUI/res/values-ka/strings.xml +@@ -1093,6 +1093,7 @@ + "გახსენით %1$s" + "დაუკარით %1$s, %2$s, %3$s-დან" + "დაუკარით %1$s %2$s-დან" ++ "%1$s გაშვებულია" + "არააქტიურია, გადაამოწმეთ აპი" + "შეცდომა, ხელახალი მცდელობა…" + "ვერ მოიძებნა" +diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml +index 6a9a9b5d8d11..419a0f3b42aa 100644 +--- a/packages/SystemUI/res/values-kk/strings.xml ++++ b/packages/SystemUI/res/values-kk/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s қолданбасын ашу" + "%3$s қолданбасында %2$s орындайтын \"%1$s\" әнін ойнату" + "%2$s қолданбасында \"%1$s\" әнін ойнату" ++ "%1$s қосулы тұр" + "Өшірулі. Қолданба тексеріңіз." + "Қате, әрекет қайталануда…" + "Табылмады" +diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml +index 080ba1958e24..8578576f09a8 100644 +--- a/packages/SystemUI/res/values-km/strings.xml ++++ b/packages/SystemUI/res/values-km/strings.xml +@@ -1093,6 +1093,7 @@ + "បើក %1$s" + "ចាក់ %1$s ច្រៀងដោយ %2$s ពី %3$s" + "ចាក់ %1$s ពី %2$s" ++ "%1$s កំពុង​ដំណើរការ" + "អសកម្ម ពិនិត្យមើល​កម្មវិធី" + "បញ្ហា កំពុងព្យាយាម​ម្ដងទៀត…" + "រកមិន​ឃើញទេ" +diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml +index f63d02f6682a..1cac8e9e44b3 100644 +--- a/packages/SystemUI/res/values-kn/strings.xml ++++ b/packages/SystemUI/res/values-kn/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s ಅನ್ನು ತೆರೆಯಿರಿ" + "%2$s ಅವರ %1$s ಹಾಡನ್ನು %3$s ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಿ" + "%1$s ಹಾಡನ್ನು %2$s ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಿ" ++ "%1$s ರನ್ ಆಗುತ್ತಿದೆ" + "ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ" + "ದೋಷ, ಮರುಪ್ರಯತ್ನಿಸಲಾಗುತ್ತಿದೆ…" + "ಕಂಡುಬಂದಿಲ್ಲ" +diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml +index 371b7de67806..0fd399fee086 100644 +--- a/packages/SystemUI/res/values-ko/strings.xml ++++ b/packages/SystemUI/res/values-ko/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s 열기" + "%3$s에서 %2$s%1$s 재생" + "%2$s에서 %1$s 재생" ++ "%1$s 실행 중" + "비활성. 앱을 확인하세요." + "오류 발생, 다시 시도 중…" + "찾을 수 없음" +diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml +index 404b9ac45179..d409be7865f5 100644 +--- a/packages/SystemUI/res/values-ky/strings.xml ++++ b/packages/SystemUI/res/values-ky/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s колдонмосун ачуу" + "%1$s ырын (аткаруучу: %2$s) %3$s колдонмосунан ойнотуу" + "%1$s ырын %2$s колдонмосунан ойнотуу" ++ "%1$s иштеп жатат" + "Жигерсиз. Колдонмону текшериңиз" + "Ката, дагы аракет жасалууда…" + "Табылган жок" +diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml +index 33fddef3efb3..4430b9d3148c 100644 +--- a/packages/SystemUI/res/values-lo/strings.xml ++++ b/packages/SystemUI/res/values-lo/strings.xml +@@ -1093,6 +1093,7 @@ + "ເປີດ %1$s" + "ຫຼິ້ນ %1$s ໂດຍ %2$s ຈາກ %3$s" + "ຫຼິ້ນ %1$s ຈາກ %2$s" ++ "%1$s ກຳລັງເຮັດວຽກຢູ່" + "ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ" + "ຜິດພາດ, ກໍາລັງ​ລອງ​ໃໝ່…" + "ບໍ່ພົບ" +diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml +index 94faaf42d1b9..890345fc6eef 100644 +--- a/packages/SystemUI/res/values-lt/strings.xml ++++ b/packages/SystemUI/res/values-lt/strings.xml +@@ -1105,6 +1105,7 @@ + "Atidaryti „%1$s“" + "Leisti %2$s – „%1$s“ iš „%3$s“" + "Leisti „%1$s“ iš „%2$s“" ++ "„%1$s“ vykdoma" + "Neaktyvu, patikrinkite progr." + "Klaida, bandoma iš naujo…" + "Nerasta" +diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml +index 0d14405ea4fb..925971c08e6d 100644 +--- a/packages/SystemUI/res/values-lv/strings.xml ++++ b/packages/SystemUI/res/values-lv/strings.xml +@@ -1099,6 +1099,7 @@ + "Atveriet lietotni %1$s." + "Atskaņojiet failu “%1$s” (izpildītājs: %2$s) no lietotnes %3$s." + "Atskaņojiet failu “%1$s” no lietotnes %2$s." ++ "Lietotne %1$s darbojas" + "Neaktīva, pārbaudiet lietotni" + "Radās kļūda. Mēģina vēlreiz…" + "Netika atrasta" +diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml +index 5fda8b211ab1..28b756013c79 100644 +--- a/packages/SystemUI/res/values-mk/strings.xml ++++ b/packages/SystemUI/res/values-mk/strings.xml +@@ -1093,6 +1093,7 @@ + "Отворете %1$s" + "Пуштете %1$s од %2$s на %3$s" + "Пуштете %1$s на %2$s" ++ "%1$s работи" + "Неактивна, провери апликација" + "Грешка, повторен обид…" + "Не е најдено" +diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml +index 6956934d7af7..d580140f8f62 100644 +--- a/packages/SystemUI/res/values-ml/strings.xml ++++ b/packages/SystemUI/res/values-ml/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s തുറക്കുക" + "%2$s എന്ന ആർട്ടിസ്റ്റിന്റെ %1$s എന്ന ഗാനം %3$s ആപ്പിൽ പ്ലേ ചെയ്യുക" + "%1$s എന്ന ഗാനം %2$s ആപ്പിൽ പ്ലേ ചെയ്യുക" ++ "%1$s റൺ ചെയ്യുന്നു" + "നിഷ്‌ക്രിയം, ആപ്പ് പരിശോധിക്കൂ" + "പിശക്, വീണ്ടും ശ്രമിക്കുന്നു…" + "കണ്ടെത്തിയില്ല" +diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml +index 0d1ad4bebce6..9df11d04f7c1 100644 +--- a/packages/SystemUI/res/values-mn/strings.xml ++++ b/packages/SystemUI/res/values-mn/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s-г нээх" + "%2$s%1$s%3$s дээр тоглуулах" + "%1$s%2$s дээр тоглуулах" ++ "%1$s ажиллаж байна" + "Идэвхгүй байна, аппыг шалгана уу" + "Алдаа, дахин оролдож байна…" + "Олдсонгүй" +diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml +index 1202a7467a2c..245188ddbc1f 100644 +--- a/packages/SystemUI/res/values-mr/strings.xml ++++ b/packages/SystemUI/res/values-mr/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s उघडा" + "%3$s मध्ये %2$s चे %1$s प्ले करा" + "%2$s मध्ये %1$s प्ले करा" ++ "%1$s रन होत आहे" + "निष्क्रिय, ॲप तपासा" + "एरर, पुन्हा प्रयत्न करत आहे…" + "आढळले नाही" +diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml +index b7d0246c4095..6ff31bcee322 100644 +--- a/packages/SystemUI/res/values-ms/strings.xml ++++ b/packages/SystemUI/res/values-ms/strings.xml +@@ -1093,6 +1093,7 @@ + "Buka %1$s" + "Mainkan %1$s oleh %2$s daripada %3$s" + "Mainkan %1$s daripada %2$s" ++ "%1$s sedang dijalankan" + "Tidak aktif, semak apl" + "Ralat, mencuba semula…" + "Tidak ditemukan" +diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml +index 81d168b79065..c46811fbdede 100644 +--- a/packages/SystemUI/res/values-my/strings.xml ++++ b/packages/SystemUI/res/values-my/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s ကို ဖွင့်ပါ" + "%2$s%1$s ကို %3$s တွင် ဖွင့်ပါ" + "%1$s ကို %2$s တွင် ဖွင့်ပါ" ++ "%1$s ပွင့်နေပါသည်" + "ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ" + "မှားသွားသည်၊ ပြန်စမ်းနေသည်…" + "မတွေ့ပါ" +diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml +index 360c58b9e2dc..6d4a6dc5da1e 100644 +--- a/packages/SystemUI/res/values-nb/strings.xml ++++ b/packages/SystemUI/res/values-nb/strings.xml +@@ -1093,6 +1093,7 @@ + "Åpne %1$s" + "Spill av %1$s av %2$s fra %3$s" + "Spill av %1$s fra %2$s" ++ "%1$s kjører" + "Inaktiv. Sjekk appen" + "Feil. Prøver igjen …" + "Ikke funnet" +diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml +index e5787b578430..f88951a2c081 100644 +--- a/packages/SystemUI/res/values-ne/strings.xml ++++ b/packages/SystemUI/res/values-ne/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s खोल्नुहोस्" + "%2$s को %1$s बोलको गीत %3$s मा बजाउनुहोस्" + "%1$s बोलको गीत %2$s मा बजाउनुहोस्" ++ "%1$s चलिरहेको छ" + "निष्क्रिय छ, एप जाँच गर्नु…" + "त्रुटि भयो, फेरि प्रयास गर्दै…" + "फेला परेन" +diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml +index 7d75b6e20a1e..e505203774b0 100644 +--- a/packages/SystemUI/res/values-nl/strings.xml ++++ b/packages/SystemUI/res/values-nl/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s openen" + "%1$s van %2$s afspelen via %3$s" + "%1$s afspelen via %2$s" ++ "%1$s is actief" + "Inactief, check de app" + "Fout. Opnieuw proberen…" + "Niet gevonden" +diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml +index ee524bf2e3c8..120eb17de984 100644 +--- a/packages/SystemUI/res/values-or/strings.xml ++++ b/packages/SystemUI/res/values-or/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s ଖୋଲନ୍ତୁ" + "%3$sରୁ %2$sଙ୍କ %1$s ଚଲାନ୍ତୁ" + "%2$sରୁ %1$s ଚଲାନ୍ତୁ" ++ "%1$s ଚାଲୁଛି" + "ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ" + "ତ୍ରୁଟି, ପୁଣି ଚେଷ୍ଟା କରୁଛି…" + "ମିଳିଲା ନାହିଁ" +diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml +index d68ab4fe347a..c5dfe0fe80ac 100644 +--- a/packages/SystemUI/res/values-pa/strings.xml ++++ b/packages/SystemUI/res/values-pa/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s ਖੋਲ੍ਹੋ" + "%3$s ਤੋਂ %2$s ਦਾ %1$s ਚਲਾਓ" + "%2$s ਤੋਂ %1$s ਚਲਾਓ" ++ "%1$s ਚੱਲ ਰਿਹਾ ਹੈ" + "ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ" + "ਗੜਬੜ, ਮੁੜ ਕੋਸ਼ਿਸ਼ ਹੋ ਰਹੀ ਹੈ…" + "ਨਹੀਂ ਮਿਲਿਆ" +diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml +index 9aade18169ad..33491b104962 100644 +--- a/packages/SystemUI/res/values-pl/strings.xml ++++ b/packages/SystemUI/res/values-pl/strings.xml +@@ -1105,6 +1105,7 @@ + "Otwórz aplikację %1$s" + "Odtwórz utwór %1$s (%2$s) w aplikacji %3$s" + "Odtwórz utwór %1$s w aplikacji %2$s" ++ "Aplikacja %1$s jest uruchomiona" + "Nieaktywny, sprawdź aplikację" + "Błąd, próbuję jeszcze raz…" + "Nie znaleziono" +diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml +index cab482ae56fd..163e89c054c1 100644 +--- a/packages/SystemUI/res/values-pt-rBR/strings.xml ++++ b/packages/SystemUI/res/values-pt-rBR/strings.xml +@@ -1093,6 +1093,7 @@ + "Abrir %1$s" + "Tocar %1$s de %2$s no app %3$s" + "Tocar %1$s no app %2$s" ++ "%1$s está em execução" + "Inativo, verifique o app" + "Erro. Tentando novamente…" + "Não encontrado" +diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml +index eec34684ff4a..b7be97060ca8 100644 +--- a/packages/SystemUI/res/values-pt-rPT/strings.xml ++++ b/packages/SystemUI/res/values-pt-rPT/strings.xml +@@ -1093,6 +1093,7 @@ + "Abrir %1$s" + "Reproduzir %1$s de %2$s a partir da app %3$s" + "Reproduzir %1$s a partir da app %2$s" ++ "%1$s em execução" + "Inativa. Consulte a app." + "Erro. A tentar novamente…" + "Não encontrado." +diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml +index cab482ae56fd..163e89c054c1 100644 +--- a/packages/SystemUI/res/values-pt/strings.xml ++++ b/packages/SystemUI/res/values-pt/strings.xml +@@ -1093,6 +1093,7 @@ + "Abrir %1$s" + "Tocar %1$s de %2$s no app %3$s" + "Tocar %1$s no app %2$s" ++ "%1$s está em execução" + "Inativo, verifique o app" + "Erro. Tentando novamente…" + "Não encontrado" +diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml +index 1e30ea713210..7e590bf62701 100644 +--- a/packages/SystemUI/res/values-ro/strings.xml ++++ b/packages/SystemUI/res/values-ro/strings.xml +@@ -1099,6 +1099,7 @@ + "Deschideți %1$s" + "Redați %1$s de la %2$s în %3$s" + "Redați %1$s în %2$s" ++ "%1$s rulează" + "Inactiv, verificați aplicația" + "Eroare, se încearcă din nou…" + "Nu s-a găsit" +diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml +index 99465d54e124..a7edb9d208b3 100644 +--- a/packages/SystemUI/res/values-ru/strings.xml ++++ b/packages/SystemUI/res/values-ru/strings.xml +@@ -1105,6 +1105,7 @@ + "Открыть приложение \"%1$s\"" + "Воспроизвести медиафайл \"%1$s\" (исполнитель: %2$s) из приложения \"%3$s\"" + "Воспроизвести медиафайл \"%1$s\" из приложения \"%2$s\"" ++ "Приложение \"%1$s\" запущено" + "Нет ответа. Проверьте приложение." + "Ошибка. Повторная попытка…" + "Не найдено." +diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml +index 6ea2a0dd5d7a..6e07a3497ce1 100644 +--- a/packages/SystemUI/res/values-si/strings.xml ++++ b/packages/SystemUI/res/values-si/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s විවෘත කරන්න" + "%2$sගේ %1$s %3$s වෙතින් වාදනය කරන්න" + "%1$s %2$s වෙතින් වාදනය කරන්න" ++ "%1$s ධාවනය වේ" + "අක්‍රියයි, යෙදුම පරීක්ෂා කරන්න" + "දෝෂයකි, නැවත උත්සාහ කරමින්…" + "හමු නොවිණි" +diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml +index 399b9797d21f..36975996ddc4 100644 +--- a/packages/SystemUI/res/values-sk/strings.xml ++++ b/packages/SystemUI/res/values-sk/strings.xml +@@ -1105,6 +1105,7 @@ + "Otvoriť %1$s" + "Prehrať skladbu %1$s od interpreta %2$s z aplikácie %3$s" + "Prehrať skladbu %1$s z aplikácie %2$s" ++ "Aplikácia %1$s je spustená" + "Neaktívne, preverte aplikáciu" + "Chyba, skúša sa znova…" + "Nenájdené" +diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml +index 0c93bced9f41..6f58aa842d59 100644 +--- a/packages/SystemUI/res/values-sl/strings.xml ++++ b/packages/SystemUI/res/values-sl/strings.xml +@@ -1105,6 +1105,7 @@ + "Odpri aplikacijo %1$s." + "Predvajaj skladbo %1$s izvajalca %2$s iz aplikacije %3$s." + "Predvajaj skladbo %1$s iz aplikacije %2$s." ++ "%1$s se izvaja" + "Neaktivno, poglejte aplikacijo" + "Napaka, vnovični poskus …" + "Ni mogoče najti" +diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml +index 7f101dbd3f57..4c1072500419 100644 +--- a/packages/SystemUI/res/values-sq/strings.xml ++++ b/packages/SystemUI/res/values-sq/strings.xml +@@ -1093,6 +1093,7 @@ + "Hap %1$s" + "Luaj %1$s nga %2$s nga %3$s" + "Luaj %1$s nga %2$s" ++ "%1$s po ekzekutohet" + "Joaktive, kontrollo aplikacionin" + "Gabim, po provohet përsëri" + "Nuk u gjet" +diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml +index 1da42cfb2d3d..5033d05ff932 100644 +--- a/packages/SystemUI/res/values-sr/strings.xml ++++ b/packages/SystemUI/res/values-sr/strings.xml +@@ -1099,6 +1099,7 @@ + "Отворите %1$s" + "Пустите %1$s извођача %2$s из апликације %3$s" + "Пустите %1$s из апликације %2$s" ++ "Апликација %1$s је покренута" + "Неактивно. Видите апликацију" + "Грешка, покушава се поново…" + "Није пронађено" +diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml +index 05aeffbc300d..96483fdb13a1 100644 +--- a/packages/SystemUI/res/values-sv/strings.xml ++++ b/packages/SystemUI/res/values-sv/strings.xml +@@ -1093,6 +1093,7 @@ + "Öppna %1$s" + "Spela upp %1$s med %2$s från %3$s" + "Spela upp %1$s från %2$s" ++ "%1$s körs" + "Inaktiv, kolla appen" + "Fel, försöker igen …" + "Hittades inte" +diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml +index 7f51e82683b7..3cd36cf11e60 100644 +--- a/packages/SystemUI/res/values-sw/strings.xml ++++ b/packages/SystemUI/res/values-sw/strings.xml +@@ -1093,6 +1093,7 @@ + "Fungua %1$s" + "Cheza %1$s ulioimbwa na %2$s katika %3$s" + "Cheza %1$s katika %2$s" ++ "%1$s inatumika" + "Haitumiki, angalia programu" + "Hitilafu, inajaribu tena…" + "Hakipatikani" +diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml +index b51fb9efbbee..8fb1a2aab36a 100644 +--- a/packages/SystemUI/res/values-ta/strings.xml ++++ b/packages/SystemUI/res/values-ta/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s ஆப்ஸைத் திறங்கள்" + "%2$s இன் %1$s பாடலை %3$s ஆப்ஸில் பிளேசெய்" + "%1$s பாடலை %2$s ஆப்ஸில் பிளேசெய்" ++ "%1$s இயங்கிக் கொண்டிருக்கிறது" + "செயலில் இல்லை , சரிபார்க்கவும்" + "பிழை, மீண்டும் முயல்கிறது…" + "இல்லை" +diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml +index 45236a795573..a48dc6b0245d 100644 +--- a/packages/SystemUI/res/values-te/strings.xml ++++ b/packages/SystemUI/res/values-te/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$sను తెరవండి" + "%3$s నుండి %2$s పాడిన %1$s‌ను ప్లే చేయండి" + "%2$s నుండి %1$s‌ను ప్లే చేయండి" ++ "%1$s రన్ అవుతోంది" + "ఇన్‌యాక్టివ్, యాప్ చెక్ చేయండి" + "లోపం, మళ్లీ ప్రయత్నిస్తోంది..." + "కనుగొనబడలేదు" +diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml +index 1fd1313719dc..c840566aa3fc 100644 +--- a/packages/SystemUI/res/values-th/strings.xml ++++ b/packages/SystemUI/res/values-th/strings.xml +@@ -1093,6 +1093,7 @@ + "เปิด %1$s" + "เปิดเพลง %1$s ของ %2$s จาก %3$s" + "เปิดเพลง %1$s จาก %2$s" ++ "%1$s กำลังทำงาน" + "ไม่มีการใช้งาน โปรดตรวจสอบแอป" + "มีข้อผิดพลาด กำลังลองอีกครั้ง…" + "ไม่พบ" +diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml +index 3837364887cf..e40abfebe217 100644 +--- a/packages/SystemUI/res/values-tl/strings.xml ++++ b/packages/SystemUI/res/values-tl/strings.xml +@@ -1093,6 +1093,7 @@ + "Buksan ang %1$s" + "I-play ang %1$s ni/ng %2$s mula sa %3$s" + "I-play ang %1$s mula sa %2$s" ++ "Tumatakbo ang %1$s" + "Hindi aktibo, tingnan ang app" + "Nagka-error, sinusubukan ulit…" + "Hindi nahanap" +diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml +index 1cd547ca7793..891fc9072e23 100644 +--- a/packages/SystemUI/res/values-tr/strings.xml ++++ b/packages/SystemUI/res/values-tr/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s uygulamasını aç" + "%3$s uygulamasından %2$s, %1$s şarkısını çal" + "%2$s uygulamasından %1$s şarkısını çal" ++ "%1$s çalışıyor" + "Devre dışı, uygulamaya bakın" + "Hata, yeniden deneniyor…" + "Bulunamadı" +diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml +index 70922aa77db3..4362e3fb2d3e 100644 +--- a/packages/SystemUI/res/values-uk/strings.xml ++++ b/packages/SystemUI/res/values-uk/strings.xml +@@ -1105,6 +1105,7 @@ + "Відкрити додаток %1$s" + "Увімкнути пісню \"%1$s\", яку виконує %2$s, у додатку %3$s" + "Увімкнути пісню \"%1$s\" у додатку %2$s" ++ "%1$s працює" + "Неактивно, перейдіть у додаток" + "Помилка. Повторна спроба…" + "Не знайдено" +diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml +index 7ef014923960..3ce7e9aea182 100644 +--- a/packages/SystemUI/res/values-ur/strings.xml ++++ b/packages/SystemUI/res/values-ur/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s کھولیں" + "%3$s سے %2$s کا %1$s چلائیں" + "%2$s سے %1$s چلائیں" ++ "%1$s چل رہی ہے" + "غیر فعال، ایپ چیک کریں" + "خرابی، دوبارہ کوشش کی جا رہی ہے…" + "نہیں ملا" +diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml +index 08ac980d3bee..85ff44736a26 100644 +--- a/packages/SystemUI/res/values-uz/strings.xml ++++ b/packages/SystemUI/res/values-uz/strings.xml +@@ -1093,6 +1093,7 @@ + "%1$s ilovasini ochish" + "%3$s ilovasida ijro etish: %1$s%2$s" + "%2$s ilovasida ijro etilmoqda: %1$s" ++ "%1$s ishlamoqda" + "Nofaol. Ilovani tekshiring" + "Xato, qayta urinilmoqda…" + "Topilmadi" +diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml +index 60b1232cd8a3..fd2fa681a135 100644 +--- a/packages/SystemUI/res/values-vi/strings.xml ++++ b/packages/SystemUI/res/values-vi/strings.xml +@@ -1093,6 +1093,7 @@ + "Mở %1$s" + "Phát %1$s của %2$s trên %3$s" + "Phát %1$s trên %2$s" ++ "%1$s đang chạy" + "Không hoạt động, hãy kiểm tra ứng dụng" + "Lỗi, đang thử lại…" + "Không tìm thấy" +diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml +index 357e59e7ece5..a73fc5e84200 100644 +--- a/packages/SystemUI/res/values-zh-rCN/strings.xml ++++ b/packages/SystemUI/res/values-zh-rCN/strings.xml +@@ -1093,6 +1093,7 @@ + "打开%1$s" + "通过%3$s播放%2$s的《%1$s》" + "通过%2$s播放《%1$s》" ++ "“%1$s”正在运行" + "无效,请检查应用" + "出现错误,正在重试…" + "未找到" +diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml +index f8ede3a55b88..6441c6d938e9 100644 +--- a/packages/SystemUI/res/values-zh-rHK/strings.xml ++++ b/packages/SystemUI/res/values-zh-rHK/strings.xml +@@ -1093,6 +1093,7 @@ + "開啟 %1$s" + "在 %3$s 播放 %2$s 的《%1$s》" + "在 %2$s 播放《%1$s》" ++ "「%1$s」執行中" + "已停用,請檢查應用程式" + "發生錯誤,正在重試…" + "找不到" +diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml +index df84fb0699c9..7aa04fca275f 100644 +--- a/packages/SystemUI/res/values-zh-rTW/strings.xml ++++ b/packages/SystemUI/res/values-zh-rTW/strings.xml +@@ -1093,6 +1093,7 @@ + "開啟「%1$s」" + "透過「%3$s」播放%2$s的〈%1$s〉" + "透過「%2$s」播放〈%1$s〉" ++ "「%1$s」執行中" + "無效,請查看應用程式" + "發生錯誤,正在重試…" + "找不到控制項" +diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml +index fe97daa7682e..fa696d145c90 100644 +--- a/packages/SystemUI/res/values-zu/strings.xml ++++ b/packages/SystemUI/res/values-zu/strings.xml +@@ -1093,6 +1093,7 @@ + "Vula i-%1$s" + "Dlala i-%1$s ka-%2$s kusuka ku-%3$s" + "Dlala i-%1$s kusuka ku-%2$s" ++ "I-%1$s iyasebenza" + "Akusebenzi, hlola uhlelo lokusebenza" + "Iphutha, iyazama futhi…" + "Ayitholakali" +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0193-DO-NOT-MERGE-Revert-Verify-URI-permissions-for-EXTRA_REMOTE_INP.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0193-DO-NOT-MERGE-Revert-Verify-URI-permissions-for-EXTRA_REMOTE_INP.bulletin.patch new file mode 100644 index 0000000000..00b967918d --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0193-DO-NOT-MERGE-Revert-Verify-URI-permissions-for-EXTRA_REMOTE_INP.bulletin.patch @@ -0,0 +1,88 @@ +From fc5ead8698ac886b4e3e118e02c9c659efab0ed3 Mon Sep 17 00:00:00 2001 +From: Ioana Alexandru +Date: Mon, 3 Jul 2023 16:29:47 +0000 +Subject: [PATCH] DO NOT MERGE Revert "Verify URI permissions for + EXTRA_REMOTE_INPUT_HISTORY_ITEMS." + +This reverts commit 43b1711332763788c7abf05c3baa931296c45bbb. + +Reason for revert: regression reported at b/289223315 + +Bug: 289223315 +Bug: 276729064 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:28428b737903c9b82d7ce3682336d15d8ad00762) +Merged-In: I101938fbc51592537023345ba1e642827510981b +Change-Id: I101938fbc51592537023345ba1e642827510981b +--- + core/java/android/app/Notification.java | 11 ----------- + .../notification/NotificationManagerServiceTest.java | 11 ----------- + 2 files changed, 22 deletions(-) + +diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java +index 1333a3590b55..1a8a84e0f182 100644 +--- a/core/java/android/app/Notification.java ++++ b/core/java/android/app/Notification.java +@@ -2803,17 +2803,6 @@ public class Notification implements Parcelable + if (person != null) { + visitor.accept(person.getIconUri()); + } +- +- final RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[]) +- extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS); +- if (history != null) { +- for (int i = 0; i < history.length; i++) { +- RemoteInputHistoryItem item = history[i]; +- if (item.getUri() != null) { +- visitor.accept(item.getUri()); +- } +- } +- } + } + + if (isStyle(MessagingStyle.class) && extras != null) { +diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +index a989c3f0eee0..a3c8cfabd3c5 100755 +--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java ++++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +@@ -116,7 +116,6 @@ import android.app.NotificationManager; + import android.app.PendingIntent; + import android.app.Person; + import android.app.RemoteInput; +-import android.app.RemoteInputHistoryItem; + import android.app.StatsManager; + import android.app.admin.DevicePolicyManagerInternal; + import android.app.usage.UsageStatsManagerInternal; +@@ -4336,12 +4335,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + .setName("People List Person 2") + .setIcon(personIcon3) + .build(); +- final Uri historyUri1 = Uri.parse("content://com.example/history1"); +- final Uri historyUri2 = Uri.parse("content://com.example/history2"); +- final RemoteInputHistoryItem historyItem1 = new RemoteInputHistoryItem(null, historyUri1, +- "a"); +- final RemoteInputHistoryItem historyItem2 = new RemoteInputHistoryItem(null, historyUri2, +- "b"); + + Bundle extras = new Bundle(); + extras.putParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents); +@@ -4349,8 +4342,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + extras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person1); + extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, + new ArrayList<>(Arrays.asList(person2, person3))); +- extras.putParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS, +- new RemoteInputHistoryItem[]{historyItem1, historyItem2}); + + Notification n = new Notification.Builder(mContext, "a") + .setContentTitle("notification with uris") +@@ -4368,8 +4359,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + verify(visitor, times(1)).accept(eq(personIcon1.getUri())); + verify(visitor, times(1)).accept(eq(personIcon2.getUri())); + verify(visitor, times(1)).accept(eq(personIcon3.getUri())); +- verify(visitor, times(1)).accept(eq(historyUri1)); +- verify(visitor, times(1)).accept(eq(historyUri2)); + } + + @Test +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0194-Verify-URI-permissions-for-EXTRA_REMOTE_INPUT_HISTORY_ITEMS-.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0194-Verify-URI-permissions-for-EXTRA_REMOTE_INPUT_HISTORY_ITEMS-.bulletin.patch new file mode 100644 index 0000000000..cfef18f968 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0194-Verify-URI-permissions-for-EXTRA_REMOTE_INPUT_HISTORY_ITEMS-.bulletin.patch @@ -0,0 +1,101 @@ +From 1a47e38d0ec1ea7c4e70a07e78924e3c8ecfb60f Mon Sep 17 00:00:00 2001 +From: Ioana Alexandru +Date: Mon, 8 May 2023 18:39:35 +0000 +Subject: [PATCH] Verify URI permissions for EXTRA_REMOTE_INPUT_HISTORY_ITEMS. + +Also added a step to serialize & deserialize the notification in the +test, to prevent exceptions about not being able to cast e.g. +Parcelable[] to RemoteInputHistoryItem[]. + +Test: atest NotificationManagerServiceTest & tested with POC from bug +Bug: 276729064 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:88e597d2b31d054ab5286b3a666accb08a8db5d5) +Merged-In: I7053ca59f9c7f1df5226418594109cfb8b609b1e +Change-Id: I7053ca59f9c7f1df5226418594109cfb8b609b1e +--- + core/java/android/app/Notification.java | 11 +++++++++++ + .../NotificationManagerServiceTest.java | 18 ++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java +index 1a8a84e0f182..f77d81fb8e7d 100644 +--- a/core/java/android/app/Notification.java ++++ b/core/java/android/app/Notification.java +@@ -2803,6 +2803,17 @@ public class Notification implements Parcelable + if (person != null) { + visitor.accept(person.getIconUri()); + } ++ ++ final RemoteInputHistoryItem[] history = getParcelableArrayFromBundle(extras, ++ Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS, RemoteInputHistoryItem.class); ++ if (history != null) { ++ for (int i = 0; i < history.length; i++) { ++ RemoteInputHistoryItem item = history[i]; ++ if (item.getUri() != null) { ++ visitor.accept(item.getUri()); ++ } ++ } ++ } + } + + if (isStyle(MessagingStyle.class) && extras != null) { +diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +index 2dff80ece44a..9ca0f557ba1d 100755 +--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java ++++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +@@ -117,6 +117,7 @@ import android.app.NotificationManager; + import android.app.PendingIntent; + import android.app.Person; + import android.app.RemoteInput; ++import android.app.RemoteInputHistoryItem; + import android.app.StatsManager; + import android.app.admin.DevicePolicyManagerInternal; + import android.app.usage.UsageStatsManagerInternal; +@@ -4360,6 +4361,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + .setName("People List Person 2") + .setIcon(personIcon3) + .build(); ++ final Uri historyUri1 = Uri.parse("content://com.example/history1"); ++ final Uri historyUri2 = Uri.parse("content://com.example/history2"); ++ final RemoteInputHistoryItem historyItem1 = new RemoteInputHistoryItem(null, historyUri1, ++ "a"); ++ final RemoteInputHistoryItem historyItem2 = new RemoteInputHistoryItem(null, historyUri2, ++ "b"); + + Bundle extras = new Bundle(); + extras.putParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents); +@@ -4367,6 +4374,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + extras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person1); + extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, + new ArrayList<>(Arrays.asList(person2, person3))); ++ extras.putParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS, ++ new RemoteInputHistoryItem[]{historyItem1, historyItem2}); + + Notification n = new Notification.Builder(mContext, "a") + .setContentTitle("notification with uris") +@@ -4375,6 +4384,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + .addExtras(extras) + .build(); + ++ // Serialize and deserialize the notification to make sure nothing breaks in the process, ++ // since that's what will usually happen before we get to call visitUris. ++ Parcel parcel = Parcel.obtain(); ++ n.writeToParcel(parcel, 0); ++ parcel.setDataPosition(0); ++ n = new Notification(parcel); ++ + Consumer visitor = (Consumer) spy(Consumer.class); + n.visitUris(visitor); + verify(visitor, times(1)).accept(eq(audioContents)); +@@ -4384,6 +4400,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { + verify(visitor, times(1)).accept(eq(personIcon1.getUri())); + verify(visitor, times(1)).accept(eq(personIcon2.getUri())); + verify(visitor, times(1)).accept(eq(personIcon3.getUri())); ++ verify(visitor, times(1)).accept(eq(historyUri1)); ++ verify(visitor, times(1)).accept(eq(historyUri2)); + } + + @Test +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0195-Do-not-share-key-mappings-with-JNI-object.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0195-Do-not-share-key-mappings-with-JNI-object.bulletin.patch new file mode 100644 index 0000000000..e9139e8e23 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0195-Do-not-share-key-mappings-with-JNI-object.bulletin.patch @@ -0,0 +1,50 @@ +From a20a075547f7914dbf894656f9eb999153b33c64 Mon Sep 17 00:00:00 2001 +From: Josep del Rio +Date: Mon, 26 Jun 2023 09:30:06 +0000 +Subject: [PATCH] Do not share key mappings with JNI object + +The key mapping information between the native key mappings and +the KeyCharacterMap object available in Java is currently shared, +which means that a read can be attempted while it's being modified. + +Bug: 274058082 +Test: Patch tested by Oppo +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3d993de0d1ada8065d1fe561f690c8f82b6a7d4b) +Merged-In: I745008a0a8ea30830660c45dcebee917b3913d13 +Change-Id: I745008a0a8ea30830660c45dcebee917b3913d13 +--- + core/jni/android_view_InputDevice.cpp | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp +index 9cc72437a023..f7c770e0bffb 100644 +--- a/core/jni/android_view_InputDevice.cpp ++++ b/core/jni/android_view_InputDevice.cpp +@@ -42,6 +42,13 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi + return NULL; + } + ++ // b/274058082: Pass a copy of the key character map to avoid concurrent ++ // access ++ std::shared_ptr map = deviceInfo.getKeyCharacterMap(); ++ if (map != nullptr) { ++ map = std::make_shared(*map); ++ } ++ + ScopedLocalRef descriptorObj(env, + env->NewStringUTF(deviceInfo.getIdentifier().descriptor.c_str())); + if (!descriptorObj.get()) { +@@ -49,8 +56,8 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi + } + + ScopedLocalRef kcmObj(env, +- android_view_KeyCharacterMap_create(env, deviceInfo.getId(), +- deviceInfo.getKeyCharacterMap())); ++ android_view_KeyCharacterMap_create(env, deviceInfo.getId(), ++ map)); + if (!kcmObj.get()) { + return NULL; + } +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0196-DO-NOT-MERGE-Verify-URI-Permissions-in-Autofill-RemoteViews.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0196-DO-NOT-MERGE-Verify-URI-Permissions-in-Autofill-RemoteViews.bulletin.patch new file mode 100644 index 0000000000..dc3b80362f --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0196-DO-NOT-MERGE-Verify-URI-Permissions-in-Autofill-RemoteViews.bulletin.patch @@ -0,0 +1,154 @@ +From 0909dc26a3c50a7a25fb12264363bfc92416db32 Mon Sep 17 00:00:00 2001 +From: Tim Yu +Date: Tue, 20 Jun 2023 21:24:36 +0000 +Subject: [PATCH] [DO NOT MERGE] Verify URI Permissions in Autofill RemoteViews + +Check permissions of URI inside of FillResponse's RemoteViews. If the +current user does not have the required permissions to view the URI, the +RemoteView is dropped from displaying. + +This fixes a security spill in which a user can view content of another +user through a malicious Autofill provider. + +Bug: 283137865 +Fixes: b/283264674 b/281666022 b/281665050 b/281848557 b/281533566 +b/281534749 b/283101289 +Test: Verified by POC app attached in bugs +Test: atest CtsAutoFillServiceTestCases (added new tests) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:73fa082a7202100da107ae14dd7742ecd86da053) +Merged-In: I6f4d2a35e89bbed7bd9e07bf5cd3e2d68b20af9a +Change-Id: I6f4d2a35e89bbed7bd9e07bf5cd3e2d68b20af9a +--- + .../com/android/server/autofill/Helper.java | 43 +++++++++++++++++++ + .../android/server/autofill/ui/FillUi.java | 11 +++-- + .../android/server/autofill/ui/SaveUi.java | 3 +- + 3 files changed, 52 insertions(+), 5 deletions(-) + +diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java +index bc5d6457c945..48113a81cca5 100644 +--- a/services/autofill/java/com/android/server/autofill/Helper.java ++++ b/services/autofill/java/com/android/server/autofill/Helper.java +@@ -18,6 +18,8 @@ package com.android.server.autofill; + + import android.annotation.NonNull; + import android.annotation.Nullable; ++import android.annotation.UserIdInt; ++import android.app.ActivityManager; + import android.app.assist.AssistStructure; + import android.app.assist.AssistStructure.ViewNode; + import android.app.assist.AssistStructure.WindowNode; +@@ -34,6 +36,7 @@ import android.view.View; + import android.view.WindowManager; + import android.view.autofill.AutofillId; + import android.view.autofill.AutofillValue; ++import android.widget.RemoteViews; + + import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + import com.android.internal.util.ArrayUtils; +@@ -42,6 +45,8 @@ import java.io.PrintWriter; + import java.util.ArrayDeque; + import java.util.ArrayList; + import java.util.Arrays; ++import java.util.concurrent.atomic.AtomicBoolean; ++ + + public final class Helper { + +@@ -75,6 +80,44 @@ public final class Helper { + throw new UnsupportedOperationException("contains static members only"); + } + ++ private static boolean checkRemoteViewUriPermissions( ++ @UserIdInt int userId, @NonNull RemoteViews rView) { ++ final AtomicBoolean permissionsOk = new AtomicBoolean(true); ++ ++ rView.visitUris(uri -> { ++ int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri); ++ boolean allowed = uriOwnerId == userId; ++ permissionsOk.set(allowed && permissionsOk.get()); ++ }); ++ ++ return permissionsOk.get(); ++ } ++ ++ /** ++ * Checks the URI permissions of the remote view, ++ * to see if the current userId is able to access it. ++ * ++ * Returns the RemoteView that is passed if user is able, null otherwise. ++ * ++ * TODO: instead of returning a null remoteview when ++ * the current userId cannot access an URI, ++ * return a new RemoteView with the URI removed. ++ */ ++ public static @Nullable RemoteViews sanitizeRemoteView(RemoteViews rView) { ++ if (rView == null) return null; ++ ++ int userId = ActivityManager.getCurrentUser(); ++ ++ boolean ok = checkRemoteViewUriPermissions(userId, rView); ++ if (!ok) { ++ Slog.w(TAG, ++ "sanitizeRemoteView() user: " + userId ++ + " tried accessing resource that does not belong to them"); ++ } ++ return (ok ? rView : null); ++ } ++ ++ + @Nullable + static AutofillId[] toArray(@Nullable ArraySet set) { + if (set == null) return null; +diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java +index 27ea3d618afa..af6e38b1d46c 100644 +--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java ++++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java +@@ -141,8 +141,9 @@ final class FillUi { + + final LayoutInflater inflater = LayoutInflater.from(mContext); + +- final RemoteViews headerPresentation = response.getHeader(); +- final RemoteViews footerPresentation = response.getFooter(); ++ final RemoteViews headerPresentation = Helper.sanitizeRemoteView(response.getHeader()); ++ final RemoteViews footerPresentation = Helper.sanitizeRemoteView(response.getFooter()); ++ + final ViewGroup decor; + if (mFullScreen) { + decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null); +@@ -220,6 +221,9 @@ final class FillUi { + ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker); + final View content; + try { ++ if (Helper.sanitizeRemoteView(response.getPresentation()) == null) { ++ throw new RuntimeException("Permission error accessing RemoteView"); ++ } + content = response.getPresentation().applyWithTheme( + mContext, decor, interceptionHandler, mThemeId); + container.addView(content); +@@ -299,7 +303,8 @@ final class FillUi { + final Dataset dataset = response.getDatasets().get(i); + final int index = dataset.getFieldIds().indexOf(focusedViewId); + if (index >= 0) { +- final RemoteViews presentation = dataset.getFieldPresentation(index); ++ final RemoteViews presentation = Helper.sanitizeRemoteView( ++ dataset.getFieldPresentation(index)); + if (presentation == null) { + Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because " + + "service didn't provide a presentation for it on " + dataset); +diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +index 826a98afe2f8..49df4a8b66ed 100644 +--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java ++++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +@@ -368,8 +368,7 @@ final class SaveUi { + return false; + } + writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION); +- +- final RemoteViews template = customDescription.getPresentation(); ++ final RemoteViews template = Helper.sanitizeRemoteView(customDescription.getPresentation()); + if (template == null) { + Slog.w(TAG, "No remote view on custom description"); + return false; +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0197-Disallow-loading-icon-from-content-URI-to-PipMenu.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0197-Disallow-loading-icon-from-content-URI-to-PipMenu.bulletin.patch new file mode 100644 index 0000000000..0c46ad6cd5 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0197-Disallow-loading-icon-from-content-URI-to-PipMenu.bulletin.patch @@ -0,0 +1,56 @@ +From cca6aca97c4baf8d05297a6e4856744ee7b16367 Mon Sep 17 00:00:00 2001 +From: Hongwei Wang +Date: Wed, 24 May 2023 20:19:43 -0700 +Subject: [PATCH] Disallow loading icon from content URI to PipMenu + +Bug: 278246904 +Test: manually, with the PoC app attached to the bug +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4bf71d74fc21cd9389dbe00fb750e2f9802eb789) +Merged-In: Idbd4081bf464e2b3420d4c3fd22ca37867d26bc0 +Change-Id: Idbd4081bf464e2b3420d4c3fd22ca37867d26bc0 +--- + .../wm/shell/pip/phone/PipMenuView.java | 21 ++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java +index 67b1e6dd4cc7..4cbaa348add4 100644 +--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java ++++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java +@@ -41,6 +41,7 @@ import android.content.Intent; + import android.graphics.Color; + import android.graphics.Rect; + import android.graphics.drawable.Drawable; ++import android.graphics.drawable.Icon; + import android.net.Uri; + import android.os.Bundle; + import android.os.Handler; +@@ -462,13 +463,19 @@ public class PipMenuView extends FrameLayout { + final PipMenuActionView actionView = + (PipMenuActionView) mActionsGroup.getChildAt(i); + +- // TODO: Check if the action drawable has changed before we reload it +- action.getIcon().loadDrawableAsync(mContext, d -> { +- if (d != null) { +- d.setTint(Color.WHITE); +- actionView.setImageDrawable(d); +- } +- }, mMainHandler); ++ final int iconType = action.getIcon().getType(); ++ if (iconType == Icon.TYPE_URI || iconType == Icon.TYPE_URI_ADAPTIVE_BITMAP) { ++ // Disallow loading icon from content URI ++ actionView.setImageDrawable(null); ++ } else { ++ // TODO: Check if the action drawable has changed before we reload it ++ action.getIcon().loadDrawableAsync(mContext, d -> { ++ if (d != null) { ++ d.setTint(Color.WHITE); ++ actionView.setImageDrawable(d); ++ } ++ }, mMainHandler); ++ } + actionView.setContentDescription(action.getContentDescription()); + if (action.isEnabled()) { + actionView.setOnClickListener(v -> { +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0198-Fixing-DatabaseUtils-to-detect-malformed-UTF-16-strings.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0198-Fixing-DatabaseUtils-to-detect-malformed-UTF-16-strings.bulletin.patch new file mode 100644 index 0000000000..9d1326b1ff --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0198-Fixing-DatabaseUtils-to-detect-malformed-UTF-16-strings.bulletin.patch @@ -0,0 +1,62 @@ +From 8bad7524a1527fb61e1615c9cee70c7e08f35590 Mon Sep 17 00:00:00 2001 +From: Kunal Malhotra +Date: Fri, 2 Jun 2023 23:32:02 +0000 +Subject: [PATCH] Fixing DatabaseUtils to detect malformed UTF-16 strings + +Test: tested with POC in bug, also using atest +Bug: 224771621 +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:fb4a72e3943d166088407e61aa4439ac349f3f12) +Merged-In: Ide65205b83063801971c5778af3154bcf3f0e530 +Change-Id: Ide65205b83063801971c5778af3154bcf3f0e530 +--- + core/java/android/database/DatabaseUtils.java | 32 +++++++++++++------ + 1 file changed, 23 insertions(+), 9 deletions(-) + +diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java +index 6c8a8500e4e3..d41df4f49d48 100644 +--- a/core/java/android/database/DatabaseUtils.java ++++ b/core/java/android/database/DatabaseUtils.java +@@ -511,17 +511,31 @@ public class DatabaseUtils { + */ + public static void appendEscapedSQLString(StringBuilder sb, String sqlString) { + sb.append('\''); +- if (sqlString.indexOf('\'') != -1) { +- int length = sqlString.length(); +- for (int i = 0; i < length; i++) { +- char c = sqlString.charAt(i); +- if (c == '\'') { +- sb.append('\''); ++ int length = sqlString.length(); ++ for (int i = 0; i < length; i++) { ++ char c = sqlString.charAt(i); ++ if (Character.isHighSurrogate(c)) { ++ if (i == length - 1) { ++ continue; ++ } ++ if (Character.isLowSurrogate(sqlString.charAt(i + 1))) { ++ // add them both ++ sb.append(c); ++ sb.append(sqlString.charAt(i + 1)); ++ continue; ++ } else { ++ // this is a lone surrogate, skip it ++ continue; + } +- sb.append(c); + } +- } else +- sb.append(sqlString); ++ if (Character.isLowSurrogate(c)) { ++ continue; ++ } ++ if (c == '\'') { ++ sb.append('\''); ++ } ++ sb.append(c); ++ } + sb.append('\''); + } + +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0200-RESTRICT-AUTOMERGE-SettingsProvider-exclude-secure_frp_mode-fr.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0200-RESTRICT-AUTOMERGE-SettingsProvider-exclude-secure_frp_mode-fr.bulletin.patch new file mode 100644 index 0000000000..83d61dd95d --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0200-RESTRICT-AUTOMERGE-SettingsProvider-exclude-secure_frp_mode-fr.bulletin.patch @@ -0,0 +1,138 @@ +From d7e13c90f9b3ae06a25ee2a102485a47bf74306e Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Fri, 28 Jul 2023 22:03:03 +0000 +Subject: [PATCH] RESTRICT AUTOMERGE: SettingsProvider: exclude secure_frp_mode + from resets + +When RescueParty detects that a system process is crashing frequently, +it tries to recover in various ways, such as by resetting all settings. +Unfortunately, this included resetting the secure_frp_mode setting, +which is the means by which the system keeps track of whether the +Factory Reset Protection (FRP) challenge has been passed yet. With this +setting reset, some FRP restrictions went away and it became possible to +bypass FRP by setting a new lockscreen credential. + +Fix this by excluding secure_frp_mode from resets. + +Note: currently this bug isn't reproducible on 'main' due to ag/23727749 +disabling much of RescueParty, but that is a temporary change. + +Bug: 253043065 +Test: With ag/23727749 reverted and with my fix to prevent + com.android.settings from crashing *not* applied, tried repeatedly + setting lockscreen credential while in FRP mode, using the + smartlock setup activity launched by intent via adb. Verified + that although RescueParty is still triggered after 5 attempts, + secure_frp_mode is no longer reset (its value remains "1"). +Test: Verified that secure_frp_mode still gets changed from 1 to 0 when + FRP is passed legitimately. +Test: atest com.android.providers.settings.SettingsProviderTest +Test: atest android.provider.SettingsProviderTest +(cherry picked from commit 9890dd7f15c091f7d1a09e4fddb9f85d32015955) +(changed Global.SECURE_FRP_MODE to Secure.SECURE_FRP_MODE, + needed because this setting was moved in U) +(removed static keyword from shouldExcludeSettingFromReset(), + needed for compatibility with Java 15 and earlier) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:30d1770dbfa5d5264083de4d50560e1bde3c4ba1) +Merged-In: Id95ed43b9cc2208090064392bcd5dc012710af93 +Change-Id: Id95ed43b9cc2208090064392bcd5dc012710af93 +--- + .../providers/settings/SettingsProvider.java | 17 ++++++++++--- + .../settings/SettingsProviderTest.java | 25 +++++++++++++++++++ + 2 files changed, 38 insertions(+), 4 deletions(-) + +diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +index db301f698753..205944c9244c 100644 +--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java ++++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +@@ -3055,6 +3055,15 @@ public class SettingsProvider extends ContentProvider { + return settingsState.getSettingLocked(name); + } + ++ private boolean shouldExcludeSettingFromReset(Setting setting, String prefix) { ++ // If a prefix was specified, exclude settings whose names don't start with it. ++ if (prefix != null && !setting.getName().startsWith(prefix)) { ++ return true; ++ } ++ // Never reset SECURE_FRP_MODE, as it could be abused to bypass FRP via RescueParty. ++ return Secure.SECURE_FRP_MODE.equals(setting.getName()); ++ } ++ + public void resetSettingsLocked(int type, int userId, String packageName, int mode, + String tag) { + resetSettingsLocked(type, userId, packageName, mode, tag, /*prefix=*/ +@@ -3077,7 +3086,7 @@ public class SettingsProvider extends ContentProvider { + Setting setting = settingsState.getSettingLocked(name); + if (packageName.equals(setting.getPackageName())) { + if ((tag != null && !tag.equals(setting.getTag())) +- || (prefix != null && !setting.getName().startsWith(prefix))) { ++ || shouldExcludeSettingFromReset(setting, prefix)) { + continue; + } + if (settingsState.resetSettingLocked(name)) { +@@ -3097,7 +3106,7 @@ public class SettingsProvider extends ContentProvider { + Setting setting = settingsState.getSettingLocked(name); + if (!SettingsState.isSystemPackage(getContext(), + setting.getPackageName())) { +- if (prefix != null && !setting.getName().startsWith(prefix)) { ++ if (shouldExcludeSettingFromReset(setting, prefix)) { + continue; + } + if (settingsState.resetSettingLocked(name)) { +@@ -3117,7 +3126,7 @@ public class SettingsProvider extends ContentProvider { + Setting setting = settingsState.getSettingLocked(name); + if (!SettingsState.isSystemPackage(getContext(), + setting.getPackageName())) { +- if (prefix != null && !setting.getName().startsWith(prefix)) { ++ if (shouldExcludeSettingFromReset(setting, prefix)) { + continue; + } + if (setting.isDefaultFromSystem()) { +@@ -3140,7 +3149,7 @@ public class SettingsProvider extends ContentProvider { + for (String name : settingsState.getSettingNamesLocked()) { + Setting setting = settingsState.getSettingLocked(name); + boolean someSettingChanged = false; +- if (prefix != null && !setting.getName().startsWith(prefix)) { ++ if (shouldExcludeSettingFromReset(setting, prefix)) { + continue; + } + if (setting.isDefaultFromSystem()) { +diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java +index f49e209c09a1..74a61274ff8f 100644 +--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java ++++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java +@@ -466,6 +466,31 @@ public class SettingsProviderTest extends BaseSettingsProviderTest { + } + } + ++ // To prevent FRP bypasses, the SECURE_FRP_MODE setting should not be reset when all other ++ // settings are reset. But it should still be possible to explicitly set its value. ++ @Test ++ public void testSecureFrpModeSettingCannotBeReset() throws Exception { ++ final String name = Settings.Secure.SECURE_FRP_MODE; ++ final String origValue = getSetting(SETTING_TYPE_GLOBAL, name); ++ setSettingViaShell(SETTING_TYPE_GLOBAL, name, "1", false); ++ try { ++ assertEquals("1", getSetting(SETTING_TYPE_GLOBAL, name)); ++ for (int type : new int[] { SETTING_TYPE_GLOBAL, SETTING_TYPE_SECURE }) { ++ resetSettingsViaShell(type, Settings.RESET_MODE_UNTRUSTED_DEFAULTS); ++ resetSettingsViaShell(type, Settings.RESET_MODE_UNTRUSTED_CHANGES); ++ resetSettingsViaShell(type, Settings.RESET_MODE_TRUSTED_DEFAULTS); ++ } ++ // The value should still be "1". It should not have been reset to null. ++ assertEquals("1", getSetting(SETTING_TYPE_GLOBAL, name)); ++ // It should still be possible to explicitly set the value to "0". ++ setSettingViaShell(SETTING_TYPE_GLOBAL, name, "0", false); ++ assertEquals("0", getSetting(SETTING_TYPE_GLOBAL, name)); ++ } finally { ++ setSettingViaShell(SETTING_TYPE_GLOBAL, name, origValue, false); ++ assertEquals(origValue, getSetting(SETTING_TYPE_GLOBAL, name)); ++ } ++ } ++ + private void doTestQueryStringInBracketsViaProviderApiForType(int type) { + // Make sure we have a clean slate. + deleteStringViaProviderApi(type, FAKE_SETTING_NAME); +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0201--RESTRICT-AUTOMERGE-Ignore-small-source-rect-hint.bulletin.patch b/aosp_diff/preliminary/frameworks/base/99_0201--RESTRICT-AUTOMERGE-Ignore-small-source-rect-hint.bulletin.patch new file mode 100644 index 0000000000..84b3251424 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0201--RESTRICT-AUTOMERGE-Ignore-small-source-rect-hint.bulletin.patch @@ -0,0 +1,86 @@ +From 438fabce71605a2f0a427f7741b0284bad753ae6 Mon Sep 17 00:00:00 2001 +From: Hongwei Wang +Date: Mon, 31 Jul 2023 16:47:45 -0700 +Subject: [PATCH] [RESTRICT AUTOMERGE] Ignore small source rect hint + +Which may be abused by malicious app to create a non-visible PiP +window that bypasses the background restriction. + +Bug: 270368476 +Test: Manually, using the POC app +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4fda9095ba9bdecb8250336d4f0ca328ed7c2aea) +Merged-In: I3531a64fc67a1b6c43997ee33b7a7d4ab4e2d985 +Change-Id: I3531a64fc67a1b6c43997ee33b7a7d4ab4e2d985 +--- + .../android/wm/shell/pip/PipBoundsAlgorithm.java | 15 +++++++++++++++ + .../android/wm/shell/pip/PipTaskOrganizer.java | 6 +++--- + .../com/android/wm/shell/pip/PipTransition.java | 2 +- + 3 files changed, 19 insertions(+), 4 deletions(-) + +diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java +index a4b866aa3f5e..b23b43111281 100644 +--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java ++++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java +@@ -182,6 +182,21 @@ public class PipBoundsAlgorithm { + return null; + } + ++ /** ++ * Returns the source hint rect if it is valid (if provided and is contained by the current ++ * task bounds and not too small). ++ */ ++ public static Rect getValidSourceHintRect(PictureInPictureParams params, Rect sourceBounds, ++ @NonNull Rect destinationBounds) { ++ final Rect sourceHintRect = getValidSourceHintRect(params, sourceBounds); ++ if (sourceHintRect != null ++ && sourceHintRect.width() > destinationBounds.width() ++ && sourceHintRect.height() > destinationBounds.height()) { ++ return sourceHintRect; ++ } ++ return null; ++ } ++ + public float getDefaultAspectRatio() { + return mDefaultAspectRatio; + } +diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +index f2bad6caf3e8..e0f542ab74ba 100644 +--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java ++++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +@@ -564,7 +564,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, + if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { + mPipMenuController.attach(mLeash); + final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( +- info.pictureInPictureParams, currentBounds); ++ info.pictureInPictureParams, currentBounds, destinationBounds); + scheduleAnimateResizePip(currentBounds, destinationBounds, 0 /* startingAngle */, + sourceHintRect, TRANSITION_DIRECTION_TO_PIP, mEnterAnimationDuration, + null /* updateBoundsCallback */); +@@ -590,9 +590,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, + return; + } + final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); +- final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( +- mPictureInPictureParams, currentBounds); + final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); ++ final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( ++ mPictureInPictureParams, currentBounds, destinationBounds); + animateResizePip(currentBounds, destinationBounds, sourceHintRect, + TRANSITION_DIRECTION_TO_PIP, mEnterAnimationDuration, 0 /* startingAngle */); + mState = State.ENTERING_PIP; +diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +index 4759550c35c0..8674d694bb42 100644 +--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java ++++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +@@ -110,7 +110,7 @@ public class PipTransition extends PipTransitionController { + if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { + final Rect sourceHintRect = + PipBoundsAlgorithm.getValidSourceHintRect( +- taskInfo.pictureInPictureParams, currentBounds); ++ taskInfo.pictureInPictureParams, currentBounds, destinationBounds); + animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds, + currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP, + 0 /* startingAngle */, Surface.ROTATION_0); +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/frameworks/base/99_0202-Add-placeholder-when-media-control-title-is-blank.patch b/aosp_diff/preliminary/frameworks/base/99_0202-Add-placeholder-when-media-control-title-is-blank.patch new file mode 100644 index 0000000000..a112b552b7 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/base/99_0202-Add-placeholder-when-media-control-title-is-blank.patch @@ -0,0 +1,181 @@ +From ded3a129effb0e1b8b3d967c8f42323fbfe57fd7 Mon Sep 17 00:00:00 2001 +From: Beth Thibodeau +Date: Tue, 30 May 2023 18:45:47 -0500 +Subject: [PATCH] Add placeholder when media control title is blank + +When an app posts a media control with no available title, show a +placeholder string with the app name instead + +Bug: 274775190 +Test: atest MediaDataManagerTest +(cherry picked from commit 070eff919c85fd83501e380a92e30caf082e9ffc) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0ad65345e93a97edba24349c052f8e001e96ec14) +Merged-In: Ie406c180af48653595e8e222a15b4dda27de2e0e +Change-Id: Ie406c180af48653595e8e222a15b4dda27de2e0e +--- + packages/SystemUI/res/values/strings.xml | 2 + + .../systemui/media/MediaDataManager.kt | 10 +- + .../systemui/media/MediaDataManagerTest.kt | 94 ++++++++++++++++++- + 3 files changed, 102 insertions(+), 4 deletions(-) + +diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml +index 4ad4fa9d0854..e8eb1c07ee90 100644 +--- a/packages/SystemUI/res/values/strings.xml ++++ b/packages/SystemUI/res/values/strings.xml +@@ -2841,6 +2841,8 @@ + Play %1$s by %2$s from %3$s + + Play %1$s from %2$s ++ ++ %1$s is running + + + Inactive, check app +diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +index eacdab6e537d..ab98869132de 100644 +--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt ++++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +@@ -568,12 +568,16 @@ class MediaDataManager( + + // Song name + var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE) +- if (song == null) { +- song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE) ++ if (song.isNullOrBlank()) { ++ song = metadata.getString(MediaMetadata.METADATA_KEY_TITLE) + } +- if (song == null) { ++ if (song.isNullOrBlank()) { + song = HybridGroupManager.resolveTitle(notif) + } ++ if (song.isNullOrBlank()) { ++ // For apps that don't include a title, add a placeholder ++ song = context.getString(R.string.controls_media_empty_title, app) ++ } + + // Artist name + var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST) +diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +index 47c5545ab587..e6d3c8a6c04e 100644 +--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt ++++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +@@ -16,6 +16,7 @@ import android.service.notification.StatusBarNotification + import android.testing.AndroidTestingRunner + import android.testing.TestableLooper.RunWithLooper + import androidx.test.filters.SmallTest ++import com.android.systemui.R + import com.android.systemui.SysuiTestCase + import com.android.systemui.broadcast.BroadcastDispatcher + import com.android.systemui.dump.DumpManager +@@ -48,9 +49,11 @@ private const val KEY = "KEY" + private const val KEY_2 = "KEY_2" + private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID" + private const val PACKAGE_NAME = "com.android.systemui" +-private const val APP_NAME = "SystemUI" ++private const val APP_NAME = "com.android.systemui.tests" + private const val SESSION_ARTIST = "artist" + private const val SESSION_TITLE = "title" ++private const val SESSION_BLANK_TITLE = " " ++private const val SESSION_EMPTY_TITLE = "" + private const val USER_ID = 0 + private val DISMISS_INTENT = Intent().apply { action = "dismiss" } + +@@ -236,6 +239,95 @@ class MediaDataManagerTest : SysuiTestCase() { + verify(listener).onMediaDataRemoved(eq(KEY)) + } + ++ @Test ++ fun testOnNotificationAdded_emptyTitle_hasPlaceholder() { ++ // When the manager has a notification with an empty title ++ val listener = mock(MediaDataManager.Listener::class.java) ++ mediaDataManager.addListener(listener) ++ whenever(controller.metadata) ++ .thenReturn( ++ metadataBuilder ++ .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_EMPTY_TITLE) ++ .build() ++ ) ++ mediaDataManager.onNotificationAdded(KEY, mediaNotification) ++ ++ // Then a media control is created with a placeholder title string ++ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) ++ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) ++ verify(listener) ++ .onMediaDataLoaded( ++ eq(KEY), ++ eq(null), ++ capture(mediaDataCaptor) ++ ) ++ val placeholderTitle = context.getString(R.string.controls_media_empty_title, APP_NAME) ++ assertThat(mediaDataCaptor.value.song).isEqualTo(placeholderTitle) ++ } ++ ++ @Test ++ fun testOnNotificationAdded_blankTitle_hasPlaceholder() { ++ // GIVEN that the manager has a notification with a blank title ++ val listener = mock(MediaDataManager.Listener::class.java) ++ mediaDataManager.addListener(listener) ++ whenever(controller.metadata) ++ .thenReturn( ++ metadataBuilder ++ .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE) ++ .build() ++ ) ++ mediaDataManager.onNotificationAdded(KEY, mediaNotification) ++ ++ // Then a media control is created with a placeholder title string ++ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) ++ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) ++ verify(listener) ++ .onMediaDataLoaded( ++ eq(KEY), ++ eq(null), ++ capture(mediaDataCaptor) ++ ) ++ val placeholderTitle = context.getString(R.string.controls_media_empty_title, APP_NAME) ++ assertThat(mediaDataCaptor.value.song).isEqualTo(placeholderTitle) ++ } ++ ++ @Test ++ fun testOnNotificationAdded_emptyMetadata_usesNotificationTitle() { ++ // When the app sets the metadata title fields to empty strings, but does include a ++ // non-blank notification title ++ val listener = mock(MediaDataManager.Listener::class.java) ++ mediaDataManager.addListener(listener) ++ whenever(controller.metadata) ++ .thenReturn( ++ metadataBuilder ++ .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_EMPTY_TITLE) ++ .putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, SESSION_EMPTY_TITLE) ++ .build() ++ ) ++ mediaNotification = ++ SbnBuilder().run { ++ setPkg(PACKAGE_NAME) ++ modifyNotification(context).also { ++ it.setSmallIcon(android.R.drawable.ic_media_pause) ++ it.setContentTitle(SESSION_TITLE) ++ it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) }) ++ } ++ build() ++ } ++ mediaDataManager.onNotificationAdded(KEY, mediaNotification) ++ ++ // Then the media control is added using the notification's title ++ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) ++ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) ++ verify(listener) ++ .onMediaDataLoaded( ++ eq(KEY), ++ eq(null), ++ capture(mediaDataCaptor) ++ ) ++ assertThat(mediaDataCaptor.value.song).isEqualTo(SESSION_TITLE) ++ } ++ + @Test + fun testOnNotificationRemoved_withResumption() { + // GIVEN that the manager has a notification with a resume action +-- +2.17.1 + diff --git a/aosp_diff/preliminary/frameworks/native/19_0019-Fix-for-heap-use-after-free-in-GPUService-cpp.bulletin.patch b/aosp_diff/preliminary/frameworks/native/19_0019-Fix-for-heap-use-after-free-in-GPUService-cpp.bulletin.patch new file mode 100644 index 0000000000..87dda0e474 --- /dev/null +++ b/aosp_diff/preliminary/frameworks/native/19_0019-Fix-for-heap-use-after-free-in-GPUService-cpp.bulletin.patch @@ -0,0 +1,209 @@ +From 1f65b3a3eba7a502b6a2318734cf293b27e8bc50 Mon Sep 17 00:00:00 2001 +From: sergiuferentz +Date: Mon, 26 Jun 2023 18:01:47 +0000 +Subject: [PATCH] Fix for heap-use-after-free in GPUService.cpp + +This adds a unit test and fix for the bug reported by libfuzzer. +Changes made: + * Expose GPUService as testable code. + * Update main_gpuservice.cpp to use the new GpuService now located at + gpuservice/GpuService.h + * Make initializer threads members of GpuService + * Join the threads in destructor to prevent heap-use-after-free. + * Add unit test that waits 3 seconds after deallocation to ensure no + wrong access is made. + +Bug: 282919145 +Test: Added unit test and ran on device with ASAN +(cherry picked from commit 3c00cbc0f119c3f59325aa6d5061529feb58462b) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:24a7874bb4093a1a6721a2002569512c43af5bdc) +Merged-In: I4d1d2d4658b575bf2c8f425f91f68f03114ad029 +Change-Id: I4d1d2d4658b575bf2c8f425f91f68f03114ad029 +--- + services/gpuservice/Android.bp | 1 + + services/gpuservice/GpuService.cpp | 10 ++-- + .../{ => include/gpuservice}/GpuService.h | 3 ++ + services/gpuservice/main_gpuservice.cpp | 2 +- + .../gpuservice/tests/unittests/Android.bp | 2 + + .../tests/unittests/GpuServiceTest.cpp | 52 +++++++++++++++++++ + 6 files changed, 66 insertions(+), 4 deletions(-) + rename services/gpuservice/{ => include/gpuservice}/GpuService.h (96%) + create mode 100644 services/gpuservice/tests/unittests/GpuServiceTest.cpp + +diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp +index b9b6a1960..8cbfa6fab 100644 +--- a/services/gpuservice/Android.bp ++++ b/services/gpuservice/Android.bp +@@ -70,6 +70,7 @@ filegroup { + cc_library_shared { + name: "libgpuservice", + defaults: ["libgpuservice_production_defaults"], ++ export_include_dirs: ["include"], + srcs: [ + ":libgpuservice_sources", + ], +diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp +index 52d5d4fc4..44af4c487 100644 +--- a/services/gpuservice/GpuService.cpp ++++ b/services/gpuservice/GpuService.cpp +@@ -16,7 +16,7 @@ + + #define ATRACE_TAG ATRACE_TAG_GRAPHICS + +-#include "GpuService.h" ++#include "gpuservice/GpuService.h" + + #include + #include +@@ -33,6 +33,7 @@ + #include + + #include ++#include + + namespace android { + +@@ -52,13 +53,16 @@ GpuService::GpuService() + : mGpuMem(std::make_shared()), + mGpuStats(std::make_unique()), + mGpuMemTracer(std::make_unique()) { +- std::thread asyncInitThread([this]() { ++ mGpuMemAsyncInitThread = std::make_unique([this] (){ + mGpuMem->initialize(); + mGpuMemTracer->initialize(mGpuMem); + }); +- asyncInitThread.detach(); + }; + ++GpuService::~GpuService() { ++ mGpuMemAsyncInitThread->join(); ++} ++ + void GpuService::setGpuStats(const std::string& driverPackageName, + const std::string& driverVersionName, uint64_t driverVersionCode, + int64_t driverBuildTime, const std::string& appPackageName, +diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/include/gpuservice/GpuService.h +similarity index 96% +rename from services/gpuservice/GpuService.h +rename to services/gpuservice/include/gpuservice/GpuService.h +index 409084b65..7d56c8389 100644 +--- a/services/gpuservice/GpuService.h ++++ b/services/gpuservice/include/gpuservice/GpuService.h +@@ -24,6 +24,7 @@ + #include + + #include ++#include + #include + + namespace android { +@@ -37,6 +38,7 @@ public: + static const char* const SERVICE_NAME ANDROID_API; + + GpuService() ANDROID_API; ++ ~GpuService(); + + protected: + status_t shellCommand(int in, int out, int err, std::vector& args) override; +@@ -81,6 +83,7 @@ private: + std::unique_ptr mGpuMemTracer; + std::mutex mLock; + std::string mDeveloperDriverPath; ++ std::unique_ptr mGpuMemAsyncInitThread; + }; + + } // namespace android +diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp +index 64aafcab6..200237219 100644 +--- a/services/gpuservice/main_gpuservice.cpp ++++ b/services/gpuservice/main_gpuservice.cpp +@@ -18,7 +18,7 @@ + #include + #include + #include +-#include "GpuService.h" ++#include "gpuservice/GpuService.h" + + using namespace android; + +diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp +index 6d87c4592..1455d2edd 100644 +--- a/services/gpuservice/tests/unittests/Android.bp ++++ b/services/gpuservice/tests/unittests/Android.bp +@@ -31,6 +31,7 @@ cc_test { + "GpuMemTest.cpp", + "GpuMemTracerTest.cpp", + "GpuStatsTest.cpp", ++ "GpuServiceTest.cpp", + ], + shared_libs: [ + "libbase", +@@ -47,6 +48,7 @@ cc_test { + "libstatslog", + "libstatspull", + "libutils", ++ "libgpuservice", + ], + static_libs: [ + "libgmock", +diff --git a/services/gpuservice/tests/unittests/GpuServiceTest.cpp b/services/gpuservice/tests/unittests/GpuServiceTest.cpp +new file mode 100644 +index 000000000..62b3e53f5 +--- /dev/null ++++ b/services/gpuservice/tests/unittests/GpuServiceTest.cpp +@@ -0,0 +1,52 @@ ++#undef LOG_TAG ++#define LOG_TAG "gpuservice_unittest" ++ ++#include "gpuservice/GpuService.h" ++ ++#include ++#include ++ ++#include ++#include ++ ++namespace android { ++namespace { ++ ++class GpuServiceTest : public testing::Test { ++public: ++ GpuServiceTest() { ++ const ::testing::TestInfo* const test_info = ++ ::testing::UnitTest::GetInstance()->current_test_info(); ++ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); ++ } ++ ++ ~GpuServiceTest() { ++ const ::testing::TestInfo* const test_info = ++ ::testing::UnitTest::GetInstance()->current_test_info(); ++ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); ++ } ++ ++}; ++ ++ ++/* ++* The behaviour before this test + fixes was UB caused by threads accessing deallocated memory. ++* ++* This test creates the service (which initializes the culprit threads), ++* deallocates it immediately and sleeps. ++* ++* GpuService's destructor gets called and joins the threads. ++* If we haven't crashed by the time the sleep time has elapsed, we're good ++* Let the test pass. ++*/ ++TEST_F(GpuServiceTest, onInitializeShouldNotCauseUseAfterFree) { ++ sp service = new GpuService(); ++ service.clear(); ++ std::this_thread::sleep_for(std::chrono::seconds(3)); ++ ++ // If we haven't crashed yet due to threads accessing freed up memory, let the test pass ++ EXPECT_TRUE(true); ++} ++ ++} // namespace ++} // namespace android +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/packages/apps/Settings/35_0035--RESTRICT-AUTOMERGE-Restrict-ApnEditor-settings.bulletin.patch b/aosp_diff/preliminary/packages/apps/Settings/35_0035--RESTRICT-AUTOMERGE-Restrict-ApnEditor-settings.bulletin.patch new file mode 100644 index 0000000000..07ee611a6c --- /dev/null +++ b/aosp_diff/preliminary/packages/apps/Settings/35_0035--RESTRICT-AUTOMERGE-Restrict-ApnEditor-settings.bulletin.patch @@ -0,0 +1,132 @@ +From 1eff772d805578f2c7d3947d0ea9e8b2c547bacd Mon Sep 17 00:00:00 2001 +From: Weng Su +Date: Fri, 7 Jul 2023 19:52:04 +0800 +Subject: [PATCH] [RESTRICT AUTOMERGE] Restrict ApnEditor settings + +- Finish ApnEditor settings if user is not an admin + +- Finish ApnEditor settings if user has DISALLOW_CONFIG_MOBILE_NETWORKS restriction + +Bug: 279902472 +Test: manual test +atest -c ApnEditorTest +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e3b554b29674ef20946451d0b46d3213838e753d) +Merged-In: Iecdbbff7e21dfb11e3ba385858747a220cfd3e04 +Change-Id: Iecdbbff7e21dfb11e3ba385858747a220cfd3e04 +--- + .../settings/network/apn/ApnEditor.java | 23 +++++++++++++++ + .../settings/network/apn/ApnEditorTest.java | 29 +++++++++++++++++++ + 2 files changed, 52 insertions(+) + +diff --git a/src/com/android/settings/network/apn/ApnEditor.java b/src/com/android/settings/network/apn/ApnEditor.java +index 0b751620ad..cc83c2e8ca 100644 +--- a/src/com/android/settings/network/apn/ApnEditor.java ++++ b/src/com/android/settings/network/apn/ApnEditor.java +@@ -25,6 +25,7 @@ import android.database.Cursor; + import android.net.Uri; + import android.os.Bundle; + import android.os.PersistableBundle; ++import android.os.UserManager; + import android.provider.Telephony; + import android.telephony.CarrierConfigManager; + import android.telephony.SubscriptionInfo; +@@ -266,6 +267,11 @@ public class ApnEditor extends SettingsPreferenceFragment + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); ++ if (isUserRestricted()) { ++ Log.e(TAG, "This setting isn't available due to user restriction."); ++ finish(); ++ return; ++ } + + setLifecycleForAllControllers(); + +@@ -1408,6 +1414,23 @@ public class ApnEditor extends SettingsPreferenceFragment + return apnData; + } + ++ @VisibleForTesting ++ boolean isUserRestricted() { ++ UserManager userManager = getContext().getSystemService(UserManager.class); ++ if (userManager == null) { ++ return false; ++ } ++ if (!userManager.isAdminUser()) { ++ Log.e(TAG, "User is not an admin"); ++ return true; ++ } ++ if (userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) { ++ Log.e(TAG, "User is not allowed to configure mobile network"); ++ return true; ++ } ++ return false; ++ } ++ + @VisibleForTesting + static class ApnData { + /** +diff --git a/tests/robotests/src/com/android/settings/network/apn/ApnEditorTest.java b/tests/robotests/src/com/android/settings/network/apn/ApnEditorTest.java +index 0a430cd09d..b2a30caf93 100644 +--- a/tests/robotests/src/com/android/settings/network/apn/ApnEditorTest.java ++++ b/tests/robotests/src/com/android/settings/network/apn/ApnEditorTest.java +@@ -34,6 +34,7 @@ import android.content.Intent; + import android.content.res.Resources; + import android.database.Cursor; + import android.net.Uri; ++import android.os.UserManager; + import android.view.KeyEvent; + import android.view.Menu; + import android.view.MenuItem; +@@ -102,6 +103,8 @@ public class ApnEditorTest { + @Mock + private FragmentActivity mActivity; + @Mock ++ private UserManager mUserManager; ++ @Mock + private ProxySubscriptionManager mProxySubscriptionMgr; + + @Captor +@@ -127,6 +130,11 @@ public class ApnEditorTest { + doReturn(mContext.getTheme()).when(mActivity).getTheme(); + doReturn(mContext.getContentResolver()).when(mActivity).getContentResolver(); + ++ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); ++ doReturn(true).when(mUserManager).isAdminUser(); ++ doReturn(false).when(mUserManager) ++ .hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS); ++ + setMockPreference(mContext); + mApnEditorUT.mApnData = new FakeApnData(APN_DATA); + mApnEditorUT.sNotSet = "Not Set"; +@@ -451,6 +459,27 @@ public class ApnEditorTest { + assertThat(ApnEditor.formatInteger("not an int")).isEqualTo("not an int"); + } + ++ @Test ++ @Config(shadows = ShadowFragment.class) ++ public void onCreate_notAdminUser_shouldFinish() { ++ doReturn(false).when(mUserManager).isAdminUser(); ++ ++ mApnEditorUT.onCreate(null); ++ ++ verify(mApnEditorUT).finish(); ++ } ++ ++ @Test ++ @Config(shadows = ShadowFragment.class) ++ public void onCreate_hasUserRestriction_shouldFinish() { ++ doReturn(true).when(mUserManager) ++ .hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS); ++ ++ mApnEditorUT.onCreate(null); ++ ++ verify(mApnEditorUT).finish(); ++ } ++ + @Test + @Config(shadows = ShadowFragment.class) + public void onCreate_noAction_shouldFinishAndNoCrash() { +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/packages/apps/Settings/36_0036-RESTRICT-AUTOMERGE-Catch-exceptions-from-setLockCredential-.bulletin.patch b/aosp_diff/preliminary/packages/apps/Settings/36_0036-RESTRICT-AUTOMERGE-Catch-exceptions-from-setLockCredential-.bulletin.patch new file mode 100644 index 0000000000..fdb4a952a9 --- /dev/null +++ b/aosp_diff/preliminary/packages/apps/Settings/36_0036-RESTRICT-AUTOMERGE-Catch-exceptions-from-setLockCredential-.bulletin.patch @@ -0,0 +1,68 @@ +From c3a629f28c5f48525be9d7026322383fdd00f46c Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Thu, 27 Jul 2023 21:45:05 +0000 +Subject: [PATCH] RESTRICT AUTOMERGE: Catch exceptions from setLockCredential() + +When LockPatternUtils#setLockCredential() fails, it can either return +false or throw an exception. Catch the exception and treat it the same +way as a false return value, to prevent crashing com.android.settings. + +Bug: 253043065 +Test: Tried setting lockscreen credential while in secure FRP mode using + smartlock setup activity launched by intent via adb. Verified + that com.android.settings no longer crashes due to the exception + from LockPatternUtils#setLockCredential(). +(cherry picked from commit 05f1eff1c9c3f82797f1a0f92ff7665b9f463488) +(moved change into ChooseLockPassword.java and ChooseLockPattern.java, + which are merged into SaveAndFinishWorker.java on udc-qpr-dev and main) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:50cb0a35c92e7baa27ed6335079d2948a56d43e0) +Merged-In: I48b9119c19fb6378b1f88d36433ee4f4c8501d76 +Change-Id: I48b9119c19fb6378b1f88d36433ee4f4c8501d76 +--- + .../android/settings/password/ChooseLockPassword.java | 9 +++++++-- + src/com/android/settings/password/ChooseLockPattern.java | 9 +++++++-- + 2 files changed, 14 insertions(+), 4 deletions(-) + +diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java +index 18fc611e14..ba886470d2 100644 +--- a/src/com/android/settings/password/ChooseLockPassword.java ++++ b/src/com/android/settings/password/ChooseLockPassword.java +@@ -1020,8 +1020,13 @@ public class ChooseLockPassword extends SettingsActivity { + + @Override + protected Pair saveAndVerifyInBackground() { +- final boolean success = mUtils.setLockCredential( +- mChosenPassword, mCurrentCredential, mUserId); ++ boolean success; ++ try { ++ success = mUtils.setLockCredential(mChosenPassword, mCurrentCredential, mUserId); ++ } catch (RuntimeException e) { ++ Log.e(TAG, "Failed to set lockscreen credential", e); ++ success = false; ++ } + if (success) { + unifyProfileCredentialIfRequested(); + } +diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java +index e9ca9c40a5..945c5ee6da 100644 +--- a/src/com/android/settings/password/ChooseLockPattern.java ++++ b/src/com/android/settings/password/ChooseLockPattern.java +@@ -906,8 +906,13 @@ public class ChooseLockPattern extends SettingsActivity { + @Override + protected Pair saveAndVerifyInBackground() { + final int userId = mUserId; +- final boolean success = mUtils.setLockCredential(mChosenPattern, mCurrentCredential, +- userId); ++ boolean success; ++ try { ++ success = mUtils.setLockCredential(mChosenPattern, mCurrentCredential, userId); ++ } catch (RuntimeException e) { ++ Log.e(TAG, "Failed to set lockscreen credential", e); ++ success = false; ++ } + if (success) { + unifyProfileCredentialIfRequested(); + } +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/packages/modules/Wifi/0009-Add-pre-share-key-check-for-wapi.bulletin.patch b/aosp_diff/preliminary/packages/modules/Wifi/0009-Add-pre-share-key-check-for-wapi.bulletin.patch new file mode 100644 index 0000000000..d508f02ab4 --- /dev/null +++ b/aosp_diff/preliminary/packages/modules/Wifi/0009-Add-pre-share-key-check-for-wapi.bulletin.patch @@ -0,0 +1,121 @@ +From 62c73a0e6741edd6ad452c26dc772591fcf12aa9 Mon Sep 17 00:00:00 2001 +From: "Nate(Qiang) Jiang" +Date: Thu, 13 Apr 2023 00:16:16 +0000 +Subject: [PATCH] Add pre-share key check for wapi + +Bug: 275339978 +Test: atest com.androi.server.wifi +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:96aaf7f7b27f709b3cb06d054cb7e3fd92e890a1) +Merged-In: Id37e395f4f4f05b7901b718e3ea84c56b95cdfe7 +Change-Id: Id37e395f4f4f05b7901b718e3ea84c56b95cdfe7 +--- + .../server/wifi/WifiConfigurationUtil.java | 5 ++- + .../server/wifi/WifiConfigManagerTest.java | 2 +- + .../wifi/WifiConfigurationUtilTest.java | 41 +++++++++++++++++++ + 3 files changed, 46 insertions(+), 2 deletions(-) + +diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java +index 5e0db72f6..4892dbf52 100644 +--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java ++++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java +@@ -695,7 +695,10 @@ public class WifiConfigurationUtil { + && !validatePassword(config.preSharedKey, isAdd, true)) { + return false; + } +- ++ if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_WAPI_PSK) ++ && !validatePassword(config.preSharedKey, isAdd, false)) { ++ return false; ++ } + if (!validateEnterpriseConfig(config, isAdd)) { + return false; + } +diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java +index d0c223445..cd1a360d0 100644 +--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java ++++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java +@@ -447,7 +447,7 @@ public class WifiConfigManagerTest extends WifiBaseTest { + public void testAddWapiPskHexNetwork() { + WifiConfiguration wapiPskNetwork = WifiConfigurationTestUtil.createWapiPskNetwork(); + wapiPskNetwork.preSharedKey = +- "123456780abcdef0123456780abcdef0"; ++ "123456780abcdef0123456780abcdef0123456780abcdef0123456780abcdef0"; + List networks = new ArrayList<>(); + networks.add(wapiPskNetwork); + +diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java +index 75cdfb5d4..b497bb5c3 100644 +--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java ++++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java +@@ -352,6 +352,18 @@ public class WifiConfigurationUtilTest extends WifiBaseTest { + assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); + } + ++ @Test ++ public void testValidateNegativeCases_BadAsciiPskLengthWapi() { ++ WifiConfiguration config = WifiConfigurationTestUtil.createWapiPskNetwork(); ++ assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); ++ ++ config.preSharedKey = "\"abcdffeeretretyetreteteteabe34tetrertertrsraaaaaaaaaaa345eqwrweewq" ++ + "weqe\""; ++ assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); ++ config.preSharedKey = "\"454\""; ++ assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); ++ } ++ + /** + * Verify that the validate method fails to validate WifiConfiguration with bad sae length. + */ +@@ -380,6 +392,15 @@ public class WifiConfigurationUtilTest extends WifiBaseTest { + assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); + } + ++ @Test ++ public void testValidateNegativeCases_MalformedAsciiPskStringWapi() { ++ WifiConfiguration config = WifiConfigurationTestUtil.createWapiPskNetwork(); ++ assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); ++ ++ config.preSharedKey = "\"abcdfefeeretrety"; ++ assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); ++ } ++ + /** + * Verify that the validate method fails to validate WifiConfiguration with malformed sae + * string. +@@ -407,6 +428,17 @@ public class WifiConfigurationUtilTest extends WifiBaseTest { + assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); + } + ++ @Test ++ public void testValidateNegativeCases_BadHexPskLengthWapi() { ++ WifiConfiguration config = WifiConfigurationTestUtil.createWapiPskNetwork(); ++ assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); ++ ++ config.preSharedKey = "abcd123456788990013453445345465465476546"; ++ assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); ++ config.preSharedKey = ""; ++ assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); ++ } ++ + /** + * Verify that the validate method fails to validate WifiConfiguration with malformed psk + * string. +@@ -420,6 +452,15 @@ public class WifiConfigurationUtilTest extends WifiBaseTest { + assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); + } + ++ @Test ++ public void testValidateNegativeCases_MalformedHexPskStringWapi() { ++ WifiConfiguration config = WifiConfigurationTestUtil.createWapiPskNetwork(); ++ assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); ++ ++ config.preSharedKey = "adbdfgretrtyrtyrty"; ++ assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); ++ } ++ + /** + * Verify that the validate method fails to validate WifiConfiguration with malformed sae + * string. +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/packages/modules/Wifi/0010-Update-password-check-for-WAPI.bulletin.patch b/aosp_diff/preliminary/packages/modules/Wifi/0010-Update-password-check-for-WAPI.bulletin.patch new file mode 100644 index 0000000000..965678737b --- /dev/null +++ b/aosp_diff/preliminary/packages/modules/Wifi/0010-Update-password-check-for-WAPI.bulletin.patch @@ -0,0 +1,99 @@ +From 0f4d0afb74c8e6f8fbc46594fcf196a3b655d0df Mon Sep 17 00:00:00 2001 +From: Oscar Shu +Date: Fri, 7 Jul 2023 02:21:41 +0000 +Subject: [PATCH] Update password check for WAPI + +Do not allow arbitrarily large passwords. + +Bug: 275339978 + +Test: compile +(cherry picked from commit 38707fb4ff1405663cc24affc95244f4cc830499) +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:9c914b0be9b553164b343ca981b5d57e163a4574) +Merged-In: I15f3aff373af56c253a50c308d886a7acf661e59 +Change-Id: I15f3aff373af56c253a50c308d886a7acf661e59 +--- + .../server/wifi/WifiConfigurationUtil.java | 22 +++++++++++++------ + .../wifi/WifiConfigurationUtilTest.java | 3 ++- + 2 files changed, 17 insertions(+), 8 deletions(-) + +diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java +index 4892dbf52..3ab3ca3d0 100644 +--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java ++++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java +@@ -444,7 +444,8 @@ public class WifiConfigurationUtil { + return true; + } + +- private static boolean validatePassword(String password, boolean isAdd, boolean isSae) { ++ private static boolean validatePassword(String password, boolean isAdd, boolean isSae, ++ boolean isWapi) { + if (isAdd) { + if (password == null) { + Log.e(TAG, "validatePassword: null string"); +@@ -486,7 +487,14 @@ public class WifiConfigurationUtil { + } + } else { + // HEX PSK string +- if (password.length() != PSK_SAE_HEX_LEN) { ++ if (isWapi) { ++ // Protect system against malicious actors injecting arbitrarily large passwords. ++ if (password.length() > 100) { ++ Log.e(TAG, "validatePassword failed: WAPI hex string too long: " ++ + password.length()); ++ return false; ++ } ++ } else if (password.length() != PSK_SAE_HEX_LEN) { + Log.e(TAG, "validatePassword failed: hex string size mismatch: " + + password.length()); + return false; +@@ -688,15 +696,15 @@ public class WifiConfigurationUtil { + return false; + } + if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_PSK) +- && !validatePassword(config.preSharedKey, isAdd, false)) { ++ && !validatePassword(config.preSharedKey, isAdd, false, false)) { + return false; + } + if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_SAE) +- && !validatePassword(config.preSharedKey, isAdd, true)) { ++ && !validatePassword(config.preSharedKey, isAdd, true, false)) { + return false; + } + if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_WAPI_PSK) +- && !validatePassword(config.preSharedKey, isAdd, false)) { ++ && !validatePassword(config.preSharedKey, isAdd, false, true)) { + return false; + } + if (!validateEnterpriseConfig(config, isAdd)) { +@@ -845,11 +853,11 @@ public class WifiConfigurationUtil { + return false; + } + if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_PSK) +- && !validatePassword(config.preSharedKey, true, false)) { ++ && !validatePassword(config.preSharedKey, true, false, false)) { + return false; + } + if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_SAE) +- && !validatePassword(config.preSharedKey, true, true)) { ++ && !validatePassword(config.preSharedKey, true, true, false)) { + return false; + } + // TBD: Validate some enterprise params as well in the future here. +diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java +index b497bb5c3..af9b08bd8 100644 +--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java ++++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java +@@ -433,7 +433,8 @@ public class WifiConfigurationUtilTest extends WifiBaseTest { + WifiConfiguration config = WifiConfigurationTestUtil.createWapiPskNetwork(); + assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); + +- config.preSharedKey = "abcd123456788990013453445345465465476546"; ++ config.preSharedKey = "01234567890123456789012345678901234567890123456789012345678901234567" ++ + "890123456789012345678901234567890"; + assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); + config.preSharedKey = ""; + assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)); +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/packages/providers/MediaProvider/08_0008-Fix-path-traversal-vulnerabilities-in-MediaProvider.bulletin.patch b/aosp_diff/preliminary/packages/providers/MediaProvider/08_0008-Fix-path-traversal-vulnerabilities-in-MediaProvider.bulletin.patch new file mode 100644 index 0000000000..dcd85828b5 --- /dev/null +++ b/aosp_diff/preliminary/packages/providers/MediaProvider/08_0008-Fix-path-traversal-vulnerabilities-in-MediaProvider.bulletin.patch @@ -0,0 +1,248 @@ +From bc4fc10769b53d92ca21646e5125b3a13719141a Mon Sep 17 00:00:00 2001 +From: Sergey Nikolaienkov +Date: Tue, 28 Mar 2023 12:22:31 +0200 +Subject: [PATCH] Fix path traversal vulnerabilities in MediaProvider + +Canonicalize filepath provided by the caller when hanling SCAN_FILE_CALL +method call in MediaProvider. +Additionally, make sure to check access permission in SCAN_FILE_CALL +(using enforceCallingPermissionInternal()). + +Preemptively canonicalize Files provided as an arguments to the public +API methods in ModernMediaScanner (scanFile(), scanDirectory() and +onDirectoryDirty()) to prevent path traversal attacks. + +Bug: 262244882 +Test: atest MediaProviderTests +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:dc981046aba07e1a83c8be3885d98aa2fd6b3002) +Merged-In: I61e77d69ae857984b819fa0ea27bec5c26a34842 +Change-Id: I61e77d69ae857984b819fa0ea27bec5c26a34842 +--- + .../providers/media/MediaProvider.java | 54 +++++++++++-------- + .../media/scan/ModernMediaScanner.java | 33 ++++++++++-- + .../providers/media/util/FileUtils.java | 47 +++++++++++----- + 3 files changed, 96 insertions(+), 38 deletions(-) + +diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java +index 114152bd..554f45cd 100644 +--- a/src/com/android/providers/media/MediaProvider.java ++++ b/src/com/android/providers/media/MediaProvider.java +@@ -5582,38 +5582,48 @@ public class MediaProvider extends ContentProvider { + BackgroundThread.waitForIdle(); + return null; + } +- case MediaStore.SCAN_FILE_CALL: +- case MediaStore.SCAN_VOLUME_CALL: { +- final int userId = Binder.getCallingUid() / PER_USER_RANGE; ++ case MediaStore.SCAN_FILE_CALL: { + final LocalCallingIdentity token = clearLocalCallingIdentity(); + final CallingIdentity providerToken = clearCallingIdentity(); ++ ++ final String filePath = arg; ++ final Uri uri; + try { +- final Bundle res = new Bundle(); +- switch (method) { +- case MediaStore.SCAN_FILE_CALL: { +- final File file = new File(arg); +- res.putParcelable(Intent.EXTRA_STREAM, scanFile(file, REASON_DEMAND)); +- break; +- } +- case MediaStore.SCAN_VOLUME_CALL: { +- final String volumeName = arg; +- try { +- MediaVolume volume = mVolumeCache.findVolume(volumeName, +- UserHandle.of(userId)); +- MediaService.onScanVolume(getContext(), volume, REASON_DEMAND); +- } catch (FileNotFoundException e) { +- Log.w(TAG, "Failed to find volume " + volumeName, e); +- } +- break; +- } ++ File file; ++ try { ++ file = FileUtils.getCanonicalFile(filePath); ++ } catch (IOException e) { ++ file = null; + } +- return res; ++ ++ uri = file != null ? scanFile(file, REASON_DEMAND) : null; ++ } finally { ++ restoreCallingIdentity(providerToken); ++ restoreLocalCallingIdentity(token); ++ } ++ ++ final Bundle res = new Bundle(); ++ res.putParcelable(Intent.EXTRA_STREAM, uri); ++ return res; ++ } ++ case MediaStore.SCAN_VOLUME_CALL: { ++ final UserHandle user = UserHandle.of(Binder.getCallingUid() / PER_USER_RANGE); ++ final LocalCallingIdentity token = clearLocalCallingIdentity(); ++ final CallingIdentity providerToken = clearCallingIdentity(); ++ ++ final String volumeName = arg; ++ try { ++ final MediaVolume volume = mVolumeCache.findVolume(volumeName, user); ++ MediaService.onScanVolume(getContext(), volume, REASON_DEMAND); ++ } catch (FileNotFoundException e) { ++ Log.w(TAG, "Failed to find volume " + volumeName, e); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + restoreCallingIdentity(providerToken); + restoreLocalCallingIdentity(token); + } ++ return Bundle.EMPTY; + } + case MediaStore.GET_VERSION_CALL: { + final String volumeName = extras.getString(Intent.EXTRA_TEXT); +diff --git a/src/com/android/providers/media/scan/ModernMediaScanner.java b/src/com/android/providers/media/scan/ModernMediaScanner.java +index 8927bfa5..5087c19a 100644 +--- a/src/com/android/providers/media/scan/ModernMediaScanner.java ++++ b/src/com/android/providers/media/scan/ModernMediaScanner.java +@@ -50,6 +50,8 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS; + + import static com.android.providers.media.util.Metrics.translateReason; + ++import static java.util.Objects.requireNonNull; ++ + import android.content.ContentProviderClient; + import android.content.ContentProviderOperation; + import android.content.ContentProviderResult; +@@ -243,7 +245,15 @@ public class ModernMediaScanner implements MediaScanner { + } + + @Override +- public void scanDirectory(File file, int reason) { ++ public void scanDirectory(@NonNull File file, int reason) { ++ requireNonNull(file); ++ try { ++ file = file.getCanonicalFile(); ++ } catch (IOException e) { ++ Log.e(TAG, "Couldn't canonicalize directory to scan" + file, e); ++ return; ++ } ++ + try (Scan scan = new Scan(file, reason, /*ownerPackage*/ null)) { + scan.run(); + } catch (OperationCanceledException ignored) { +@@ -253,12 +263,21 @@ public class ModernMediaScanner implements MediaScanner { + } + + @Override +- public Uri scanFile(File file, int reason) { ++ @Nullable ++ public Uri scanFile(@NonNull File file, int reason) { + return scanFile(file, reason, /*ownerPackage*/ null); + } + + @Override + public Uri scanFile(File file, int reason, @Nullable String ownerPackage) { ++ requireNonNull(file); ++ try { ++ file = file.getCanonicalFile(); ++ } catch (IOException e) { ++ Log.e(TAG, "Couldn't canonicalize file to scan" + file, e); ++ return null; ++ } ++ + try (Scan scan = new Scan(file, reason, ownerPackage)) { + scan.run(); + return scan.getFirstResult(); +@@ -294,9 +313,17 @@ public class ModernMediaScanner implements MediaScanner { + + @Override + public void onDirectoryDirty(File dir) { ++ requireNonNull(dir); ++ try { ++ dir = dir.getCanonicalFile(); ++ } catch (IOException e) { ++ Log.e(TAG, "Couldn't canonicalize directory" + dir, e); ++ return; ++ } ++ + synchronized (mPendingCleanDirectories) { + mPendingCleanDirectories.remove(dir.getPath()); +- FileUtils.setDirectoryDirty(dir, /*isDirty*/ true); ++ FileUtils.setDirectoryDirty(dir, /* isDirty */ true); + } + } + +diff --git a/src/com/android/providers/media/util/FileUtils.java b/src/com/android/providers/media/util/FileUtils.java +index a0f666fb..e5c62d16 100644 +--- a/src/com/android/providers/media/util/FileUtils.java ++++ b/src/com/android/providers/media/util/FileUtils.java +@@ -1101,18 +1101,25 @@ public class FileUtils { + } + + public static @Nullable String extractRelativePath(@Nullable String data) { +- data = getCanonicalPath(data); + if (data == null) return null; + +- final Matcher matcher = PATTERN_RELATIVE_PATH.matcher(data); ++ final String path; ++ try { ++ path = getCanonicalPath(data); ++ } catch (IOException e) { ++ Log.d(TAG, "Unable to get canonical path from invalid data path: " + data, e); ++ return null; ++ } ++ ++ final Matcher matcher = PATTERN_RELATIVE_PATH.matcher(path); + if (matcher.find()) { +- final int lastSlash = data.lastIndexOf('/'); ++ final int lastSlash = path.lastIndexOf('/'); + if (lastSlash == -1 || lastSlash < matcher.end()) { + // This is a file in the top-level directory, so relative path is "/" + // which is different than null, which means unknown path + return "/"; + } else { +- return data.substring(matcher.end(), lastSlash + 1); ++ return path.substring(matcher.end(), lastSlash + 1); + } + } else { + return null; +@@ -1667,15 +1674,29 @@ public class FileUtils { + return null; + } + +- @Nullable +- private static String getCanonicalPath(@Nullable String path) { +- if (path == null) return null; ++ /** ++ * Returns the canonical {@link File} for the provided abstract pathname. ++ * ++ * @return The canonical pathname string denoting the same file or directory as this abstract ++ * pathname ++ * @see File#getCanonicalFile() ++ */ ++ @NonNull ++ public static File getCanonicalFile(@NonNull String path) throws IOException { ++ Objects.requireNonNull(path); ++ return new File(path).getCanonicalFile(); ++ } + +- try { +- return new File(path).getCanonicalPath(); +- } catch (IOException e) { +- Log.d(TAG, "Unable to get canonical path from invalid data path: " + path, e); +- return null; +- } ++ /** ++ * Returns the canonical pathname string of the provided abstract pathname. ++ * ++ * @return The canonical pathname string denoting the same file or directory as this abstract ++ * pathname. ++ * @see File#getCanonicalPath() ++ */ ++ @NonNull ++ public static String getCanonicalPath(@NonNull String path) throws IOException { ++ Objects.requireNonNull(path); ++ return new File(path).getCanonicalPath(); + } + } +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/packages/services/Telecomm/12_0012-Fix-vulnerability-in-CallRedirectionService-.bulletin.patch b/aosp_diff/preliminary/packages/services/Telecomm/12_0012-Fix-vulnerability-in-CallRedirectionService-.bulletin.patch new file mode 100644 index 0000000000..fdd5681c7b --- /dev/null +++ b/aosp_diff/preliminary/packages/services/Telecomm/12_0012-Fix-vulnerability-in-CallRedirectionService-.bulletin.patch @@ -0,0 +1,51 @@ +From ce284c334907b4ebe171d61111cec48c4368eda7 Mon Sep 17 00:00:00 2001 +From: Grace Jia +Date: Thu, 20 Jul 2023 13:42:50 -0700 +Subject: [PATCH] Fix vulnerability in CallRedirectionService. + +Currently when the CallRedirectionService binding died, we didn't do +anything, which cause malicious app start activities even not run in the +background by implementing a CallRedirectionService and overriding the +onPlaceCall method to schedule a activity start job in an independent +process and then kill itself. In that way, the activity can still +start after the CallRedirectionService died. Fix this by unbinding the +service when the binding died. + +Bug: b/289809991 +Test: Using testapp provided in bug to make sure the test activity can't +be started +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:29b52e3cd027da2d8644450a4dee3a7d95dc0043) +Merged-In: I065d361b83700474a1efab2a75928427ee0a14ba +Change-Id: I065d361b83700474a1efab2a75928427ee0a14ba +--- + .../callredirection/CallRedirectionProcessor.java | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java +index 4f486b2c..471a82ab 100644 +--- a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java ++++ b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java +@@ -164,6 +164,20 @@ public class CallRedirectionProcessor implements CallRedirectionCallback { + Log.endSession(); + } + } ++ ++ @Override ++ public void onBindingDied(ComponentName componentName) { ++ // Make sure we unbind the service if binding died to avoid background stating ++ // activity leaks ++ Log.startSession("CRSC.oBD"); ++ try { ++ synchronized (mTelecomLock) { ++ finishCallRedirection(); ++ } ++ } finally { ++ Log.endSession(); ++ } ++ } + } + + private class CallRedirectionAdapter extends ICallRedirectionAdapter.Stub { +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/system/bt/39_0039-Fix-an-integer-underflow-in-build_read_multi_rsp.bulletin.patch b/aosp_diff/preliminary/system/bt/39_0039-Fix-an-integer-underflow-in-build_read_multi_rsp.bulletin.patch new file mode 100644 index 0000000000..684fda867e --- /dev/null +++ b/aosp_diff/preliminary/system/bt/39_0039-Fix-an-integer-underflow-in-build_read_multi_rsp.bulletin.patch @@ -0,0 +1,84 @@ +From 3e6b85c42e96adbb5a9dd45eddb035a70a63cc8e Mon Sep 17 00:00:00 2001 +From: Hui Peng +Date: Thu, 27 Jul 2023 04:09:04 +0000 +Subject: [PATCH] Fix an integer underflow in build_read_multi_rsp + +This is a backport of Ia60dd829ff9152c083de1f4c1265bb3ad595dcc4 +to sc-dev + +Bug: 273874525 +Test: manual +Ignore-AOSP-First: security +Tag: #security +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d5f27984f4ca265f28a4adf5835b0198a3e19aed) +Merged-In: Ia60dd829ff9152c083de1f4c1265bb3ad595dcc4 +Change-Id: Ia60dd829ff9152c083de1f4c1265bb3ad595dcc4 +--- + stack/gatt/gatt_sr.cc | 28 +++++++++++++++++----------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +diff --git a/stack/gatt/gatt_sr.cc b/stack/gatt/gatt_sr.cc +index 2c736f332..266dc2895 100644 +--- a/stack/gatt/gatt_sr.cc ++++ b/stack/gatt/gatt_sr.cc +@@ -21,6 +21,7 @@ + * this file contains the GATT server functions + * + ******************************************************************************/ ++#include + #include "bt_target.h" + #include "osi/include/osi.h" + +@@ -172,12 +173,24 @@ static void build_read_multi_rsp(tGATT_SR_CMD* p_cmd, uint16_t mtu) { + } + + if (p_rsp != NULL) { +- total_len = (p_buf->len + p_rsp->attr_value.len); ++ total_len = p_buf->len; + if (p_cmd->multi_req.variable_len) { + total_len += 2; + } + + if (total_len > mtu) { ++ VLOG(1) << "Buffer space not enough for this data item, skipping"; ++ break; ++ } ++ ++ len = std::min((size_t) p_rsp->attr_value.len, mtu - total_len); ++ ++ if (len == 0) { ++ VLOG(1) << "Buffer space not enough for this data item, skipping"; ++ break; ++ } ++ ++ if (len < p_rsp->attr_value.len) { + /* just send the partial response for the overflow case */ + len = p_rsp->attr_value.len - (total_len - mtu); + is_overflow = true; +@@ -189,20 +202,13 @@ static void build_read_multi_rsp(tGATT_SR_CMD* p_cmd, uint16_t mtu) { + } + + if (p_cmd->multi_req.variable_len) { +- UINT16_TO_STREAM(p, len); ++ UINT16_TO_STREAM(p, (uint16_t) len); + p_buf->len += 2; + } + + if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii]) { +- // check for possible integer overflow +- if (p_buf->len + len <= UINT16_MAX) { +- memcpy(p, p_rsp->attr_value.value, len); +- if (!is_overflow) p += len; +- p_buf->len += len; +- } else { +- p_cmd->status = GATT_NOT_FOUND; +- break; +- } ++ ARRAY_TO_STREAM(p, p_rsp->attr_value.value, (uint16_t) len); ++ p_buf->len += (uint16_t) len; + } else { + p_cmd->status = GATT_NOT_FOUND; + break; +-- +2.42.0.rc2.253.gd59a3bf2b4-goog + diff --git a/aosp_diff/preliminary/tools/apksig/0001-Limit-the-number-of-supported-v1-and-v2-signers.bulletin.patch b/aosp_diff/preliminary/tools/apksig/0001-Limit-the-number-of-supported-v1-and-v2-signers.bulletin.patch new file mode 100644 index 0000000000..b23bfe203b --- /dev/null +++ b/aosp_diff/preliminary/tools/apksig/0001-Limit-the-number-of-supported-v1-and-v2-signers.bulletin.patch @@ -0,0 +1,1474 @@ +From 0caee3f60872729a5622650f333fc6076cf948c6 Mon Sep 17 00:00:00 2001 +From: Michael Groover +Date: Fri, 31 Mar 2023 14:30:21 -0500 +Subject: [PATCH] Limit the number of supported v1 and v2 signers + +The v1 and v2 APK Signature Schemes support multiple signers; this +was intended to allow multiple entities to sign an APK. Previously, +there were no limits placed on the number of signers that could +sign an APK, but this commit sets a hard limit of 10 supported +signers for these signature schemes to ensure a large number of +signers does not place undue burden on the platform. + +Bug: 266580022 +Test: gradlew test +(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:dae412630054cc9ec19ec03e0e827585e619f6ac) +Merged-In: I77f4218599511ff4f9f3790e4942a329d5a18da4 +Change-Id: I77f4218599511ff4f9f3790e4942a329d5a18da4 +--- + .../java/com/android/apksig/ApkVerifier.java | 29 +++++ + .../java/com/android/apksig/Constants.java | 5 + + .../internal/apk/v1/V1SchemeSigner.java | 6 ++ + .../internal/apk/v1/V1SchemeVerifier.java | 6 ++ + .../internal/apk/v2/V2SchemeSigner.java | 8 ++ + .../internal/apk/v2/V2SchemeVerifier.java | 5 + + .../com/android/apksig/ApkSignerTest.java | 100 ++++++++++++++++++ + .../com/android/apksig/ApkVerifierTest.java | 31 ++++++ + .../com/android/apksig/v1-only-10-signers.apk | Bin 0 -> 18389 bytes + .../com/android/apksig/v1-only-11-signers.apk | Bin 0 -> 22297 bytes + .../com/android/apksig/v2-only-10-signers.apk | Bin 0 -> 20688 bytes + .../com/android/apksig/v2-only-11-signers.apk | Bin 0 -> 24784 bytes + 12 files changed, 190 insertions(+) + create mode 100644 src/test/resources/com/android/apksig/v1-only-10-signers.apk + create mode 100644 src/test/resources/com/android/apksig/v1-only-11-signers.apk + create mode 100644 src/test/resources/com/android/apksig/v2-only-10-signers.apk + create mode 100644 src/test/resources/com/android/apksig/v2-only-11-signers.apk + +diff --git a/src/main/java/com/android/apksig/ApkVerifier.java b/src/main/java/com/android/apksig/ApkVerifier.java +index 354dfbd..c0cc9c5 100644 +--- a/src/main/java/com/android/apksig/ApkVerifier.java ++++ b/src/main/java/com/android/apksig/ApkVerifier.java +@@ -1198,6 +1198,15 @@ public class ApkVerifier { + } + + private void mergeFrom(ApkSigningBlockUtils.Result source) { ++ if (source == null) { ++ return; ++ } ++ if (source.containsErrors()) { ++ mErrors.addAll(source.getErrors()); ++ } ++ if (source.containsWarnings()) { ++ mWarnings.addAll(source.getWarnings()); ++ } + switch (source.signatureSchemeVersion) { + case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2: + mVerifiedUsingV2Scheme = source.verified; +@@ -1717,6 +1726,16 @@ public class ApkVerifier { + */ + JAR_SIG_NO_SIGNATURES("No JAR signatures"), + ++ /** ++ * APK signature scheme v1 has exceeded the maximum number of jar signers. ++ *
    ++ *
  • Parameter 1: maximum allowed signers ({@code Integer})
  • ++ *
  • Parameter 2: total number of signers ({@code Integer})
  • ++ *
++ */ ++ JAR_SIG_MAX_SIGNATURES_EXCEEDED( ++ "APK Signature Scheme v1 only supports a maximum of %1$d signers, found %2$d"), ++ + /** + * APK does not contain any entries covered by JAR signatures. + */ +@@ -2158,6 +2177,16 @@ public class ApkVerifier { + "APK Signature Scheme v2 signature %1$s indicates the APK is signed using %2$s but " + + "no such signature was found. Signature stripped?"), + ++ /** ++ * APK signature scheme v2 has exceeded the maximum number of signers. ++ *
    ++ *
  • Parameter 1: maximum allowed signers ({@code Integer})
  • ++ *
  • Parameter 2: total number of signers ({@code Integer})
  • ++ *
++ */ ++ V2_SIG_MAX_SIGNATURES_EXCEEDED( ++ "APK Signature Scheme V2 only supports a maximum of %1$d signers, found %2$d"), ++ + /** + * APK Signature Scheme v2 signature contains no signers. + */ +diff --git a/src/main/java/com/android/apksig/Constants.java b/src/main/java/com/android/apksig/Constants.java +index 680c5c3..c771aca 100644 +--- a/src/main/java/com/android/apksig/Constants.java ++++ b/src/main/java/com/android/apksig/Constants.java +@@ -34,6 +34,11 @@ public class Constants { + public static final int VERSION_APK_SIGNATURE_SCHEME_V3 = 3; + public static final int VERSION_APK_SIGNATURE_SCHEME_V4 = 4; + ++ /** ++ * The maximum number of signers supported by the v1 and v2 APK Signature Schemes. ++ */ ++ public static final int MAX_APK_SIGNERS = 10; ++ + public static final String MANIFEST_ENTRY_NAME = V1SchemeConstants.MANIFEST_ENTRY_NAME; + + public static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = +diff --git a/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeSigner.java b/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeSigner.java +index 85301ca..758ddd1 100644 +--- a/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeSigner.java ++++ b/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeSigner.java +@@ -16,6 +16,7 @@ + + package com.android.apksig.internal.apk.v1; + ++import static com.android.apksig.Constants.MAX_APK_SIGNERS; + import static com.android.apksig.internal.pkcs7.AlgorithmIdentifier.getSignerInfoDigestAlgorithmOid; + import static com.android.apksig.internal.pkcs7.AlgorithmIdentifier.getSignerInfoSignatureAlgorithm; + +@@ -246,6 +247,11 @@ public abstract class V1SchemeSigner { + if (signerConfigs.isEmpty()) { + throw new IllegalArgumentException("At least one signer config must be provided"); + } ++ if (signerConfigs.size() > MAX_APK_SIGNERS) { ++ throw new IllegalArgumentException( ++ "APK Signature Scheme v1 only supports a maximum of " + MAX_APK_SIGNERS + ", " ++ + signerConfigs.size() + " provided"); ++ } + OutputManifestFile manifest = + generateManifestFile( + jarEntryDigestAlgorithm, jarEntryDigests, sourceManifestBytes); +diff --git a/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeVerifier.java b/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeVerifier.java +index 6d7e997..d3caeff 100644 +--- a/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeVerifier.java ++++ b/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeVerifier.java +@@ -16,6 +16,7 @@ + + package com.android.apksig.internal.apk.v1; + ++import static com.android.apksig.Constants.MAX_APK_SIGNERS; + import static com.android.apksig.internal.oid.OidConstants.getSigAlgSupportedApiLevels; + import static com.android.apksig.internal.pkcs7.AlgorithmIdentifier.getJcaDigestAlgorithm; + import static com.android.apksig.internal.pkcs7.AlgorithmIdentifier.getJcaSignatureAlgorithm; +@@ -301,6 +302,11 @@ public abstract class V1SchemeVerifier { + result.addError(Issue.JAR_SIG_NO_SIGNATURES); + return; + } ++ if (signers.size() > MAX_APK_SIGNERS) { ++ result.addError(Issue.JAR_SIG_MAX_SIGNATURES_EXCEEDED, MAX_APK_SIGNERS, ++ signers.size()); ++ return; ++ } + + // Verify each signer's signature block file .(RSA|DSA|EC) against the corresponding + // signature file .SF. Any error encountered for any signer terminates verification, to +diff --git a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java +index b69b7d3..06da96c 100644 +--- a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java ++++ b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java +@@ -16,6 +16,7 @@ + + package com.android.apksig.internal.apk.v2; + ++import static com.android.apksig.Constants.MAX_APK_SIGNERS; + import static com.android.apksig.internal.apk.ApkSigningBlockUtils.encodeAsSequenceOfLengthPrefixedElements; + import static com.android.apksig.internal.apk.ApkSigningBlockUtils.encodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes; + import static com.android.apksig.internal.apk.ApkSigningBlockUtils.encodeCertificates; +@@ -28,6 +29,7 @@ import com.android.apksig.internal.apk.SignatureAlgorithm; + import com.android.apksig.internal.util.Pair; + import com.android.apksig.util.DataSource; + import com.android.apksig.util.RunnablesExecutor; ++ + import java.io.IOException; + import java.nio.ByteBuffer; + import java.nio.ByteOrder; +@@ -184,6 +186,12 @@ public abstract class V2SchemeSigner { + // FORMAT: + // * length-prefixed sequence of length-prefixed signer blocks. + ++ if (signerConfigs.size() > MAX_APK_SIGNERS) { ++ throw new IllegalArgumentException( ++ "APK Signature Scheme v2 only supports a maximum of " + MAX_APK_SIGNERS + ", " ++ + signerConfigs.size() + " provided"); ++ } ++ + List signerBlocks = new ArrayList<>(signerConfigs.size()); + if (preservedV2SignerBlocks != null && preservedV2SignerBlocks.size() > 0) { + signerBlocks.addAll(preservedV2SignerBlocks); +diff --git a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java +index f367908..4d6e3e1 100644 +--- a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java ++++ b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java +@@ -16,6 +16,8 @@ + + package com.android.apksig.internal.apk.v2; + ++import static com.android.apksig.Constants.MAX_APK_SIGNERS; ++ + import com.android.apksig.ApkVerifier.Issue; + import com.android.apksig.apk.ApkFormatException; + import com.android.apksig.apk.ApkUtils; +@@ -222,6 +224,9 @@ public abstract class V2SchemeVerifier { + return; + } + } ++ if (signerCount > MAX_APK_SIGNERS) { ++ result.addError(Issue.V2_SIG_MAX_SIGNATURES_EXCEEDED, MAX_APK_SIGNERS, signerCount); ++ } + } + + /** +diff --git a/src/test/java/com/android/apksig/ApkSignerTest.java b/src/test/java/com/android/apksig/ApkSignerTest.java +index d799201..7dcf110 100644 +--- a/src/test/java/com/android/apksig/ApkSignerTest.java ++++ b/src/test/java/com/android/apksig/ApkSignerTest.java +@@ -817,6 +817,106 @@ public class ApkSignerTest { + new ApkSigner.Builder(signers).setV1SigningEnabled(true))); + } + ++ @Test ++ public void testV1SigningAllowedWithMaximumNumberOfSigners() throws Exception { ++ // The APK Signature Scheme v1 supports a maximum of 10 signers; this test verifies a ++ // signing config with the maximum number of signers is allowed to sign the APK. ++ List signers = List.of( ++ getDefaultSignerConfigFromResources("dsa-1024"), ++ getDefaultSignerConfigFromResources("dsa-2048"), ++ getDefaultSignerConfigFromResources("dsa-3072"), ++ getDefaultSignerConfigFromResources("rsa-1024"), ++ getDefaultSignerConfigFromResources("rsa-2048"), ++ getDefaultSignerConfigFromResources("rsa-3072"), ++ getDefaultSignerConfigFromResources("rsa-4096"), ++ getDefaultSignerConfigFromResources("rsa-8192"), ++ getDefaultSignerConfigFromResources("ec-p256"), ++ getDefaultSignerConfigFromResources("ec-p384") ++ ); ++ sign("original.apk", ++ new ApkSigner.Builder(signers) ++ .setV1SigningEnabled(true) ++ .setV2SigningEnabled(false) ++ .setV3SigningEnabled(false) ++ .setV4SigningEnabled(false)); ++ } ++ ++ @Test ++ public void testV1SigningRejectedWithMoreThanMaximumNumberOfSigners() throws Exception { ++ // This test ensures a v1 signing config with more than the maximum supported number ++ // of signers will fail to sign. ++ List signers = List.of( ++ getDefaultSignerConfigFromResources("dsa-1024"), ++ getDefaultSignerConfigFromResources("dsa-2048"), ++ getDefaultSignerConfigFromResources("dsa-3072"), ++ getDefaultSignerConfigFromResources("rsa-1024"), ++ getDefaultSignerConfigFromResources("rsa-2048"), ++ getDefaultSignerConfigFromResources("rsa-3072"), ++ getDefaultSignerConfigFromResources("rsa-4096"), ++ getDefaultSignerConfigFromResources("rsa-8192"), ++ getDefaultSignerConfigFromResources("ec-p256"), ++ getDefaultSignerConfigFromResources("ec-p384"), ++ getDefaultSignerConfigFromResources("ec-p521") ++ ); ++ assertThrows(IllegalArgumentException.class, () -> ++ sign("original.apk", ++ new ApkSigner.Builder(signers) ++ .setV1SigningEnabled(true) ++ .setV2SigningEnabled(false) ++ .setV3SigningEnabled(false) ++ .setV4SigningEnabled(false))); ++ } ++ ++ @Test ++ public void testV2SigningAllowedWithMaximumNumberOfSigners() throws Exception { ++ // The APK Signature Scheme v2 supports a maximum of 10 signers; this test verifies a ++ // signing config with the maximum number of signers is allowed to sign the APK. ++ List signers = List.of( ++ getDefaultSignerConfigFromResources("dsa-1024"), ++ getDefaultSignerConfigFromResources("dsa-2048"), ++ getDefaultSignerConfigFromResources("dsa-3072"), ++ getDefaultSignerConfigFromResources("rsa-1024"), ++ getDefaultSignerConfigFromResources("rsa-2048"), ++ getDefaultSignerConfigFromResources("rsa-3072"), ++ getDefaultSignerConfigFromResources("rsa-4096"), ++ getDefaultSignerConfigFromResources("rsa-8192"), ++ getDefaultSignerConfigFromResources("ec-p256"), ++ getDefaultSignerConfigFromResources("ec-p384") ++ ); ++ sign("original.apk", ++ new ApkSigner.Builder(signers) ++ .setV1SigningEnabled(false) ++ .setV2SigningEnabled(true) ++ .setV3SigningEnabled(false) ++ .setV4SigningEnabled(false)); ++ } ++ ++ @Test ++ public void testV2SigningRejectedWithMoreThanMaximumNumberOfSigners() throws Exception { ++ // This test ensures a v2 signing config with more than the maximum supported number ++ // of signers will fail to sign. ++ List signers = List.of( ++ getDefaultSignerConfigFromResources("dsa-1024"), ++ getDefaultSignerConfigFromResources("dsa-2048"), ++ getDefaultSignerConfigFromResources("dsa-3072"), ++ getDefaultSignerConfigFromResources("rsa-1024"), ++ getDefaultSignerConfigFromResources("rsa-2048"), ++ getDefaultSignerConfigFromResources("rsa-3072"), ++ getDefaultSignerConfigFromResources("rsa-4096"), ++ getDefaultSignerConfigFromResources("rsa-8192"), ++ getDefaultSignerConfigFromResources("ec-p256"), ++ getDefaultSignerConfigFromResources("ec-p384"), ++ getDefaultSignerConfigFromResources("ec-p521") ++ ); ++ assertThrows(IllegalArgumentException.class, () -> ++ sign("original.apk", ++ new ApkSigner.Builder(signers) ++ .setV1SigningEnabled(false) ++ .setV2SigningEnabled(true) ++ .setV3SigningEnabled(false) ++ .setV4SigningEnabled(false))); ++ } ++ + @Test + public void testWeirdZipCompressionMethod() throws Exception { + // Any ZIP compression method other than STORED is treated as DEFLATED by Android. +diff --git a/src/test/java/com/android/apksig/ApkVerifierTest.java b/src/test/java/com/android/apksig/ApkVerifierTest.java +index 9e1a75e..79950dc 100644 +--- a/src/test/java/com/android/apksig/ApkVerifierTest.java ++++ b/src/test/java/com/android/apksig/ApkVerifierTest.java +@@ -244,6 +244,20 @@ public class ApkVerifierTest { + "v1-only-with-dsa-sha256-2.16.840.1.101.3.4.3.2-%s.apk", DSA_KEY_NAMES); + } + ++ @Test ++ public void testV1MaxSupportedSignersAccepted() throws Exception { ++ // The APK Signature Scheme V1 supports a maximum of 10 signers; this test ensures an ++ // APK signed with that many signers successfully verifies. ++ assertVerified(verify("v1-only-10-signers.apk")); ++ } ++ ++ @Test ++ public void testV1MoreThanMaxSupportedSignersRejected() throws Exception { ++ // This test ensure an APK signed with more than the supported number of signers fails ++ // to verify. ++ assertVerificationFailure("v1-only-11-signers.apk", Issue.JAR_SIG_MAX_SIGNATURES_EXCEEDED); ++ } ++ + @Test + public void testV2StrippedRejected() throws Exception { + // APK signed with v1 and v2 schemes, but v2 signature was stripped from the file (by using +@@ -629,6 +643,23 @@ public class ApkVerifierTest { + Issue.V2_SIG_NO_SUPPORTED_SIGNATURES); + } + ++ @Test ++ public void testV2MaxSupportedSignersAccepted() throws Exception { ++ // The APK Signature Scheme v2 supports a maximum of 10 signers; this test ensures an ++ // APK signed with that many signers successfully verifies. ++ assertVerified(verifyForMinSdkVersion("v2-only-10-signers.apk", AndroidSdkVersion.N)); ++ } ++ ++ @Test ++ public void testV2MoreThanMaxSupportedSignersRejected() throws Exception { ++ // This test ensure an APK signed with more than the supported number of signers fails ++ // to verify. ++ assertVerificationFailure( ++ verifyForMinSdkVersion("v2-only-11-signers.apk", AndroidSdkVersion.N), ++ Issue.V2_SIG_MAX_SIGNATURES_EXCEEDED); ++ } ++ ++ + @Test + public void testCorrectCertUsedFromPkcs7SignedDataCertsSet() throws Exception { + // Obtained by prepending the rsa-1024 certificate to the PKCS#7 SignedData certificates set +diff --git a/src/test/resources/com/android/apksig/v1-only-10-signers.apk b/src/test/resources/com/android/apksig/v1-only-10-signers.apk +new file mode 100644 +index 0000000000000000000000000000000000000000..198beeb651079d24338984de7f32e8e0c7b4ff78 +GIT binary patch +literal 18389 +zcmeIabyQr-5-&VB!9s#da0$WP-9mssa0%}2?(P=c-Q9x+_rcwQ1ef3rZ*nxrJ?DJq +ze($fh*6mrnT4wfd*RI{w)m>FR(&7-1Z~y=-0F($h2tN);c|rgH-!c*a5@4-oV_|2l +zqh~{-Wo@JLFaQ960}y`s77X-zFaR!~0#t&2{A&VrzWluoDp5dL5R{RT<&4ao2>2~6 +z3G^+j2?XV20R+^l-C3Pwot2#}1f71Jt(~m|Js&#jx?>4C1G=-iGYBlq^$2VoEC_53 +zt@ZTO00ew%o)K%FW#53-JWD_gf?qp8pg*)hH~66qy4kPoZ*+kZfOUZb03M*K7Qh^! +z3$O-Q0E|E-4XAAi`q%*U06G9WP`?qt7T^Tx*8!C_pwbr9V-D*1^>^RE{@+dnpmzmg +z1wal|etVbS(zo}?1S-Gv|B^soko;Z;l`x2ftpt|MCpo>A}FT?bo@b%1<`2XAce2@R_8U6`h%UVg`{|5gXPozQeiVA>*{dQkMj_=XF +zNgKbpuC;}cuB4W^k-nadEsdj@X_#D-ISM~2cT+N(KS>Xtw@xotFe)sC3HVC_Ar$cE +zuf4#9;5c+rG__Jgc~9 +zjNnItmF|v*EztbP!{M@O@oXf}P3Km^l{7qXMTj1NhYZt2zQ%bReI<yZX7jzat(dIt3q2LBw{RHDL6tCdzd{E$f8q6F0uQl- +zaX|r-Xy%Ll`fY~-?!0-IqAg3qJ5N{>-Etd@HE8o)iZaUTffbX*^7T4_SKGzb5p`*4 +z9~=$dnC-IE5W8qQrAFT^vz2Oj%2Pgc){G=Xpz4wRfXw$Y`PWF>e{xHxbDn +z3>eCk7#2(VDcpr+d*h--rhDO84x#WYj&?Pq#bICpC+b@EpfMW={ZGRd9yDxq +zOtoxmKuShe&oL}U(hxLUdsoc$S&fowqt)cdp8*DS|(Uq1_f%?i|%Ka=kAA%OLMBemAf${9_D7@M?FZ*kG` +z*qrK?=)`WoGtX;@px}YVW6(nG6XIY_>*naNzVJrds)R|7{RtT#7GN_!oQ&V?2GLWE +z;GSL=ZLC`f;uHSa=Uk`*!Wu|wQJl_p?D_bY@A;RBSE9HHJ*xvF76tGKEF#li!vJ@L +z8Tw!ufZ52@huHWnx50Jh{TASV5#$x9rwQ4_>#?TUApG9$%13z2#$sI0qA$?FdE +zX&qM)?{2qae8!4mrpjf04G{O0 +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 +zEdXJvXh3)%(%Z_KU-#u>y8la`VV% +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 +z_DLu*e2MNaKG( +z^lyY{*tuAK7bHYnAR+p}to{cZf03dp%^#&`0whJT|0G43ASt3jhNt~aind{wC|!&u +z$mIWx6rn?J`uF&6lKJO-GscJzl!3*V5NN;DB>;?dKAA$X&_y;P80tY{i4S^a48};z +zS&ae_QZhmjmsLBlGS}=h(lpLuB>t%~Sbu%kDYxA~!~JsJIbG|rY(ExkMCEz8&C$E~ +zx6fnMif;`)o}ViFRY4~fHPF0y`kOdW$NVBrg(;4*$wBK8;+Kkblt)qzk6Bh6G|PN= +zB&9<{S_IPs*21$)ItDdfhV@YbtHpR*k7FeUZ!y2OTq1$%KZS-+B!fC1n!>3c;ys(n +zIq7Q@8~mWB_=q^3XqV&?Uw67U!x(`D%Rs^K{>>FNC2iWN&22d(@UZQb|0%aJ2Jd}S +zq}CiSMQPY6?+~NuKE2^SWKWnESDmGBICyA*j~^~2LT8eVKx2C+nc2@=N{ePks^k8zoO$2(E&OCuKf3xB#8!{ +zCSl?zVI~PSD4oY(!B$lINa|_p>P(sIYDsIq)z)lqCu*?GZ!ukkj6R$u4jG|)yKFw_ +zG`6;s#dtEJ3*<1qdt*HE=p?DEr2B;yQC@Xo?i^@lXFnluo@RzD@z7RmCn(h0HnS{c +zK5~8hFt{teYb}cwZq|0<5HDPQU)4XvsNH&8@*Y?7vjG9TZ3q>92xds%Wi=1H2JS)h +z6i|(AsYBmK@3Q?i5&DF{NDuu9L?!e-oFgBcud)(i0v6UIaR8DHnGZj9G-2oC^?c=? +zszIL}US$3KM1~?0yWM!0xIIprS>*z-XszC&NPj5RZ4jSU-X*{Dd|0K-AFAMs_BM2W +zZYYuJtng+`5tcZK`}IBjvZ1lZ(Pm#qZT-q(>;A&xR;Q~==Sm?DG+GBy{c}VdMI5Fw +zKufYr+Va3Y5w8C`^e@#UqX+epoP6{b%1P7WP+VOmeJ+~X|_X16UG;=XV#OP +zR`le@p^cCGL87gkSa|AY=N#)(g-sp*pbr0IF~rP3|37W`Z?qwv#7Dn8ketGRyrX}~ +z#b0DqU;hVXxC4^a2^f%XK+qjRodxL2^0Y@zADv7@0UE;GSD*(DW#6V9cMgT8;U$tR`S%VgDej*jU2f%PJF)1zA%E24@gtN-kRJ>&O^d +zobCD45vion@NT`CV8$B-ro(Ak|&mWB8`C;aK=Z@^)$Ohg^;4!{sIi +z4koKRZ2eV>rqLaGKKW54<5U_Qcm?#kkhC9JjfPq +zlRX_f{oVb-{2AFm{k;vw;A#N5A_+}dTwhUz+tD!#^_w>~sd0mk)mZr^dFqz~;>N*E +zcIq6pySxxZ50V1+eaDjC1*B4Hygw;4B=CNj_WZGOb>tg#QaRPk#^Ct@=ohs{&_eI=SPP^lEXPR!Cu$$!P1eD +zkFr9$+2>OukEav|>bLZ}=Jf;eE_Iv(r*RsL>MY%wH`t09=~QZEM;5&5`Hm-R7yG@5 +z`?+E1Zo(w2<;(wmYe;Yf&^`zmR1mw941mz!W%YU#DQ~_-{jed-s$OXktrNBg2 +zQ(KFG9B5*wuW4#(XsB&$u8l+^8s#5fqC@UCVc2Y6O|<11+s=-44KogAR_t{H3S#9+tgwTzq2t +zqvMgiq-p035fPSh`pg>k4YzxIk6lhqMODvku^$Ru%u+Nt0*s=cOKBbTJGAXx2ixDY +zP^sH{TsIQ$I6QK+m_N4(VMRw%&Ck!z@#rnG%i`=s)#z!#lSN+~d(Twcq1mk{h7^Xd +zHTTNN4+Y6lx!m2-!>HN0*2!@yLMj3dh2gm}IfMGwfxtQSv4hwy0$SaQgOJD-=*|z6?Iz +zNyjb&BW99PUGXkb8j9&NR}(vz`&;|uWSn#wQrE35GDIK7q?W@HvuAJ1ZmR9{xjbwg +zHN!*j`uBxa7g<{NfGt63ULm?L!E* +z!4k!WC6cAO2W2f&R!w`Yd(`Jbfld6L2I^!7eZ^&`LdX65i!3yc7I>DTjRE=Na~t48 +z<>NLPG%$>I3XbgXOc_T#C#TxHnld8E>i$w??{lZeIwg7Ez2m`@jrn>_&CVuc-BEQ> +zigArOFdNuPEh&zejM?I~1ALJni-1~@r%;3Il@cvIK_`wv?DNF}`tqUhfq!en$~4_- +zRZHi-`_oP?x)E7^8(WKQI#$sau8Fq`yc?U~QELt81J8`$eWTSEB(z+5HWM(8Gk4oX +zJAEWfkX$z-rdVt53(plxU1YDYm%)e2lRaWscx1&K`v=!`Uev4+J-or|pIzd@ML~M?3UiBWzH+2S +zOx#ogWqETr!Af}MDB$8`nWCIkt!(Jdalm}3ClAe-^u>sK8rL@cdi&Ak%{!Xu=sXis +z*$Zx>N2@V4?#tX%cv2kwT}X?MH%!N!-O_nIb9)g=D&4)tGa`jhs)NlSkF+Dfe=|EX +z(Xs!}9Qd#HSy}oaY#gAF{XkIukJ?B8`pPsInNCC3=3^sT#2nF +z42?{1>@G4$3$le_jTMW-U&BtJ7mnKXa_knp$}%je@n<%bi^&2`56@@Fuifno0rwy5 +zZ?9=^n +z77i75#;?czq=qN3J!8zd(O>D_#QM1sf?*)bRnuK-5V-99c_eT?Bb#S+oi +zW;Erlep78mTpK1Qt`^2frV*LTAqi}R!5Vt#K;ckhs8FGGFv)-uJNzOXZ?;UZ#qxv? +zocHX#>*%bOa&A+~4v#l&=2}?J>HbhMwxFf)8o{RV(&|gGCxVIk-X}w!p=acaRrfLz +zje4-k6(WV{gU9A)gI|cEHkYTl9x)$973xRWNwkzDG0dBNnS8}a5i}R7zl&g*(mmIRYXKG9O+$j6IYun=ZS +zWj7)`^rHuUk$z`o7#OL>Ht~x@gYjybtyO*-pJh!t-P(KiCg3YiWYRI}i?r)sEiMNp +zlB#ei+P$6vpgFknI3R$zsXi2ioko^kTL%?$T8z9^F$u=rGCex+e>3A$aZ#C~qdFj^ +z7-Ld6zb^VR_kog)O}t8@t9pr2B-_mt_%%XFt9b3)LZ$9w*BtLrMHAq35b?D!h*%;V3xg +zD74&sNcaa50{GYPbr|mR(#6;OjlQh+qas$Pp@mJX1t(@D(0x8t8%OY6ZBL{&7{#_lM +zxGd4z%<-*ie3y=M;nooRGc3vpDbQ?SyQ-olN-+y!R@$j>)6`$=BK4l=(zL@h3mSTf+>+W +zn6@z&+?SYVeyno!g^!3KRznxn+wed52!@72ZgOoIuA|9_jJ+y`%4OzZd-^~+_MVHk +zw&aVcN!hW|GxN^;phUMFl^iCwUF@;8N|Oc`M)$di}UD=w*VO<|H>bC?Vvc?-j-Fa@4b=HbnYTtK#6V|cp +z8|6Hd4er{_zaVu;KTWS%R6^6c37JcRjL)`GM6P4G3BG$zm!;*LYH5*FgO;u(7bj25 +z!?P9ZMSUJAtH$v_tT0$h;$`xsk#LWT+C0;TlDGmJ)tihO{rFGu3G7TStKNz9ol3B2>j +zYU>V#fh%c!ebAU-o6MI%)zXYbI)pY?IJ*&$9b-6i_XD5@JsB$XR;Y!RDM_GL9|D79~WK(%)rw*xD2u9){B5YYmr*erTT)yIjG>lddNfB +zJbhV76KGCj+oLQZ=C?Q)OcV(5DQjHuyjOmL7msnFw~lkksn`FVEEco1F>shS?LOY& +z(xlajIVIX|;Bt#j=lRham=n8fGY68L +z6VoI-YTC+OPiO~@a2-OLneHCzFoD$hfKob%a#hTiF#fuNcv3$R1Ruu_Y3L@sA4o-# +zDiL~E5J;T`^$KHxs+fYY$kXy|IJV9??wyYATU`ztF5U5k_=zG_ZKKUT_{jj^)L%bS +z^?#`i&Ib5A8i{HhB2|UR2mQ>F4*^>24h9mA;xmU3m?9zEVm-1igyj|bEPO8DA>2LY +z2xD21fS|HJy4}oY^z|qd*qh*V_B|8N0Er8}S0^%TIaK|Px=`&*>?@5;fDbZr+EV1Y)=BQ6%yAsLx5QoCzY0HFquez&9oahEoomIj +zPreA1Z3Je3FMi1n=w(?9jUe`BA0{$8Q3h{_1M1-K(mJ9X;;?_dCrVh6;k)Ow3(5B; +zOfByYgX)Hc-_#@b!b}xpSyxbbE1IMpy3>{}|HgHH{)ludE3PPN4pTlf`7nlri0P$i^J-2NUfmtIJM#TJc*zrdpO3FLLv-)mOd)=SGR+1p1Np2s;|*a?kmf}dy{o5ySpWgWz?7)w9j +z^T=v?^3y_h3KIfUf(BoF2$D8{F0wWj`-pfg`wf-H&BdXu;h9C=-AgA4nh(>wxnDS~W(xf`i&7mX@brTki^n@S +zqnjNl-{9DU3)P5gyM~$o(dxfe+T(@#if-uyFit}?x}A_U5O2aja#%k@FXKAGd9B(V +z&DI5BFqhCyNi!8L)+x@8;ajx0_aQ7lm^P`(#!Nv5&wy*kZl8@iYL?*a4IUy23CXe` +zRce-{lH9G2=!%YDH&jk!s@m#Y@4`|K+SEx)&_Ds|ImdLLJaqrC6~+Vynw7LDV|)-I +z*WKq=T@%Bi`mYZQc8p+g%YVQEO?2z}YIGauj5(-+oumR7za +zO)Ov@*F}*oK1t*c6RRhTMrwrDA*OH7o^Ss$Gi^rv3Po~G7#B*y_|uaKPt#czEjFpt +z&3&~IJncPR6UEAkY30eN`Yh&80twDWAv2Lb;+G3!g@@#{dA=r)K$-?-`Nx| +z4CG$C(bsvxx1mYAE@y8l+3#BKoej88Zd^CzfXcZLtaaalUE%0|WDd;$JW)-oAK60; +zmscMF16Hi%b3Z2W6M*>~uSgzUAchKwJFMPSsLLPa&+lic{G*bhD{{NDox^DBfM28o^lm7%#kf7*`5kpoXpDb0Hw? +z#V)?1j|?=sD_uVkUI}v3t+A)$;vJLqdUGH9}iNWs00w&~R=-7F)5AV5!pp +zP{JxswSB^;lpSVhgV{Y-E;xb|nOgBRH>HiiNoP3rc2Mx^!*HiiXQzPs9@i16Q)oyw +zLNdxG-M7tH%hh`rNkX+T6oPz<_^^+B7Sxi)RRLaMFT@Uotw+?l2d= +zT4;O2>bxg-h=Gde0qRGUDKus_dJhWrc?a^g|DZA@`QM6(2+PXRNQ&qUNs9aO0X$cm +zK6`vsqH-^7Y!rauWieJ}Mx<`)`Ygdxz{tRuw@^Mp^m29&{wNyYy@HHk?1$MKa}`{O +zRfS3q3F&R@_<)qA-#i~49K;vusopSvY3Q6I6cZK$R_Q)dMIugt8Cebq$q=k{LTNHM +zIyk^?mso*+!TDGUu?AW_c3OBTz(>JF#^#RE0VLJf< +zd^SU%LeoEiI&%vIW9J=Fr$!>FE7jKVb!y>~bN=wjH3TV5RWkCC7;DW|dpH=pCt2K% +z_u1w3x*JJeg7?sVFgm%{q50dLmjl@^#-1;VET{NOEk)db*aZd-2l)FxX8`f;yY!!b +z)$r|lR1jRGNyIqF%JZKH{~tvBI1n6gzk~QQ`0i&KevUNz +zlZKWTe*qvY_%p!Yzl$dP{{;9Jy7V)`&v80`k^oNlR|x-1!;f6RBmN2D*VvAqN%%RC +z;ZG8DN&W)hzoB4&>?eRzm_Vu=2)5dJG7*x7%A_#46edGGQk +w5uTv`>G**YzwcyzevY42;-3(veBVKQry!-pp+HkF0DuYlkbr8*{NGyt2buzz&Hw-a + +literal 0 +HcmV?d00001 + +diff --git a/src/test/resources/com/android/apksig/v1-only-11-signers.apk b/src/test/resources/com/android/apksig/v1-only-11-signers.apk +new file mode 100644 +index 0000000000000000000000000000000000000000..95e6c61e2f6f1b75c0941c21a8e728d60821894a +GIT binary patch +literal 22297 +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 +z6G!97 +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 +z+bS*?E$ow+nNbavl}Pi5M8K1cC5&#J;?k +zF?e0C_lp%r>PGzzA0q3Xr@ksPusTeJi92GoSyU{I7H!s96&Vhvxewt`E4t=)U5}`h +z27njr=yB=NgoI9I4~pg%h~sCXkU+4zN1$W5ih*-M@i(fxDdCe|8;8!Pj3 +zv#H14cXq=$lrnVty+`WX6n*xM6YmDLJ&mCxqZ>Mm?$!Ep=8y`aEhPo*PVZORGergQ +zLAh*&Y7VqfCkeFc3ze%Dg`}1(oAo)%UeLBx4?rBjfALDmNJslWb@+GGq4Sq_p9=wU +z3ISLj{kIwK2N!>lRYToBXv2dlzyhc%V0D1s15}e~)Q{kmxo_?8juZS?#SpTFzPDa(b +z_UZm{9;wv1@!|IQ`SJ1T`SE^IvDCTl`S#9n?7^O*e4AQtAT0KI6=ESKr4u1k2!q{T +zCcwf)_rqWq<{o$hYU=#=or#@D`J<4R%Oi!;EAce>fE6#X|=V)UO4YM|N +z80kLI_#ML(WGXCJV5YP8R7^Q=NZVV_|2y{Y1VQKY`*zvW(cOYovY;87=S+?~gqe%sxo1+2W +z#->I<$^XPPqRvECF8QeX(@Vw(iw6C5qq3%){PH!r(b(DWbKyC0aNQ^;r_-20HrT5& +zF^P~ye&>#s(e@38zNp$W*>d@O!4|iZbej51`m;J1yg%Km2FY}*sg?ob(s}GCeHDeD +z208`m8Ei!5J)xsv$K*+Zkv|M3lO~NZ2aE(B#KpWWG%KDqA+8EoC0#j#BL+h)=(9cb +z$n>jA()5QE%A>)E9cI=hi}mXfN%ECEP1}p?;Zv8e4U?obCHk~B*W@kW*GeQT;wASj +zrib3<;#`x-Z7-t3(JJsH>@>!jBGj>s23kG2G0GrrlJM>A!x1*Eb(e|Wr5(L`KDUN4 +zuft5p8GldgsoWLm>8Al_Ep*g#S691L&|JuPa(2VA#W(+9e)z+So*W>6;(yDRe>Z@F +z<4waeAz=CP3n2f&!Tc{a0xAHj)8vl<6uE!^iroJgK%oT)pvVBI^tWjLoFlH1Ft?Wt +zke}fvAr<@k;igH +zj%QzyLl%1E==KfwvMXt)uDs=t2VAuO@kBXDjN}0RC +zJW5XMO0}>kAI6nQ)n2l(yu!Uzgya<-PN>Jq#}ftTNWjY3JvAsP%G>6j(FyzdzeFc= +zC)tO9A5t2sL${2|Ef3G5780ab;l7PlGK``@Fl#UMg3RGb^q=uciaO_3^P}_iNj`TS +z9J7#=?oM!()>6)xyPG<=J>EMeA!eu1lD=~On#wz*wSL$QqenAIjrN^pJCdTjPo?5MA7TJqv@eIo|3f^;D9_!5F?wDNJ= +z8s1vdle~r@tGc7cBWk^nZx^SxfilI(P8r^d)k(TF1v`0iLi+`bgP@a~P-m}l5*=;%H7 +zv>)W6nh@u=v9#D{U=;0eOi3+qZ|{OcZ8o3|zB7UGi_u(?&~feEO+-7-JnRte@|7@y +zciWAaVXk>DyjK3^Du0K$3Nlib;u*`tB`@kcFx1Ac@)#oMoB#UwmW1lcY$0Emb9!Oc +z(Q@;#^ay+p=fK$Z%b5xbv+!YDt1I8~P4y=Ji`a*O`4tXqBzQ71^gZImim_@@adQcz +z)!mUq8^O7=z?+NJk7djnrNd9ogO)43c_^kt@5emSIreF{I?iq%WT|Fj^32TTZ#eN^ +zZ6-80Z*$XNh_DO~!K~^Z7|y$TWb%3!jv`dldiqS~gbKmchnfM)($2X5&FsuT!}>pu +z;NLQ}vJ695*Z^_+UjX^vX6Ikn2$-EMVqIvKg0On+++-bc-WeSk7uvbH5!g%_o0wra +z+(}u=m(H +zb~(y^#&HS!5x=4{i;aPNF&Rt&tT*S&6PTQUkB$r}Ca@S(NaIw=*HvpE2oxVL-B+kg +z3FvY-IUryWZ+HDp9T{{9OmBEVxUW9B +zjnC_-<~F4saQRSYZieMt9uKEr@>`p3;_jNRY>BT5h +ziWH;`o>-g@elLvNT$b*3#&{N0Xc*xj(NdaBw`j35O-BDQXd%>a6<$D%DUZ-b{#%cn +zCa%XTJ<=HBGh^?oh)GzdjT4&gP;OPiHK#DnYxIZ%dvNM}6l)K&#j$0R%Cymw*XrKu +zB9jIBWNi!w%agwyHzH1}j4lUV^~obgGk@Fecw7#VWxB0zjPxYJ`SKnVsD(=DgAf<( +z_=$g{|5Yg(TAHa{!ZQ9)f`)c$rT_N2yjhofN8iyDOvQy<23lQ_ZXMb3>X#%UH4bG5 +zkr^NqCl4+sSYUVcm!h!C$Zz+yLB;G=V^V5n!I*pIXBPotb1vmK6{&jagVM^eW`&De +z!lbz`GobEA;@RK!!0fjulFkJLi+ +zZxd%b3fMZA$eJ&f@4Ib3di0Q(F5*KUc-mA#^ftV=QZD?cd7{Xi{;!Tk_(qOHQL!Ij=4Nd(Ffo;d{?biqCsY9mI-xN3=k&~% +zkX$>WmN&qmEDCGXl$IH^?Ji2@a6~&@C7025NRb|&rgE6KCQJsbf$?oWOdua1+GSm}B7bx2zkdkpT=k3kJe&>U +z*2B9beM&n^t6o$>)wc_lONfBOvQ|W*XT1w@_)L?f^Eu7hD!CdZLq{QAk${V9FV36t +zI#OPP?S(*TsD{wnY^M?Lh=bBH)0do}9241xm=g8;R08F&^;_Z*W{B#LLblgl*CCNv +zg^)E`qrPFyz5b&tC7(lnVpm`}5N}aji$iRiQk5gM-WfH74V#MSXNqKyt}~mxrw<=H +zy4G@MJipvoMZa)&0YSssa_>$aw-`xSU2jBAAXPY3;XsyQHZM~p9TLL5bOa|IedS&j +z#ad4)(P_JKO^rc%Nky3`eHpyu9S%;=43Ykr0C{CBkvL!$ohMdpLkwqn8v%YBKMv2^Y~FgHvNom+M$Woig!$y95hg)#3-lkl~ddJ(0;NrtBX&R=J-|!43lKJ +za{AT1xJ+iHd=;|tOIK(>PiO2-W}|;~J9TBEersyh1?f&QVp=6jIh))CBP^p81h=&w3PBgDUQr(>jB|hn54Jf*kn?pW}-JLXG|1 +zFg-*r=Pi+%Myy*zqbQRm{V +zH=BLEA5M|Aj35U5irrt#x?=AQ%?v=a8iz7UeH&{PE7B;KDEsgPgwh +z)EnA~C0GlaZlQm~Jc28IJ*bjFs9G7j6UJLxkU-=w1ncV@osMeO7fmFTTmjq51WWXp +z-=HuysFEQVgCsrQj&1Ln?b+q*xz+Ww;no93fEPbf-9E-5+FuR`T2thmdH|^|2n*2q +zcqFoIh;$_!55zlb9#{y`CrB{pkLzp#z{+^g%XJ8Tpw@S&^DwzUFX0}sXK1U+xVRMq +zF&!4Z<09kWz+%A}tVd>Eff6@7WEXNQdQcI48xl5P*)1O~_{U)^gEd@8CbyU!I}h#3AthXhb6L$o`qyUVlxv +z&z0g}>R4rB3S@|p-Tq^)Tdm{~(gNG5M@#(8Gg;N$CR5;`Nq+& +zAj>=XfqhKNp%DZ=tRwgq7pfo)@uPY;ht$qUr&z4(&-jUJay-xM4k7tIcxh!lVcAtmM)wQi27+BkFgDwFsHGfdSR(2@F)ZDnMhl4@ +zb{0x0~Ct0+AB +z3a{z$_kia_rfF;}^ewIQqRd>h1PvA-U$f2jD?$v6*q}|Zq1ea>(Wfgze9kpR1Rmr7f)K`c@%JlvKbtsgER6 +ze38T(CR&FV1K$XvM?l+=z1XocH)}yah9tQlhz%}b+WuzB%Y2?mhebMV_gG`>gYFTx +znQ}$>tm<@BT^3_IU*czz5D31qUU5af+LSIcK?8=G0h(`}l$D6HvUbHwgSj_ihI(&! +zwzUbi6dcVZ2i)p>vVopc8n?{Zz;kZ+YdrR#*4PGK8AHDUy-`o98#{svSJWH>9xdO@ +z=X_1(#Rc{~Uz0q$feRH7ciMO=*Hk>qUp&sz#Lf#e0Mne}RnsvlKQ4jGZr^mzM2S~) +z;HoN_&F4x~Y^`I1bGNH|$@rq_S$w!LGlsTVpCGt#8vhNZKm$|F_l8fD$(Y;98Koezjfg#&~xBRT^zAio@(R&cpE*2FLddKW&1Z&Ua6ag+58;GZxfCwF!Mj +z>|)OoVS8Cm{4@O)B&r9j6sym34T%K?Rj_Rl6{!lMK_j_|SuDjS{NG##M!2Dg;LmAy6udaFW{@U37(G?gs^noQAuEes&3b?sXfJzJvf{!6PPb(wAz+ +zSgkrjOBSe!{m9R=j05$`V?`-xS{dja_FnW<&~{9tTQSzOqDG?Ven_sj)rLr}T34go +zNAyLe$kszLn&(g4ff5rO?}o9o`- +zVLA%@7x4c=WwOw+{x8b+Z<+Zf8nsV6Z~!wOkpIoh|Amb|RA#&j1F|_*;0QVrZAc~I +zkV;iAtnRTYU!{SlBc>{!BN^Rlg&)3almU8{x#&UysUd}b0G-|%37%^2=$z}Q(`a4l +z?bx12>6-g#o5vpCCN8ZuY9UKk{d=f&WP}J`KU|wgAY33XA3Qv5)C3m(b_*c{g!XPP +z{pYt(?OTZvku1BMgzyZ$MqnUbJg5N?JO&)9uy3E)Z>74 +z1x6<;T-S%2$kmyzo1SxQQ9$tLbe!NOwev-lf#9k?ru%9{100RtbzPZMT!rO`Q%+>- +z!@!3~f&<~|4D+^@!@9Ms;@f*{RB6)4w_48%7IB{bwUolEM{CY(I%30@dsXoXb?IA} +z>)*KN2vaD->{4A<)4A*3x9RK~shwTs*5>-OY{lQ>?P@3t!5c+JD|l>!FIKH*C-8@G +zLPYqJ$)j9zo}7!l!u6@QHf^Jaoi3Je +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 + +literal 0 +HcmV?d00001 + +diff --git a/src/test/resources/com/android/apksig/v2-only-10-signers.apk b/src/test/resources/com/android/apksig/v2-only-10-signers.apk +new file mode 100644 +index 0000000000000000000000000000000000000000..ad34c14ced8a53dd4c5cbe18a147de6e99264bda +GIT binary patch +literal 20688 +zcmeHv1z1(hy8kXxK)NJ0-MHy)6r>SQxq#^Uh*a4$J?+osI*7*$H{h+hHD-qrq+LhCl1-G{| +zgS)ud!(A+#%*^yaaPbAdm<7Lzi-8vW%76m=TLm!aPi5c+Kb3)-eJfu)7X%J|4grCD +zflDKh9mo{q1hNNN0y#TSb^!jIL1rKmkSkDc3335>0QDw7?hNEEK#d(x^R3;*VE?xh +z9GEMB6(DsWznII5bTOaYKz>pGH347He!m8C6o6nbBNrDZ5Hhl}i<70@ov(dZf%@-b +zTwK6`^7n*_YUJQxU}t1&28;{A24MqVd~bVE#s|t5_q(WrUE~l2kRgzNuTuf8`2qT` +zrmw&TIs^GvnEuuHW_Fqq|LT2y9RK1s{MGnIPMVVc&iEHRQ32!?AB2i}abGIIA4j{8 +zHVHdZCwog%MI$>)b2Dcbc6VEwDD@^gJPCY}rZoN#+HUaxlOEx4d{icD2qRn?4}vS} +z50OR}G)Xr!N>6Nwet?dSPK56bA~5J6Qc+deBWLn+-X3}$U(H6m;oh_I)@#eeoSZ5~ +z0t;28D;c%O@QJ9P*E@Th;jnuqpB236qQmB-IY1QHD9;%dgm&YPu94vcV?U9bq0z@h +zdG2>~{S@#d~~~I#BeUY2Cdr$wO4fG-K=|TfMS-HFe(p2jgUK!S*|( +zwkOTh)611iPPe>5ny^fs?%V95>2_XO&y#f^;_>mch_xJT9lH17xTkjO^_gmY99 +z{h1Zb(-9lAW8|}S?W98_GGV) +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 +zHb)ceoaJ*xUO6e3FQ;hU{o-@RnK9|Z)TV>R> +zj?HqYxC~y!W+hH85Bunlzt&Cos@tb%Q##{>o231zNN;>O-6xrpnLc#!c6SRKg@Ehp +z*eF|xb%^y#ll}HFr)hg~&bx)!hBiSM%1FGiZ$lPJdbo0`MtkW|c;I6rV_Ec;60V{s +zP47hf=mKAN6n=zMHx!8FPtiz?d=yIHi$zDR6h_ZBZhD&)e&0(<9Cv#-jA=;c5tWp` +z=UoG{AzvF3m*J%{J(>8LD+@U%uJL@mZoMB`Oe?xWd+|N9`6RRvi<|Pnopt+HlaIy( +zK6a!r_q8zL9aBbpn(GzJ(yQ`sj46*;k3c7VRn*gR?Xx*IJJreH;hHSku?<O~h +z%b4ycU6q*Gb~EeU7eWkWPGDFO6+3%620xoA>O6-nt*%tty<)SIg~Vx3SYm71vmh=&5QxPhB5p^?sBSQ3TMv*T07B4T3(UFJ#H%>W>?NY=KPcaOS~?kTAu>)aE5yR +zs(F;%Qgo)b=hIhu;+It4<$Gdd()eb-%L?Kx*%uCrWG*GSD}}tv?p=@Lx3QA1A3qvM +zdZ3u}M)2dzUFh2T{e87;QfI>C$qM7z#OsXWjKr?nHf8l6_ufz-TtEUiD4%iLW&`F% +z_e!up%@PV}boTUfH9YeYtU?cm#C839tX17WlQ8(}Nt_^ymID*42sux6!(~Of +zG%os{{JG(FxGCpqE8w?%O}}#Hocz&o-N+*2mp{F1x!ag^H++h5+-Q=^h__&bDW7>T +z83MQSIlU}S!U&=H)IG&Ce>6J#yxziKiz2mx7FxxrT$x~|5ob1mHPj6 +zrEUf6DpUcX)&F#+fifIWpZ{z}!UgE#@GT^31B7L9zB|)>m+KWjo3A(_(2-Fub|ge# +zPzVB-0~>+$ZA${h%!JJW@RomYrn!0e5kEN7--^HNqlLix7LyZ!fd4i;6pR9u1i=an +za73v4Z{WoSqLguLv1F~`MYtQ3neo0<${C6st!;gmP=_%SO_-@(DEN?K=j1MD3f(i5 +z$esWf6zG(6?c~NEY}+^(XSFZ +za?7fzHYz8Y*wg^S$D=lvy>qEm_h+3~%_iudPffC!7>s1B+;qlC$bXxgr*kpX{~VjG +zfv2thFQCm8=;QbeZMFc~@V=uhOrwQ-w5Epc{|RmU2tE!j4nA%Uo{KOr=S30mw;}?c +z0~dk)4WVd%L#P4gUoe7Pp%3O%p1dXeVH>kp#JEF-5jXtsdcf+ +za*)yFrDldJ#suW$YzwW%&_VcJKQhlp($s&9i+RMoVS%8YN=F!-*kU +z#2GC|<_)CW_h;Flf-j`Z)tNgP035!iU%-tD)YmxI>-}m*ElWPRQ?c8$^ZI1f+$Y09$ysE)>(=Nzk8H+e6V9}E)qZB#yV|R)-d+>TxwE9!6Xaf?h(z8S+ +z-I-^Fi~00htmvPFD7;}nmzNqv(O-{h49Y7agFb8skDFnfG5*OISQWMF2>CHoR6pJq}wqa6> +zMeSwJ(`upJt~;$5{J1fC?v&LRu +z&dClVEFw`uk|9goez2t!kq@7qf+oF*p!>z0{y$A&3Lplz{|Ch2Gav$o-^Ab}AO`B+ +z#o)tj7oDqVcd3661K6J+&BMv@gAc&N#lgw>qZnKif7!=B?N4$*1N9F9UUN6{^{8eX +z#zD{Ot=eB0Q}3&EI={^7(WsPvl6s0(z3PKZFtteHx^Kic$=rH92qWwTtdO?`K8AR& +zg>(hBe`}r|%&M04Dv@D)#E4Plh#PdJ;H&k{D!gA+c*HCzoum1GajG| +zfr=STSWb;fYt998g%!{5%$`YZ1Q1>~ +z;36QbU}vYkIwKeyCxe=x2yT&0$eLlwNpwdP9gv_hT1chQ+BwFy$qALt&*d91c=6r# +zJlb1uG_){6iUW_xS?D&nN5~n2C~*<>`?yL~(A_sXn5B1J%HwtE&IgCMG>1m#-9i~& +z6y#7x>kN{5zR!-V;SYZ>QXQI!fB*6mMljVUoHMFLR-LMi9tbdn;6Eq=A_$u^wl9C0 +z0Pcnr)njmo7Av{^Pm17|4SrSxKTjyYbKo|IrpNUGOGJh8$rZkK{>PG^(^gP=6XZcx%-s<|^W?~1pXPtj2MIUK9VS7ZEfEzG8$S--km +z^2FMMvGjOix){XPdk6CDoPf(}#t~IYMXGYj%vICX@0xE8PM;(6h|4zUaig`z%o@#;skPbaU`oV^a_6WN*sRNExTQxJD2=Y +zCjxFpO^+H9ByivNEh{7Bbh=^PI}`wQ1^cxQULMw1W_cuam^!yC?)PzN2X}Z+`4VC7 +zNes!(3TvwFiTxA44}9^S-p@bFZN|JC0|f^Wj<#hqdEpK2Lg@h>0P^@-PXDQ#rlEmA +zdVmW4zCwTjoD&B?^zW_^0Idi*`xYq%)HCEi)pM9*Ia}T+iUoi}bB##keYBehtNSI_v +zX}8Y6xTc+i^FoSZbdhZRwjc2#tH4(hQo~yzN2yf|-6!$g_O*cr!GeBrgn^n%tA-AI +zt0^y$B#K@iJR!1pU4`Q}{?fPPv$0=B%P~TK+vR$w!yKHD+@o!ILf=xqtOHAHb*1Am +zKjQr&Dc9|KxDOU4KS8TL#mbwLK|RJ1#z+z2hmxjUh`Im)f5wy3p!v(WuWFWFnXVh9 +z(x`H)#p_VVz8#U(>>^mg;`;2H?TsQXLIo0>YMTO2(mACud`kT50^G|w?#HH +zH0%s=uB$djAGY|+x1F88oGw0k3F)1C#Cl3mxJOYN$TUwCP;9*?2Cc)IL^0_#^{4Nh +zJBRA+-b)ai9qyAk&HUuN5Ezh2v8IH1kPH*6SANK4B|VxM$T?SiEsdi#fChuXyZdnv +z6G<#O{vC&4xu@wMX6ypS<0;z&O`XACnWy8k4c8Nz$1M0oFP9^g$UaL78=C!Oo_^Wj +zugwzxHJcR|n}R8K6Ps|yn@&m$;Z&U=GJzi~Y#uG?LtFYW5*;9Y$Ffz#N#^orlywZ4 +z!6X&tAFY}f^{TUVt-wuOr|a#}!Oz|kx7~~zZIxf0nQ6g|lgh{C>D`7AD8_^&&0K1` +zI;rTJg)LkU31mh-qkLJKu^wKEyIr;rn7E0DV|eAAZ%yCA=%e?7stGG!u(E@45&1-{ +z=n4p?^7@T}iqhFZ=shBP4Gg@88E#(;U}cL}Yqz0oYIdzK7jF}r$a^KyVIwSM# +zM_poGc(=V3i`RtwjTfVbjE7d3xi;#l!^PU0--qzMOd}1!bGh}b +zBC$2L{tdrdkhqXA4?2Y0*XaOp2QPcVyoG1Qs9!ok7v}vaDugT!a}6zSB9^fiB=h7X +zZ#-=F30G9Ed>N_of}y{H|0#9dkXmaPc{D=aZoP|#fKO5m@72uZ#^ob@uVwqw(1!vg +zX^%1H*GwOB7aI{#@37tAX4ESR8MA=FyNkYW}q(XVSHaafYtlsC+x3`9Nk*P-7` +z+YJ=3t(>7NIt&tk>c(NE)`&0l(lYAT^k2F;@*ZxxM|CT4Tfrj#-EEyUfmeNUyC>2nhoov26m*0vOsu{p)WUq^%?AcRK*v@*yYv89m!)ki2 +zZ#7P08Mf#OER;UfMA*JJB4R1Dv9z9jjYYY}fzTDEeS9dvu%oAM+!>n2K6G2V`0)bH +z)yS#s!8Sa;PS>kOTf=l3Ihff_RCDxQVY0P&kHjx=1<*g;bIFFi>EIH`O_knQyGF_1AlKv<&Ik` +zg%vE#OtwXyw_xPuP)p#qwlNZ +zInq1J1pO#R|IGdR!|PrG9Kfd3-&e=qihpvyzP;`R&iQfhZ>!^&3vWF9>q{)@0h>z$ +z)Dv3ox!ShuLy>|nhj-B3s(f_Q1RCZ%dnD4)>)r97_Oh?`9&5OKi~IZCYp3#;3j&JP +zTIu%9WPEBL)6v(K^ +zgy9=(wJU0w7%qUh{iNRUNz-03G__LZZZJXUzRE*+!pu--)4!~YY~jqs_t37U#W8Wd +zXw0nJYKoEpdEh8>p|7Bj&G)&kV$l*+<{h$^hj*oInUmFziZ=1zv_wg9DLA2TBH0E_ +zT*JS$MnGGYx`|uU&|I?hp4pwAoD0vO#T+clx@OuxM)PES)eTY%&D43Zgm?N0PIRl8 +zxS==HkcowGblFD7{@|$ih7ZZF+@I>Q*45|A=0}b;VLW9uZwt@Wo;?1^{rP2szjl9s +z_m!ykG;Ue@)%A}YfaJ}p%$t&8rkWD9KC-^he!FdQwjYt9)^`@lE=k#05-}Ki)KwPY +z&>3uSl?0o&N6E1bgWQm}!ZoLPnL%E=!EeaZYc%R?m-z(|U(zc{(OpJDN9kJ=2C2w5 +zNc1>h_3HQ@!_gY$s==ds3Eqd4eaRS&mO1wX+LL5Ig^fgw^{RH*&j!{V>W56)?fL~) +z!uBi!dRjsi#Z@*KY*BYjY_2?acyPN-bA|+-VIW0@5=LF!@+!W;L{pXNiOhYNI3sP+ +z69x-~`gp_ya|Uu020=x4o!#g&xu>%Mqs%DFk9%A{hA%8k+FQ}yc~}#A+Nb8>aldNx +znU`B`49cm=+o#|viq8$99+9$UCgNI$UU$i@C+V$=63=cpmIey6XZH}3-@l_PaOVLC +z=g?t-I$Yi0ar?`5);Dbw(lU(Oj6~PN>p(V7SR%IB4)q)T%MRN$l^03KE{8s4k0{o> +zTMFu^NbkC?Q57B2mv;OJ3`w@CUmuvs37IN~sgM>jk +zpO@+>CAWrJ$!UA#jX1NA*;`(AIgUMxPI+idVRZaa#;WC9WRPjer74Gz`i6g} +zUDc5CVSfr+>&WV5F_7=0?#(iB9ff9MO|MsP6e8#H4#{JkDhgJI-|`6GLqB_2%0mAj +z#k#5-F|$+ehZK<|~eTZR)Wf +zMqCxrYiC7u=o2J;Q2@*VpbvlR$^Z3wk_3oiTqHL$C&_PDzdwI-;5P?;bKo}zzH;FE +z|M^R($ivkv@4zK(>`koU+?*=%UP>i?gBrp6&quN%O-=Q7ZCCK*hzeZcxzEi;Ih+;z0iaoSo#C + +literal 0 +HcmV?d00001 + +diff --git a/src/test/resources/com/android/apksig/v2-only-11-signers.apk b/src/test/resources/com/android/apksig/v2-only-11-signers.apk +new file mode 100644 +index 0000000000000000000000000000000000000000..674b6e4d7d67810c70aaf4255db90b710bf37d23 +GIT binary patch +literal 24784 +zcmeHw1z1(h*6`ubNOyPVp&Lm-T0-dt>F!P`K~j+p=|)1jB%~WDK^l~91o=05z1R1B +zz4!iK{P8`H!?X76HD_k+!5V`2G|FdQPvRgvS{v`lH{=ESp`Uf0%z#nknVc+rF?*%4@dJ6`D{D50SkS)jr +z~jvzQVCuc_s+sEI=FazyBXx!eA1Ne`E +zfM95EuWxH;V+zm(ql3_a4}SE$#jyeW_IbB$Ft;^W9%KO2KiZUmdp-dEv*nv$1A~G3 +zo0$G9`lhxTV*keuL;r6){0zXr`)iyC(6GuA> +z69q$C3o}zEXI6I`>nOEGTP!hb;l>ocC)C}dfyO;T5!eU}R$zK^Nh~m?OaNFCNx(SO +zz%VtjIXVsr2?-C|8-%0Zfv5aH`H+Oc-)V2?ZG0sQ{wMdIjSpVC#%3fG&%{s>l)GLa +z6d1e_5%BtGhcO)HWBf(ln^zkoCj49f^Ltn1 +zW`*;Tc*4~cp{P6;*U19~YYf}&`OiH>v`x~-k63Dz+$$+x9e*}@;Vsbqn9%03iE?he +zoWb#-*ONw6qtNZzxQtCSdKP29~H4&yPdrIX*jF@C~1V0BG$D5#|`yL%|ZHYOo%70-S8 +zu5QzE`ZeECYPIOArqp&vNqd1 +z)l^ +zRNd~|wm!TvIgPvMyIXw~hOa&0CDyDU)FI)sC<5cL4eB>UR}1H-qyWQ+!FXVM>^jZ` +z+|}W4R!9}R2+U5gZo!vdj}9(V{1bvC&0;= +zn7T(LD3}A{+OueD#%qz>%{7%gg_eD)EZNvqG?GWJRr0DD0cZO`UJCaDS6cAGee;9N +z?9fwdw7{kN``PXf_Lrpgv%?J3kCopBks}1kDlND33dYl-Bqp!c*_}4uG^P2x^x%Ii +zGJDq^`Jo?<$m3?Zph!1cHXnDll{r}>hY~I|eneVP0?>MXG_9D=C5pc;`8B%<&S;kg +zbQ{_6QZDQcMKuhIG*M?e;p_`~9kCBoi?PBK{;$KH&5M(g+r?zazz=Onar7c^L_DRy +zLyuUE?eBFlL97p-mmsBl7OoSiftQCg70{1c4sA#cc8q%P3MZUNYf{iwb!DR=bqh$Ah}?*9m^xVlHo|0 +z*yNj&yH|E8S5`G0q7vu19pjdI)ukilhCT0$ +za)EVwmZ#q+`y6p}7v5{Jt??1{`G~C~ZqpuWeC%LVjP0uj +z#?$}+2?SRH;E)Loh5~~TL0^NDWufr8=pl%3@QhDnhWKEhAz17f5HvVwbr@)51QRDi +z7Ip{+7lafKg`Ee&$;r;n&B4nK(ZWOF;)L+A^ZpI}^`JngT1X%i(+|>6074252mr;S +zrd$QEYMjfMW@}z*-W@O?IP9q7tua_ke<*U?r;ak>dMORHWBD3E=oH0Du8~%9a*t)$mzf{iF@vV3%K?djeED7bnb^x{BJ9e<_1#Y0 +zWrcjbs1`lsvUiEmQYFXT>frPT#R7xJN$QcoS-I1>y&4M|Ydyksf?TsPxqJ&TrFG?B +z#IbT$TST+9Y)9*CA~~Lmeq3o|j(`pb1_58g>Fuk$n4|j=J+g7dPwI80={-`OVv^|* +zV139-Wd3kEVJ;&e^rTJr>p^5-kQd(0iXqd=p)F6Xu}xIm!}!MGnAnb+*#dO4N!Vw} +z@>3AC)ClA>!R8nr>n4k*cMsnoT4%KGnR3Q`N}ty@X_~G!z_)&4PxT-($0(?vI)3^H +zt2;*-q6i@YWPk(}1{VhVS*HL()E9L!3sUsN9oF&`_%xaU2-)q&R517uT>oEpK)&sO +z1p^C#hJw2JNx-1lKoDjyHraz1$K=YR8;cY8kBC@oPK0j}hQQc<1j<#-6Ig_#q1uvN +zEN&UvvYS_S;0Du7gmdO8+5-9^@Rx$wN_a8NU#=sbT03d-d+5mum7``%A +zqlq@l4yw +zd2lh4_oA?0lbD}_$@)-LJNo4;N3<4uhr)tZA%<;+@X~WFhim_(s0I{@C;GD-S@GtS +z98kXdtH;4&BLvO`zMipJn#Nw}JgF=@A~=pu7u<7EXJ|bAO0zyrEyb^v_50+{AF+zR +z*5^W;UasmB<=!uxmg#C#J`K)^^hLmip3dM^)ET|55+oZ=nG22-$*8VDd|*yYvvn|O +zO1(67QqcK45bZGoa!?qtCS!;=S;jQ=4$_>h{iYtXW4LQ@kLo>TkrVcm^|>B~yGfT1 +z1if+RVJTm;2yeCB9UpIJ%IlyfeWhe+)J^g!ImvoYr*fZ49mPKWUXaDc9WVtb^_ppw +zArSSm?JIc?qF%qpteQ9}ks%v~WMLr7OrH<}fKMQPW?nBXlKZ_a((H;KvBRiSE*4}t +zwCBtyE(U63`uXZ(gSnA7 +z;vhzxJ^@Al^88M7|&zfQnvLNx~+kiz#;?KRuA|S1(o2lFXh-vkpoYr#o*)I@+R=QeMIn!i-gj +zIwM{l$bJTUkJjaKh4uJCO*7(Y2&KVgeJvF9&Uofm8UZ}Xdr`4rgCpf$O2$|Y5{CTd +zxnX`sxF5ZFtpq4lwUDkgoC3@Z#4)m11YP8HqHBB@@SK%sxQh3RB`<9I#*})IIOHQ1 +z+e_m(;~tz4>B6R +z1zeX8i824+iGJDPpL!x05JU^sPiTN*}_Y+FIJi~lhw>BOUtUL8S$j!B4uj+`0 +zV1UVOO3j83(h@~$+zY}&;U{RunLmg^^LTftsxdH)JL%?p^H0D<1pq|=Ze7$ppoU0- +z$$gmUkcQFJVQFi2s7tW&NVa*oh~6SfZu7bfef)axrU6Wj8)up$AE@$x#1`LcIu{X9 +z>%!nGBT@05M$Ie;4Ew@vwNQ-0f&{|=jSA4qPK1DU)3Xe_Y`3j!?x011Sh +z2O#iAEKyiUmWn6D)BUev2~G$v#~)$|4sM>GV~JbzFR{e8L4hzmfbRbsOF-Yo5&@vf +z0s0z_>u4bYq}bR(7rj9xrE#9SZ4MgjAm`(xrA*2PDWcansq2c~aWrMjjfnPHbFTw$ +z3S+{l(|sV9n3t^GYf|j2xWX5EVp;iTxpl&>6Fl%|dYHsLO(Ss{uecR0 +z-;Yy+4uh0AiNPiBj{Ar`rELqzRrh17!Ef&uR>(xS2+p&X}fHD9rbs(XZu0#ieqLLQ8~ +z&Tf|6Qub9e*f7rto-KN73i7gf0NFN(#y%AlNvO({1=iOr=rWdaBm3aXWT))|OwLx~ +z($>3)jl0>z#chE);fRrA*!1*a+<@cA4L+&F%7JNf#||cx8%ksta}OPlowjE(m#niX +zfB5JTFi-weW1nNw_Z{xfZo4`Xh>$H*o-oh_Etc{aE(&lJ2OK~ZU&CCmeTHpgDsPI$ +z*}u-^d`fg#DpyL{bnw+pla+X+Apfc->SLsdDDmX7E+0JMyw}ZJhht9V{kHNbsg9je +zXi;gbvYm2_9B$UJp#V)4@=dqXXcHQv1Qo*mWY`%$4)@sF6!aTt{Cg3h36(89~sZ2wGeX=fp7dM +z>`xQ)z9at#Tv?ZQH+PmwV&q6Lfj0&Tp5!i_f%EWciLP{f7146`rAs_-uUqfuW|Ok+&|YlMEM74!$jXjfNN3G4+l%vY{-cf* +z#=d3-tP8Tp)5TtaOx=or`e&t)+mT3wQw2TEQeVutSScUM>AQ0u{G9Z?EavMtpfL=^(35#`4nPcQLN}KE} +zvWd;_xtaDJ3qpo6CXp@i3LQ>ECP?;+CrRjnhRIpf<|>jg91wZ&5$!`Tyj44OPzzZe +zFqW8O=v!6ekXR(S$aF(2nhxy*Ke(T}R^%_`s^;{uTHC58i>fb+^;9%nao^qO@cYX2 +znJM_|*p=b3M^fsQj`%W(M;V9Sem$Wh^Fem4G{7^{&P6|Fn^-7e5w6c%txp +zM&M}P6?$v!_*gZI&yp}|!x>VDGl(Ap{tIT?Lg3;EU(XHr +zf{@+`?K7wBDy~D@F&7hz2{T!Bb7n7xr|sO>r6PSLCnk3U!Hf;r#Mlk|m*ZSn9xb5> +zWzTJ#lSP&z&1{ui6-XUJ!CbbP#u(BpoUfb`)aye$sPt3#B#sv@K0m8`yj|YKqaGkOAkgL +zj6crRC?b_aVokkK#WE{G&G)cR+}879uIL83gpt3W#t1fVJ~2j(l=W0ISXZD);iT=! +zT^w#FH{sZ91>&}EdaH+Q#i*IBM!Q?`e +z=hd=rMyXXu>^ND($5kDd@ekzb!oJ{kA+7Z~79jV3Uyc4Y>c5TpZ=?R(sQ*tl>XyK+ +zLIsdo{d+JC;N*b${C7JN&cGP^?4MV9sT7PO$gTaoSZNi>Tl$sq2Qs#K`?px7{ZkO +z_pxGv;7izdnKHMqBHi^%OnF8Xvxj2Fs#`xM)F97C<7TMk3%n%VzjWnDqG^GD+7svu +z4?QbcJ^krVzHI`F+q_;If)mL>?y&t-;zk>Gp!W~H?Ux9}+5Q-E_j-+dMM;$@q4DMI)7*w|;-rAK0F8`9fo +zb8ldnYt@SuzPmOMNENub-DH9S=1Ur=fkX(o*ol1Pv>D#8v45jVNOI5H+TeWqCbvK* +zOe=wjdNW%zfP6l+AM#x#%pGMK!iS+mQs@b2U1~{wHge;1s`l>*B!jhYN&TN=vlZ}d +zEB_PH<^qgy_%3ZWfV5%#khU=OW|Fb0Dw_W-Y2$r+d>!LcibtYT02x@GwDpXz% +zHk`iGL`P(VLsH7J+-d|pNbc%S?3pG>`RBZtN9+s}7~x7X@&s;T@7>KYeZQXme?{KD +zCC13YYsw~alX2{pNA9cJ-G_~b*a6+#m7x^5op +z4DaJzrDTA7OtKc~gOII*ry=MldnFaIW)}zMB99daVj2dwo;oKv{u^=ouW}g%NW7r{ +zA}0_04l)3MfqPM)b|axWRE3*?l3tKTiYAo8e|C=Ey>URHlpjAqd +zl*y=OBM7yr&Z}Y@=AQK_xel3Z9Ko-dp1b%M<_uqJ%aA!A$oWyVTz$afsoH40)R~ +z02N;+j5x}-n>|3bPCO_^e`yqIcQHkUgv{!-@l8WWg+|!d +zPjahssposg#bb1&iR9gN6W0xVQFrs=p_6n@kqiH18P5jgvo^b;NtkT1UhoN3@JF^U +zTKqv$f7#)mSw?7R3lPK%%nrKAVA3rQNg@qzBNM*zXLXD>je9>PQh8b}QU^<|*pkSg +zGvAWGl1sbGjC3kU>J0-78C9b0gr>D=eJafP60 +zdFZ){>qL2oI~Mk=Au#XXiW6|P1K?H|9s@PR6bvBsuX*dQ~$io+p3Q8 +zBTd+vd^j%mwQObdo{Yo-~Fml*Cn0%fp@^Q$T +zCM*%m@xvurC}!2nsYJSo5kq?AbDr@U2CMhg<4Gu+uuPd~yK6>mRccj5@Ux%1Tb +zo@Y~QHF}3S^mQ3#Xi`+XW^Ubh@*@mDqQ8~rz%>ql +zTaAhUYDhpRKz?7|Eb#m*!_|oml$)Wcq%KozmCDAL6Ej+Zl&zEG{xj>jt&EtM3hL`& +zCEd+e1#xGDOs+(2we?puXxNjp>UCAa%Y_41Vv +z-oEjnq;PxO>l2EFj)-~Wp`39#c5rfeLcCe5vbm0uL;GUOVC1d;g8Y9iFkV1HS{P8z +zAMrOdpibn#xBhqW_w5eVHNbCRpZWq&y^lXsFPa--y#R%C20?*C1mf=}XDComcVIz( +z$W1!}Zw38nbDWEtmy7=&>h~S}^`Jl~%Abit!GeGk9UAaOppd?8d5$c_aigczo#;WT +z2B~s2H90m6=Pp2!G`gAi%u;vColF!`cj~a1^PexO@h;7C<0(_(cI2w9IN$fPS$T`# +zVHq?oxp3L`EH>SihD4*q|0|trWej&JxQY_lA?n@k7e7?Tdc`fLyv6*ow~rUD#Xkk& +z-qYvA!7XEDrDU5I2#J+ONKk-kmPyE*XUI-;hZLL;Akdpjq)^*B#I(r@7B4O4>eG4g +zKJq+2Ty`)pH-wFa8j&^EsdJB%H3E@gLTZmO6)T_*X7*8vU7btgb!ct|hd4Ec#+KYd +z>E7jKQ$}kK5_+y>J+0!4h#RR4&A<*vdqWRJaf)$GvBIof@u>$4Od-^t>;N8^#R=Vy +zFNGiTlO@G#s3)4tBzAwW1HbI>M?3Jx2?cl#Jm$>gqBd|9FJJCOnV)UIh4`104fx)8 +zQRr!tvpNraO(;dOd(a3@atn0pWjx4N%qZ0GE{sc&t8h9Q_i4ZSVB&ar?0>ln!6O=7 +zuJH+d?Jk|gAYZ!bZ-By)F1nGs#VAx_6?3m*@!Hh8>_bKaA_5<~Lj}p^vj9wU)43L_ +zDYT+DRvz@l7n5^^AeP?8;FcR4PRn@*1PNt{@>x?C4HthYzif;?2k3K7o8Z^=Rvz

T-B=bzm-_C*KM(pfm^o+$s+UfRV&DMU+4y$=qeR +z@g!Bt5@*Sa>!SWgtNWP4he~&F +zb1t6|>~An9>s;Es;r+}T@9F*ai|o#`kK>?_VBE2`^hPhN!2@VofCqp+{?^lftEVZ5 +zAdoI#f`6&);xm&^9+Upjf-FiM*7>$W5Z3+4G6y&$4Aj@QpyuE +z&Xmwa5PAJvlkqN4EOwCa&=%v=uY(vQ$T6&89aZqfy*3FHr;zq|@wLd%(|TAec4 +zHcX~^z@-|mO&RlHL`I_vXBCz6i(jUbErw)6O!Q#9{GFIew4Tq&ay5wA0ag@+uL)QT +zbgVnoq||wgKg1=a4(d~5tbD~0*%N9Q=~l>{6o`zSv}#vMoCkG(eKs?H+!pR5=lQ8X +zU}5gsqTI8O=QYv8=>5SA(s~WE=sD|qN8Y>);B=bHENff+N>~Z(8rXD1RIiz^3r5$UDiVJY7cwyYgM0dA +zhkxy!08z8vaJJ5ybvL$-a8Pknq>G^Fd?Fq6+1xs9RS&wkA34z;+;<^Uf&bi0?wYKI +z4kd)3%2h21nu9ljrky +z+SsNQ{4&vnYQaH_aMxs`#p&A-#h7~~%Rz}dSQrLGAN{KOmdDc81Rf-8d_~O)&Vl6O +zF(b)C7)onD<&_mL3_|#YQX9LqErgnzUEm%}gh#Lt^;^%k*d5o1cY1YiWVc0L3pabKb7WITU7G(=Db~1*(7bN}W +z^3_Dx!W+)09JvxgrDcNv`G70RnjzKJFp_A9ob7fOHx943EY{RKTK)RDp4YnFRp?9p +zqLkOjOIs!{xe5*ODEC?JbJ6P-gbm8*UgB!5BTF#eEz+y0C$L|Y*pV~HBnv{g3ecwA +zNjV7Ow<({eDL4z}ht`QjO|BAM?WLyItLnd_GV5k@5ij#V-q(u0m0=BG +zq_l8bv{O+)b|*GNv{G5yH~3MVu3@e%q+hL*G;-(7jY2n{rDNl3x{RCnicoO13mwg)=f+s$lCOqI^{)Z@U}P +zKb1<~2W3lDTNv$_huta?BZ<%ArbQ-gRU?3IBnhmxbhHhjZPpHl@d` +z&9YC!;8}7@BXb#LjCab{`(}$J`L!CE!|NYJ@>TU=s$}lng+H{ToU~c+h*!r>YC&y$ +zt7kbuU=gOIZ`arc7@4QW2K4S;S8j0ICRc}nd#u<&q#^l3(a0}A>-Y(tSSZ6!yBPd=(5A8)f{tto-%#)B#^saZH8mXP+WkwgHp%C +zjr=mECI*`V&xbH1b|r2yk}u@gUh$QM$CeJP@|1|l&&(m6D9u3yALpFdHA#~)?k2ly +z(D<#EyrID$2OTvt(E>66_@m!`>bIZzH-5?sI2=J32&4YPt7BlyHLyYk-n_aEzYKq@ +zju#0ZujBN?8~(fS>rbzH@v{S)QvX;Te@Fiketm!43o83(;@?-t&u*jfh;J{kqz3M+ +z4p2^Nu5q^Q+J(Y~pha}hJSn +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 +Tg9RFHk9CIzHQe49++O|{heuzh + +literal 0 +HcmV?d00001 + +-- +2.42.0.rc2.253.gd59a3bf2b4-goog +