Merge "Redact key value from log when DEBUG is false"
diff --git a/Android.bp b/Android.bp
index 0277af0..d3bced1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -357,9 +357,6 @@
srcs: [
"core/java/android/net/annotations/PolicyDirection.java",
"core/java/com/android/internal/util/HexDump.java",
- "core/java/com/android/internal/util/IState.java",
- "core/java/com/android/internal/util/State.java",
- "core/java/com/android/internal/util/StateMachine.java",
"core/java/com/android/internal/util/WakeupMessage.java",
"services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java",
"telephony/java/android/telephony/Annotation.java",
@@ -408,11 +405,9 @@
srcs: [
"core/java/android/content/pm/BaseParceledListSlice.java",
"core/java/android/content/pm/ParceledListSlice.java",
- "core/java/android/os/HandlerExecutor.java",
"core/java/com/android/internal/util/AsyncChannel.java",
"core/java/com/android/internal/util/AsyncService.java",
"core/java/com/android/internal/util/Protocol.java",
- "core/java/com/android/internal/util/Preconditions.java",
"telephony/java/android/telephony/Annotation.java",
":net-utils-framework-wifi-common-srcs",
],
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 65a6547..1767678 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -77,22 +77,16 @@
// Module sources
":art.module.public.api{.public.stubs.source}",
":conscrypt.module.public.api{.public.stubs.source}",
- ":framework-connectivity-sources",
- ":framework-mediaprovider-sources",
- ":framework-permission-sources",
- ":framework-sdkextensions-sources",
- ":framework-statsd-sources",
- ":framework-tethering-srcs",
- ":framework-wifi-updatable-sources",
":i18n.module.public.api{.public.stubs.source}",
- ":ike-srcs",
- ":updatable-media-srcs",
// No longer part of the stubs, but are included in the docs.
":android-test-base-sources",
":android-test-mock-sources",
":android-test-runner-sources",
],
+ arg_files: [
+ "core/res/AndroidManifest.xml",
+ ],
libs: framework_docs_only_libs,
create_doc_stubs: true,
annotations_enabled: true,
@@ -106,6 +100,7 @@
merge_annotations_dirs: [
"metalava-manual",
],
+ write_sdk_values: true,
}
droidstubs {
@@ -114,6 +109,24 @@
args: metalava_framework_docs_args,
}
+// Defaults module for doc-stubs targets that use module source code as input.
+// This is the default/normal.
+stubs_defaults {
+ name: "framework-doc-stubs-sources-default",
+ defaults: ["framework-doc-stubs-default"],
+ srcs: [
+ ":framework-connectivity-sources",
+ ":framework-mediaprovider-sources",
+ ":framework-permission-sources",
+ ":framework-sdkextensions-sources",
+ ":framework-statsd-sources",
+ ":framework-tethering-srcs",
+ ":framework-wifi-updatable-sources",
+ ":ike-srcs",
+ ":updatable-media-srcs",
+ ],
+}
+
droidstubs {
name: "android-non-updatable-doc-stubs-system",
defaults: ["android-non-updatable-doc-stubs-defaults"],
@@ -123,26 +136,46 @@
droidstubs {
name: "framework-doc-stubs",
- defaults: ["framework-doc-stubs-default"],
- arg_files: [
- "core/res/AndroidManifest.xml",
- ],
+ defaults: ["framework-doc-stubs-sources-default"],
args: metalava_framework_docs_args,
- write_sdk_values: true,
}
droidstubs {
name: "framework-doc-system-stubs",
- defaults: ["framework-doc-stubs-default"],
- arg_files: [
- "core/res/AndroidManifest.xml",
- ],
+ defaults: ["framework-doc-stubs-sources-default"],
args: metalava_framework_docs_args +
" --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ",
- write_sdk_values: true,
api_levels_sdk_type: "system",
}
+// Experimental target building doc stubs with module stub source code as input.
+// This is intended to eventually replace framework-doc-stubs, once all diffs
+// have been eliminated.
+droidstubs {
+ name: "framework-doc-stubs-module-stubs",
+ defaults: ["framework-doc-stubs-default"],
+ args: metalava_framework_docs_args,
+ srcs: [
+ ":android.net.ipsec.ike{.public.stubs.source}",
+ ":framework-connectivity{.public.stubs.source}",
+ ":framework-media{.public.stubs.source}",
+ ":framework-mediaprovider{.public.stubs.source}",
+ ":framework-permission{.public.stubs.source}",
+ ":framework-sdkextensions{.public.stubs.source}",
+ ":framework-statsd{.public.stubs.source}",
+ ":framework-tethering{.public.stubs.source}",
+ ":framework-wifi{.public.stubs.source}",
+ ],
+ aidl: {
+ local_include_dirs: [
+ "apex/media/aidl/stable",
+ ],
+ include_dirs: [
+ "packages/modules/Connectivity/framework/aidl-export",
+ ],
+ },
+}
+
/////////////////////////////////////////////////////////////////////
// API docs are created from the generated stub source files
// using droiddoc
diff --git a/OWNERS b/OWNERS
index 03cfac9..ab5bd18 100644
--- a/OWNERS
+++ b/OWNERS
@@ -23,6 +23,9 @@
# via https://android.git.corp.google.com/All-Projects/+/refs/meta/config/rules.pl.
per-file */api/*current.txt = *
+# Test mapping changes can be made by anyone
+per-file */TEST_MAPPING = *
+
# Support bulk translation updates
per-file */res*/values*/*.xml = byi@google.com, delphij@google.com
diff --git a/TestProtoLibraries.bp b/TestProtoLibraries.bp
index 513d45f..afc11bb 100644
--- a/TestProtoLibraries.bp
+++ b/TestProtoLibraries.bp
@@ -30,6 +30,6 @@
type: "full",
},
errorprone: {
- javacflags: ["-Xep:MissingOverride:OFF"], // b/72714520
+ enabled: false,
},
}
diff --git a/apct-tests/perftests/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp
index 91e2074..c967e51 100644
--- a/apct-tests/perftests/multiuser/Android.bp
+++ b/apct-tests/perftests/multiuser/Android.bp
@@ -31,5 +31,6 @@
],
platform_apis: true,
test_suites: ["device-tests"],
+ data: ["trace_configs/*"],
certificate: "platform",
}
diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml
index 9117561..bec3cc9 100644
--- a/apct-tests/perftests/multiuser/AndroidTest.xml
+++ b/apct-tests/perftests/multiuser/AndroidTest.xml
@@ -16,14 +16,51 @@
<configuration description="Runs MultiUserPerfTests metric instrumentation.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-metric-instrumentation" />
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="MultiUserPerfTests.apk" />
<option name="test-file-name" value="MultiUserPerfDummyApp.apk" />
</target_preparer>
+ <!-- Needed for pushing the trace config file -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file" key="trace_config_multi_user.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+ <!--Install the content provider automatically when we push some file in sdcard folder.-->
+ <!--Needed to avoid the installation during the test suite.-->
+ <option name="push-file" key="trace_config_multi_user.textproto" value="/sdcard/sample.textproto" />
+ </target_preparer>
+
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false" />
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.perftests.multiuser" />
<option name="hidden-api-checks" value="false"/>
+
+ <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+ <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+ <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+ <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
</test>
</configuration>
diff --git a/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto b/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto
new file mode 100644
index 0000000..93b06e8
--- /dev/null
+++ b/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto
@@ -0,0 +1,154 @@
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# proto-message: TraceConfig
+
+# Enable periodic flushing of the trace buffer into the output file.
+write_into_file: true
+
+# Writes the userspace buffer into the file every 1s.
+file_write_period_ms: 1000
+
+# See b/126487238 - we need to guarantee ordering of events.
+flush_period_ms: 10000
+
+# The trace buffers needs to be big enough to hold |file_write_period_ms| of
+# trace data. The trace buffer sizing depends on the number of trace categories
+# enabled and the device activity.
+
+# RSS events
+buffers {
+ size_kb: 32768
+ fill_policy: RING_BUFFER
+}
+
+# procfs polling
+buffers {
+ size_kb: 8192
+ fill_policy: RING_BUFFER
+}
+
+data_sources {
+ config {
+ name: "linux.ftrace"
+ target_buffer: 0
+ ftrace_config {
+ # These parameters affect only the kernel trace buffer size and how
+ # frequently it gets moved into the userspace buffer defined above.
+ buffer_size_kb: 16384
+ drain_period_ms: 250
+
+ # Store certain high-volume "sched" ftrace events in a denser format
+ # (falling back to the default format if not supported by the tracer).
+ compact_sched {
+ enabled: true
+ }
+
+ # Enables symbol name resolution against /proc/kallsyms
+ symbolize_ksyms: true
+
+ # We need to do process tracking to ensure kernel ftrace events targeted at short-lived
+ # threads are associated correctly
+ ftrace_events: "task/task_newtask"
+ ftrace_events: "task/task_rename"
+ ftrace_events: "sched/sched_process_exit"
+ ftrace_events: "sched/sched_process_free"
+
+ # Memory events
+ ftrace_events: "rss_stat"
+ ftrace_events: "ion_heap_shrink"
+ ftrace_events: "ion_heap_grow"
+ ftrace_events: "ion/ion_stat"
+ ftrace_events: "dmabuf_heap/dma_heap_stat"
+ ftrace_events: "oom_score_adj_update"
+ ftrace_events: "gpu_mem/gpu_mem_total"
+
+ # Old (kernel) LMK
+ ftrace_events: "lowmemorykiller/lowmemory_kill"
+
+ atrace_apps: "*"
+
+ atrace_categories: "am"
+ atrace_categories: "binder_driver"
+ atrace_categories: "bionic"
+ atrace_categories: "dalvik"
+ atrace_categories: "input"
+ atrace_categories: "pm"
+ atrace_categories: "res"
+ atrace_categories: "rro"
+ atrace_categories: "ss"
+ atrace_categories: "view"
+ atrace_categories: "wm"
+
+ atrace_categories: "freq"
+ atrace_categories: "sched"
+ atrace_categories: "sync"
+ atrace_categories: "workq"
+
+ }
+ }
+}
+
+data_sources: {
+ config {
+ name: "android.gpu.memory"
+ target_buffer: 0
+ }
+}
+
+data_sources {
+ config {
+ name: "linux.process_stats"
+ target_buffer: 1
+ process_stats_config {
+ proc_stats_poll_ms: 10000
+ }
+ }
+}
+
+data_sources {
+ config {
+ name: "linux.sys_stats"
+ target_buffer: 1
+ sys_stats_config {
+ meminfo_period_ms: 1000
+ meminfo_counters: MEMINFO_MEM_TOTAL
+ meminfo_counters: MEMINFO_MEM_FREE
+ meminfo_counters: MEMINFO_MEM_AVAILABLE
+ meminfo_counters: MEMINFO_BUFFERS
+ meminfo_counters: MEMINFO_CACHED
+ meminfo_counters: MEMINFO_SWAP_CACHED
+ meminfo_counters: MEMINFO_ACTIVE
+ meminfo_counters: MEMINFO_INACTIVE
+ meminfo_counters: MEMINFO_ACTIVE_ANON
+ meminfo_counters: MEMINFO_INACTIVE_ANON
+ meminfo_counters: MEMINFO_ACTIVE_FILE
+ meminfo_counters: MEMINFO_INACTIVE_FILE
+ meminfo_counters: MEMINFO_UNEVICTABLE
+ meminfo_counters: MEMINFO_SWAP_TOTAL
+ meminfo_counters: MEMINFO_SWAP_FREE
+ meminfo_counters: MEMINFO_DIRTY
+ meminfo_counters: MEMINFO_WRITEBACK
+ meminfo_counters: MEMINFO_ANON_PAGES
+ meminfo_counters: MEMINFO_MAPPED
+ meminfo_counters: MEMINFO_SHMEM
+ }
+ }
+}
+
+data_sources: {
+ config: {
+ name: "android.surfaceflinger.frametimeline"
+ }
+}
diff --git a/apex/media/OWNERS b/apex/media/OWNERS
index ced2fb5..73f02d3 100644
--- a/apex/media/OWNERS
+++ b/apex/media/OWNERS
@@ -1,10 +1,10 @@
-andrewlewis@google.com
-aquilescanta@google.com
-chz@google.com
+# Bug component: 1344
hdmoon@google.com
hkuang@google.com
jinpark@google.com
klhyun@google.com
lnilsson@google.com
-marcone@google.com
sungsoo@google.com
+
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/api/Android.bp b/api/Android.bp
index fbfbc7c..0acd759 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -24,9 +24,8 @@
default_applicable_licenses: ["frameworks_base_license"],
}
-python_binary_host {
- name: "api_versions_trimmer",
- srcs: ["api_versions_trimmer.py"],
+python_defaults {
+ name: "python3_version_defaults",
version: {
py2: {
enabled: false,
@@ -38,6 +37,12 @@
},
}
+python_binary_host {
+ name: "api_versions_trimmer",
+ srcs: ["api_versions_trimmer.py"],
+ defaults: ["python3_version_defaults"],
+}
+
python_test_host {
name: "api_versions_trimmer_unittests",
main: "api_versions_trimmer_unittests.py",
@@ -45,24 +50,35 @@
"api_versions_trimmer_unittests.py",
"api_versions_trimmer.py",
],
+ defaults: ["python3_version_defaults"],
test_options: {
unit_test: true,
},
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- embedded_launcher: false,
- },
+}
+
+python_binary_host {
+ name: "merge_annotation_zips",
+ srcs: ["merge_annotation_zips.py"],
+ defaults: ["python3_version_defaults"],
+}
+
+python_test_host {
+ name: "merge_annotation_zips_test",
+ main: "merge_annotation_zips_test.py",
+ srcs: [
+ "merge_annotation_zips.py",
+ "merge_annotation_zips_test.py",
+ ],
+ defaults: ["python3_version_defaults"],
+ test_options: {
+ unit_test: true,
},
}
metalava_cmd = "$(location metalava)"
// Silence reflection warnings. See b/168689341
metalava_cmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED "
-metalava_cmd += " --no-banner --format=v2 "
+metalava_cmd += " --quiet --no-banner --format=v2 "
genrule {
name: "current-api-xml",
@@ -118,13 +134,13 @@
":android-incompatibilities.api.public.latest",
":frameworks-base-api-current.txt",
],
- out: ["stdout.txt"],
+ out: ["updated-baseline.txt"],
tools: ["metalava"],
cmd: metalava_cmd +
"--check-compatibility:api:released $(location :android.api.public.latest) " +
"--baseline:compatibility:released $(location :android-incompatibilities.api.public.latest) " +
- "$(location :frameworks-base-api-current.txt) " +
- "> $(genDir)/stdout.txt",
+ "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " +
+ "$(location :frameworks-base-api-current.txt)",
}
genrule {
@@ -231,14 +247,14 @@
":frameworks-base-api-current.txt",
":frameworks-base-api-system-current.txt",
],
- out: ["stdout.txt"],
+ out: ["updated-baseline.txt"],
tools: ["metalava"],
cmd: metalava_cmd +
"--check-compatibility:api:released $(location :android.api.system.latest) " +
"--check-compatibility:base $(location :frameworks-base-api-current.txt) " +
"--baseline:compatibility:released $(location :android-incompatibilities.api.system.latest) " +
- "$(location :frameworks-base-api-system-current.txt) " +
- "> $(genDir)/stdout.txt",
+ "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " +
+ "$(location :frameworks-base-api-system-current.txt)",
}
genrule {
@@ -320,7 +336,7 @@
":frameworks-base-api-current.txt",
":frameworks-base-api-module-lib-current.txt",
],
- out: ["stdout.txt"],
+ out: ["updated-baseline.txt"],
tools: ["metalava"],
cmd: metalava_cmd +
"--check-compatibility:api:released $(location :android.api.module-lib.latest) " +
@@ -329,8 +345,8 @@
// MODULE_LIBS -> public.
"--check-compatibility:base $(location :frameworks-base-api-current.txt) " +
"--baseline:compatibility:released $(location :android-incompatibilities.api.module-lib.latest) " +
- "$(location :frameworks-base-api-module-lib-current.txt) " +
- "> $(genDir)/stdout.txt",
+ "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " +
+ "$(location :frameworks-base-api-module-lib-current.txt)",
}
genrule {
diff --git a/api/api_versions_trimmer_unittests.py b/api/api_versions_trimmer_unittests.py
index 4eb929e..d2e5b7d 100644
--- a/api/api_versions_trimmer_unittests.py
+++ b/api/api_versions_trimmer_unittests.py
@@ -304,4 +304,4 @@
if __name__ == "__main__":
- unittest.main()
+ unittest.main(verbosity=2)
diff --git a/api/merge_annotation_zips.py b/api/merge_annotation_zips.py
new file mode 100755
index 0000000..9c67d7b
--- /dev/null
+++ b/api/merge_annotation_zips.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Script to merge annotation XML files (created by e.g. metalava)."""
+
+from pathlib import Path
+import sys
+import xml.etree.ElementTree as ET
+import zipfile
+
+
+def validate_xml_assumptions(root):
+ """Verify the format of the annotations XML matches expectations"""
+ prevName = ""
+ assert root.tag == 'root'
+ for child in root:
+ assert child.tag == 'item', 'unexpected tag: %s' % child.tag
+ assert list(child.attrib.keys()) == ['name'], 'unexpected attribs: %s' % child.attrib.keys()
+ assert prevName < child.get('name'), 'items unexpectedly not strictly sorted (possibly duplicate entries)'
+ prevName = child.get('name')
+
+
+def merge_xml(a, b):
+ """Merge two annotation xml files"""
+ for xml in [a, b]:
+ validate_xml_assumptions(xml)
+ a.extend(b[:])
+ a[:] = sorted(a[:], key=lambda x: x.get('name'))
+ validate_xml_assumptions(a)
+
+
+def merge_zip_file(out_dir, zip_file):
+ """Merge the content of the zip_file into out_dir"""
+ for filename in zip_file.namelist():
+ path = Path(out_dir, filename)
+ if path.exists():
+ existing_xml = ET.parse(path)
+ with zip_file.open(filename) as other_file:
+ other_xml = ET.parse(other_file)
+ merge_xml(existing_xml.getroot(), other_xml.getroot())
+ existing_xml.write(path, encoding='UTF-8', xml_declaration=True)
+ else:
+ zip_file.extract(filename, out_dir)
+
+
+def main():
+ out_dir = Path(sys.argv[1])
+ zip_filenames = sys.argv[2:]
+
+ assert not out_dir.exists()
+ out_dir.mkdir()
+ for zip_filename in zip_filenames:
+ with zipfile.ZipFile(zip_filename) as zip_file:
+ merge_zip_file(out_dir, zip_file)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/api/merge_annotation_zips_test.py b/api/merge_annotation_zips_test.py
new file mode 100644
index 0000000..26795c47
--- /dev/null
+++ b/api/merge_annotation_zips_test.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import io
+from pathlib import Path
+import tempfile
+import unittest
+import zipfile
+
+import merge_annotation_zips
+
+
+zip_a = {
+ 'android/provider/annotations.xml':
+ """<?xml version="1.0" encoding="UTF-8"?>
+<root>
+ <item name="android.provider.BlockedNumberContract boolean isBlocked(android.content.Context, java.lang.String)">
+ <annotation name="androidx.annotation.WorkerThread"/>
+ </item>
+ <item name="android.provider.SimPhonebookContract.SimRecords android.net.Uri getItemUri(int, int, int) 2">
+ <annotation name="androidx.annotation.IntRange">
+ <val name="from" val="1" />
+ </annotation>
+ </item>
+</root>""",
+ 'android/os/annotations.xml':
+ """<?xml version="1.0" encoding="UTF-8"?>
+<root>
+ <item name="android.app.ActionBar void setCustomView(int) 0">
+ <annotation name="androidx.annotation.LayoutRes"/>
+ </item>
+</root>
+"""
+}
+
+zip_b = {
+ 'android/provider/annotations.xml':
+ """<?xml version="1.0" encoding="UTF-8"?>
+<root>
+ <item name="android.provider.MediaStore QUERY_ARG_MATCH_FAVORITE">
+ <annotation name="androidx.annotation.IntDef">
+ <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" />
+ <val name="flag" val="true" />
+ </annotation>
+ </item>
+ <item name="android.provider.MediaStore QUERY_ARG_MATCH_PENDING">
+ <annotation name="androidx.annotation.IntDef">
+ <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" />
+ <val name="flag" val="true" />
+ </annotation>
+ </item>
+</root>"""
+}
+
+zip_c = {
+ 'android/app/annotations.xml':
+ """<?xml version="1.0" encoding="UTF-8"?>
+<root>
+ <item name="android.app.ActionBar void setCustomView(int) 0">
+ <annotation name="androidx.annotation.LayoutRes"/>
+ </item>
+</root>"""
+}
+
+merged_provider = """<?xml version='1.0' encoding='UTF-8'?>
+<root>
+ <item name="android.provider.BlockedNumberContract boolean isBlocked(android.content.Context, java.lang.String)">
+ <annotation name="androidx.annotation.WorkerThread" />
+ </item>
+ <item name="android.provider.MediaStore QUERY_ARG_MATCH_FAVORITE">
+ <annotation name="androidx.annotation.IntDef">
+ <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" />
+ <val name="flag" val="true" />
+ </annotation>
+ </item>
+ <item name="android.provider.MediaStore QUERY_ARG_MATCH_PENDING">
+ <annotation name="androidx.annotation.IntDef">
+ <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" />
+ <val name="flag" val="true" />
+ </annotation>
+ </item>
+<item name="android.provider.SimPhonebookContract.SimRecords android.net.Uri getItemUri(int, int, int) 2">
+ <annotation name="androidx.annotation.IntRange">
+ <val name="from" val="1" />
+ </annotation>
+ </item>
+</root>"""
+
+
+
+class MergeAnnotationZipsTest(unittest.TestCase):
+
+ def test_merge_zips(self):
+ with tempfile.TemporaryDirectory() as out_dir:
+ for zip_content in [zip_a, zip_b, zip_c]:
+ f = io.BytesIO()
+ with zipfile.ZipFile(f, "w") as zip_file:
+ for filename, content in zip_content.items():
+ zip_file.writestr(filename, content)
+ merge_annotation_zips.merge_zip_file(out_dir, zip_file)
+
+ # Unchanged
+ self.assertEqual(zip_a['android/os/annotations.xml'], Path(out_dir, 'android/os/annotations.xml').read_text())
+ self.assertEqual(zip_c['android/app/annotations.xml'], Path(out_dir, 'android/app/annotations.xml').read_text())
+
+ # Merged
+ self.assertEqual(merged_provider, Path(out_dir, 'android/provider/annotations.xml').read_text())
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)
diff --git a/cmds/idmap2/include/idmap2/FileUtils.h b/cmds/idmap2/include/idmap2/FileUtils.h
index c4e0e1f..8fcaeb1 100644
--- a/cmds/idmap2/include/idmap2/FileUtils.h
+++ b/cmds/idmap2/include/idmap2/FileUtils.h
@@ -17,6 +17,8 @@
#ifndef IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
#define IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
+#include <sys/types.h>
+
#include <string>
namespace android::idmap2::utils {
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index e7e9e4c..a1206f9 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -93,7 +93,7 @@
"--idmap-path", GetIdmapPath()});
// clang-format on
ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
+ ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
struct stat st;
ASSERT_EQ(stat(GetIdmapPath().c_str(), &st), 0);
@@ -119,7 +119,7 @@
"--idmap-path", GetIdmapPath()});
// clang-format on
ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
+ ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
// clang-format off
result = ExecuteBinary({"idmap2",
@@ -127,14 +127,14 @@
"--idmap-path", GetIdmapPath()});
// clang-format on
ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
- ASSERT_NE(result->stdout.find(R::target::integer::literal::int1 + " -> 0x7f010000"),
+ ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+ ASSERT_NE(result->stdout_str.find(R::target::integer::literal::int1 + " -> 0x7f010000"),
std::string::npos);
- ASSERT_NE(result->stdout.find(R::target::string::literal::str1 + " -> 0x7f020000"),
+ ASSERT_NE(result->stdout_str.find(R::target::string::literal::str1 + " -> 0x7f020000"),
std::string::npos);
- ASSERT_NE(result->stdout.find(R::target::string::literal::str3 + " -> 0x7f020001"),
+ ASSERT_NE(result->stdout_str.find(R::target::string::literal::str3 + " -> 0x7f020001"),
std::string::npos);
- ASSERT_NE(result->stdout.find(R::target::string::literal::str4 + " -> 0x7f020002"),
+ ASSERT_NE(result->stdout_str.find(R::target::string::literal::str4 + " -> 0x7f020002"),
std::string::npos);
// clang-format off
@@ -144,8 +144,8 @@
"--idmap-path", GetIdmapPath()});
// clang-format on
ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
- ASSERT_NE(result->stdout.find("00000000: 504d4449 magic"), std::string::npos);
+ ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+ ASSERT_NE(result->stdout_str.find("00000000: 504d4449 magic"), std::string::npos);
// clang-format off
result = ExecuteBinary({"idmap2",
@@ -170,7 +170,7 @@
"--idmap-path", GetIdmapPath()});
// clang-format on
ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
+ ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
// clang-format off
result = ExecuteBinary({"idmap2",
@@ -180,9 +180,9 @@
"--resid", R::target::string::literal::str1});
// clang-format on
ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
- ASSERT_NE(result->stdout.find("overlay-1"), std::string::npos);
- ASSERT_EQ(result->stdout.find("overlay-1-sv"), std::string::npos);
+ ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+ ASSERT_NE(result->stdout_str.find("overlay-1"), std::string::npos);
+ ASSERT_EQ(result->stdout_str.find("overlay-1-sv"), std::string::npos);
// clang-format off
result = ExecuteBinary({"idmap2",
@@ -192,9 +192,9 @@
"--resid", "test.target:string/str1"});
// clang-format on
ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
- ASSERT_NE(result->stdout.find("overlay-1"), std::string::npos);
- ASSERT_EQ(result->stdout.find("overlay-1-sv"), std::string::npos);
+ ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+ ASSERT_NE(result->stdout_str.find("overlay-1"), std::string::npos);
+ ASSERT_EQ(result->stdout_str.find("overlay-1-sv"), std::string::npos);
// clang-format off
result = ExecuteBinary({"idmap2",
@@ -204,8 +204,8 @@
"--resid", "test.target:string/str1"});
// clang-format on
ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
- ASSERT_NE(result->stdout.find("overlay-1-sv"), std::string::npos);
+ ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+ ASSERT_NE(result->stdout_str.find("overlay-1-sv"), std::string::npos);
unlink(GetIdmapPath().c_str());
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 5de5f83..e4e7d4e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -954,7 +954,7 @@
field public static final int measureWithLargestChild = 16843476; // 0x10102d4
field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad
field public static final int mediaRouteTypes = 16843694; // 0x10103ae
- field public static final int memtagMode = 16844313; // 0x1010619
+ field public static final int memtagMode = 16844324; // 0x1010624
field public static final int menuCategory = 16843230; // 0x10101de
field public static final int mimeGroup = 16844309; // 0x1010615
field public static final int mimeType = 16842790; // 0x1010026
@@ -978,7 +978,7 @@
field public static final int multiArch = 16843918; // 0x101048e
field public static final int multiprocess = 16842771; // 0x1010013
field public static final int name = 16842755; // 0x1010003
- field public static final int nativeHeapZeroInitialized = 16844314; // 0x101061a
+ field public static final int nativeHeapZeroInitialized = 16844325; // 0x1010625
field public static final int navigationBarColor = 16843858; // 0x1010452
field public static final int navigationBarDividerColor = 16844141; // 0x101056d
field public static final int navigationContentDescription = 16843969; // 0x10104c1
@@ -8657,6 +8657,15 @@
field public static final int TELEPHONY = 4194304; // 0x400000
}
+ public final class BluetoothCsipSetCoordinator implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
+ method public void close();
+ method protected void finalize();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice);
+ method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH) public static final String ACTION_CSIS_CONNECTION_STATE_CHANGED = "android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED";
+ }
+
public final class BluetoothDevice implements android.os.Parcelable {
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
@@ -8703,6 +8712,7 @@
field public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
field public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
field public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
+ field public static final String EXTRA_IS_COORDINATED_SET_MEMBER = "android.bluetooth.extra.IS_COORDINATED_SET_MEMBER";
field public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
field public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
field public static final String EXTRA_PAIRING_VARIANT = "android.bluetooth.device.extra.PAIRING_VARIANT";
@@ -9083,6 +9093,7 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
field public static final int A2DP = 2; // 0x2
+ field public static final int CSIP_SET_COORDINATOR = 25; // 0x19
field public static final String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE";
field public static final String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
field public static final int GATT = 7; // 0x7
@@ -29935,6 +29946,11 @@
ctor public OperationCanceledException(String);
}
+ public interface OutcomeReceiver<R, E extends java.lang.Throwable> {
+ method public default void onError(@NonNull E);
+ method public void onResult(@NonNull R);
+ }
+
public final class Parcel {
method public void appendFrom(android.os.Parcel, int, int);
method @Nullable public android.os.IBinder[] createBinderArray();
@@ -30329,6 +30345,7 @@
method public void close();
method @NonNull public static android.os.SharedMemory create(@Nullable String, int) throws android.system.ErrnoException;
method public int describeContents();
+ method @NonNull public static android.os.SharedMemory fromFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
method public int getSize();
method @NonNull public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
method @NonNull public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
@@ -41029,6 +41046,7 @@
method public String getNetworkOperator();
method public String getNetworkOperatorName();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getNetworkSelectionMode();
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getNetworkSlicingConfiguration(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.data.SlicingConfig,android.telephony.TelephonyManager.SlicingException>);
method public String getNetworkSpecifier();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getNetworkType();
method @Deprecated public int getPhoneCount();
@@ -41262,6 +41280,13 @@
field public static final int ERROR_TIMEOUT = 1; // 0x1
}
+ public static class TelephonyManager.SlicingException extends java.lang.Exception {
+ ctor public TelephonyManager.SlicingException(int);
+ method public int getErrorCode();
+ field public static final int ERROR_MODEM_ERROR = 2; // 0x2
+ field public static final int ERROR_TIMEOUT = 1; // 0x1
+ }
+
public abstract static class TelephonyManager.UssdResponseCallback {
ctor public TelephonyManager.UssdResponseCallback();
method public void onReceiveUssdResponse(android.telephony.TelephonyManager, String, CharSequence);
@@ -41437,6 +41462,88 @@
method @NonNull public android.telephony.data.ApnSetting.Builder setUser(@Nullable String);
}
+ public final class NetworkSliceInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=0xffffffff, to=0xfffffe) public int getMappedHplmnSliceDifferentiator();
+ method public int getMappedHplmnSliceServiceType();
+ method @IntRange(from=0xffffffff, to=0xfffffe) public int getSliceDifferentiator();
+ method public int getSliceServiceType();
+ method public int getStatus();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.NetworkSliceInfo> CREATOR;
+ field public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1; // 0xffffffff
+ field public static final int SLICE_SERVICE_TYPE_EMBB = 1; // 0x1
+ field public static final int SLICE_SERVICE_TYPE_MIOT = 3; // 0x3
+ field public static final int SLICE_SERVICE_TYPE_NONE = 0; // 0x0
+ field public static final int SLICE_SERVICE_TYPE_URLLC = 2; // 0x2
+ field public static final int SLICE_STATUS_ALLOWED = 2; // 0x2
+ field public static final int SLICE_STATUS_CONFIGURED = 1; // 0x1
+ field public static final int SLICE_STATUS_DEFAULT_CONFIGURED = 5; // 0x5
+ field public static final int SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_PLMN = 3; // 0x3
+ field public static final int SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_REGISTERED_AREA = 4; // 0x4
+ field public static final int SLICE_STATUS_UNKNOWN = 0; // 0x0
+ }
+
+ public static final class NetworkSliceInfo.Builder {
+ ctor public NetworkSliceInfo.Builder();
+ method @NonNull public android.telephony.data.NetworkSliceInfo build();
+ method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setMappedHplmnSliceDifferentiator(@IntRange(from=0xffffffff, to=0xfffffe) int);
+ method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setMappedHplmnSliceServiceType(int);
+ method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setSliceDifferentiator(@IntRange(from=0xffffffff, to=0xfffffe) int);
+ method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setSliceServiceType(int);
+ method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setStatus(int);
+ }
+
+ public final class RouteSelectionDescriptor implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getDataNetworkName();
+ method @IntRange(from=0x0, to=0xff) public int getPrecedence();
+ method public int getSessionType();
+ method @NonNull public java.util.List<android.telephony.data.NetworkSliceInfo> getSliceInfo();
+ method public int getSscMode();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.RouteSelectionDescriptor> CREATOR;
+ field public static final int ROUTE_SSC_MODE_1 = 1; // 0x1
+ field public static final int ROUTE_SSC_MODE_2 = 2; // 0x2
+ field public static final int ROUTE_SSC_MODE_3 = 3; // 0x3
+ field public static final int SESSION_TYPE_IPV4 = 0; // 0x0
+ field public static final int SESSION_TYPE_IPV4V6 = 2; // 0x2
+ field public static final int SESSION_TYPE_IPV6 = 1; // 0x1
+ }
+
+ public final class SlicingConfig implements android.os.Parcelable {
+ ctor public SlicingConfig();
+ method public int describeContents();
+ method @NonNull public java.util.List<android.telephony.data.NetworkSliceInfo> getSliceInfo();
+ method @NonNull public java.util.List<android.telephony.data.UrspRule> getUrspRules();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.SlicingConfig> CREATOR;
+ }
+
+ public final class TrafficDescriptor implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getDataNetworkName();
+ method @Nullable public String getOsAppId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.TrafficDescriptor> CREATOR;
+ }
+
+ public static final class TrafficDescriptor.Builder {
+ ctor public TrafficDescriptor.Builder();
+ method @NonNull public android.telephony.data.TrafficDescriptor build();
+ method @NonNull public android.telephony.data.TrafficDescriptor.Builder setDataNetworkName(@NonNull String);
+ method @NonNull public android.telephony.data.TrafficDescriptor.Builder setOsAppId(@NonNull String);
+ }
+
+ public final class UrspRule implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=0x0, to=0xff) public int getPrecedence();
+ method @NonNull public java.util.List<android.telephony.data.RouteSelectionDescriptor> getRouteSelectionDescriptor();
+ method @NonNull public java.util.List<android.telephony.data.TrafficDescriptor> getTrafficDescriptors();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.UrspRule> CREATOR;
+ }
+
}
package android.telephony.emergency {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index bfa5a7b..66d6124 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -132,6 +132,11 @@
field public static final int VPN_UID = 1016; // 0x3f8
}
+ public final class ServiceManager {
+ method public static boolean isDeclared(@NonNull String);
+ method @Nullable public static android.os.IBinder waitForDeclaredService(@NonNull String);
+ }
+
public class StatsServiceManager {
method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsCompanionServiceRegisterer();
method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsManagerServiceRegisterer();
@@ -155,6 +160,11 @@
method public static int getNumSignalStrengthLevels();
}
+ public class SubscriptionManager {
+ method public void addSubscriptionInfoRecord(@NonNull String, @Nullable String, int, int);
+ method public void removeSubscriptionInfoRecord(@NonNull String, int);
+ }
+
public class TelephonyManager {
method @NonNull public static int[] getAllNetworkTypes();
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index aa528ba0..e601583 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1507,9 +1507,26 @@
method public void onOobData(int, @NonNull android.bluetooth.OobData);
}
+ public final class BluetoothCsipSetCoordinator implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<java.lang.Integer> getAllGroupIds(@Nullable android.os.ParcelUuid);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice);
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.Map getGroupUuidMapByDevice(@Nullable android.bluetooth.BluetoothDevice);
+ method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.UUID groupLock(int, @Nullable java.util.concurrent.Executor, @Nullable android.bluetooth.BluetoothCsipSetCoordinator.ClientLockCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean groupUnlock(@NonNull java.util.UUID);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice, int);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CSIS_DEVICE_AVAILABLE = "android.bluetooth.action.CSIS_DEVICE_AVAILABLE";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CSIS_SET_MEMBER_AVAILABLE = "android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE";
+ }
+
+ public static interface BluetoothCsipSetCoordinator.ClientLockCallback {
+ method public void onGroupLockSet(int, int, boolean);
+ }
+
public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean cancelBondProcess();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean fetchUuidsWithSdp(int);
method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getSimAccessPermission();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
@@ -1559,7 +1576,10 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInbandRingingEnabled();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startScoUsingVirtualVoiceCall();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean stopScoUsingVirtualVoiceCall();
}
public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
@@ -1643,6 +1663,7 @@
field @NonNull public static final android.os.ParcelUuid AVRCP_TARGET;
field @NonNull public static final android.os.ParcelUuid BASE_UUID;
field @NonNull public static final android.os.ParcelUuid BNEP;
+ field @NonNull public static final android.os.ParcelUuid COORDINATED_SET;
field @NonNull public static final android.os.ParcelUuid DIP;
field @NonNull public static final android.os.ParcelUuid GENERIC_MEDIA_CONTROL;
field @NonNull public static final android.os.ParcelUuid HEARING_AID;
@@ -7239,6 +7260,7 @@
public class SystemConfigManager {
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
+ method @NonNull public java.util.List<java.lang.String> getEnabledComponentOverrides(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public int[] getSystemPermissionUids(@NonNull String);
}
@@ -9669,6 +9691,25 @@
field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public final class NetworkRegistrationInfo implements android.os.Parcelable {
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
method public int getRegistrationState();
@@ -10335,6 +10376,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
@@ -10507,6 +10549,14 @@
field public static final int RESULT_SUCCESS = 0; // 0x0
}
+ public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception {
+ method public int getErrorCode();
+ field public static final int ERROR_INVALID_INFO_RECEIVED = 2; // 0x2
+ field public static final int ERROR_MODEM_RESPONSE_ERROR = 3; // 0x3
+ field public static final int ERROR_PHONE_NOT_AVAILABLE = 1; // 0x1
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ }
+
public final class ThermalMitigationRequest implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.telephony.DataThrottlingRequest getDataThrottlingRequest();
@@ -10631,7 +10681,7 @@
method public int getPduSessionId();
method public int getProtocolType();
method public long getRetryDurationMillis();
- method @Nullable public android.telephony.data.SliceInfo getSliceInfo();
+ method @Nullable public android.telephony.data.NetworkSliceInfo getSliceInfo();
method @Deprecated public int getSuggestedRetryTime();
method @NonNull public java.util.List<android.telephony.data.TrafficDescriptor> getTrafficDescriptors();
method public void writeToParcel(android.os.Parcel, int);
@@ -10667,7 +10717,7 @@
method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.SliceInfo);
+ method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.NetworkSliceInfo);
method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setTrafficDescriptors(@NonNull java.util.List<android.telephony.data.TrafficDescriptor>);
}
@@ -10740,7 +10790,7 @@
method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback);
method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback);
method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback);
- method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.SliceInfo, @Nullable android.telephony.data.TrafficDescriptor, boolean, @NonNull android.telephony.data.DataServiceCallback);
+ method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.NetworkSliceInfo, @Nullable android.telephony.data.TrafficDescriptor, boolean, @NonNull android.telephony.data.DataServiceCallback);
}
public class DataServiceCallback {
@@ -10798,32 +10848,6 @@
method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
}
- public final class SliceInfo implements android.os.Parcelable {
- method public int describeContents();
- method @IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getMappedHplmnSliceDifferentiator();
- method public int getMappedHplmnSliceServiceType();
- method @IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getSliceDifferentiator();
- method public int getSliceServiceType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.SliceInfo> CREATOR;
- field public static final int MAX_SLICE_DIFFERENTIATOR = 16777214; // 0xfffffe
- field public static final int MIN_SLICE_DIFFERENTIATOR = -1; // 0xffffffff
- field public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1; // 0xffffffff
- field public static final int SLICE_SERVICE_TYPE_EMBB = 1; // 0x1
- field public static final int SLICE_SERVICE_TYPE_MIOT = 3; // 0x3
- field public static final int SLICE_SERVICE_TYPE_NONE = 0; // 0x0
- field public static final int SLICE_SERVICE_TYPE_URLLC = 2; // 0x2
- }
-
- public static final class SliceInfo.Builder {
- ctor public SliceInfo.Builder();
- method @NonNull public android.telephony.data.SliceInfo build();
- method @NonNull public android.telephony.data.SliceInfo.Builder setMappedHplmnSliceDifferentiator(@IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
- method @NonNull public android.telephony.data.SliceInfo.Builder setMappedHplmnSliceServiceType(int);
- method @NonNull public android.telephony.data.SliceInfo.Builder setSliceDifferentiator(@IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
- method @NonNull public android.telephony.data.SliceInfo.Builder setSliceServiceType(int);
- }
-
public final class ThrottleStatus implements android.os.Parcelable {
method public int describeContents();
method public int getApnType();
@@ -10852,15 +10876,6 @@
method @NonNull public android.telephony.data.ThrottleStatus.Builder setTransportType(int);
}
- public final class TrafficDescriptor implements android.os.Parcelable {
- ctor public TrafficDescriptor(@Nullable String, @Nullable String);
- method public int describeContents();
- method @Nullable public String getDnn();
- method @Nullable public String getOsAppId();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.TrafficDescriptor> CREATOR;
- }
-
}
package android.telephony.euicc {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 6613947..d905bbe 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1649,6 +1649,28 @@
field public static final String MBMS_STREAMING_SERVICE_OVERRIDE_METADATA = "mbms-streaming-service-override";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ ctor public ModemActivityInfo(long, int, int, @NonNull int[], int);
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public boolean isEmpty();
+ method public boolean isValid();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public class PhoneNumberUtils {
method public static int getMinMatchForTest();
method public static void setMinMatchForTest(int);
diff --git a/core/java/Android.bp b/core/java/Android.bp
index eee696b..949ba6a 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -341,6 +341,27 @@
],
}
+java_library {
+ name: "modules-utils-statemachine",
+ srcs: [
+ "com/android/internal/util/IState.java",
+ "com/android/internal/util/State.java",
+ "com/android/internal/util/StateMachine.java",
+ ],
+ libs: [
+ "framework-annotations-lib",
+ "unsupportedappusage",
+ ],
+ sdk_version: "module_current",
+ min_sdk_version: "29",
+
+ visibility: ["//visibility:public"],
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
+}
+
filegroup {
name: "framework-ims-common-shared-srcs",
srcs: [
@@ -365,10 +386,7 @@
"android/util/Rational.java",
"com/android/internal/util/FastXmlSerializer.java",
"com/android/internal/util/HexDump.java",
- "com/android/internal/util/IState.java",
"com/android/internal/util/MessageUtils.java",
- "com/android/internal/util/State.java",
- "com/android/internal/util/StateMachine.java",
"com/android/internal/util/WakeupMessage.java",
],
visibility: [
diff --git a/core/java/android/annotation/SuppressLint.java b/core/java/android/annotation/SuppressLint.java
new file mode 100644
index 0000000..2d3456b
--- /dev/null
+++ b/core/java/android/annotation/SuppressLint.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should ignore the specified warnings for the annotated element. */
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressLint {
+ /**
+ * The set of warnings (identified by the lint issue id) that should be
+ * ignored by lint. It is not an error to specify an unrecognized name.
+ */
+ String[] value();
+}
diff --git a/core/java/android/annotation/TargetApi.java b/core/java/android/annotation/TargetApi.java
new file mode 100644
index 0000000..975318e
--- /dev/null
+++ b/core/java/android/annotation/TargetApi.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should treat this type as targeting a given API level, no matter what the
+ project target is. */
+@Target({TYPE, METHOD, CONSTRUCTOR, FIELD})
+@Retention(RetentionPolicy.CLASS)
+public @interface TargetApi {
+ /**
+ * This sets the target api level for the type..
+ */
+ int value();
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 56ec8ea..749e8f5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1041,16 +1041,17 @@
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
- CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings,
+ CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial, AutofillOptions autofillOptions,
ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
if (services != null) {
if (false) {
// Test code to make sure the app could see the passed-in services.
- for (String name : services.keySet()) {
- if (services.get(name) == null) {
+ for (Object oname : services.keySet()) {
+ if (services.get(oname) == null) {
continue; // AM just passed in a null service.
}
+ String name = (String) oname;
// See b/79378449 about the following exemption.
switch (name) {
@@ -6298,7 +6299,13 @@
final File cacheDir = context.getCacheDir();
if (cacheDir != null) {
// Provide a usable directory for temporary files
- System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
+ String tmpdir = cacheDir.getAbsolutePath();
+ System.setProperty("java.io.tmpdir", tmpdir);
+ try {
+ android.system.Os.setenv("TMPDIR", tmpdir, true);
+ } catch (ErrnoException ex) {
+ Log.w(TAG, "Unable to initialize $TMPDIR", ex);
+ }
} else {
Log.v(TAG, "Unable to initialize \"java.io.tmpdir\" property "
+ "due to missing cache directory");
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 45a8388..6e9157e 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -72,7 +72,7 @@
IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
int debugMode, boolean enableBinderTracking, boolean trackAllocation,
boolean restrictedBackupMode, boolean persistent, in Configuration config,
- in CompatibilityInfo compatInfo, in Map<String, IBinder> services,
+ in CompatibilityInfo compatInfo, in Map services,
in Bundle coreSettings, in String buildSerial, in AutofillOptions autofillOptions,
in ContentCaptureOptions contentCaptureOptions, in long[] disabledCompatChanges);
void runIsolatedEntryPoint(in String entryPoint, in String[] entryPointArgs);
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index 71b28fb..6c435b9 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -54,7 +54,7 @@
* @see android.support.v4.app.JobIntentService
*
* @deprecated IntentService is subject to all the
- * <a href="/preview/features/background.html">background execution limits</a>
+ * <a href="{@docRoot}about/versions/oreo/background.html">background execution limits</a>
* imposed with Android 8.0 (API level 26). Consider using {@link androidx.work.WorkManager}
* or {@link androidx.core.app.JobIntentService}, which uses jobs
* instead of services when running on Android 8.0 or higher.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 3ad8b4b..d28e489 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -223,14 +223,14 @@
void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
void clearCrossProfileIntentFilters(in ComponentName admin);
- boolean setPermittedAccessibilityServices(in ComponentName admin,in List packageList);
- List getPermittedAccessibilityServices(in ComponentName admin);
- List getPermittedAccessibilityServicesForUser(int userId);
+ boolean setPermittedAccessibilityServices(in ComponentName admin,in List<String> packageList);
+ List<String> getPermittedAccessibilityServices(in ComponentName admin);
+ List<String> getPermittedAccessibilityServicesForUser(int userId);
boolean isAccessibilityServicePermittedByAdmin(in ComponentName admin, String packageName, int userId);
- boolean setPermittedInputMethods(in ComponentName admin,in List packageList);
- List getPermittedInputMethods(in ComponentName admin);
- List getPermittedInputMethodsForCurrentUser();
+ boolean setPermittedInputMethods(in ComponentName admin,in List<String> packageList);
+ List<String> getPermittedInputMethods(in ComponentName admin);
+ List<String> getPermittedInputMethodsForCurrentUser();
boolean isInputMethodPermittedByAdmin(in ComponentName admin, String packageName, int userId);
boolean setPermittedCrossProfileNotificationListeners(in ComponentName admin, in List<String> packageList);
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 4d73a61..6d777cf 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -171,9 +171,9 @@
mLaunchCount = stats.mLaunchCount;
mAppLaunchCount = stats.mAppLaunchCount;
mLastEvent = stats.mLastEvent;
- mActivities = stats.mActivities;
- mForegroundServices = stats.mForegroundServices;
- mChooserCounts = stats.mChooserCounts;
+ mActivities = stats.mActivities.clone();
+ mForegroundServices = new ArrayMap<>(stats.mForegroundServices);
+ mChooserCounts = new ArrayMap<>(stats.mChooserCounts);
}
/**
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index d487025..313dd3e 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2819,6 +2819,10 @@
} else if (profile == BluetoothProfile.VOLUME_CONTROL) {
BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this);
return true;
+ } else if (profile == BluetoothProfile.CSIP_SET_COORDINATOR) {
+ BluetoothCsipSetCoordinator csipSetCoordinator =
+ new BluetoothCsipSetCoordinator(context, listener);
+ return true;
} else {
return false;
}
@@ -2908,6 +2912,11 @@
BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy;
vcs.close();
break;
+ case BluetoothProfile.CSIP_SET_COORDINATOR:
+ BluetoothCsipSetCoordinator csipSetCoordinator =
+ (BluetoothCsipSetCoordinator) proxy;
+ csipSetCoordinator.close();
+ break;
}
}
diff --git a/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java b/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java
new file mode 100644
index 0000000..cb542e5
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java
@@ -0,0 +1,550 @@
+/*
+ * Copyright 2021 HIMSA II K/S - www.himsa.com.
+ * Represented by EHIMA - www.ehima.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.util.CloseGuard;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.Executor;
+
+/**
+ * This class provides the public APIs to control the Bluetooth CSIP set coordinator.
+ *
+ * <p>BluetoothCsipSetCoordinator is a proxy object for controlling the Bluetooth VC
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothCsipSetCoordinator proxy object.
+ *
+ */
+public final class BluetoothCsipSetCoordinator implements BluetoothProfile, AutoCloseable {
+ private static final String TAG = "BluetoothCsipSetCoordinator";
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ private CloseGuard mCloseGuard;
+
+ /**
+ * @hide
+ */
+ @SystemApi
+ public interface ClientLockCallback {
+ /**
+ * @hide
+ */
+ @SystemApi void onGroupLockSet(int groupId, int opStatus, boolean isLocked);
+ }
+
+ private static class BluetoothCsipSetCoordinatorLockCallbackDelegate
+ extends IBluetoothCsipSetCoordinatorLockCallback.Stub {
+ private final ClientLockCallback mCallback;
+ private final Executor mExecutor;
+
+ BluetoothCsipSetCoordinatorLockCallbackDelegate(
+ Executor executor, ClientLockCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onGroupLockSet(int groupId, int opStatus, boolean isLocked) {
+ mExecutor.execute(() -> mCallback.onGroupLockSet(groupId, opStatus, isLocked));
+ }
+ };
+
+ /**
+ * Intent used to broadcast the change in connection state of the CSIS
+ * Client.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CSIS_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED";
+
+ /**
+ * Intent used to expose broadcast receiving device.
+ *
+ * <p>This intent will have 2 extras:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote Broadcast receiver device. </li>
+ * <li> {@link #EXTRA_CSIS_GROUP_ID} - Group identifier. </li>
+ * <li> {@link #EXTRA_CSIS_GROUP_SIZE} - Group size. </li>
+ * <li> {@link #EXTRA_CSIS_GROUP_TYPE_UUID} - Group type UUID. </li>
+ * </ul>
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CSIS_DEVICE_AVAILABLE =
+ "android.bluetooth.action.CSIS_DEVICE_AVAILABLE";
+
+ /**
+ * Used as an extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent.
+ * Contains the group id.
+ *
+ * @hide
+ */
+ public static final String EXTRA_CSIS_GROUP_ID = "android.bluetooth.extra.CSIS_GROUP_ID";
+
+ /**
+ * Group size as int extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent.
+ *
+ * @hide
+ */
+ public static final String EXTRA_CSIS_GROUP_SIZE = "android.bluetooth.extra.CSIS_GROUP_SIZE";
+
+ /**
+ * Group type uuid extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent.
+ *
+ * @hide
+ */
+ public static final String EXTRA_CSIS_GROUP_TYPE_UUID =
+ "android.bluetooth.extra.CSIS_GROUP_TYPE_UUID";
+
+ /**
+ * Intent used to broadcast information about identified set member
+ * ready to connect.
+ *
+ * <p>This intent will have one extra:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
+ * be null if no device is active. </li>
+ * <li> {@link #EXTRA_CSIS_GROUP_ID} - Group identifier. </li>
+ * </ul>
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CSIS_SET_MEMBER_AVAILABLE =
+ "android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE";
+
+ /**
+ * This represents an invalid group ID.
+ *
+ * @hide
+ */
+ public static final int GROUP_ID_INVALID = IBluetoothCsipSetCoordinator.CSIS_GROUP_ID_INVALID;
+
+ /**
+ * Indicating that group was locked with success.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_SUCCESS = 0;
+
+ /**
+ * Indicating that group locked failed due to invalid group ID.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_FAILED_INVALID_GROUP = 1;
+
+ /**
+ * Indicating that group locked failed due to empty group.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_FAILED_GROUP_EMPTY = 2;
+
+ /**
+ * Indicating that group locked failed due to group members being disconnected.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_FAILED_GROUP_NOT_CONNECTED = 3;
+
+ /**
+ * Indicating that group locked failed due to group member being already locked.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_FAILED_LOCKED_BY_OTHER = 4;
+
+ /**
+ * Indicating that group locked failed due to other reason.
+ *
+ * @hide
+ */
+ public static final int GROUP_LOCK_FAILED_OTHER_REASON = 5;
+
+ /**
+ * Indicating that group member in locked state was lost.
+ *
+ * @hide
+ */
+ public static final int LOCKED_GROUP_MEMBER_LOST = 6;
+
+ private BluetoothAdapter mAdapter;
+ private final BluetoothProfileConnector<IBluetoothCsipSetCoordinator> mProfileConnector =
+ new BluetoothProfileConnector(this, BluetoothProfile.CSIP_SET_COORDINATOR, TAG,
+ IBluetoothCsipSetCoordinator.class.getName()) {
+ @Override
+ public IBluetoothCsipSetCoordinator getServiceInterface(IBinder service) {
+ return IBluetoothCsipSetCoordinator.Stub.asInterface(
+ Binder.allowBlocking(service));
+ }
+ };
+
+ /**
+ * Create a BluetoothCsipSetCoordinator proxy object for interacting with the local
+ * Bluetooth CSIS service.
+ */
+ /*package*/ BluetoothCsipSetCoordinator(Context context, ServiceListener listener) {
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mProfileConnector.connect(context, listener);
+ mCloseGuard = new CloseGuard();
+ mCloseGuard.open("close");
+ }
+
+ /**
+ * @hide
+ */
+ protected void finalize() {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ }
+
+ /**
+ * @hide
+ */
+ public void close() {
+ mProfileConnector.disconnect();
+ }
+
+ private IBluetoothCsipSetCoordinator getService() {
+ return mProfileConnector.getService();
+ }
+
+ /**
+ * Lock the set.
+ * @param groupId group ID to lock,
+ * @param executor callback executor,
+ * @param cb callback to report lock and unlock events - stays valid until the app unlocks
+ * using the returned lock identifier or the lock timeouts on the remote side,
+ * as per CSIS specification,
+ * @return unique lock identifier used for unlocking or null if lock has failed.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public
+ @Nullable UUID groupLock(int groupId, @Nullable @CallbackExecutor Executor executor,
+ @Nullable ClientLockCallback cb) {
+ if (VDBG) {
+ log("groupLockSet()");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled()) {
+ IBluetoothCsipSetCoordinatorLockCallback delegate = null;
+ if ((executor != null) && (cb != null)) {
+ delegate = new BluetoothCsipSetCoordinatorLockCallbackDelegate(executor, cb);
+ }
+ return service.groupLock(groupId, delegate).getUuid();
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return null;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return null;
+ }
+ }
+
+ /**
+ * Unlock the set.
+ * @param lockUuid unique lock identifier
+ * @return true if unlocked, false on error
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean groupUnlock(@NonNull UUID lockUuid) {
+ if (VDBG) {
+ log("groupLockSet()");
+ }
+ if (lockUuid == null) {
+ return false;
+ }
+
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled()) {
+ service.groupUnlock(new ParcelUuid(lockUuid));
+ return true;
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * Get device's groups.
+ * @param device the active device
+ * @return Map of groups ids and related UUIDs
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @NonNull Map getGroupUuidMapByDevice(@Nullable BluetoothDevice device) {
+ if (VDBG) {
+ log("getGroupUuidMapByDevice()");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled()) {
+ return service.getGroupUuidMapByDevice(device);
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return new HashMap<>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new HashMap<>();
+ }
+ }
+
+ /**
+ * Get group id for the given UUID
+ * @param uuid
+ * @return list of group IDs
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @NonNull List<Integer> getAllGroupIds(@Nullable ParcelUuid uuid) {
+ if (VDBG) {
+ log("getAllGroupIds()");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled()) {
+ return service.getAllGroupIds(uuid);
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return new ArrayList<Integer>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<Integer>();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NonNull List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) {
+ log("getConnectedDevices()");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ if (service != null && isEnabled()) {
+ try {
+ return service.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public
+ @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
+ @NonNull int[] states) {
+ if (VDBG) {
+ log("getDevicesMatchingStates(states=" + Arrays.toString(states) + ")");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ if (service != null && isEnabled()) {
+ try {
+ return service.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public
+ @BluetoothProfile.BtProfileState int getConnectionState(
+ @Nullable BluetoothDevice device) {
+ if (VDBG) {
+ log("getState(" + device + ")");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return service.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ /**
+ * Set connection policy of the profile
+ *
+ * <p> The device should already be paired.
+ * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+ * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+ *
+ * @param device Paired bluetooth device
+ * @param connectionPolicy is the connection policy to set to for this profile
+ * @return true if connectionPolicy is set, false on error
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setConnectionPolicy(
+ @Nullable BluetoothDevice device, @ConnectionPolicy int connectionPolicy) {
+ if (DBG) {
+ log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+ && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ return false;
+ }
+ return service.setConnectionPolicy(device, connectionPolicy);
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * Get the connection policy of the profile.
+ *
+ * <p> The connection policy can be any of:
+ * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+ * {@link #CONNECTION_POLICY_UNKNOWN}
+ *
+ * @param device Bluetooth device
+ * @return connection policy of the device
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
+ if (VDBG) {
+ log("getConnectionPolicy(" + device + ")");
+ }
+ final IBluetoothCsipSetCoordinator service = getService();
+ try {
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ return service.getConnectionPolicy(device);
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ }
+ }
+
+ private boolean isEnabled() {
+ return mAdapter.getState() == BluetoothAdapter.STATE_ON;
+ }
+
+ private static boolean isValidDevice(@Nullable BluetoothDevice device) {
+ return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 0969ec2..1054b4c 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -106,7 +106,7 @@
* <p>Sent when a remote device is found during discovery.
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
- * {@link #EXTRA_RSSI} if they are available.
+ * {@link #EXTRA_RSSI} and/or {@link #EXTRA_IS_COORDINATED_SET_MEMBER} if they are available.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} and
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive.
*/
@@ -257,6 +257,15 @@
public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
/**
+ * Used as an bool extra field in {@link #ACTION_FOUND} intents.
+ * It contains the information if device is discovered as member of a coordinated set or not.
+ * Pairing with device that belongs to a set would trigger pairing with the rest of set members.
+ * See Bluetooth CSIP specification for more details.
+ */
+ public static final String EXTRA_IS_COORDINATED_SET_MEMBER =
+ "android.bluetooth.extra.IS_COORDINATED_SET_MEMBER";
+
+ /**
* Used as a Parcelable {@link BluetoothClass} extra field in {@link
* #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
*/
@@ -1326,7 +1335,7 @@
* @throws IllegalArgumentException if an invalid transport was specified
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean createBond(int transport) {
return createBondInternal(transport, null, null);
@@ -1622,13 +1631,38 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
public boolean fetchUuidsWithSdp() {
+ return fetchUuidsWithSdp(TRANSPORT_AUTO);
+ }
+
+ /**
+ * Perform a service discovery on the remote device to get the UUIDs supported with the
+ * specific transport.
+ *
+ * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
+ * with the UUIDs supported by the remote end. If there is an error
+ * in getting the SDP or GATT records or if the process takes a long time, or the device
+ * is bonding and we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the
+ * UUIDs that is currently present in the cache. Clients should use the {@link #getUuids}
+ * to get UUIDs if service discovery is not to be performed. If there is an ongoing bonding
+ * process, service discovery or device inquiry, the request will be queued.
+ *
+ * @param transport - provide type of transport (e.g. LE or Classic).
+ * @return False if the check fails, True if the process of initiating an ACL connection
+ * to the remote device was started or cached UUIDs will be broadcast with the specific
+ * transport.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean fetchUuidsWithSdp(@Transport int transport) {
final IBluetooth service = sService;
if (service == null || !isBluetoothEnabled()) {
Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
return false;
}
try {
- return service.fetchRemoteUuids(this);
+ return service.fetchRemoteUuids(this, transport);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 632572d..18aa23a 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -1018,8 +1018,8 @@
* - binder is dead or Bluetooth is disabled or other error
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- @UnsupportedAppUsage
public boolean startScoUsingVirtualVoiceCall() {
if (DBG) log("startScoUsingVirtualVoiceCall()");
final IBluetoothHeadset service = mService;
@@ -1048,8 +1048,8 @@
* - binder is dead or Bluetooth is disabled or other error
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- @UnsupportedAppUsage
public boolean stopScoUsingVirtualVoiceCall() {
if (DBG) log("stopScoUsingVirtualVoiceCall()");
final IBluetoothHeadset service = mService;
@@ -1227,7 +1227,8 @@
* @return true if in-band ringing is enabled, false if in-band ringing is disabled
* @hide
*/
- @RequiresPermission(android.Manifest.permission.BLUETOOTH)
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean isInbandRingingEnabled() {
if (DBG) {
log("isInbandRingingEnabled()");
diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
index 75fcab9..6bbe95e 100644
--- a/core/java/android/bluetooth/BluetoothLeAudio.java
+++ b/core/java/android/bluetooth/BluetoothLeAudio.java
@@ -65,9 +65,6 @@
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED =
@@ -82,9 +79,6 @@
* be null if no device is active. </li>
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -92,12 +86,148 @@
"android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED";
/**
+ * Intent used to broadcast group node status information.
+ *
+ * <p>This intent will have 3 extra:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
+ * be null if no device is active. </li>
+ * <li> {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id. </li>
+ * <li> {@link #EXTRA_LE_AUDIO_GROUP_NODE_STATUS} - Group node status. </li>
+ * </ul>
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_LE_AUDIO_GROUP_NODE_STATUS_CHANGED =
+ "android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED";
+
+
+ /**
+ * Intent used to broadcast group status information.
+ *
+ * <p>This intent will have 4 extra:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
+ * be null if no device is active. </li>
+ * <li> {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id. </li>
+ * <li> {@link #EXTRA_LE_AUDIO_GROUP_STATUS} - Group status. </li>
+ * </ul>
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_LE_AUDIO_GROUP_STATUS_CHANGED =
+ "android.bluetooth.action.LE_AUDIO_GROUP_STATUS_CHANGED";
+
+ /**
+ * Intent used to broadcast group audio configuration changed information.
+ *
+ * <p>This intent will have 5 extra:
+ * <ul>
+ * <li> {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id. </li>
+ * <li> {@link #EXTRA_LE_AUDIO_DIRECTION} - Direction as bit mask. </li>
+ * <li> {@link #EXTRA_LE_AUDIO_SINK_LOCATION} - Sink location as per Bluetooth Assigned
+ * Numbers </li>
+ * <li> {@link #EXTRA_LE_AUDIO_SOURCE_LOCATION} - Source location as per Bluetooth Assigned
+ * Numbers </li>
+ * <li> {@link #EXTRA_LE_AUDIO_AVAILABLE_CONTEXTS} - Available contexts for group as per
+ * Bluetooth Assigned Numbers </li>
+ * </ul>
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_LE_AUDIO_CONF_CHANGED =
+ "android.bluetooth.action.LE_AUDIO_CONF_CHANGED";
+
+ /**
+ * Indicates conversation between humans as, for example, in telephony or video calls.
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_COMMUNICATION = 0x0002;
+
+ /**
+ * Indicates media as, for example, in music, public radio, podcast or video soundtrack.
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_MEDIA = 0x0004;
+
+ /**
* This represents an invalid group ID.
*
* @hide
*/
public static final int GROUP_ID_INVALID = IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
+ /**
+ * Contains group id.
+ * @hide
+ */
+ public static final String EXTRA_LE_AUDIO_GROUP_ID =
+ "android.bluetooth.extra.LE_AUDIO_GROUP_ID";
+
+ /**
+ * Contains group node status, can be any of
+ * <p>
+ * <ul>
+ * <li> {@link #GROUP_NODE_ADDED} </li>
+ * <li> {@link #GROUP_NODE_REMOVED} </li>
+ * </ul>
+ * <p>
+ * @hide
+ */
+ public static final String EXTRA_LE_AUDIO_GROUP_NODE_STATUS =
+ "android.bluetooth.extra.LE_AUDIO_GROUP_NODE_STATUS";
+
+ /**
+ * Contains group status, can be any of
+ *
+ * <p>
+ * <ul>
+ * <li> {@link #GROUP_STATUS_IDLE} </li>
+ * <li> {@link #GROUP_STATUS_STREAMING} </li>
+ * <li> {@link #GROUP_STATUS_SUSPENDED} </li>
+ * <li> {@link #GROUP_STATUS_RECONFIGURED} </li>
+ * <li> {@link #GROUP_STATUS_DESTROYED} </li>
+ * </ul>
+ * <p>
+ * @hide
+ */
+ public static final String EXTRA_LE_AUDIO_GROUP_STATUS =
+ "android.bluetooth.extra.LE_AUDIO_GROUP_STATUS";
+
+ /**
+ * Contains bit mask for direction, bit 0 set when Sink, bit 1 set when Source.
+ * @hide
+ */
+ public static final String EXTRA_LE_AUDIO_DIRECTION =
+ "android.bluetooth.extra.LE_AUDIO_DIRECTION";
+
+ /**
+ * Contains source location as per Bluetooth Assigned Numbers
+ * @hide
+ */
+ public static final String EXTRA_LE_AUDIO_SOURCE_LOCATION =
+ "android.bluetooth.extra.LE_AUDIO_SOURCE_LOCATION";
+
+ /**
+ * Contains sink location as per Bluetooth Assigned Numbers
+ * @hide
+ */
+ public static final String EXTRA_LE_AUDIO_SINK_LOCATION =
+ "android.bluetooth.extra.LE_AUDIO_SINK_LOCATION";
+
+ /**
+ * Contains available context types for group as per Bluetooth Assigned Numbers
+ * @hide
+ */
+ public static final String EXTRA_LE_AUDIO_AVAILABLE_CONTEXTS =
+ "android.bluetooth.extra.LE_AUDIO_AVAILABLE_CONTEXTS";
+
private BluetoothAdapter mAdapter;
private final BluetoothProfileConnector<IBluetoothLeAudio> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.LE_AUDIO, "BluetoothLeAudio",
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index bea32ab..c4649b4 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -229,12 +229,18 @@
int MCP_SERVER = 24;
/**
+ * Coordinated Set Identification Profile set coordinator
+ *
+ */
+ int CSIP_SET_COORDINATOR = 25;
+
+ /**
* Max profile ID. This value should be updated whenever a new profile is added to match
* the largest value assigned to a profile.
*
* @hide
*/
- int MAX_PROFILE_ID = 24;
+ int MAX_PROFILE_ID = 25;
/**
* Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index d072593..7e4ee9e8 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -182,6 +182,11 @@
/** @hide */
@NonNull
@SystemApi
+ public static final ParcelUuid COORDINATED_SET =
+ ParcelUuid.fromString("00001846-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/core/java/android/bluetooth/OWNERS b/core/java/android/bluetooth/OWNERS
index 2239100..fbee577 100644
--- a/core/java/android/bluetooth/OWNERS
+++ b/core/java/android/bluetooth/OWNERS
@@ -1,5 +1,6 @@
# Bug component: 27441
-zachoverflow@google.com
-siyuanh@google.com
rahulsabnis@google.com
+sattiraju@google.com
+siyuanh@google.com
+zachoverflow@google.com
diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl
index 0b950b4..11ea16f 100644
--- a/core/java/android/content/om/IOverlayManager.aidl
+++ b/core/java/android/content/om/IOverlayManager.aidl
@@ -39,7 +39,7 @@
* requested user, an empty map is returned.
*/
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- Map getAllOverlays(in int userId);
+ Map<String, List<OverlayInfo>> getAllOverlays(in int userId);
/**
* Returns information about all overlays for the given target package for
@@ -51,7 +51,7 @@
* @return A list of OverlayInfo objects; if no overlays exist for the
* requested package, an empty list is returned.
*/
- List getOverlayInfosForTarget(in String targetPackageName, in int userId);
+ List<OverlayInfo> getOverlayInfosForTarget(in String targetPackageName, in int userId);
/**
* Returns information about the overlay with the given package name for the
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
index 0ba92cc..504a7bd 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
+++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.content.IntentFilter;
import android.os.Parcel;
-import android.os.Parcelable;
import android.util.Pair;
import com.android.internal.util.DataClass;
@@ -168,19 +167,6 @@
+ '}';
}
- public static final Parcelable.Creator<ParsedIntentInfo> CREATOR =
- new Parcelable.Creator<ParsedIntentInfo>() {
- @Override
- public ParsedIntentInfo createFromParcel(Parcel source) {
- return new ParsedIntentInfo(source);
- }
-
- @Override
- public ParsedIntentInfo[] newArray(int size) {
- return new ParsedIntentInfo[size];
- }
- };
-
public boolean isHasDefault() {
return hasDefault;
}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 0a76a9c..9e78a6b 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1440,14 +1440,14 @@
* Assuming that the bottom edge of the device faces the
* user and that the screen is face-up, tilting the top edge
* of the device toward the ground creates a positive pitch
- * angle. The range of values is -π to π.</li>
+ * angle. The range of values is -π/2 to π/2.</li>
* <li>values[2]: <i>Roll</i>, angle of rotation about the y axis. This
* value represents the angle between a plane perpendicular
* to the device's screen and a plane perpendicular to the
* ground. Assuming that the bottom edge of the device faces
* the user and that the screen is face-up, tilting the left
* edge of the device toward the ground creates a positive
- * roll angle. The range of values is -π/2 to π/2.</li>
+ * roll angle. The range of values is -π to π.</li>
* </ul>
* <p>
* Applying these three rotations in the azimuth, pitch, roll order
diff --git a/core/java/android/hardware/radio/ITuner.aidl b/core/java/android/hardware/radio/ITuner.aidl
index 429f1f3..7bf234b 100644
--- a/core/java/android/hardware/radio/ITuner.aidl
+++ b/core/java/android/hardware/radio/ITuner.aidl
@@ -80,14 +80,14 @@
void setConfigFlag(int flag, boolean value);
/**
- * @param parameters Vendor-specific key-value pairs, must be Map<String, String>
- * @return Vendor-specific key-value pairs, must be Map<String, String>
+ * @param parameters Vendor-specific key-value pairs
+ * @return Vendor-specific key-value pairs
*/
- Map setParameters(in Map parameters);
+ Map<String, String> setParameters(in Map<String, String> parameters);
/**
* @param keys Parameter keys to fetch
- * @return Vendor-specific key-value pairs, must be Map<String, String>
+ * @return Vendor-specific key-value pairs
*/
- Map getParameters(in List<String> keys);
+ Map<String, String> getParameters(in List<String> keys);
}
diff --git a/core/java/android/hardware/radio/ITunerCallback.aidl b/core/java/android/hardware/radio/ITunerCallback.aidl
index b32daa5..f98947b 100644
--- a/core/java/android/hardware/radio/ITunerCallback.aidl
+++ b/core/java/android/hardware/radio/ITunerCallback.aidl
@@ -36,7 +36,7 @@
void onProgramListUpdated(in ProgramList.Chunk chunk);
/**
- * @param parameters Vendor-specific key-value pairs, must be Map<String, String>
+ * @param parameters Vendor-specific key-value pairs
*/
- void onParametersUpdated(in Map parameters);
+ void onParametersUpdated(in Map<String, String> parameters);
}
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index beff0f7..e3f7001 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -220,7 +220,7 @@
}
@Override
- public void onParametersUpdated(Map parameters) {
+ public void onParametersUpdated(Map<String, String> parameters) {
mHandler.post(() -> mCallback.onParametersUpdated(parameters));
}
}
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 68917a8..08f75df 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -47,7 +47,6 @@
import android.util.BackupUtils;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.net.module.util.NetworkIdentityUtils;
@@ -151,24 +150,6 @@
}
}
- private static boolean sForceAllNetworkTypes = false;
-
- /**
- * Results in matching against all mobile network types.
- *
- * <p>See {@link #matchesMobile} and {@link matchesMobileWildcard}.
- */
- @VisibleForTesting
- public static void forceAllNetworkTypes() {
- sForceAllNetworkTypes = true;
- }
-
- /** Resets the affect of {@link #forceAllNetworkTypes}. */
- @VisibleForTesting
- public static void resetForceAllNetworkTypes() {
- sForceAllNetworkTypes = false;
- }
-
/**
* Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
* the given IMSI.
@@ -611,7 +592,7 @@
// Only metered mobile network would be matched regardless of metered filter.
// This is used to exclude non-metered APNs, e.g. IMS. See ag/908650.
// TODO: Respect metered filter and remove mMetered condition.
- return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered))
+ return (ident.mType == TYPE_MOBILE && ident.mMetered)
&& !ArrayUtils.isEmpty(mMatchSubscriberIds)
&& ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
&& matchesCollapsedRatType(ident);
@@ -726,7 +707,7 @@
if (ident.mType == TYPE_WIMAX) {
return true;
} else {
- return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered))
+ return (ident.mType == TYPE_MOBILE && ident.mMetered)
&& matchesCollapsedRatType(ident);
}
}
diff --git a/core/java/android/net/PacProxyManager.java b/core/java/android/net/PacProxyManager.java
index 8f7ad8c..da79634 100644
--- a/core/java/android/net/PacProxyManager.java
+++ b/core/java/android/net/PacProxyManager.java
@@ -94,7 +94,7 @@
}
/**
- * Updates the PAC Proxy Installer with current Proxy information.
+ * Updates the PAC Proxy Service with current Proxy information.
*/
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STACK,
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 5a25cfc..ae8d010 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -23,6 +23,9 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
@@ -126,6 +129,24 @@
private static final boolean DBG = false;
/**
+ * When enabled, apps targeting < Android 12 are considered legacy for
+ * the NSD native daemon.
+ * The platform will only keep the daemon running as long as there are
+ * any legacy apps connected.
+ *
+ * After Android 12, directly communicate with native daemon might not
+ * work since the native damon won't always stay alive.
+ * Use the NSD APIs from NsdManager as the replacement is recommended.
+ * An another alternative could be bundling your own mdns solutions instead of
+ * depending on the system mdns native daemon.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
+ public static final long RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS = 191844585L;
+
+ /**
* Broadcast intent action to indicate whether network service discovery is
* enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state
* information as int.
@@ -203,6 +224,9 @@
public static final int DAEMON_CLEANUP = BASE + 21;
/** @hide */
+ public static final int DAEMON_STARTUP = BASE + 22;
+
+ /** @hide */
public static final int ENABLE = BASE + 24;
/** @hide */
public static final int DISABLE = BASE + 25;
@@ -232,6 +256,8 @@
EVENT_NAMES.put(RESOLVE_SERVICE, "RESOLVE_SERVICE");
EVENT_NAMES.put(RESOLVE_SERVICE_FAILED, "RESOLVE_SERVICE_FAILED");
EVENT_NAMES.put(RESOLVE_SERVICE_SUCCEEDED, "RESOLVE_SERVICE_SUCCEEDED");
+ EVENT_NAMES.put(DAEMON_CLEANUP, "DAEMON_CLEANUP");
+ EVENT_NAMES.put(DAEMON_STARTUP, "DAEMON_STARTUP");
EVENT_NAMES.put(ENABLE, "ENABLE");
EVENT_NAMES.put(DISABLE, "DISABLE");
EVENT_NAMES.put(NATIVE_DAEMON_EVENT, "NATIVE_DAEMON_EVENT");
@@ -494,6 +520,12 @@
} catch (InterruptedException e) {
fatal("Interrupted wait at init");
}
+ if (CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) {
+ return;
+ }
+ // Only proactively start the daemon if the target SDK < S, otherwise the internal service
+ // would automatically start/stop the native daemon as needed.
+ mAsyncChannel.sendMessage(DAEMON_STARTUP);
}
private static void fatal(String msg) {
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 1692921f..fb21ce3 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -31,6 +31,7 @@
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Set;
+import java.util.function.Supplier;
/**
* A mapping from String keys to values of various types. In most cases, you
@@ -38,7 +39,8 @@
* {@link PersistableBundle} subclass.
*/
public class BaseBundle {
- private static final String TAG = "Bundle";
+ /** @hide */
+ protected static final String TAG = "Bundle";
static final boolean DEBUG = false;
// Keep them in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
@@ -95,7 +97,7 @@
Parcel mParcelledData = null;
/**
- * Whether {@link #mParcelledData} was generated by native coed or not.
+ * Whether {@link #mParcelledData} was generated by native code or not.
*/
private boolean mParcelledByNative;
@@ -198,7 +200,7 @@
if (size == 0) {
return null;
}
- Object o = mMap.valueAt(0);
+ Object o = getValueAt(0);
try {
return (String) o;
} catch (ClassCastException e) {
@@ -229,7 +231,12 @@
* using the currently assigned class loader.
*/
@UnsupportedAppUsage
- /* package */ void unparcel() {
+ final void unparcel() {
+ unparcel(/* itemwise */ false);
+ }
+
+ /** Deserializes the underlying data and each item if {@code itemwise} is true. */
+ final void unparcel(boolean itemwise) {
synchronized (this) {
final Parcel source = mParcelledData;
if (source != null) {
@@ -241,9 +248,45 @@
+ ": no parcelled data");
}
}
+ if (itemwise) {
+ for (int i = 0, n = mMap.size(); i < n; i++) {
+ // Triggers deserialization of i-th item, if needed
+ getValueAt(i);
+ }
+ }
}
}
+ /**
+ * Returns the value for key {@code key}.
+ *
+ * This call should always be made after {@link #unparcel()} or inside a lock after making sure
+ * {@code mMap} is not null.
+ *
+ * @hide
+ */
+ final Object getValue(String key) {
+ int i = mMap.indexOfKey(key);
+ return (i >= 0) ? getValueAt(i) : null;
+ }
+
+ /**
+ * Returns the value for a certain position in the array map.
+ *
+ * This call should always be made after {@link #unparcel()} or inside a lock after making sure
+ * {@code mMap} is not null.
+ *
+ * @hide
+ */
+ final Object getValueAt(int i) {
+ Object object = mMap.valueAt(i);
+ if (object instanceof Supplier<?>) {
+ object = ((Supplier<?>) object).get();
+ mMap.setValueAt(i, object);
+ }
+ return object;
+ }
+
private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel,
boolean parcelledByNative) {
if (LOG_DEFUSABLE && sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
@@ -282,15 +325,8 @@
map.ensureCapacity(count);
}
try {
- if (parcelledByNative) {
- // If it was parcelled by native code, then the array map keys aren't sorted
- // by their hash codes, so use the safe (slow) one.
- parcelledData.readArrayMapSafelyInternal(map, count, mClassLoader);
- } else {
- // If parcelled by Java, we know the contents are sorted properly,
- // so we can use ArrayMap.append().
- parcelledData.readArrayMapInternal(map, count, mClassLoader);
- }
+ recycleParcel &= parcelledData.readArrayMap(map, count, !parcelledByNative,
+ /* lazy */ true, mClassLoader);
} catch (BadParcelableException e) {
if (sShouldDefuse) {
Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e);
@@ -342,7 +378,7 @@
/** @hide */
ArrayMap<String, Object> getMap() {
- unparcel();
+ unparcel(/* itemwise */ true);
return mMap;
}
@@ -400,7 +436,12 @@
}
/**
- * @hide This kind-of does an equality comparison. Kind-of.
+ * Performs a loose equality check, which means there can be false negatives but if the method
+ * returns true than both objects are guaranteed to be equal.
+ *
+ * The point is that this method is a light-weight check in performance terms.
+ *
+ * @hide
*/
public boolean kindofEquals(BaseBundle other) {
if (other == null) {
@@ -415,6 +456,12 @@
} else if (isParcelled()) {
return mParcelledData.compareData(other.mParcelledData) == 0;
} else {
+ // Following semantic above of failing in case we get a serialized value vs a
+ // deserialized one, we'll compare the map. If a certain element hasn't been
+ // deserialized yet, it's a Supplier (or more specifically a LazyValue, but let's
+ // pretend we don't know that here :P), we'll use that element's equality comparison as
+ // map naturally does. That will takes care of comparing the payload if needed (see
+ // Parcel.readLazyValue() for details).
return mMap.equals(other.mMap);
}
}
@@ -453,7 +500,7 @@
final int N = fromMap.size();
mMap = new ArrayMap<>(N);
for (int i = 0; i < N; i++) {
- mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
+ mMap.append(fromMap.keyAt(i), deepCopyValue(from.getValueAt(i)));
}
}
} else {
@@ -526,7 +573,7 @@
@Nullable
public Object get(String key) {
unparcel();
- return mMap.get(key);
+ return getValue(key);
}
/**
@@ -1001,7 +1048,7 @@
*/
char getChar(String key, char defaultValue) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return defaultValue;
}
@@ -1266,7 +1313,7 @@
@Nullable
Serializable getSerializable(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -1289,7 +1336,7 @@
@Nullable
ArrayList<Integer> getIntegerArrayList(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -1312,7 +1359,7 @@
@Nullable
ArrayList<String> getStringArrayList(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -1335,7 +1382,7 @@
@Nullable
ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -1404,7 +1451,7 @@
@Nullable
short[] getShortArray(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -1427,7 +1474,7 @@
@Nullable
char[] getCharArray(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -1496,7 +1543,7 @@
@Nullable
float[] getFloatArray(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -1585,7 +1632,7 @@
void writeToParcelInner(Parcel parcel, int flags) {
// If the parcel has a read-write helper, we can't just copy the blob, so unparcel it first.
if (parcel.hasReadWriteHelper()) {
- unparcel();
+ unparcel(/* itemwise */ true);
}
// Keep implementation in sync with writeToParcel() in
// frameworks/native/libs/binder/PersistableBundle.cpp.
@@ -1660,10 +1707,13 @@
}
if (parcel.hasReadWriteHelper()) {
- // If the parcel has a read-write helper, then we can't lazily-unparcel it, so just
- // unparcel right away.
+ // If the parcel has a read-write helper, it's better to deserialize immediately
+ // otherwise the helper would have to either maintain valid state long after the bundle
+ // had been constructed with parcel or to make sure they trigger deserialization of the
+ // bundle immediately; neither of which is obvious.
synchronized (this) {
initializeFromParcelLocked(parcel, /*recycleParcel=*/ false, isNativeBundle);
+ unparcel(/* itemwise */ true);
}
return;
}
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 1c1f5c0..5626bde 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -330,47 +330,9 @@
// It's been unparcelled, so we need to walk the map
for (int i=mMap.size()-1; i>=0; i--) {
Object obj = mMap.valueAt(i);
- if (obj instanceof Parcelable) {
- if ((((Parcelable)obj).describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
- fdFound = true;
- break;
- }
- } else if (obj instanceof Parcelable[]) {
- Parcelable[] array = (Parcelable[]) obj;
- for (int n = array.length - 1; n >= 0; n--) {
- Parcelable p = array[n];
- if (p != null && ((p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
- fdFound = true;
- break;
- }
- }
- } else if (obj instanceof SparseArray) {
- SparseArray<? extends Parcelable> array =
- (SparseArray<? extends Parcelable>) obj;
- for (int n = array.size() - 1; n >= 0; n--) {
- Parcelable p = array.valueAt(n);
- if (p != null && (p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
- fdFound = true;
- break;
- }
- }
- } else if (obj instanceof ArrayList) {
- ArrayList array = (ArrayList) obj;
- // an ArrayList here might contain either Strings or
- // Parcelables; only look inside for Parcelables
- if (!array.isEmpty() && (array.get(0) instanceof Parcelable)) {
- for (int n = array.size() - 1; n >= 0; n--) {
- Parcelable p = (Parcelable) array.get(n);
- if (p != null && ((p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
- fdFound = true;
- break;
- }
- }
- }
+ if (Parcel.hasFileDescriptors(obj)) {
+ fdFound = true;
+ break;
}
}
}
@@ -391,7 +353,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Bundle filterValues() {
- unparcel();
+ unparcel(/* itemwise */ true);
Bundle bundle = this;
if (mMap != null) {
ArrayMap<String, Object> map = mMap;
@@ -972,7 +934,7 @@
@Nullable
public Bundle getBundle(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -999,7 +961,7 @@
@Nullable
public <T extends Parcelable> T getParcelable(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -1026,7 +988,7 @@
@Nullable
public Parcelable[] getParcelableArray(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -1053,7 +1015,7 @@
@Nullable
public <T extends Parcelable> ArrayList<T> getParcelableArrayList(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -1077,7 +1039,7 @@
@Nullable
public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(@Nullable String key) {
unparcel();
- Object o = mMap.get(key);
+ Object o = getValue(key);
if (o == null) {
return null;
}
@@ -1300,7 +1262,7 @@
public void writeToParcel(Parcel parcel, int flags) {
final boolean oldAllowFds = parcel.pushAllowFds((mFlags & FLAG_ALLOW_FDS) != 0);
try {
- super.writeToParcelInner(parcel, flags);
+ writeToParcelInner(parcel, flags);
} finally {
parcel.restoreAllowFds(oldAllowFds);
}
@@ -1312,7 +1274,7 @@
* @param parcel The parcel to overwrite this bundle from.
*/
public void readFromParcel(Parcel parcel) {
- super.readFromParcelInner(parcel);
+ readFromParcelInner(parcel);
mFlags = FLAG_ALLOW_FDS;
maybePrefillHasFds();
}
diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl
index 4d160da..d83d94a 100644
--- a/core/java/android/os/ISystemConfig.aidl
+++ b/core/java/android/os/ISystemConfig.aidl
@@ -40,4 +40,9 @@
* @see SystemConfigManager#getSystemPermissionUids
*/
int[] getSystemPermissionUids(String permissionName);
+
+ /**
+ * @see SystemConfigManager#getEnabledComponentOverrides
+ */
+ List<String> getEnabledComponentOverrides(String packageName);
}
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index a870c04..c575c80e 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -69,3 +69,6 @@
# UpdateEngine
per-file *UpdateEngine* = file:/platform/system/update_engine:/OWNERS
+
+# VINTF
+per-file Vintf* = file:/platform/system/libvintf:/OWNERS
diff --git a/core/java/android/os/OutcomeReceiver.java b/core/java/android/os/OutcomeReceiver.java
new file mode 100644
index 0000000..01b2764
--- /dev/null
+++ b/core/java/android/os/OutcomeReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.NonNull;
+
+/**
+ * Callback interface intended for use when an asynchronous operation may result in a failure.
+ *
+ * This interface may be used in cases where an asynchronous API may complete either with a value
+ * or with a {@link Throwable} that indicates an error.
+ * @param <R> The type of the result that's being sent.
+ * @param <E> The type of the {@link Throwable} that contains more information about the error.
+ */
+public interface OutcomeReceiver<R, E extends Throwable> {
+ /**
+ * Called when the asynchronous operation succeeds and delivers a result value.
+ * @param result The value delivered by the asynchronous operation.
+ */
+ void onResult(@NonNull R result);
+
+ /**
+ * Called when the asynchronous operation fails. The mode of failure is indicated by the
+ * {@link Throwable} passed as an argument to this method.
+ * @param error A subclass of {@link Throwable} with more details about the error that occurred.
+ */
+ default void onError(@NonNull E error) {}
+}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 6acdcc4..7f2e2b1 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -16,6 +16,8 @@
package android.os;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -26,6 +28,7 @@
import android.util.ArraySet;
import android.util.ExceptionUtils;
import android.util.Log;
+import android.util.MathUtils;
import android.util.Size;
import android.util.SizeF;
import android.util.Slog;
@@ -56,7 +59,9 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
+import java.util.function.Supplier;
/**
* Container for a message (data and object references) that can
@@ -279,6 +284,8 @@
@CriticalNative
private static native void nativeMarkSensitive(long nativePtr);
+ @FastNative
+ private static native void nativeMarkForBinder(long nativePtr, IBinder binder);
@CriticalNative
private static native int nativeDataSize(long nativePtr);
@CriticalNative
@@ -495,6 +502,16 @@
/**
* Parcel data should be zero'd before realloc'd or deleted.
+ *
+ * Note: currently this feature requires multiple things to work in concert:
+ * - markSensitive must be called on every relative Parcel
+ * - FLAG_CLEAR_BUF must be passed into the kernel
+ * This requires having code which does the right thing in every method and in every backend
+ * of AIDL. Rather than exposing this API, it should be replaced with a single API on
+ * IBinder objects which can be called once, and the information should be fed into the
+ * Parcel using markForBinder APIs. In terms of code size and number of API calls, this is
+ * much more extensible.
+ *
* @hide
*/
public final void markSensitive() {
@@ -502,9 +519,23 @@
}
/**
+ * Associate this parcel with a binder object. This marks the parcel as being prepared for a
+ * transaction on this specific binder object. Based on this, the format of the wire binder
+ * protocol may change. This should be called before any data is written to the parcel. If this
+ * is called multiple times, this will only be marked for the last binder. For future
+ * compatibility, it is recommended to call this on all parcels which are being sent over
+ * binder.
+ *
+ * @hide
+ */
+ public void markForBinder(@NonNull IBinder binder) {
+ nativeMarkForBinder(mNativePtr, binder);
+ }
+
+ /**
* Returns the total amount of data contained in the parcel.
*/
- public final int dataSize() {
+ public int dataSize() {
return nativeDataSize(mNativePtr);
}
@@ -649,6 +680,66 @@
}
/**
+ * Check if the object used in {@link #readValue(ClassLoader)} / {@link #writeValue(Object)}
+ * has file descriptors.
+ *
+ * <p>For most cases, it will use the self-reported {@link Parcelable#describeContents()} method
+ * for that.
+ *
+ * @throws IllegalArgumentException if you provide any object not supported by above methods.
+ * Most notably, if you pass {@link Parcel}, this method will throw, for that check
+ * {@link Parcel#hasFileDescriptors()}
+ *
+ * @hide
+ */
+ public static boolean hasFileDescriptors(Object value) {
+ if (value instanceof LazyValue) {
+ return ((LazyValue) value).hasFileDescriptors();
+ } else if (value instanceof Parcelable) {
+ if ((((Parcelable) value).describeContents()
+ & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+ return true;
+ }
+ } else if (value instanceof Parcelable[]) {
+ Parcelable[] array = (Parcelable[]) value;
+ for (int n = array.length - 1; n >= 0; n--) {
+ Parcelable p = array[n];
+ if (p != null && ((p.describeContents()
+ & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
+ return true;
+ }
+ }
+ } else if (value instanceof SparseArray<?>) {
+ SparseArray<?> array = (SparseArray<?>) value;
+ for (int n = array.size() - 1; n >= 0; n--) {
+ Object object = array.valueAt(n);
+ if (object instanceof Parcelable) {
+ Parcelable p = (Parcelable) object;
+ if (p != null && (p.describeContents()
+ & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+ return true;
+ }
+ }
+ }
+ } else if (value instanceof ArrayList<?>) {
+ ArrayList<?> array = (ArrayList<?>) value;
+ for (int n = array.size() - 1; n >= 0; n--) {
+ Object object = array.get(n);
+ if (object instanceof Parcelable) {
+ Parcelable p = (Parcelable) object;
+ if (p != null && ((p.describeContents()
+ & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
+ return true;
+ }
+ }
+ }
+ } else {
+ getValueType(value); // Will throw if value is not supported
+ }
+ return false;
+ }
+
+ /**
* Store or read an IBinder interface token in the parcel at the current
* {@link #dataPosition}. This is used to validate that the marshalled
* transaction is intended for the target interface.
@@ -1795,108 +1886,206 @@
* should be used).</p>
*/
public final void writeValue(@Nullable Object v) {
+ if (v instanceof LazyValue) {
+ LazyValue value = (LazyValue) v;
+ value.writeToParcel(this);
+ return;
+ }
+ int type = getValueType(v);
+ writeInt(type);
+ if (isLengthPrefixed(type)) {
+ // Length
+ int length = dataPosition();
+ writeInt(-1); // Placeholder
+ // Object
+ int start = dataPosition();
+ writeValue(type, v);
+ int end = dataPosition();
+ // Backpatch length
+ setDataPosition(length);
+ writeInt(end - start);
+ setDataPosition(end);
+ } else {
+ writeValue(type, v);
+ }
+ }
+
+ /** @hide */
+ public static int getValueType(@Nullable Object v) {
if (v == null) {
- writeInt(VAL_NULL);
+ return VAL_NULL;
} else if (v instanceof String) {
- writeInt(VAL_STRING);
- writeString((String) v);
+ return VAL_STRING;
} else if (v instanceof Integer) {
- writeInt(VAL_INTEGER);
- writeInt((Integer) v);
+ return VAL_INTEGER;
} else if (v instanceof Map) {
- writeInt(VAL_MAP);
- writeMap((Map) v);
+ return VAL_MAP;
} else if (v instanceof Bundle) {
// Must be before Parcelable
- writeInt(VAL_BUNDLE);
- writeBundle((Bundle) v);
+ return VAL_BUNDLE;
} else if (v instanceof PersistableBundle) {
- writeInt(VAL_PERSISTABLEBUNDLE);
- writePersistableBundle((PersistableBundle) v);
+ // Must be before Parcelable
+ return VAL_PERSISTABLEBUNDLE;
+ } else if (v instanceof SizeF) {
+ // Must be before Parcelable
+ return VAL_SIZEF;
} else if (v instanceof Parcelable) {
// IMPOTANT: cases for classes that implement Parcelable must
- // come before the Parcelable case, so that their specific VAL_*
+ // come before the Parcelable case, so that their speci fic VAL_*
// types will be written.
- writeInt(VAL_PARCELABLE);
- writeParcelable((Parcelable) v, 0);
+ return VAL_PARCELABLE;
} else if (v instanceof Short) {
- writeInt(VAL_SHORT);
- writeInt(((Short) v).intValue());
+ return VAL_SHORT;
} else if (v instanceof Long) {
- writeInt(VAL_LONG);
- writeLong((Long) v);
+ return VAL_LONG;
} else if (v instanceof Float) {
- writeInt(VAL_FLOAT);
- writeFloat((Float) v);
+ return VAL_FLOAT;
} else if (v instanceof Double) {
- writeInt(VAL_DOUBLE);
- writeDouble((Double) v);
+ return VAL_DOUBLE;
} else if (v instanceof Boolean) {
- writeInt(VAL_BOOLEAN);
- writeInt((Boolean) v ? 1 : 0);
+ return VAL_BOOLEAN;
} else if (v instanceof CharSequence) {
// Must be after String
- writeInt(VAL_CHARSEQUENCE);
- writeCharSequence((CharSequence) v);
+ return VAL_CHARSEQUENCE;
} else if (v instanceof List) {
- writeInt(VAL_LIST);
- writeList((List) v);
+ return VAL_LIST;
} else if (v instanceof SparseArray) {
- writeInt(VAL_SPARSEARRAY);
- writeSparseArray((SparseArray) v);
+ return VAL_SPARSEARRAY;
} else if (v instanceof boolean[]) {
- writeInt(VAL_BOOLEANARRAY);
- writeBooleanArray((boolean[]) v);
+ return VAL_BOOLEANARRAY;
} else if (v instanceof byte[]) {
- writeInt(VAL_BYTEARRAY);
- writeByteArray((byte[]) v);
+ return VAL_BYTEARRAY;
} else if (v instanceof String[]) {
- writeInt(VAL_STRINGARRAY);
- writeStringArray((String[]) v);
+ return VAL_STRINGARRAY;
} else if (v instanceof CharSequence[]) {
// Must be after String[] and before Object[]
- writeInt(VAL_CHARSEQUENCEARRAY);
- writeCharSequenceArray((CharSequence[]) v);
+ return VAL_CHARSEQUENCEARRAY;
} else if (v instanceof IBinder) {
- writeInt(VAL_IBINDER);
- writeStrongBinder((IBinder) v);
+ return VAL_IBINDER;
} else if (v instanceof Parcelable[]) {
- writeInt(VAL_PARCELABLEARRAY);
- writeParcelableArray((Parcelable[]) v, 0);
+ return VAL_PARCELABLEARRAY;
} else if (v instanceof int[]) {
- writeInt(VAL_INTARRAY);
- writeIntArray((int[]) v);
+ return VAL_INTARRAY;
} else if (v instanceof long[]) {
- writeInt(VAL_LONGARRAY);
- writeLongArray((long[]) v);
+ return VAL_LONGARRAY;
} else if (v instanceof Byte) {
- writeInt(VAL_BYTE);
- writeInt((Byte) v);
+ return VAL_BYTE;
} else if (v instanceof Size) {
- writeInt(VAL_SIZE);
- writeSize((Size) v);
- } else if (v instanceof SizeF) {
- writeInt(VAL_SIZEF);
- writeSizeF((SizeF) v);
+ return VAL_SIZE;
} else if (v instanceof double[]) {
- writeInt(VAL_DOUBLEARRAY);
- writeDoubleArray((double[]) v);
+ return VAL_DOUBLEARRAY;
} else {
Class<?> clazz = v.getClass();
if (clazz.isArray() && clazz.getComponentType() == Object.class) {
// Only pure Object[] are written here, Other arrays of non-primitive types are
// handled by serialization as this does not record the component type.
- writeInt(VAL_OBJECTARRAY);
- writeArray((Object[]) v);
+ return VAL_OBJECTARRAY;
} else if (v instanceof Serializable) {
// Must be last
- writeInt(VAL_SERIALIZABLE);
- writeSerializable((Serializable) v);
+ return VAL_SERIALIZABLE;
} else {
- throw new RuntimeException("Parcel: unable to marshal value " + v);
+ throw new IllegalArgumentException("Parcel: unknown type for value " + v);
}
}
}
+ /**
+ * Writes value {@code v} in the parcel. This does NOT write the int representing the type
+ * first.
+ *
+ * @hide
+ */
+ public void writeValue(int type, @Nullable Object v) {
+ switch (type) {
+ case VAL_NULL:
+ break;
+ case VAL_STRING:
+ writeString((String) v);
+ break;
+ case VAL_INTEGER:
+ writeInt((Integer) v);
+ break;
+ case VAL_MAP:
+ writeMap((Map) v);
+ break;
+ case VAL_BUNDLE:
+ writeBundle((Bundle) v);
+ break;
+ case VAL_PERSISTABLEBUNDLE:
+ writePersistableBundle((PersistableBundle) v);
+ break;
+ case VAL_PARCELABLE:
+ writeParcelable((Parcelable) v, 0);
+ break;
+ case VAL_SHORT:
+ writeInt(((Short) v).intValue());
+ break;
+ case VAL_LONG:
+ writeLong((Long) v);
+ break;
+ case VAL_FLOAT:
+ writeFloat((Float) v);
+ break;
+ case VAL_DOUBLE:
+ writeDouble((Double) v);
+ break;
+ case VAL_BOOLEAN:
+ writeInt((Boolean) v ? 1 : 0);
+ break;
+ case VAL_CHARSEQUENCE:
+ writeCharSequence((CharSequence) v);
+ break;
+ case VAL_LIST:
+ writeList((List) v);
+ break;
+ case VAL_SPARSEARRAY:
+ writeSparseArray((SparseArray) v);
+ break;
+ case VAL_BOOLEANARRAY:
+ writeBooleanArray((boolean[]) v);
+ break;
+ case VAL_BYTEARRAY:
+ writeByteArray((byte[]) v);
+ break;
+ case VAL_STRINGARRAY:
+ writeStringArray((String[]) v);
+ break;
+ case VAL_CHARSEQUENCEARRAY:
+ writeCharSequenceArray((CharSequence[]) v);
+ break;
+ case VAL_IBINDER:
+ writeStrongBinder((IBinder) v);
+ break;
+ case VAL_PARCELABLEARRAY:
+ writeParcelableArray((Parcelable[]) v, 0);
+ break;
+ case VAL_INTARRAY:
+ writeIntArray((int[]) v);
+ break;
+ case VAL_LONGARRAY:
+ writeLongArray((long[]) v);
+ break;
+ case VAL_BYTE:
+ writeInt((Byte) v);
+ break;
+ case VAL_SIZE:
+ writeSize((Size) v);
+ break;
+ case VAL_SIZEF:
+ writeSizeF((SizeF) v);
+ break;
+ case VAL_DOUBLEARRAY:
+ writeDoubleArray((double[]) v);
+ break;
+ case VAL_OBJECTARRAY:
+ writeArray((Object[]) v);
+ break;
+ case VAL_SERIALIZABLE:
+ writeSerializable((Serializable) v);
+ break;
+ default:
+ throw new RuntimeException("Parcel: unable to marshal value " + v);
+ }
+ }
/**
* Flatten the name of the class of the Parcelable and its contents
@@ -3167,7 +3356,190 @@
@Nullable
public final Object readValue(@Nullable ClassLoader loader) {
int type = readInt();
+ final Object object;
+ if (isLengthPrefixed(type)) {
+ int length = readInt();
+ int start = dataPosition();
+ object = readValue(type, loader);
+ int actual = dataPosition() - start;
+ if (actual != length) {
+ Log.w(TAG,
+ "Unparcelling of " + object + " of type " + Parcel.valueTypeToString(type)
+ + " consumed " + actual + " bytes, but " + length + " expected.");
+ }
+ } else {
+ object = readValue(type, loader);
+ }
+ return object;
+ }
+ /**
+ * This will return a {@link Supplier} for length-prefixed types that deserializes the object
+ * when {@link Supplier#get()} is called, for other types it will return the object itself.
+ *
+ * <p>After calling {@link Supplier#get()} the parcel cursor will not change. Note that you
+ * shouldn't recycle the parcel, not at least until all objects have been retrieved. No
+ * synchronization attempts are made.
+ *
+ * </p>The supplier returned implements {@link #equals(Object)} and {@link #hashCode()}. Two
+ * suppliers are equal if either of the following is true:
+ * <ul>
+ * <li>{@link Supplier#get()} has been called on both and both objects returned are equal.
+ * <li>{@link Supplier#get()} hasn't been called on either one and everything below is true:
+ * <ul>
+ * <li>The {@code loader} parameters used to retrieve each are equal.
+ * <li>They both have the same type.
+ * <li>They have the same payload length.
+ * <li>Their binary content is the same.
+ * </ul>
+ * </ul>
+ *
+ * @hide
+ */
+ @Nullable
+ public Object readLazyValue(@Nullable ClassLoader loader) {
+ int start = dataPosition();
+ int type = readInt();
+ if (isLengthPrefixed(type)) {
+ int length = readInt();
+ setDataPosition(MathUtils.addOrThrow(dataPosition(), length));
+ return new LazyValue(this, start, length, type, loader);
+ } else {
+ return readValue(type, loader);
+ }
+ }
+
+ private static final class LazyValue implements Supplier<Object> {
+ private final int mPosition;
+ private final int mLength;
+ private final int mType;
+ @Nullable private final ClassLoader mLoader;
+ @Nullable private Object mObject;
+ @Nullable private volatile Parcel mValueParcel;
+
+ /**
+ * This goes from non-null to null once. Always check the nullability of this object before
+ * performing any operations, either involving itself or mObject since the happens-before
+ * established by this volatile will guarantee visibility of either. We can assume this
+ * parcel won't change anymore.
+ */
+ @Nullable private volatile Parcel mSource;
+
+ LazyValue(Parcel source, int position, int length, int type, @Nullable ClassLoader loader) {
+ mSource = requireNonNull(source);
+ mPosition = position;
+ mLength = length;
+ mType = type;
+ mLoader = loader;
+ }
+
+ @Override
+ public Object get() {
+ Parcel source = mSource;
+ if (source != null) {
+ synchronized (source) {
+ int restore = source.dataPosition();
+ try {
+ source.setDataPosition(mPosition);
+ mObject = source.readValue(mLoader);
+ } finally {
+ source.setDataPosition(restore);
+ }
+ mSource = null;
+ }
+ }
+ return mObject;
+ }
+
+ public void writeToParcel(Parcel out) {
+ Parcel source = mSource;
+ if (source != null) {
+ out.appendFrom(source, mPosition, mLength + 8);
+ } else {
+ out.writeValue(mObject);
+ }
+ }
+
+ public boolean hasFileDescriptors() {
+ Parcel source = mSource;
+ return (source != null)
+ ? getValueParcel(source).hasFileDescriptors()
+ : Parcel.hasFileDescriptors(mObject);
+ }
+
+ @Override
+ public String toString() {
+ return (mSource != null)
+ ? "Supplier{" + valueTypeToString(mType) + "@" + mPosition + "+" + mLength + '}'
+ : "Supplier{" + mObject + "}";
+ }
+
+ /**
+ * We're checking if the *lazy value* is equal to another one, not if the *object*
+ * represented by the lazy value is equal to the other one. So, if there are two lazy values
+ * and one of them has been deserialized but the other hasn't this will always return false.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof LazyValue)) {
+ return false;
+ }
+ LazyValue value = (LazyValue) other;
+ // Check if they are either both serialized or both deserialized.
+ Parcel source = mSource;
+ Parcel otherSource = value.mSource;
+ if ((source == null) != (otherSource == null)) {
+ return false;
+ }
+ // If both are deserialized, compare the live objects.
+ if (source == null) {
+ // Note that here it's guaranteed that both mObject references contain valid values
+ // (possibly null) since mSource will have provided the memory barrier for those and
+ // once deserialized we never go back to serialized state.
+ return Objects.equals(mObject, value.mObject);
+ }
+ // Better safely fail here since this could mean we get different objects.
+ if (!Objects.equals(mLoader, value.mLoader)) {
+ return false;
+ }
+ // Otherwise compare metadata prior to comparing payload.
+ if (mType != value.mType || mLength != value.mLength) {
+ return false;
+ }
+ // Finally we compare the payload.
+ return getValueParcel(source).compareData(value.getValueParcel(otherSource)) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ // Accessing mSource first to provide memory barrier for mObject
+ return Objects.hash(mSource == null, mObject, mLoader, mType, mLength);
+ }
+
+ /** This extracts the parcel section responsible for the object and returns it. */
+ private Parcel getValueParcel(Parcel source) {
+ Parcel parcel = mValueParcel;
+ if (parcel == null) {
+ parcel = Parcel.obtain();
+ // mLength is the length of object representation, excluding the type and length.
+ // mPosition is the position of the entire value container, right before the type.
+ // So, we add 4 bytes for the type + 4 bytes for the length written.
+ parcel.appendFrom(source, mPosition, mLength + 8);
+ mValueParcel = parcel;
+ }
+ return parcel;
+ }
+ }
+
+ /**
+ * Reads a value from the parcel of type {@code type}. Does NOT read the int representing the
+ * type first.
+ */
+ @Nullable
+ private Object readValue(int type, @Nullable ClassLoader loader) {
switch (type) {
case VAL_NULL:
return null;
@@ -3266,6 +3638,20 @@
}
}
+ private boolean isLengthPrefixed(int type) {
+ switch (type) {
+ case VAL_PARCELABLE:
+ case VAL_PARCELABLEARRAY:
+ case VAL_LIST:
+ case VAL_SPARSEARRAY:
+ case VAL_BUNDLE:
+ case VAL_SERIALIZABLE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
/**
* Read and return a new Parcelable from the parcel. The given class loader
* will be used to load any enclosed Parcelables. If it is null, the default
@@ -3564,49 +3950,49 @@
}
}
- /* package */ void readArrayMapInternal(@NonNull ArrayMap outVal, int N,
- @Nullable ClassLoader loader) {
- if (DEBUG_ARRAY_MAP) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Log.d(TAG, "Reading " + N + " ArrayMap entries", here);
- }
- int startPos;
- while (N > 0) {
- if (DEBUG_ARRAY_MAP) startPos = dataPosition();
- String key = readString();
- Object value = readValue(loader);
- if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read #" + (N-1) + " "
- + (dataPosition()-startPos) + " bytes: key=0x"
- + Integer.toHexString((key != null ? key.hashCode() : 0)) + " " + key);
- outVal.append(key, value);
- N--;
- }
- outVal.validate();
+ /* package */ void readArrayMapInternal(@NonNull ArrayMap<? super String, Object> outVal,
+ int size, @Nullable ClassLoader loader) {
+ readArrayMap(outVal, size, /* sorted */ true, /* lazy */ false, loader);
}
- /* package */ void readArrayMapSafelyInternal(@NonNull ArrayMap outVal, int N,
- @Nullable ClassLoader loader) {
- if (DEBUG_ARRAY_MAP) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Log.d(TAG, "Reading safely " + N + " ArrayMap entries", here);
- }
- while (N > 0) {
+ /**
+ * Reads a map into {@code map}.
+ *
+ * @param sorted Whether the keys are sorted by their hashes, if so we use an optimized path.
+ * @param lazy Whether to populate the map with lazy {@link Supplier} objects for
+ * length-prefixed values. See {@link Parcel#readLazyValue(ClassLoader)} for more
+ * details.
+ * @return whether the parcel can be recycled or not.
+ * @hide
+ */
+ boolean readArrayMap(ArrayMap<? super String, Object> map, int size, boolean sorted,
+ boolean lazy, @Nullable ClassLoader loader) {
+ boolean recycle = true;
+ while (size > 0) {
String key = readString();
- if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read safe #" + (N-1) + ": key=0x"
- + (key != null ? key.hashCode() : 0) + " " + key);
- Object value = readValue(loader);
- outVal.put(key, value);
- N--;
+ Object value = (lazy) ? readLazyValue(loader) : readValue(loader);
+ if (value instanceof LazyValue) {
+ recycle = false;
+ }
+ if (sorted) {
+ map.append(key, value);
+ } else {
+ map.put(key, value);
+ }
+ size--;
}
+ if (sorted) {
+ map.validate();
+ }
+ return recycle;
}
/**
* @hide For testing only.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void readArrayMap(@NonNull ArrayMap outVal, @Nullable ClassLoader loader) {
+ public void readArrayMap(@NonNull ArrayMap<? super String, Object> outVal,
+ @Nullable ClassLoader loader) {
final int N = readInt();
if (N < 0) {
return;
@@ -3691,4 +4077,38 @@
public long getBlobAshmemSize() {
return nativeGetBlobAshmemSize(mNativePtr);
}
+
+ private static String valueTypeToString(int type) {
+ switch (type) {
+ case VAL_NULL: return "VAL_NULL";
+ case VAL_INTEGER: return "VAL_INTEGER";
+ case VAL_MAP: return "VAL_MAP";
+ case VAL_BUNDLE: return "VAL_BUNDLE";
+ case VAL_PERSISTABLEBUNDLE: return "VAL_PERSISTABLEBUNDLE";
+ case VAL_PARCELABLE: return "VAL_PARCELABLE";
+ case VAL_SHORT: return "VAL_SHORT";
+ case VAL_LONG: return "VAL_LONG";
+ case VAL_FLOAT: return "VAL_FLOAT";
+ case VAL_DOUBLE: return "VAL_DOUBLE";
+ case VAL_BOOLEAN: return "VAL_BOOLEAN";
+ case VAL_CHARSEQUENCE: return "VAL_CHARSEQUENCE";
+ case VAL_LIST: return "VAL_LIST";
+ case VAL_SPARSEARRAY: return "VAL_SPARSEARRAY";
+ case VAL_BOOLEANARRAY: return "VAL_BOOLEANARRAY";
+ case VAL_BYTEARRAY: return "VAL_BYTEARRAY";
+ case VAL_STRINGARRAY: return "VAL_STRINGARRAY";
+ case VAL_CHARSEQUENCEARRAY: return "VAL_CHARSEQUENCEARRAY";
+ case VAL_IBINDER: return "VAL_IBINDER";
+ case VAL_PARCELABLEARRAY: return "VAL_PARCELABLEARRAY";
+ case VAL_INTARRAY: return "VAL_INTARRAY";
+ case VAL_LONGARRAY: return "VAL_LONGARRAY";
+ case VAL_BYTE: return "VAL_BYTE";
+ case VAL_SIZE: return "VAL_SIZE";
+ case VAL_SIZEF: return "VAL_SIZEF";
+ case VAL_DOUBLEARRAY: return "VAL_DOUBLEARRAY";
+ case VAL_OBJECTARRAY: return "VAL_OBJECTARRAY";
+ case VAL_SERIALIZABLE: return "VAL_SERIALIZABLE";
+ default: return "UNKNOWN(" + type + ")";
+ }
+ }
}
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index f7d7b21..4e8418b 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -17,6 +17,8 @@
package android.os;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import android.util.Log;
@@ -27,7 +29,15 @@
import java.util.Map;
-/** @hide */
+/**
+ * Manage binder services as registered with the binder context manager. These services must be
+ * declared statically on an Android device (SELinux access_vector service_manager, w/ service
+ * names in service_contexts files), and they do not follow the activity lifecycle. When
+ * building applications, android.app.Service should be preferred.
+ *
+ * @hide
+ **/
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class ServiceManager {
private static final String TAG = "ServiceManager";
private static final Object sLock = new Object();
@@ -98,10 +108,12 @@
int COUNT = GET_SERVICE + 1;
}
+ /** @hide */
public static final StatLogger sStatLogger = new StatLogger(new String[] {
"getService()",
});
+ /** @hide */
@UnsupportedAppUsage
public ServiceManager() {
}
@@ -123,6 +135,7 @@
*
* @param name the name of the service to get
* @return a reference to the service, or <code>null</code> if the service doesn't exist
+ * @hide
*/
@UnsupportedAppUsage
public static IBinder getService(String name) {
@@ -160,6 +173,7 @@
*
* @param name the name of the new service
* @param service the service object
+ * @hide
*/
@UnsupportedAppUsage
public static void addService(String name, IBinder service) {
@@ -174,6 +188,7 @@
* @param service the service object
* @param allowIsolated set to true to allow isolated sandboxed processes
* to access this service
+ * @hide
*/
@UnsupportedAppUsage
public static void addService(String name, IBinder service, boolean allowIsolated) {
@@ -189,6 +204,7 @@
* @param allowIsolated set to true to allow isolated sandboxed processes
* @param dumpPriority supported dump priority levels as a bitmask
* to access this service
+ * @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static void addService(String name, IBinder service, boolean allowIsolated,
@@ -203,6 +219,7 @@
/**
* Retrieve an existing service called @a name from the
* service manager. Non-blocking.
+ * @hide
*/
@UnsupportedAppUsage
public static IBinder checkService(String name) {
@@ -239,6 +256,7 @@
*
* @return true if the service is declared somewhere (eg. VINTF manifest) and
* waitForService should always be able to return the service.
+ * @hide
*/
public static String[] getDeclaredInstances(@NonNull String iface) {
try {
@@ -256,6 +274,7 @@
* will wait for it to be ready.
*
* @return {@code null} only if there are permission problems or fatal errors.
+ * @hide
*/
public static IBinder waitForService(@NonNull String name) {
return Binder.allowBlocking(waitForServiceNative(name));
@@ -263,7 +282,6 @@
private static native IBinder waitForServiceNative(@NonNull String name);
-
/**
* Returns the specified service from the service manager, if declared.
*
@@ -272,8 +290,10 @@
*
* @return {@code null} if the service is not declared in the manifest, or if there are
* permission problems, or if there are fatal errors.
+ * @hide
*/
- public static IBinder waitForDeclaredService(@NonNull String name) {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @Nullable public static IBinder waitForDeclaredService(@NonNull String name) {
return isDeclared(name) ? waitForService(name) : null;
}
@@ -281,6 +301,7 @@
* Return a list of all currently running services.
* @return an array of all currently running services, or <code>null</code> in
* case of an exception
+ * @hide
*/
@UnsupportedAppUsage
public static String[] listServices() {
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 755c35f..3739040 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -98,6 +98,10 @@
return mServiceManager.updatableViaApex(name);
}
+ public ConnectionInfo getConnectionInfo(String name) throws RemoteException {
+ return mServiceManager.getConnectionInfo(name);
+ }
+
public void registerClientCallback(String name, IBinder service, IClientCallback cb)
throws RemoteException {
throw new RemoteException();
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index 136e3de..46eb2ec 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -93,6 +93,26 @@
}
}
+ /**
+ * Creates an instance from existing shared memory passed as {@link ParcelFileDescriptor}.
+ *
+ * <p> The {@code fd} should be a shared memory created from
+ {@code SharedMemory or ASharedMemory}. This can be useful when shared memory is passed as
+ file descriptor through JNI or binder service implemented in cpp.
+ * <p> Note that newly created {@code SharedMemory} takes ownership of passed {@code fd} and
+ * the original {@code fd} becomes detached (Check {@link ParcelFileDescriptor#detachFd()}).
+ * If the caller wants to use the file descriptor after the call, the caller should duplicate
+ * the file descriptor (Check {@link ParcelFileDescriptor#dup()}) and pass the duped version
+ * instead.
+ *
+ * @param fd File descriptor of shared memory passed as {@link ParcelFileDescriptor}.
+ */
+ public static @NonNull SharedMemory fromFileDescriptor(@NonNull ParcelFileDescriptor fd) {
+ FileDescriptor f = new FileDescriptor();
+ f.setInt$(fd.detachFd());
+ return new SharedMemory(f);
+ }
+
private static final int PROT_MASK = OsConstants.PROT_READ | OsConstants.PROT_WRITE
| OsConstants.PROT_EXEC | OsConstants.PROT_NONE;
diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java
index 9bfa8ad..a6316df 100644
--- a/core/java/android/os/SystemConfigManager.java
+++ b/core/java/android/os/SystemConfigManager.java
@@ -17,6 +17,7 @@
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -129,4 +130,21 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Get enabled component for a specific package
+ *
+ * @param packageName The target package.
+ * @return The enabled component
+ * {@hide}
+ */
+ @SystemApi
+ @NonNull
+ public List<String> getEnabledComponentOverrides(@NonNull String packageName) {
+ try {
+ return mInterface.getEnabledComponentOverrides(packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index bf0b655..1f11197 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -97,8 +97,11 @@
* ["android.hidl.manager@1.0", "android.hardware.camera.device@1.0",
* "android.hardware.camera.device@3.2"]. There are no duplicates.
*
- * For AIDL HALs, the version is stripped away
- * (e.g. "android.hardware.light").
+ * For AIDL HALs, the version is a single number
+ * (e.g. "android.hardware.light@1"). Historically, this API strips the
+ * version number for AIDL HALs (e.g. "android.hardware.light"). Users
+ * of this API must be able to handle both for backwards compatibility.
+ *
* @hide
*/
@TestApi
diff --git a/core/java/android/os/connectivity/CellularBatteryStats.java b/core/java/android/os/connectivity/CellularBatteryStats.java
index 121fd33..fc17002 100644
--- a/core/java/android/os/connectivity/CellularBatteryStats.java
+++ b/core/java/android/os/connectivity/CellularBatteryStats.java
@@ -109,7 +109,7 @@
CellSignalStrength.getNumSignalStrengthLevels()));
mTxTimeMs = Arrays.copyOfRange(
txTimeMs, 0,
- Math.min(txTimeMs.length, ModemActivityInfo.TX_POWER_LEVELS));
+ Math.min(txTimeMs.length, ModemActivityInfo.getNumTxPowerLevels()));
mMonitoredRailChargeConsumedMaMs = monitoredRailChargeConsumedMaMs;
}
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
index 19a3a8b..b5466b6 100644
--- a/core/java/android/permission/OWNERS
+++ b/core/java/android/permission/OWNERS
@@ -1,11 +1,12 @@
# Bug component: 137825
-eugenesusla@google.com
evanseverson@google.com
evanxinchen@google.com
ewol@google.com
guojing@google.com
jaysullivan@google.com
+olekarg@google.com
+pyuli@google.com
ntmyren@google.com
svetoslavganov@android.com
svetoslavganov@google.com
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index f0f0867..505f400 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -2351,7 +2351,10 @@
final int ellipsisStringLen = ellipsisString.length();
// Use the ellipsis string only if there are that at least as many characters to replace.
final boolean useEllipsisString = ellipsisCount >= ellipsisStringLen;
- for (int i = 0; i < ellipsisCount; i++) {
+ final int min = Math.max(0, start - ellipsisStart - lineStart);
+ final int max = Math.min(ellipsisCount, end - ellipsisStart - lineStart);
+
+ for (int i = min; i < max; i++) {
final char c;
if (useEllipsisString && i < ellipsisStringLen) {
c = ellipsisString.charAt(i);
@@ -2360,9 +2363,7 @@
}
final int a = i + ellipsisStart + lineStart;
- if (start <= a && a < end) {
- dest[destoff + a - start] = c;
- }
+ dest[destoff + a - start] = c;
}
}
diff --git a/core/java/android/util/apk/OWNERS b/core/java/android/util/apk/OWNERS
index 52c9550..0f4e869 100644
--- a/core/java/android/util/apk/OWNERS
+++ b/core/java/android/util/apk/OWNERS
@@ -1 +1,3 @@
include /core/java/android/content/pm/OWNERS
+cbrubaker@google.com
+mpgroover@google.com
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index 844b156..c7609a6 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -310,7 +310,7 @@
String extension = null;
// If we couldn't do anything with the hint, move toward the content disposition
- if (filename == null && contentDisposition != null) {
+ if (contentDisposition != null) {
filename = parseContentDisposition(contentDisposition);
if (filename != null) {
int index = filename.lastIndexOf('/') + 1;
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index ea39f6d..fcaeeff 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -396,8 +396,9 @@
// Prompt user to add this person to contacts
final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
if (extras != null) {
- extras.remove(EXTRA_URI_CONTENT);
- intent.putExtras(extras);
+ Bundle bundle = new Bundle(extras);
+ bundle.remove(EXTRA_URI_CONTENT);
+ intent.putExtras(bundle);
}
getContext().startActivity(intent);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index dd2940f..e8db609 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -66,7 +66,6 @@
import android.telephony.CellSignalStrength;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
-import android.telephony.ModemActivityInfo.TransmitPower;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -7205,7 +7204,7 @@
public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
if (mModemControllerActivity == null) {
mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS);
+ ModemActivityInfo.getNumTxPowerLevels());
}
return mModemControllerActivity;
}
@@ -8687,7 +8686,7 @@
if (in.readInt() != 0) {
mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS, in);
+ ModemActivityInfo.getNumTxPowerLevels(), in);
} else {
mModemControllerActivity = null;
}
@@ -9953,7 +9952,7 @@
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS);
+ ModemActivityInfo.getNumTxPowerLevels());
mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null, mOnBatteryTimeBase);
mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
mOnBatteryTimeBase);
@@ -11131,26 +11130,7 @@
}
}
- private ModemActivityInfo mLastModemActivityInfo =
- new ModemActivityInfo(0, 0, 0, new int[0], 0);
-
- private ModemActivityInfo getDeltaModemActivityInfo(ModemActivityInfo activityInfo) {
- if (activityInfo == null) {
- return null;
- }
- int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
- for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
- txTimeMs[i] = activityInfo.getTransmitPowerInfo().get(i).getTimeInMillis()
- - mLastModemActivityInfo.getTransmitPowerInfo().get(i).getTimeInMillis();
- }
- ModemActivityInfo deltaInfo = new ModemActivityInfo(activityInfo.getTimestamp(),
- activityInfo.getSleepTimeMillis() - mLastModemActivityInfo.getSleepTimeMillis(),
- activityInfo.getIdleTimeMillis() - mLastModemActivityInfo.getIdleTimeMillis(),
- txTimeMs,
- activityInfo.getReceiveTimeMillis() - mLastModemActivityInfo.getReceiveTimeMillis());
- mLastModemActivityInfo = activityInfo;
- return deltaInfo;
- }
+ private ModemActivityInfo mLastModemActivityInfo = null;
/**
* Distribute Cell radio energy info and network traffic to apps.
@@ -11159,7 +11139,9 @@
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
}
- ModemActivityInfo deltaInfo = getDeltaModemActivityInfo(activityInfo);
+ ModemActivityInfo deltaInfo = mLastModemActivityInfo == null ? activityInfo
+ : mLastModemActivityInfo.getDelta(activityInfo);
+ mLastModemActivityInfo = activityInfo;
// Add modem tx power to history.
addModemTxPowerToHistory(deltaInfo);
@@ -11191,10 +11173,9 @@
mModemActivity.getSleepTimeCounter().addCountLocked(
deltaInfo.getSleepTimeMillis());
mModemActivity.getRxTimeCounter().addCountLocked(deltaInfo.getReceiveTimeMillis());
- for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+ for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels(); lvl++) {
mModemActivity.getTxTimeCounters()[lvl]
- .addCountLocked(deltaInfo.getTransmitPowerInfo()
- .get(lvl).getTimeInMillis());
+ .addCountLocked(deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl));
}
// POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
@@ -11208,11 +11189,11 @@
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE)
+ deltaInfo.getReceiveTimeMillis() *
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
- List<TransmitPower> txPowerInfo = deltaInfo.getTransmitPowerInfo();
- for (int i = 0; i < Math.min(txPowerInfo.size(),
+ for (int i = 0; i < Math.min(ModemActivityInfo.getNumTxPowerLevels(),
CellSignalStrength.getNumSignalStrengthLevels()); i++) {
- energyUsed += txPowerInfo.get(i).getTimeInMillis() * mPowerProfile
- .getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
+ energyUsed += deltaInfo.getTransmitDurationMillisAtPowerLevel(i)
+ * mPowerProfile.getAveragePower(
+ PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
}
// We store the power drain as mAms.
@@ -11307,10 +11288,10 @@
}
if (totalTxPackets > 0 && entry.txPackets > 0) {
- for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
- long txMs =
- entry.txPackets * deltaInfo.getTransmitPowerInfo()
- .get(lvl).getTimeInMillis();
+ for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels();
+ lvl++) {
+ long txMs = entry.txPackets
+ * deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl);
txMs /= totalTxPackets;
activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs);
}
@@ -11341,20 +11322,16 @@
if (activityInfo == null) {
return;
}
- List<TransmitPower> txPowerInfo = activityInfo.getTransmitPowerInfo();
- if (txPowerInfo == null || txPowerInfo.size() != ModemActivityInfo.TX_POWER_LEVELS) {
- return;
- }
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
int levelMaxTimeSpent = 0;
- for (int i = 1; i < txPowerInfo.size(); i++) {
- if (txPowerInfo.get(i).getTimeInMillis() > txPowerInfo.get(levelMaxTimeSpent)
- .getTimeInMillis()) {
+ for (int i = 1; i < ModemActivityInfo.getNumTxPowerLevels(); i++) {
+ if (activityInfo.getTransmitDurationMillisAtPowerLevel(i)
+ > activityInfo.getTransmitDurationMillisAtPowerLevel(levelMaxTimeSpent)) {
levelMaxTimeSpent = i;
}
}
- if (levelMaxTimeSpent == ModemActivityInfo.TX_POWER_LEVELS - 1) {
+ if (levelMaxTimeSpent == ModemActivityInfo.getNumTxPowerLevels() - 1) {
mHistoryCur.states2 |= HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG;
addHistoryRecordLocked(elapsedRealtime, uptime);
}
@@ -12771,7 +12748,7 @@
timeInRxSignalStrengthLevelMs[i]
= getPhoneSignalStrengthTime(i, rawRealTime, which) / 1000;
}
- long[] txTimeMs = new long[Math.min(ModemActivityInfo.TX_POWER_LEVELS,
+ long[] txTimeMs = new long[Math.min(ModemActivityInfo.getNumTxPowerLevels(),
counter.getTxTimeCounters().length)];
long totalTxTimeMs = 0;
for (int i = 0; i < txTimeMs.length; i++) {
@@ -14817,7 +14794,7 @@
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_BT_TX_LEVELS, in);
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS, in);
+ ModemActivityInfo.getNumTxPowerLevels(), in);
mHasWifiReporting = in.readInt() != 0;
mHasBluetoothReporting = in.readInt() != 0;
mHasModemReporting = in.readInt() != 0;
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index ea3b3a7..7766b77 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -10,4 +10,6 @@
per-file *ChargeCalculator* = file:/BATTERY_STATS_OWNERS
per-file *PowerCalculator* = file:/BATTERY_STATS_OWNERS
per-file *PowerEstimator* = file:/BATTERY_STATS_OWNERS
+per-file *Kernel* = file:/BATTERY_STATS_OWNERS
+per-file *MultiState* = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 0e02af2..cd52db4 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -33,13 +33,11 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.ZygoteProcess;
-import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
import android.security.keystore2.AndroidKeyStoreProvider;
import android.system.ErrnoException;
@@ -58,7 +56,6 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Preconditions;
-import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
import dalvik.system.ZygoteHooks;
@@ -517,7 +514,6 @@
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
- performSystemServerDexOpt(systemServerClasspath);
// Capturing profiles is only supported for debug or eng builds since selinux normally
// prevents it.
if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {
@@ -659,95 +655,6 @@
}
/**
- * Performs dex-opt on the elements of {@code classPath}, if needed. We choose the instruction
- * set of the current runtime.
- */
- private static void performSystemServerDexOpt(String classPath) {
- final String[] classPathElements = classPath.split(":");
- final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
-
- String classPathForElement = "";
- for (String classPathElement : classPathElements) {
- // We default to the verify filter because the compilation will happen on /data and
- // system server cannot load executable code outside /system.
- String systemServerFilter = SystemProperties.get(
- "dalvik.vm.systemservercompilerfilter", "verify");
-
- String classLoaderContext =
- getSystemServerClassLoaderContext(classPathForElement);
- int dexoptNeeded;
- try {
- dexoptNeeded = DexFile.getDexOptNeeded(
- classPathElement, instructionSet, systemServerFilter,
- classLoaderContext, false /* newProfile */, false /* downgrade */);
- } catch (FileNotFoundException ignored) {
- // Do not add to the classpath.
- Log.w(TAG, "Missing classpath element for system server: " + classPathElement);
- continue;
- } catch (IOException e) {
- // Not fully clear what to do here as we don't know the cause of the
- // IO exception. Add to the classpath to be conservative, but don't
- // attempt to compile it.
- Log.w(TAG, "Error checking classpath element for system server: "
- + classPathElement, e);
- dexoptNeeded = DexFile.NO_DEXOPT_NEEDED;
- }
-
- if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
- final String packageName = "*";
- final String outputPath = null;
- final int dexFlags = 0;
- final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
- final String seInfo = null;
- final int targetSdkVersion = 0; // SystemServer targets the system's SDK version
- // Wait for installd to be made available
- IInstalld installd = IInstalld.Stub.asInterface(
- ServiceManager.waitForService("installd"));
-
- try {
- installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
- instructionSet, dexoptNeeded, outputPath, dexFlags, systemServerFilter,
- uuid, classLoaderContext, seInfo, false /* downgrade */,
- targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
- "server-dexopt");
- } catch (RemoteException | ServiceSpecificException e) {
- // Ignore (but log), we need this on the classpath for fallback mode.
- Log.w(TAG, "Failed compiling classpath element for system server: "
- + classPathElement, e);
- }
- }
-
- classPathForElement = encodeSystemServerClassPath(
- classPathForElement, classPathElement);
- }
- }
-
- /**
- * Encodes the system server class loader context in a format that is accepted by dexopt. This
- * assumes the system server is always loaded with a {@link dalvik.system.PathClassLoader}.
- *
- * Note that ideally we would use the {@code DexoptUtils} to compute this. However we have no
- * dependency here on the server so we hard code the logic again.
- */
- private static String getSystemServerClassLoaderContext(String classPath) {
- return classPath == null ? "PCL[]" : "PCL[" + classPath + "]";
- }
-
- /**
- * Encodes the class path in a format accepted by dexopt.
- *
- * @param classPath The old class path (may be empty).
- * @param newElement The new class path elements
- * @return The class path encoding resulted from appending {@code newElement} to {@code
- * classPath}.
- */
- private static String encodeSystemServerClassPath(String classPath, String newElement) {
- return (classPath == null || classPath.isEmpty())
- ? newElement
- : classPath + ":" + newElement;
- }
-
- /**
* Prepare the arguments and forks for the system server process.
*
* @return A {@code Runnable} that provides an entrypoint into system_server code in the child
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index b90722c..09bb327 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -62,6 +62,7 @@
void onActiveDataSubIdChanged(in int subId);
void onRadioPowerStateChanged(in int state);
void onCallAttributesChanged(in CallAttributes callAttributes);
+ @SuppressWarnings(value={"untyped-collection"})
void onEmergencyNumberListChanged(in Map emergencyNumberList);
void onOutgoingEmergencyCall(in EmergencyNumber placedEmergencyNumber, int subscriptionId);
void onOutgoingEmergencySms(in EmergencyNumber sentEmergencyNumber, int subscriptionId);
diff --git a/core/java/com/android/internal/util/IState.java b/core/java/com/android/internal/util/IState.java
index 07837bf..41b3d5e 100644
--- a/core/java/com/android/internal/util/IState.java
+++ b/core/java/com/android/internal/util/IState.java
@@ -27,12 +27,12 @@
public interface IState {
/**
- * Returned by processMessage to indicate the the message was processed.
+ * Returned by processMessage to indicate the message was processed.
*/
static final boolean HANDLED = true;
/**
- * Returned by processMessage to indicate the the message was NOT processed.
+ * Returned by processMessage to indicate the message was NOT processed.
*/
static final boolean NOT_HANDLED = false;
diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS
index 5b68159..100a605d 100644
--- a/core/java/com/android/internal/util/OWNERS
+++ b/core/java/com/android/internal/util/OWNERS
@@ -1,6 +1,7 @@
per-file AsyncChannel* = lorenzo@google.com, satk@google.com, etancohen@google.com
per-file MessageUtils*, Protocol*, RingBuffer*, TokenBucket* = jchalard@google.com, lorenzo@google.com, satk@google.com
per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS
per-file Protocol* = etancohen@google.com, lorenzo@google.com
per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
per-file DataClass* = eugenesusla@google.com
\ No newline at end of file
diff --git a/core/java/com/android/internal/util/State.java b/core/java/com/android/internal/util/State.java
index 4613dad8..d5c0f60 100644
--- a/core/java/com/android/internal/util/State.java
+++ b/core/java/com/android/internal/util/State.java
@@ -16,6 +16,7 @@
package com.android.internal.util;
+import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Message;
@@ -25,6 +26,7 @@
*
* The class for implementing states in a StateMachine
*/
+@SuppressLint("AndroidFrameworkRequiresPermission")
public class State implements IState {
/**
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 4cff785..cb8d9d1 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -48,7 +48,7 @@
* in Object Oriented programming and are used to perform initialization and
* cleanup of the state respectively. The <code>getName</code> method returns the
* name of the state; the default implementation returns the class name. It may be
- * desirable to have <code>getName</code> return the the state instance name instead,
+ * desirable to have <code>getName</code> return the state instance name instead,
* in particular if a particular state class has multiple instances.</p>
*
* <p>When a state machine is created, <code>addState</code> is used to build the
@@ -433,14 +433,14 @@
/**
* Convenience constant that maybe returned by processMessage
- * to indicate the the message was processed and is not to be
+ * to indicate the message was processed and is not to be
* processed by parent states
*/
public static final boolean HANDLED = true;
/**
* Convenience constant that maybe returned by processMessage
- * to indicate the the message was NOT processed and is to be
+ * to indicate the message was NOT processed and is to be
* processed by parent states
*/
public static final boolean NOT_HANDLED = false;
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 59e95c9..1132422 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -546,13 +546,14 @@
if (!isSystemProcess()) {
return;
}
- // Read configuration of libs from apex module.
+ // Read configuration of features and libs from apex module.
+ int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES;
// TODO: Use a solid way to filter apex module folders?
for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) {
if (f.isFile() || f.getPath().contains("@")) {
continue;
}
- readPermissions(Environment.buildPath(f, "etc", "permissions"), ALLOW_LIBS);
+ readPermissions(Environment.buildPath(f, "etc", "permissions"), apexPermissionFlag);
}
}
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 701960e..6fb2904 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -75,3 +75,7 @@
# VINTF
per-file android_os_VintfObject* = file:platform/system/libvintf:/OWNERS
per-file android_os_VintfRuntimeInfo* = file:platform/system/libvintf:/OWNERS
+
+# Battery
+per-file com_android_internal_os_Kernel* = file:/BATTERY_STATS_OWNERS
+per-file com_android_internal_os_*MultiStateCounter* = file:/BATTERY_STATS_OWNERS
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 241570a..ac32038 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -98,6 +98,15 @@
}
}
+static void android_os_Parcel_markForBinder(JNIEnv* env, jclass clazz, jlong nativePtr,
+ jobject binder)
+{
+ Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
+ if (parcel) {
+ parcel->markForBinder(ibinderForJavaObject(env, binder));
+ }
+}
+
static jint android_os_Parcel_dataSize(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
@@ -766,7 +775,9 @@
static const JNINativeMethod gParcelMethods[] = {
// @CriticalNative
- {"nativeMarkSensitive", "(J)V", (void*)android_os_Parcel_markSensitive},
+ {"nativeMarkSensitive", "(J)V", (void*)android_os_Parcel_markSensitive},
+ // @FastNative
+ {"nativeMarkForBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_markForBinder},
// @CriticalNative
{"nativeDataSize", "(J)I", (void*)android_os_Parcel_dataSize},
// @CriticalNative
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 6374305..ff9e27f 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -263,8 +263,12 @@
sprintf(proc_path, "/proc/%d/cmdline", pid);
fd = open(proc_path, O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
- int rc = read(fd, cmdline, sizeof(cmdline)-1);
- cmdline[rc] = 0;
+ ssize_t rc = read(fd, cmdline, sizeof(cmdline) - 1);
+ if (rc < 0) {
+ ALOGE("read /proc/%d/cmdline (%s)", pid, strerror(errno));
+ } else {
+ cmdline[rc] = 0;
+ }
close(fd);
}
diff --git a/core/jni/com_android_internal_content_om_OverlayConfig.cpp b/core/jni/com_android_internal_content_om_OverlayConfig.cpp
index 6aa7c10..b37269c 100644
--- a/core/jni/com_android_internal_content_om_OverlayConfig.cpp
+++ b/core/jni/com_android_internal_content_om_OverlayConfig.cpp
@@ -73,13 +73,13 @@
}
if (result->status != 0) {
- LOG(ERROR) << "idmap2: " << result->stderr;
- return nullptr;
+ LOG(ERROR) << "idmap2: " << result->stderr_str;
+ return nullptr;
}
// Return the paths of the idmaps created or updated during the idmap invocation.
std::vector<std::string> idmap_paths;
- std::istringstream input(result->stdout);
+ std::istringstream input(result->stdout_str);
std::string path;
while (std::getline(input, path)) {
idmap_paths.push_back(path);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 8b9a688..288327e 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -62,7 +62,6 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
-#include <sys/utsname.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -837,26 +836,6 @@
}
}
-static bool NeedsNoRandomizeWorkaround() {
-#if !defined(__arm__)
- return false;
-#else
- int major;
- int minor;
- struct utsname uts;
- if (uname(&uts) == -1) {
- return false;
- }
-
- if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
- return false;
- }
-
- // Kernels before 3.4.* need the workaround.
- return (major < 3) || ((major == 3) && (minor < 4));
-#endif
-}
-
// Utility to close down the Zygote socket file descriptors while
// the child is still running as root with Zygote's privileges. Each
// descriptor (if any) is closed via dup3(), replacing it with a valid
@@ -1150,14 +1129,14 @@
}
// Relabel directory
-static void relabelDir(const char* path, security_context_t context, fail_fn_t fail_fn) {
+static void relabelDir(const char* path, const char* context, fail_fn_t fail_fn) {
if (setfilecon(path, context) != 0) {
fail_fn(CREATE_ERROR("Failed to setfilecon %s %s", path, strerror(errno)));
}
}
// Relabel all directories under a path non-recursively.
-static void relabelAllDirs(const char* path, security_context_t context, fail_fn_t fail_fn) {
+static void relabelAllDirs(const char* path, const char* context, fail_fn_t fail_fn) {
DIR* dir = opendir(path);
if (dir == nullptr) {
fail_fn(CREATE_ERROR("Failed to opendir %s", path));
@@ -1232,7 +1211,7 @@
snprintf(internalDePath, PATH_MAX, "/data/user_de");
snprintf(externalPrivateMountPath, PATH_MAX, "/mnt/expand");
- security_context_t dataDataContext = nullptr;
+ char* dataDataContext = nullptr;
if (getfilecon(internalDePath, &dataDataContext) < 0) {
fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", internalDePath,
strerror(errno)));
@@ -1687,15 +1666,6 @@
// runtime.
runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK;
- if (NeedsNoRandomizeWorkaround()) {
- // Work around ARM kernel ASLR lossage (http://b/5817320).
- int old_personality = personality(0xffffffff);
- int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
- if (new_personality == -1) {
- ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
- }
- }
-
SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities,
fail_fn);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0135e45c..35a3cde 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -196,6 +196,9 @@
android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.CSIS_DEVICE_AVAILABLE" />
+ <protected-broadcast android:name="android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE" />
<protected-broadcast
android:name="android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 14d3147..ac19121 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3026,6 +3026,11 @@
and one pSIM) -->
<integer name="config_num_physical_slots">1</integer>
+ <!-- When a radio power off request is received, we will delay completing the request until
+ either IMS moves to the deregistered state or the timeout defined by this configuration
+ elapses. If 0, this feature is disabled and we do not delay radio power off requests.-->
+ <integer name="config_delay_for_ims_dereg_millis">0</integer>
+
<!--Thresholds for LTE dbm in status bar-->
<integer-array translatable="false" name="config_lteDbmThresholds">
<item>-140</item> <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6a4702b..c1c1858 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3046,6 +3046,9 @@
<public name="canPauseRecording" />
<!-- attribute definitions go here -->
<public name="requireDeviceScreenOn" />
+ </public-group>
+
+ <public-group type="attr" first-id="0x01010624">
<public name="memtagMode" />
<public name="nativeHeapZeroInitialized" />
</public-group>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2be5152..aebad6a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -476,6 +476,7 @@
<java-symbol type="string" name="config_deviceSpecificDevicePolicyManagerService" />
<java-symbol type="string" name="config_deviceSpecificAudioService" />
<java-symbol type="integer" name="config_num_physical_slots" />
+ <java-symbol type="integer" name="config_delay_for_ims_dereg_millis" />
<java-symbol type="array" name="config_integrityRuleProviderPackages" />
<java-symbol type="bool" name="config_useAssistantVolume" />
<java-symbol type="string" name="config_bandwidthEstimateSource" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 37d059a..f1c66c5 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -265,7 +265,7 @@
<!-- USA: 5-6 digits (premium codes from https://www.premiumsmsrefunds.com/ShortCodes.htm),
visual voicemail code for T-Mobile: 122 -->
- <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567|244444" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245" />
+ <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567|244444" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245|611611" />
<!-- Vietnam: 1-5 digits (standard system default, not country specific) -->
<shortcode country="vn" pattern="\\d{1,5}" free="5001|9055" />
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 000e870..2d63351 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -88,6 +88,11 @@
false /* launchActivity */);
@Test
+ public void testTemporaryDirectory() throws Exception {
+ assertEquals(System.getProperty("java.io.tmpdir"), System.getenv("TMPDIR"));
+ }
+
+ @Test
public void testDoubleRelaunch() throws Exception {
final Activity activity = mActivityTestRule.launchActivity(new Intent());
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
diff --git a/core/tests/coretests/src/com/android/internal/util/OWNERS b/core/tests/coretests/src/com/android/internal/util/OWNERS
new file mode 100644
index 0000000..d832745
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/OWNERS
@@ -0,0 +1,2 @@
+per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS
\ No newline at end of file
diff --git a/core/tests/hosttests/Android.mk b/core/tests/hosttests/Android.mk
deleted file mode 100644
index f26d401..0000000
--- a/core/tests/hosttests/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/hosttests/test-apps/Android.mk b/core/tests/hosttests/test-apps/Android.mk
deleted file mode 100644
index e25764f..0000000
--- a/core/tests/hosttests/test-apps/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.bp b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.bp
new file mode 100644
index 0000000..d439124
--- /dev/null
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "DownloadManagerTestApp",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "android-common",
+ "mockwebserver",
+ "junit",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+
+ platform_apis: true,
+
+ // Need to run as system app to get access to Settings. This test won't work for user builds.
+ certificate: "platform",
+}
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
deleted file mode 100644
index d9e6151..0000000
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-common mockwebserver junit
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-
-LOCAL_PACKAGE_NAME := DownloadManagerTestApp
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-ifneq ($(TARGET_BUILD_VARIANT),user)
-# Need to run as system app to get access to Settings. This test won't work for user builds.
-LOCAL_CERTIFICATE := platform
-endif
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.bp
new file mode 100644
index 0000000..d0645b0
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.bp
@@ -0,0 +1,47 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// The application with a minimal main dex
+android_test_helper_app {
+ name: "MultiDexLegacyAndException",
+
+ static_libs: [
+ "android-support-multidex",
+ "android-support-multidex-instrumentation",
+ "androidx.test.rules",
+ ],
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "16",
+
+ javacflags: ["-nowarn"],
+
+ main_dex_rules: [":mainDexClassesRules"],
+ dxflags: [
+ // --debug triggers the old --minimal-main-dex behavior
+ "--debug",
+ ],
+ optimize: {
+ // disable optimization to force D8 instead of R8, as R8 doesn't support
+ // --main-dex-rules.
+ enabled: false,
+ },
+
+ min_sdk_version: "16",
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
deleted file mode 100644
index 2d8556f..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-
-## The application with a minimal main dex
-include $(CLEAR_VARS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex android-support-multidex-instrumentation androidx.test.rules
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := 8
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyAndException
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_JAVACFLAGS := -nowarn
-
-mainDexList:= \
- $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
-
-LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-
-LOCAL_MIN_SDK_VERSION := 8
-
-include $(BUILD_PACKAGE)
-
-$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
- $(hide) mkdir -p $(dir $@)
- PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
- echo "com/android/multidexlegacyandexception/Test.class" >> $@
-
-$(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.bp
new file mode 100644
index 0000000..c0c8aba
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.bp
@@ -0,0 +1,70 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// The application with a minimal main dex
+android_test_helper_app {
+ name: "MultiDexLegacyTestApp",
+
+ static_libs: ["android-support-multidex"],
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "16",
+
+ main_dex_rules: [
+ ":mainDexClassesRules",
+ "mainDexClasses.rules",
+ ],
+ dxflags: [
+ // --debug triggers the old --minimal-main-dex behavior
+ "--debug",
+ ],
+ optimize: {
+ // disable optimization to force D8 instead of R8, as R8 doesn't support
+ // --main-dex-rules.
+ enabled: false,
+ },
+
+ min_sdk_version: "16",
+}
+
+android_test_helper_app {
+ name: "MultiDexLegacyTestApp2",
+
+ static_libs: ["android-support-multidex"],
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "16",
+
+ main_dex_rules: [
+ ":mainDexClassesRules",
+ "mainDexClasses.rules",
+ ],
+ dxflags: [
+ // --release disables the old --minimal-main-dex behavior
+ "--release",
+ ],
+ optimize: {
+ // disable optimization to force D8 instead of R8, as R8 doesn't support
+ // --main-dex-rules.
+ enabled: false,
+ },
+
+ min_sdk_version: "16",
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
deleted file mode 100644
index d7af2d9..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ /dev/null
@@ -1,87 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-
-## The application with a minimal main dex
-include $(CLEAR_VARS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := 8
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_EMMA_INSTRUMENT := false
-
-mainDexList:= \
- $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
-
-LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-
-LOCAL_MIN_SDK_VERSION := 8
-
-include $(BUILD_PACKAGE)
-
-$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
- $(hide) mkdir -p $(dir $@)
- PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
- echo "com/android/multidexlegacytestapp/Test.class" >> $@
-
-$(built_dex_intermediate): $(mainDexList)
-
-## The application with a full main dex
-include $(CLEAR_VARS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := 8
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp2
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_EMMA_INSTRUMENT := false
-
-mainDexList2:= \
- $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
-
-LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList2)
-
-LOCAL_MIN_SDK_VERSION := 8
-
-include $(BUILD_PACKAGE)
-
-$(mainDexList2): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
- $(hide) mkdir -p $(dir $@)
- PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
- echo "com/android/multidexlegacytestapp/Test.class" >> $@
-
-$(built_dex_intermediate): $(mainDexList2)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/mainDexClasses.rules b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/mainDexClasses.rules
new file mode 100644
index 0000000..91e6ddb
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/mainDexClasses.rules
@@ -0,0 +1 @@
+-keep class com.android.multidexlegacytestapp.Test
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/Android.bp
new file mode 100644
index 0000000..fe29416
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// The application with a minimal main dex
+android_test {
+ name: "MultiDexLegacyTestAppTests",
+
+ static_libs: ["android-support-multidex-instrumentation"],
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "16",
+
+ javacflags: ["-nowarn"],
+
+ min_sdk_version: "16",
+
+ instrumentation_for: "MultiDexLegacyTestApp",
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/Android.mk
deleted file mode 100644
index 236c740..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-
-## The application with a minimal main dex
-include $(CLEAR_VARS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex-instrumentation
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := 8
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyTestAppTests
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_JAVACFLAGS := -nowarn
-
-LOCAL_MIN_SDK_VERSION := 8
-
-LOCAL_INSTRUMENTATION_FOR := MultiDexLegacyTestApp
-
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.dex.output.multidex.legacy=true
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.bp
new file mode 100644
index 0000000..c558153
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.bp
@@ -0,0 +1,57 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// The tests with only one dex
+android_test {
+ name: "MultiDexLegacyTestAppTests2",
+
+ static_libs: [
+ "android-support-multidex-instrumentation",
+ "androidx.test.rules",
+ ],
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "16",
+
+ javacflags: ["-nowarn"],
+
+ min_sdk_version: "16",
+
+ instrumentation_for: "MultiDexLegacyTestApp",
+}
+
+// The tests with a minimal main dex
+android_test {
+ name: "MultiDexLegacyTestAppTests2-multidex",
+
+ static_libs: [
+ "android-support-multidex-instrumentation",
+ "androidx.test.rules",
+ ],
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "16",
+
+ javacflags: ["-nowarn"],
+
+ min_sdk_version: "16",
+
+ instrumentation_for: "MultiDexLegacyTestApp",
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.mk
deleted file mode 100644
index 6f6ccfe..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.mk
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-
-## The tests with only one dex
-include $(CLEAR_VARS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex-instrumentation androidx.test.rules
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyTestAppTests2
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_JAVACFLAGS := -nowarn
-
-LOCAL_MIN_SDK_VERSION := 8
-
-LOCAL_INSTRUMENTATION_FOR := MultiDexLegacyTestApp
-
-include $(BUILD_PACKAGE)
-
-
-## The tests with a minimal main dex
-include $(CLEAR_VARS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex-instrumentation androidx.test.rules
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := 8
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyTestAppTests2-multidex
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_JAVACFLAGS := -nowarn
-
-LOCAL_MIN_SDK_VERSION := 8
-
-LOCAL_INSTRUMENTATION_FOR := MultiDexLegacyTestApp
-
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.dex.output.multidex.legacy=true
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/Android.bp
new file mode 100644
index 0000000..15bc4efb
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/Android.bp
@@ -0,0 +1,48 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+ name: "MultiDexLegacyTestApp_without_corrupted",
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "16",
+
+ static_libs: ["android-support-multidex"],
+}
+
+java_genrule {
+ name: "MultiDexLegacyTestApp_genrule",
+ srcs: [
+ ":MultiDexLegacyTestApp_without_corrupted",
+ ],
+ tools: [
+ "soong_zip",
+ "merge_zips",
+ ],
+ out: ["MultiDexLegacyTestApp_with_corrupted.apk"],
+ cmd: "touch $(genDir)/classes2.dex &&" +
+ " $(location soong_zip) -o $(genDir)/corrupted.zip -j -f $(genDir)/classes2.dex &&" +
+ " $(location merge_zips) $(out) $(location :MultiDexLegacyTestApp_without_corrupted) $(genDir)/corrupted.zip",
+}
+
+android_test_import {
+ name: "MultiDexLegacyTestApp_corrupted",
+ apk: ":MultiDexLegacyTestApp_genrule",
+ default_dev_cert: true,
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/Android.mk
deleted file mode 100644
index 33a46ea..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := 18
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp_corrupted
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_PACKAGE)
-
-corrupted_classes2_dex := $(dir $(built_dex))/classes2.dex
-
-$(corrupted_classes2_dex): $(built_dex)
- $(hide) touch $@
-
-$(LOCAL_BUILT_MODULE): $(corrupted_classes2_dex)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.bp
new file mode 100644
index 0000000..de0657f
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "MultiDexLegacyTestServices",
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "16",
+
+ static_libs: ["android-support-multidex"],
+
+ main_dex_rules: [":mainDexClassesRules"],
+ dxflags: [
+ // --debug triggers the old --minimal-main-dex behavior
+ "--debug",
+ ],
+ optimize: {
+ // disable optimization to force D8 instead of R8, as R8 doesn't support
+ // --main-dex-rules.
+ enabled: false,
+ },
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
deleted file mode 100644
index efc0688..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := 9
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyTestServices
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
-
-mainDexList:= \
- $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
-
-LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_EMMA_INSTRUMENT := false
-
-include $(BUILD_PACKAGE)
-
-$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
- $(hide) mkdir -p $(dir $@)
- PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
-
-$(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp
index 56f10fe..b62b25c 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp
@@ -24,7 +24,7 @@
android_test {
name: "MultiDexLegacyTestServicesTests",
srcs: ["src/**/*.java"],
- sdk_version: "9",
+ sdk_version: "16",
dex_preopt: {
enabled: false,
},
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.bp
new file mode 100644
index 0000000..75c753c
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "MultiDexLegacyTestServicesTests2",
+
+ srcs: ["src/**/*.java"],
+
+ libs: ["android-support-multidex"],
+ static_libs: ["androidx.test.rules"],
+
+ sdk_version: "16",
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
deleted file mode 100644
index 3920fd6..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyTestServicesTests2
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_JAVA_LIBRARIES := android-support-multidex
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-
-LOCAL_SDK_VERSION := 9
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.bp
new file mode 100644
index 0000000..23c62dc
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+ name: "MultiDexLegacyVersionedTestApp_v1",
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "16",
+
+ static_libs: ["android-support-multidex"],
+
+ main_dex_rules: [
+ ":mainDexClassesRules",
+ "mainDexClasses.rules",
+ ],
+ dxflags: [
+ // --debug triggers the old --minimal-main-dex behavior
+ "--debug",
+ ],
+ optimize: {
+ // disable optimization to force D8 instead of R8, as R8 doesn't support
+ // --main-dex-rules.
+ enabled: false,
+ },
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
deleted file mode 100644
index 2323ad9..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := 9
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyVersionedTestApp_v1
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_EMMA_INSTRUMENT := false
-
-mainDexList:= \
- $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
-
-LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-
-include $(BUILD_PACKAGE)
-
-$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
- $(hide) mkdir -p $(dir $@)
- PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
- echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
-
-$(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/mainDexClasses.rules b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/mainDexClasses.rules
new file mode 100644
index 0000000..1cdf3af
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/mainDexClasses.rules
@@ -0,0 +1 @@
+-keep class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.bp
new file mode 100644
index 0000000..6cd3df7
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+ name: "MultiDexLegacyVersionedTestApp_v2",
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "16",
+
+ static_libs: ["android-support-multidex"],
+
+ main_dex_rules: [
+ ":mainDexClassesRules",
+ "mainDexClasses.rules",
+ ],
+ dxflags: [
+ // --debug triggers the old --minimal-main-dex behavior
+ "--debug",
+ ],
+ optimize: {
+ // disable optimization to force D8 instead of R8, as R8 doesn't support
+ // --main-dex-rules.
+ enabled: false,
+ },
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
deleted file mode 100644
index 79a5906..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := 9
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyVersionedTestApp_v2
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_EMMA_INSTRUMENT := false
-
-mainDexList:= \
- $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
-
-LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-
-include $(BUILD_PACKAGE)
-
-$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
- $(hide) mkdir -p $(dir $@)
- PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
- echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
-
-$(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/mainDexClasses.rules b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/mainDexClasses.rules
new file mode 100644
index 0000000..1cdf3af
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/mainDexClasses.rules
@@ -0,0 +1 @@
+-keep class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.bp
new file mode 100644
index 0000000..34dba40
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+ name: "MultiDexLegacyVersionedTestApp_v3",
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "16",
+
+ static_libs: ["android-support-multidex"],
+
+ main_dex_rules: [
+ ":mainDexClassesRules",
+ "mainDexClasses.rules",
+ ],
+ dxflags: [
+ // --debug triggers the old --minimal-main-dex behavior
+ "--debug",
+ ],
+ optimize: {
+ // disable optimization to force D8 instead of R8, as R8 doesn't support
+ // --main-dex-rules.
+ enabled: false,
+ },
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
deleted file mode 100644
index 521bad0..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := 9
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyVersionedTestApp_v3
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
-
-mainDexList:= \
- $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_EMMA_INSTRUMENT := false
-
-LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-
-include $(BUILD_PACKAGE)
-
-$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
- $(hide) mkdir -p $(dir $@)
- PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
- echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
-
-$(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/mainDexClasses.rules b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/mainDexClasses.rules
new file mode 100644
index 0000000..1cdf3af
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/mainDexClasses.rules
@@ -0,0 +1 @@
+-keep class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
index edf473e..b85cb9c 100644
--- a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
@@ -542,83 +542,83 @@
public void testStateMachineEnterExitTransitionToTest() throws Exception {
//if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger();
- StateMachineEnterExitTransitionToTest smEnterExitTranstionToTest =
- new StateMachineEnterExitTransitionToTest("smEnterExitTranstionToTest");
- smEnterExitTranstionToTest.start();
- if (smEnterExitTranstionToTest.isDbg()) {
+ StateMachineEnterExitTransitionToTest smEnterExitTransitionToTest =
+ new StateMachineEnterExitTransitionToTest("smEnterExitTransitionToTest");
+ smEnterExitTransitionToTest.start();
+ if (smEnterExitTransitionToTest.isDbg()) {
tlog("testStateMachineEnterExitTransitionToTest E");
}
- synchronized (smEnterExitTranstionToTest) {
- smEnterExitTranstionToTest.sendMessage(TEST_CMD_1);
+ synchronized (smEnterExitTransitionToTest) {
+ smEnterExitTransitionToTest.sendMessage(TEST_CMD_1);
try {
// wait for the messages to be handled
- smEnterExitTranstionToTest.wait();
+ smEnterExitTransitionToTest.wait();
} catch (InterruptedException e) {
tloge("testStateMachineEnterExitTransitionToTest: exception while waiting "
+ e.getMessage());
}
}
- dumpLogRecs(smEnterExitTranstionToTest);
+ dumpLogRecs(smEnterExitTransitionToTest);
- assertEquals(9, smEnterExitTranstionToTest.getLogRecCount());
+ assertEquals(9, smEnterExitTransitionToTest.getLogRecCount());
LogRec lr;
- lr = smEnterExitTranstionToTest.getLogRec(0);
+ lr = smEnterExitTransitionToTest.getLogRec(0);
assertEquals(ENTER, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS1, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS1, lr.getState());
- lr = smEnterExitTranstionToTest.getLogRec(1);
+ lr = smEnterExitTransitionToTest.getLogRec(1);
assertEquals(EXIT, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS1, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS1, lr.getState());
- lr = smEnterExitTranstionToTest.getLogRec(2);
+ lr = smEnterExitTransitionToTest.getLogRec(2);
assertEquals(ENTER, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS2, lr.getState());
- lr = smEnterExitTranstionToTest.getLogRec(3);
+ lr = smEnterExitTransitionToTest.getLogRec(3);
assertEquals(TEST_CMD_1, lr.getWhat());
- assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS2, lr.getOriginalState());
- assertEquals(smEnterExitTranstionToTest.mS3, lr.getDestState());
+ assertEquals(smEnterExitTransitionToTest.mS2, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS2, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS3, lr.getDestState());
- lr = smEnterExitTranstionToTest.getLogRec(4);
+ lr = smEnterExitTransitionToTest.getLogRec(4);
assertEquals(TEST_CMD_1, lr.getWhat());
- assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS2, lr.getOriginalState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+ assertEquals(smEnterExitTransitionToTest.mS2, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS2, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
assertEquals(EXIT, lr.getInfo());
- lr = smEnterExitTranstionToTest.getLogRec(5);
+ lr = smEnterExitTransitionToTest.getLogRec(5);
assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(ENTER, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS3, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS3, lr.getOriginalState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+ assertEquals(smEnterExitTransitionToTest.mS3, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS3, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
- lr = smEnterExitTranstionToTest.getLogRec(6);
+ lr = smEnterExitTransitionToTest.getLogRec(6);
assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(EXIT, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS3, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS3, lr.getOriginalState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+ assertEquals(smEnterExitTransitionToTest.mS3, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS3, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
- lr = smEnterExitTranstionToTest.getLogRec(7);
+ lr = smEnterExitTransitionToTest.getLogRec(7);
assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(ENTER, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getOriginalState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getDestState());
- lr = smEnterExitTranstionToTest.getLogRec(8);
+ lr = smEnterExitTransitionToTest.getLogRec(8);
assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(EXIT, lr.getInfo());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getState());
- assertEquals(smEnterExitTranstionToTest.mS4, lr.getOriginalState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getState());
+ assertEquals(smEnterExitTransitionToTest.mS4, lr.getOriginalState());
- if (smEnterExitTranstionToTest.isDbg()) {
+ if (smEnterExitTransitionToTest.isDbg()) {
tlog("testStateMachineEnterExitTransitionToTest X");
}
}
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index 8f175bb..1e68585 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -160,7 +160,7 @@
* not the case, the {@link SessionTranscriptMismatchException} exception is thrown.
*
* <p>If not {@code null} the {@code requestMessage} parameter must contain data for the request
- * from the verifier. The content can be defined in the way appropriate for the credential, byt
+ * from the verifier. The content can be defined in the way appropriate for the credential, but
* there are three requirements that must be met to work with this API:
* <ul>
* <li>The content must be a CBOR-encoded structure.</li>
@@ -205,9 +205,9 @@
* must appear somewhere in {@code sessionTranscript} and ditto for the 32 bytes for the Y
* coordinate.
*
- * <p>If {@code readerAuth} is not {@code null} it must be the bytes of a {@code COSE_Sign1}
- * structure as defined in RFC 8152. For the payload nil shall be used and the
- * detached payload is the ReaderAuthenticationBytes CBOR described below.
+ * <p>If {@code readerSignature} is not {@code null} it must be the bytes of a
+ * {@code COSE_Sign1} structure as defined in RFC 8152. For the payload nil shall be used and
+ * the detached payload is the ReaderAuthenticationBytes CBOR described below.
* <pre>
* ReaderAuthentication = [
* "ReaderAuthentication",
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index f3cfcf1..67358c4 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -579,7 +579,7 @@
//
// Note: mNamespace == KeyProperties.NAMESPACE_APPLICATION implies that the target domain
// is Domain.APP and Domain.SELINUX is the target domain otherwise.
- if (alias != descriptor.alias
+ if (!alias.equals(descriptor.alias)
|| descriptor.domain != targetDomain
|| (descriptor.domain == Domain.SELINUX && descriptor.nspace != targetNamespace)) {
throw new KeyStoreException("Can only replace keys with same alias: " + alias
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index 8a10599..2c3567a 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -1,37 +1,37 @@
// Auto-generated by ./tools/localedata/extract_icu_data.py
const char SCRIPT_CODES[][4] = {
- /* 0 */ {'A', 'h', 'o', 'm'},
- /* 1 */ {'A', 'r', 'a', 'b'},
- /* 2 */ {'A', 'r', 'm', 'i'},
- /* 3 */ {'A', 'r', 'm', 'n'},
- /* 4 */ {'A', 'v', 's', 't'},
- /* 5 */ {'B', 'a', 'm', 'u'},
- /* 6 */ {'B', 'a', 's', 's'},
- /* 7 */ {'B', 'e', 'n', 'g'},
- /* 8 */ {'B', 'r', 'a', 'h'},
- /* 9 */ {'C', 'a', 'k', 'm'},
- /* 10 */ {'C', 'a', 'n', 's'},
- /* 11 */ {'C', 'a', 'r', 'i'},
- /* 12 */ {'C', 'h', 'a', 'm'},
- /* 13 */ {'C', 'h', 'e', 'r'},
- /* 14 */ {'C', 'h', 'r', 's'},
- /* 15 */ {'C', 'o', 'p', 't'},
- /* 16 */ {'C', 'p', 'r', 't'},
- /* 17 */ {'C', 'y', 'r', 'l'},
- /* 18 */ {'D', 'e', 'v', 'a'},
- /* 19 */ {'E', 'g', 'y', 'p'},
- /* 20 */ {'E', 't', 'h', 'i'},
- /* 21 */ {'G', 'e', 'o', 'r'},
- /* 22 */ {'G', 'o', 'n', 'g'},
- /* 23 */ {'G', 'o', 'n', 'm'},
- /* 24 */ {'G', 'o', 't', 'h'},
- /* 25 */ {'G', 'r', 'e', 'k'},
- /* 26 */ {'G', 'u', 'j', 'r'},
- /* 27 */ {'G', 'u', 'r', 'u'},
- /* 28 */ {'H', 'a', 'n', 's'},
- /* 29 */ {'H', 'a', 'n', 't'},
- /* 30 */ {'H', 'a', 't', 'r'},
+ /* 0 */ {'A', 'g', 'h', 'b'},
+ /* 1 */ {'A', 'h', 'o', 'm'},
+ /* 2 */ {'A', 'r', 'a', 'b'},
+ /* 3 */ {'A', 'r', 'm', 'i'},
+ /* 4 */ {'A', 'r', 'm', 'n'},
+ /* 5 */ {'A', 'v', 's', 't'},
+ /* 6 */ {'B', 'a', 'm', 'u'},
+ /* 7 */ {'B', 'a', 's', 's'},
+ /* 8 */ {'B', 'e', 'n', 'g'},
+ /* 9 */ {'B', 'r', 'a', 'h'},
+ /* 10 */ {'C', 'a', 'k', 'm'},
+ /* 11 */ {'C', 'a', 'n', 's'},
+ /* 12 */ {'C', 'a', 'r', 'i'},
+ /* 13 */ {'C', 'h', 'a', 'm'},
+ /* 14 */ {'C', 'h', 'e', 'r'},
+ /* 15 */ {'C', 'h', 'r', 's'},
+ /* 16 */ {'C', 'o', 'p', 't'},
+ /* 17 */ {'C', 'p', 'r', 't'},
+ /* 18 */ {'C', 'y', 'r', 'l'},
+ /* 19 */ {'D', 'e', 'v', 'a'},
+ /* 20 */ {'E', 'g', 'y', 'p'},
+ /* 21 */ {'E', 't', 'h', 'i'},
+ /* 22 */ {'G', 'e', 'o', 'r'},
+ /* 23 */ {'G', 'o', 'n', 'g'},
+ /* 24 */ {'G', 'o', 'n', 'm'},
+ /* 25 */ {'G', 'o', 't', 'h'},
+ /* 26 */ {'G', 'r', 'e', 'k'},
+ /* 27 */ {'G', 'u', 'j', 'r'},
+ /* 28 */ {'G', 'u', 'r', 'u'},
+ /* 29 */ {'H', 'a', 'n', 's'},
+ /* 30 */ {'H', 'a', 'n', 't'},
/* 31 */ {'H', 'e', 'b', 'r'},
/* 32 */ {'H', 'l', 'u', 'w'},
/* 33 */ {'H', 'm', 'n', 'g'},
@@ -55,52 +55,53 @@
/* 51 */ {'L', 'y', 'd', 'i'},
/* 52 */ {'M', 'a', 'n', 'd'},
/* 53 */ {'M', 'a', 'n', 'i'},
- /* 54 */ {'M', 'e', 'r', 'c'},
- /* 55 */ {'M', 'l', 'y', 'm'},
- /* 56 */ {'M', 'o', 'n', 'g'},
- /* 57 */ {'M', 'r', 'o', 'o'},
- /* 58 */ {'M', 'y', 'm', 'r'},
- /* 59 */ {'N', 'a', 'r', 'b'},
- /* 60 */ {'N', 'k', 'o', 'o'},
- /* 61 */ {'N', 's', 'h', 'u'},
- /* 62 */ {'O', 'g', 'a', 'm'},
- /* 63 */ {'O', 'l', 'c', 'k'},
- /* 64 */ {'O', 'r', 'k', 'h'},
- /* 65 */ {'O', 'r', 'y', 'a'},
- /* 66 */ {'O', 's', 'g', 'e'},
- /* 67 */ {'P', 'a', 'u', 'c'},
- /* 68 */ {'P', 'h', 'l', 'i'},
- /* 69 */ {'P', 'h', 'n', 'x'},
- /* 70 */ {'P', 'l', 'r', 'd'},
- /* 71 */ {'P', 'r', 't', 'i'},
- /* 72 */ {'R', 'u', 'n', 'r'},
- /* 73 */ {'S', 'a', 'm', 'r'},
- /* 74 */ {'S', 'a', 'r', 'b'},
- /* 75 */ {'S', 'a', 'u', 'r'},
- /* 76 */ {'S', 'g', 'n', 'w'},
- /* 77 */ {'S', 'i', 'n', 'h'},
- /* 78 */ {'S', 'o', 'g', 'd'},
- /* 79 */ {'S', 'o', 'r', 'a'},
- /* 80 */ {'S', 'o', 'y', 'o'},
- /* 81 */ {'S', 'y', 'r', 'c'},
- /* 82 */ {'T', 'a', 'l', 'e'},
- /* 83 */ {'T', 'a', 'l', 'u'},
- /* 84 */ {'T', 'a', 'm', 'l'},
- /* 85 */ {'T', 'a', 'n', 'g'},
- /* 86 */ {'T', 'a', 'v', 't'},
- /* 87 */ {'T', 'e', 'l', 'u'},
- /* 88 */ {'T', 'f', 'n', 'g'},
- /* 89 */ {'T', 'h', 'a', 'a'},
- /* 90 */ {'T', 'h', 'a', 'i'},
- /* 91 */ {'T', 'i', 'b', 't'},
- /* 92 */ {'U', 'g', 'a', 'r'},
- /* 93 */ {'V', 'a', 'i', 'i'},
- /* 94 */ {'W', 'c', 'h', 'o'},
- /* 95 */ {'X', 'p', 'e', 'o'},
- /* 96 */ {'X', 's', 'u', 'x'},
- /* 97 */ {'Y', 'i', 'i', 'i'},
- /* 98 */ {'~', '~', '~', 'A'},
- /* 99 */ {'~', '~', '~', 'B'},
+ /* 54 */ {'M', 'e', 'd', 'f'},
+ /* 55 */ {'M', 'e', 'r', 'c'},
+ /* 56 */ {'M', 'l', 'y', 'm'},
+ /* 57 */ {'M', 'o', 'n', 'g'},
+ /* 58 */ {'M', 'r', 'o', 'o'},
+ /* 59 */ {'M', 'y', 'm', 'r'},
+ /* 60 */ {'N', 'a', 'r', 'b'},
+ /* 61 */ {'N', 'k', 'o', 'o'},
+ /* 62 */ {'N', 's', 'h', 'u'},
+ /* 63 */ {'O', 'g', 'a', 'm'},
+ /* 64 */ {'O', 'l', 'c', 'k'},
+ /* 65 */ {'O', 'r', 'k', 'h'},
+ /* 66 */ {'O', 'r', 'y', 'a'},
+ /* 67 */ {'O', 's', 'g', 'e'},
+ /* 68 */ {'P', 'a', 'u', 'c'},
+ /* 69 */ {'P', 'h', 'l', 'i'},
+ /* 70 */ {'P', 'h', 'n', 'x'},
+ /* 71 */ {'P', 'l', 'r', 'd'},
+ /* 72 */ {'P', 'r', 't', 'i'},
+ /* 73 */ {'R', 'u', 'n', 'r'},
+ /* 74 */ {'S', 'a', 'm', 'r'},
+ /* 75 */ {'S', 'a', 'r', 'b'},
+ /* 76 */ {'S', 'a', 'u', 'r'},
+ /* 77 */ {'S', 'g', 'n', 'w'},
+ /* 78 */ {'S', 'i', 'n', 'h'},
+ /* 79 */ {'S', 'o', 'g', 'd'},
+ /* 80 */ {'S', 'o', 'r', 'a'},
+ /* 81 */ {'S', 'o', 'y', 'o'},
+ /* 82 */ {'S', 'y', 'r', 'c'},
+ /* 83 */ {'T', 'a', 'l', 'e'},
+ /* 84 */ {'T', 'a', 'l', 'u'},
+ /* 85 */ {'T', 'a', 'm', 'l'},
+ /* 86 */ {'T', 'a', 'n', 'g'},
+ /* 87 */ {'T', 'a', 'v', 't'},
+ /* 88 */ {'T', 'e', 'l', 'u'},
+ /* 89 */ {'T', 'f', 'n', 'g'},
+ /* 90 */ {'T', 'h', 'a', 'a'},
+ /* 91 */ {'T', 'h', 'a', 'i'},
+ /* 92 */ {'T', 'i', 'b', 't'},
+ /* 93 */ {'U', 'g', 'a', 'r'},
+ /* 94 */ {'V', 'a', 'i', 'i'},
+ /* 95 */ {'W', 'c', 'h', 'o'},
+ /* 96 */ {'X', 'p', 'e', 'o'},
+ /* 97 */ {'X', 's', 'u', 'x'},
+ /* 98 */ {'Y', 'i', 'i', 'i'},
+ /* 99 */ {'~', '~', '~', 'A'},
+ /* 100 */ {'~', '~', '~', 'B'},
};
@@ -109,9 +110,9 @@
{0xA0000000u, 46u}, // aai -> Latn
{0xA8000000u, 46u}, // aak -> Latn
{0xD0000000u, 46u}, // aau -> Latn
- {0x61620000u, 17u}, // ab -> Cyrl
+ {0x61620000u, 18u}, // ab -> Cyrl
{0xA0200000u, 46u}, // abi -> Latn
- {0xC0200000u, 17u}, // abq -> Cyrl
+ {0xC0200000u, 18u}, // abq -> Cyrl
{0xC4200000u, 46u}, // abr -> Latn
{0xCC200000u, 46u}, // abt -> Latn
{0xE0200000u, 46u}, // aby -> Latn
@@ -121,11 +122,11 @@
{0x80600000u, 46u}, // ada -> Latn
{0x90600000u, 46u}, // ade -> Latn
{0xA4600000u, 46u}, // adj -> Latn
- {0xBC600000u, 91u}, // adp -> Tibt
- {0xE0600000u, 17u}, // ady -> Cyrl
+ {0xBC600000u, 92u}, // adp -> Tibt
+ {0xE0600000u, 18u}, // ady -> Cyrl
{0xE4600000u, 46u}, // adz -> Latn
- {0x61650000u, 4u}, // ae -> Avst
- {0x84800000u, 1u}, // aeb -> Arab
+ {0x61650000u, 5u}, // ae -> Avst
+ {0x84800000u, 2u}, // aeb -> Arab
{0xE0800000u, 46u}, // aey -> Latn
{0x61660000u, 46u}, // af -> Latn
{0x88C00000u, 46u}, // agc -> Latn
@@ -136,15 +137,15 @@
{0xC0C00000u, 46u}, // agq -> Latn
{0x80E00000u, 46u}, // aha -> Latn
{0xACE00000u, 46u}, // ahl -> Latn
- {0xB8E00000u, 0u}, // aho -> Ahom
+ {0xB8E00000u, 1u}, // aho -> Ahom
{0x99200000u, 46u}, // ajg -> Latn
{0x616B0000u, 46u}, // ak -> Latn
- {0xA9400000u, 96u}, // akk -> Xsux
+ {0xA9400000u, 97u}, // akk -> Xsux
{0x81600000u, 46u}, // ala -> Latn
{0xA1600000u, 46u}, // ali -> Latn
{0xB5600000u, 46u}, // aln -> Latn
- {0xCD600000u, 17u}, // alt -> Cyrl
- {0x616D0000u, 20u}, // am -> Ethi
+ {0xCD600000u, 18u}, // alt -> Cyrl
+ {0x616D0000u, 21u}, // am -> Ethi
{0xB1800000u, 46u}, // amm -> Latn
{0xB5800000u, 46u}, // amn -> Latn
{0xB9800000u, 46u}, // amo -> Latn
@@ -157,25 +158,25 @@
{0xA5C00000u, 46u}, // aoj -> Latn
{0xB1C00000u, 46u}, // aom -> Latn
{0xE5C00000u, 46u}, // aoz -> Latn
- {0x89E00000u, 1u}, // apc -> Arab
- {0x8DE00000u, 1u}, // apd -> Arab
+ {0x89E00000u, 2u}, // apc -> Arab
+ {0x8DE00000u, 2u}, // apd -> Arab
{0x91E00000u, 46u}, // ape -> Latn
{0xC5E00000u, 46u}, // apr -> Latn
{0xC9E00000u, 46u}, // aps -> Latn
{0xE5E00000u, 46u}, // apz -> Latn
- {0x61720000u, 1u}, // ar -> Arab
- {0x61725842u, 99u}, // ar-XB -> ~~~B
- {0x8A200000u, 2u}, // arc -> Armi
+ {0x61720000u, 2u}, // ar -> Arab
+ {0x61725842u, 100u}, // ar-XB -> ~~~B
+ {0x8A200000u, 3u}, // arc -> Armi
{0x9E200000u, 46u}, // arh -> Latn
{0xB6200000u, 46u}, // arn -> Latn
{0xBA200000u, 46u}, // aro -> Latn
- {0xC2200000u, 1u}, // arq -> Arab
- {0xCA200000u, 1u}, // ars -> Arab
- {0xE2200000u, 1u}, // ary -> Arab
- {0xE6200000u, 1u}, // arz -> Arab
- {0x61730000u, 7u}, // as -> Beng
+ {0xC2200000u, 2u}, // arq -> Arab
+ {0xCA200000u, 2u}, // ars -> Arab
+ {0xE2200000u, 2u}, // ary -> Arab
+ {0xE6200000u, 2u}, // arz -> Arab
+ {0x61730000u, 8u}, // as -> Beng
{0x82400000u, 46u}, // asa -> Latn
- {0x92400000u, 76u}, // ase -> Sgnw
+ {0x92400000u, 77u}, // ase -> Sgnw
{0x9A400000u, 46u}, // asg -> Latn
{0xBA400000u, 46u}, // aso -> Latn
{0xCE400000u, 46u}, // ast -> Latn
@@ -183,29 +184,29 @@
{0x9A600000u, 46u}, // atg -> Latn
{0xA6600000u, 46u}, // atj -> Latn
{0xE2800000u, 46u}, // auy -> Latn
- {0x61760000u, 17u}, // av -> Cyrl
- {0xAEA00000u, 1u}, // avl -> Arab
+ {0x61760000u, 18u}, // av -> Cyrl
+ {0xAEA00000u, 2u}, // avl -> Arab
{0xB6A00000u, 46u}, // avn -> Latn
{0xCEA00000u, 46u}, // avt -> Latn
{0xD2A00000u, 46u}, // avu -> Latn
- {0x82C00000u, 18u}, // awa -> Deva
+ {0x82C00000u, 19u}, // awa -> Deva
{0x86C00000u, 46u}, // awb -> Latn
{0xBAC00000u, 46u}, // awo -> Latn
{0xDEC00000u, 46u}, // awx -> Latn
{0x61790000u, 46u}, // ay -> Latn
{0x87000000u, 46u}, // ayb -> Latn
{0x617A0000u, 46u}, // az -> Latn
- {0x617A4951u, 1u}, // az-IQ -> Arab
- {0x617A4952u, 1u}, // az-IR -> Arab
- {0x617A5255u, 17u}, // az-RU -> Cyrl
- {0x62610000u, 17u}, // ba -> Cyrl
- {0xAC010000u, 1u}, // bal -> Arab
+ {0x617A4951u, 2u}, // az-IQ -> Arab
+ {0x617A4952u, 2u}, // az-IR -> Arab
+ {0x617A5255u, 18u}, // az-RU -> Cyrl
+ {0x62610000u, 18u}, // ba -> Cyrl
+ {0xAC010000u, 2u}, // bal -> Arab
{0xB4010000u, 46u}, // ban -> Latn
- {0xBC010000u, 18u}, // bap -> Deva
+ {0xBC010000u, 19u}, // bap -> Deva
{0xC4010000u, 46u}, // bar -> Latn
{0xC8010000u, 46u}, // bas -> Latn
{0xD4010000u, 46u}, // bav -> Latn
- {0xDC010000u, 5u}, // bax -> Bamu
+ {0xDC010000u, 6u}, // bax -> Bamu
{0x80210000u, 46u}, // bba -> Latn
{0x84210000u, 46u}, // bbb -> Latn
{0x88210000u, 46u}, // bbc -> Latn
@@ -219,31 +220,31 @@
{0xB0410000u, 46u}, // bcm -> Latn
{0xB4410000u, 46u}, // bcn -> Latn
{0xB8410000u, 46u}, // bco -> Latn
- {0xC0410000u, 20u}, // bcq -> Ethi
+ {0xC0410000u, 21u}, // bcq -> Ethi
{0xD0410000u, 46u}, // bcu -> Latn
{0x8C610000u, 46u}, // bdd -> Latn
- {0x62650000u, 17u}, // be -> Cyrl
+ {0x62650000u, 18u}, // be -> Cyrl
{0x94810000u, 46u}, // bef -> Latn
{0x9C810000u, 46u}, // beh -> Latn
- {0xA4810000u, 1u}, // bej -> Arab
+ {0xA4810000u, 2u}, // bej -> Arab
{0xB0810000u, 46u}, // bem -> Latn
{0xCC810000u, 46u}, // bet -> Latn
{0xD8810000u, 46u}, // bew -> Latn
{0xDC810000u, 46u}, // bex -> Latn
{0xE4810000u, 46u}, // bez -> Latn
{0x8CA10000u, 46u}, // bfd -> Latn
- {0xC0A10000u, 84u}, // bfq -> Taml
- {0xCCA10000u, 1u}, // bft -> Arab
- {0xE0A10000u, 18u}, // bfy -> Deva
- {0x62670000u, 17u}, // bg -> Cyrl
- {0x88C10000u, 18u}, // bgc -> Deva
- {0xB4C10000u, 1u}, // bgn -> Arab
- {0xDCC10000u, 25u}, // bgx -> Grek
- {0x84E10000u, 18u}, // bhb -> Deva
+ {0xC0A10000u, 85u}, // bfq -> Taml
+ {0xCCA10000u, 2u}, // bft -> Arab
+ {0xE0A10000u, 19u}, // bfy -> Deva
+ {0x62670000u, 18u}, // bg -> Cyrl
+ {0x88C10000u, 19u}, // bgc -> Deva
+ {0xB4C10000u, 2u}, // bgn -> Arab
+ {0xDCC10000u, 26u}, // bgx -> Grek
+ {0x84E10000u, 19u}, // bhb -> Deva
{0x98E10000u, 46u}, // bhg -> Latn
- {0xA0E10000u, 18u}, // bhi -> Deva
+ {0xA0E10000u, 19u}, // bhi -> Deva
{0xACE10000u, 46u}, // bhl -> Latn
- {0xB8E10000u, 18u}, // bho -> Deva
+ {0xB8E10000u, 19u}, // bho -> Deva
{0xE0E10000u, 46u}, // bhy -> Latn
{0x62690000u, 46u}, // bi -> Latn
{0x85010000u, 46u}, // bib -> Latn
@@ -254,8 +255,8 @@
{0xB9010000u, 46u}, // bio -> Latn
{0xC1010000u, 46u}, // biq -> Latn
{0x9D210000u, 46u}, // bjh -> Latn
- {0xA1210000u, 20u}, // bji -> Ethi
- {0xA5210000u, 18u}, // bjj -> Deva
+ {0xA1210000u, 21u}, // bji -> Ethi
+ {0xA5210000u, 19u}, // bjj -> Deva
{0xB5210000u, 46u}, // bjn -> Latn
{0xB9210000u, 46u}, // bjo -> Latn
{0xC5210000u, 46u}, // bjr -> Latn
@@ -266,39 +267,39 @@
{0xC1410000u, 46u}, // bkq -> Latn
{0xD1410000u, 46u}, // bku -> Latn
{0xD5410000u, 46u}, // bkv -> Latn
- {0xCD610000u, 86u}, // blt -> Tavt
+ {0xCD610000u, 87u}, // blt -> Tavt
{0x626D0000u, 46u}, // bm -> Latn
{0x9D810000u, 46u}, // bmh -> Latn
{0xA9810000u, 46u}, // bmk -> Latn
{0xC1810000u, 46u}, // bmq -> Latn
{0xD1810000u, 46u}, // bmu -> Latn
- {0x626E0000u, 7u}, // bn -> Beng
+ {0x626E0000u, 8u}, // bn -> Beng
{0x99A10000u, 46u}, // bng -> Latn
{0xB1A10000u, 46u}, // bnm -> Latn
{0xBDA10000u, 46u}, // bnp -> Latn
- {0x626F0000u, 91u}, // bo -> Tibt
+ {0x626F0000u, 92u}, // bo -> Tibt
{0xA5C10000u, 46u}, // boj -> Latn
{0xB1C10000u, 46u}, // bom -> Latn
{0xB5C10000u, 46u}, // bon -> Latn
- {0xE1E10000u, 7u}, // bpy -> Beng
+ {0xE1E10000u, 8u}, // bpy -> Beng
{0x8A010000u, 46u}, // bqc -> Latn
- {0xA2010000u, 1u}, // bqi -> Arab
+ {0xA2010000u, 2u}, // bqi -> Arab
{0xBE010000u, 46u}, // bqp -> Latn
{0xD6010000u, 46u}, // bqv -> Latn
{0x62720000u, 46u}, // br -> Latn
- {0x82210000u, 18u}, // bra -> Deva
- {0x9E210000u, 1u}, // brh -> Arab
- {0xDE210000u, 18u}, // brx -> Deva
+ {0x82210000u, 19u}, // bra -> Deva
+ {0x9E210000u, 2u}, // brh -> Arab
+ {0xDE210000u, 19u}, // brx -> Deva
{0xE6210000u, 46u}, // brz -> Latn
{0x62730000u, 46u}, // bs -> Latn
{0xA6410000u, 46u}, // bsj -> Latn
- {0xC2410000u, 6u}, // bsq -> Bass
+ {0xC2410000u, 7u}, // bsq -> Bass
{0xCA410000u, 46u}, // bss -> Latn
- {0xCE410000u, 20u}, // bst -> Ethi
+ {0xCE410000u, 21u}, // bst -> Ethi
{0xBA610000u, 46u}, // bto -> Latn
{0xCE610000u, 46u}, // btt -> Latn
- {0xD6610000u, 18u}, // btv -> Deva
- {0x82810000u, 17u}, // bua -> Cyrl
+ {0xD6610000u, 19u}, // btv -> Deva
+ {0x82810000u, 18u}, // bua -> Cyrl
{0x8A810000u, 46u}, // buc -> Latn
{0x8E810000u, 46u}, // bud -> Latn
{0x9A810000u, 46u}, // bug -> Latn
@@ -312,7 +313,7 @@
{0xC6C10000u, 46u}, // bwr -> Latn
{0x9EE10000u, 46u}, // bxh -> Latn
{0x93010000u, 46u}, // bye -> Latn
- {0xB7010000u, 20u}, // byn -> Ethi
+ {0xB7010000u, 21u}, // byn -> Ethi
{0xC7010000u, 46u}, // byr -> Latn
{0xCB010000u, 46u}, // bys -> Latn
{0xD7010000u, 46u}, // byv -> Latn
@@ -327,44 +328,44 @@
{0xB4020000u, 46u}, // can -> Latn
{0xA4220000u, 46u}, // cbj -> Latn
{0x9C420000u, 46u}, // cch -> Latn
- {0xBC420000u, 9u}, // ccp -> Cakm
- {0x63650000u, 17u}, // ce -> Cyrl
+ {0xBC420000u, 10u}, // ccp -> Cakm
+ {0x63650000u, 18u}, // ce -> Cyrl
{0x84820000u, 46u}, // ceb -> Latn
{0x80A20000u, 46u}, // cfa -> Latn
{0x98C20000u, 46u}, // cgg -> Latn
{0x63680000u, 46u}, // ch -> Latn
{0xA8E20000u, 46u}, // chk -> Latn
- {0xB0E20000u, 17u}, // chm -> Cyrl
+ {0xB0E20000u, 18u}, // chm -> Cyrl
{0xB8E20000u, 46u}, // cho -> Latn
{0xBCE20000u, 46u}, // chp -> Latn
- {0xC4E20000u, 13u}, // chr -> Cher
+ {0xC4E20000u, 14u}, // chr -> Cher
{0x89020000u, 46u}, // cic -> Latn
- {0x81220000u, 1u}, // cja -> Arab
- {0xB1220000u, 12u}, // cjm -> Cham
+ {0x81220000u, 2u}, // cja -> Arab
+ {0xB1220000u, 13u}, // cjm -> Cham
{0xD5220000u, 46u}, // cjv -> Latn
- {0x85420000u, 1u}, // ckb -> Arab
+ {0x85420000u, 2u}, // ckb -> Arab
{0xAD420000u, 46u}, // ckl -> Latn
{0xB9420000u, 46u}, // cko -> Latn
{0xE1420000u, 46u}, // cky -> Latn
{0x81620000u, 46u}, // cla -> Latn
{0x91820000u, 46u}, // cme -> Latn
- {0x99820000u, 80u}, // cmg -> Soyo
+ {0x99820000u, 81u}, // cmg -> Soyo
{0x636F0000u, 46u}, // co -> Latn
- {0xBDC20000u, 15u}, // cop -> Copt
+ {0xBDC20000u, 16u}, // cop -> Copt
{0xC9E20000u, 46u}, // cps -> Latn
- {0x63720000u, 10u}, // cr -> Cans
- {0x9E220000u, 17u}, // crh -> Cyrl
- {0xA6220000u, 10u}, // crj -> Cans
- {0xAA220000u, 10u}, // crk -> Cans
- {0xAE220000u, 10u}, // crl -> Cans
- {0xB2220000u, 10u}, // crm -> Cans
+ {0x63720000u, 11u}, // cr -> Cans
+ {0x9E220000u, 18u}, // crh -> Cyrl
+ {0xA6220000u, 11u}, // crj -> Cans
+ {0xAA220000u, 11u}, // crk -> Cans
+ {0xAE220000u, 11u}, // crl -> Cans
+ {0xB2220000u, 11u}, // crm -> Cans
{0xCA220000u, 46u}, // crs -> Latn
{0x63730000u, 46u}, // cs -> Latn
{0x86420000u, 46u}, // csb -> Latn
- {0xDA420000u, 10u}, // csw -> Cans
- {0x8E620000u, 67u}, // ctd -> Pauc
- {0x63750000u, 17u}, // cu -> Cyrl
- {0x63760000u, 17u}, // cv -> Cyrl
+ {0xDA420000u, 11u}, // csw -> Cans
+ {0x8E620000u, 68u}, // ctd -> Pauc
+ {0x63750000u, 18u}, // cu -> Cyrl
+ {0x63760000u, 18u}, // cv -> Cyrl
{0x63790000u, 46u}, // cy -> Latn
{0x64610000u, 46u}, // da -> Latn
{0x8C030000u, 46u}, // dad -> Latn
@@ -372,11 +373,11 @@
{0x98030000u, 46u}, // dag -> Latn
{0x9C030000u, 46u}, // dah -> Latn
{0xA8030000u, 46u}, // dak -> Latn
- {0xC4030000u, 17u}, // dar -> Cyrl
+ {0xC4030000u, 18u}, // dar -> Cyrl
{0xD4030000u, 46u}, // dav -> Latn
{0x8C230000u, 46u}, // dbd -> Latn
{0xC0230000u, 46u}, // dbq -> Latn
- {0x88430000u, 1u}, // dcc -> Arab
+ {0x88430000u, 2u}, // dcc -> Arab
{0xB4630000u, 46u}, // ddn -> Latn
{0x64650000u, 46u}, // de -> Latn
{0x8C830000u, 46u}, // ded -> Latn
@@ -384,53 +385,54 @@
{0x80C30000u, 46u}, // dga -> Latn
{0x9CC30000u, 46u}, // dgh -> Latn
{0xA0C30000u, 46u}, // dgi -> Latn
- {0xACC30000u, 1u}, // dgl -> Arab
+ {0xACC30000u, 2u}, // dgl -> Arab
{0xC4C30000u, 46u}, // dgr -> Latn
{0xE4C30000u, 46u}, // dgz -> Latn
{0x81030000u, 46u}, // dia -> Latn
{0x91230000u, 46u}, // dje -> Latn
+ {0x95830000u, 54u}, // dmf -> Medf
{0xA5A30000u, 46u}, // dnj -> Latn
{0x85C30000u, 46u}, // dob -> Latn
- {0xA1C30000u, 18u}, // doi -> Deva
+ {0xA1C30000u, 19u}, // doi -> Deva
{0xBDC30000u, 46u}, // dop -> Latn
{0xD9C30000u, 46u}, // dow -> Latn
- {0x9E230000u, 56u}, // drh -> Mong
+ {0x9E230000u, 57u}, // drh -> Mong
{0xA2230000u, 46u}, // dri -> Latn
- {0xCA230000u, 20u}, // drs -> Ethi
+ {0xCA230000u, 21u}, // drs -> Ethi
{0x86430000u, 46u}, // dsb -> Latn
{0xB2630000u, 46u}, // dtm -> Latn
{0xBE630000u, 46u}, // dtp -> Latn
{0xCA630000u, 46u}, // dts -> Latn
- {0xE2630000u, 18u}, // dty -> Deva
+ {0xE2630000u, 19u}, // dty -> Deva
{0x82830000u, 46u}, // dua -> Latn
{0x8A830000u, 46u}, // duc -> Latn
{0x8E830000u, 46u}, // dud -> Latn
{0x9A830000u, 46u}, // dug -> Latn
- {0x64760000u, 89u}, // dv -> Thaa
+ {0x64760000u, 90u}, // dv -> Thaa
{0x82A30000u, 46u}, // dva -> Latn
{0xDAC30000u, 46u}, // dww -> Latn
{0xBB030000u, 46u}, // dyo -> Latn
{0xD3030000u, 46u}, // dyu -> Latn
- {0x647A0000u, 91u}, // dz -> Tibt
+ {0x647A0000u, 92u}, // dz -> Tibt
{0x9B230000u, 46u}, // dzg -> Latn
{0xD0240000u, 46u}, // ebu -> Latn
{0x65650000u, 46u}, // ee -> Latn
{0xA0A40000u, 46u}, // efi -> Latn
{0xACC40000u, 46u}, // egl -> Latn
- {0xE0C40000u, 19u}, // egy -> Egyp
+ {0xE0C40000u, 20u}, // egy -> Egyp
{0x81440000u, 46u}, // eka -> Latn
{0xE1440000u, 37u}, // eky -> Kali
- {0x656C0000u, 25u}, // el -> Grek
+ {0x656C0000u, 26u}, // el -> Grek
{0x81840000u, 46u}, // ema -> Latn
{0xA1840000u, 46u}, // emi -> Latn
{0x656E0000u, 46u}, // en -> Latn
- {0x656E5841u, 98u}, // en-XA -> ~~~A
+ {0x656E5841u, 99u}, // en-XA -> ~~~A
{0xB5A40000u, 46u}, // enn -> Latn
{0xC1A40000u, 46u}, // enq -> Latn
{0x656F0000u, 46u}, // eo -> Latn
{0xA2240000u, 46u}, // eri -> Latn
{0x65730000u, 46u}, // es -> Latn
- {0x9A440000u, 23u}, // esg -> Gonm
+ {0x9A440000u, 24u}, // esg -> Gonm
{0xD2440000u, 46u}, // esu -> Latn
{0x65740000u, 46u}, // et -> Latn
{0xC6640000u, 46u}, // etr -> Latn
@@ -441,7 +443,7 @@
{0xBAC40000u, 46u}, // ewo -> Latn
{0xCEE40000u, 46u}, // ext -> Latn
{0x83240000u, 46u}, // eza -> Latn
- {0x66610000u, 1u}, // fa -> Arab
+ {0x66610000u, 2u}, // fa -> Arab
{0x80050000u, 46u}, // faa -> Latn
{0x84050000u, 46u}, // fab -> Latn
{0x98050000u, 46u}, // fag -> Latn
@@ -451,7 +453,7 @@
{0xA0A50000u, 46u}, // ffi -> Latn
{0xB0A50000u, 46u}, // ffm -> Latn
{0x66690000u, 46u}, // fi -> Latn
- {0x81050000u, 1u}, // fia -> Arab
+ {0x81050000u, 2u}, // fia -> Arab
{0xAD050000u, 46u}, // fil -> Latn
{0xCD050000u, 46u}, // fit -> Latn
{0x666A0000u, 46u}, // fj -> Latn
@@ -468,7 +470,7 @@
{0xBE250000u, 46u}, // frp -> Latn
{0xC6250000u, 46u}, // frr -> Latn
{0xCA250000u, 46u}, // frs -> Latn
- {0x86850000u, 1u}, // fub -> Arab
+ {0x86850000u, 2u}, // fub -> Arab
{0x8E850000u, 46u}, // fud -> Latn
{0x92850000u, 46u}, // fue -> Latn
{0x96850000u, 46u}, // fuf -> Latn
@@ -486,14 +488,14 @@
{0x9C060000u, 46u}, // gah -> Latn
{0xA4060000u, 46u}, // gaj -> Latn
{0xB0060000u, 46u}, // gam -> Latn
- {0xB4060000u, 28u}, // gan -> Hans
+ {0xB4060000u, 29u}, // gan -> Hans
{0xD8060000u, 46u}, // gaw -> Latn
{0xE0060000u, 46u}, // gay -> Latn
{0x80260000u, 46u}, // gba -> Latn
{0x94260000u, 46u}, // gbf -> Latn
- {0xB0260000u, 18u}, // gbm -> Deva
+ {0xB0260000u, 19u}, // gbm -> Deva
{0xE0260000u, 46u}, // gby -> Latn
- {0xE4260000u, 1u}, // gbz -> Arab
+ {0xE4260000u, 2u}, // gbz -> Arab
{0xC4460000u, 46u}, // gcr -> Latn
{0x67640000u, 46u}, // gd -> Latn
{0x90660000u, 46u}, // gde -> Latn
@@ -502,38 +504,38 @@
{0x84860000u, 46u}, // geb -> Latn
{0xA4860000u, 46u}, // gej -> Latn
{0xAC860000u, 46u}, // gel -> Latn
- {0xE4860000u, 20u}, // gez -> Ethi
+ {0xE4860000u, 21u}, // gez -> Ethi
{0xA8A60000u, 46u}, // gfk -> Latn
- {0xB4C60000u, 18u}, // ggn -> Deva
+ {0xB4C60000u, 19u}, // ggn -> Deva
{0xC8E60000u, 46u}, // ghs -> Latn
{0xAD060000u, 46u}, // gil -> Latn
{0xB1060000u, 46u}, // gim -> Latn
- {0xA9260000u, 1u}, // gjk -> Arab
+ {0xA9260000u, 2u}, // gjk -> Arab
{0xB5260000u, 46u}, // gjn -> Latn
- {0xD1260000u, 1u}, // gju -> Arab
+ {0xD1260000u, 2u}, // gju -> Arab
{0xB5460000u, 46u}, // gkn -> Latn
{0xBD460000u, 46u}, // gkp -> Latn
{0x676C0000u, 46u}, // gl -> Latn
- {0xA9660000u, 1u}, // glk -> Arab
+ {0xA9660000u, 2u}, // glk -> Arab
{0xB1860000u, 46u}, // gmm -> Latn
- {0xD5860000u, 20u}, // gmv -> Ethi
+ {0xD5860000u, 21u}, // gmv -> Ethi
{0x676E0000u, 46u}, // gn -> Latn
{0x8DA60000u, 46u}, // gnd -> Latn
{0x99A60000u, 46u}, // gng -> Latn
{0x8DC60000u, 46u}, // god -> Latn
- {0x95C60000u, 20u}, // gof -> Ethi
+ {0x95C60000u, 21u}, // gof -> Ethi
{0xA1C60000u, 46u}, // goi -> Latn
- {0xB1C60000u, 18u}, // gom -> Deva
- {0xB5C60000u, 87u}, // gon -> Telu
+ {0xB1C60000u, 19u}, // gom -> Deva
+ {0xB5C60000u, 88u}, // gon -> Telu
{0xC5C60000u, 46u}, // gor -> Latn
{0xC9C60000u, 46u}, // gos -> Latn
- {0xCDC60000u, 24u}, // got -> Goth
+ {0xCDC60000u, 25u}, // got -> Goth
{0x86260000u, 46u}, // grb -> Latn
- {0x8A260000u, 16u}, // grc -> Cprt
- {0xCE260000u, 7u}, // grt -> Beng
+ {0x8A260000u, 17u}, // grc -> Cprt
+ {0xCE260000u, 8u}, // grt -> Beng
{0xDA260000u, 46u}, // grw -> Latn
{0xDA460000u, 46u}, // gsw -> Latn
- {0x67750000u, 26u}, // gu -> Gujr
+ {0x67750000u, 27u}, // gu -> Gujr
{0x86860000u, 46u}, // gub -> Latn
{0x8A860000u, 46u}, // guc -> Latn
{0x8E860000u, 46u}, // gud -> Latn
@@ -543,25 +545,25 @@
{0xE6860000u, 46u}, // guz -> Latn
{0x67760000u, 46u}, // gv -> Latn
{0x96A60000u, 46u}, // gvf -> Latn
- {0xC6A60000u, 18u}, // gvr -> Deva
+ {0xC6A60000u, 19u}, // gvr -> Deva
{0xCAA60000u, 46u}, // gvs -> Latn
- {0x8AC60000u, 1u}, // gwc -> Arab
+ {0x8AC60000u, 2u}, // gwc -> Arab
{0xA2C60000u, 46u}, // gwi -> Latn
- {0xCEC60000u, 1u}, // gwt -> Arab
+ {0xCEC60000u, 2u}, // gwt -> Arab
{0xA3060000u, 46u}, // gyi -> Latn
{0x68610000u, 46u}, // ha -> Latn
- {0x6861434Du, 1u}, // ha-CM -> Arab
- {0x68615344u, 1u}, // ha-SD -> Arab
+ {0x6861434Du, 2u}, // ha-CM -> Arab
+ {0x68615344u, 2u}, // ha-SD -> Arab
{0x98070000u, 46u}, // hag -> Latn
- {0xA8070000u, 28u}, // hak -> Hans
+ {0xA8070000u, 29u}, // hak -> Hans
{0xB0070000u, 46u}, // ham -> Latn
{0xD8070000u, 46u}, // haw -> Latn
- {0xE4070000u, 1u}, // haz -> Arab
+ {0xE4070000u, 2u}, // haz -> Arab
{0x84270000u, 46u}, // hbb -> Latn
- {0xE0670000u, 20u}, // hdy -> Ethi
+ {0xE0670000u, 21u}, // hdy -> Ethi
{0x68650000u, 31u}, // he -> Hebr
{0xE0E70000u, 46u}, // hhy -> Latn
- {0x68690000u, 18u}, // hi -> Deva
+ {0x68690000u, 19u}, // hi -> Deva
{0x81070000u, 46u}, // hia -> Latn
{0x95070000u, 46u}, // hif -> Latn
{0x99070000u, 46u}, // hig -> Latn
@@ -569,24 +571,24 @@
{0xAD070000u, 46u}, // hil -> Latn
{0x81670000u, 46u}, // hla -> Latn
{0xD1670000u, 32u}, // hlu -> Hluw
- {0x8D870000u, 70u}, // hmd -> Plrd
+ {0x8D870000u, 71u}, // hmd -> Plrd
{0xCD870000u, 46u}, // hmt -> Latn
- {0x8DA70000u, 1u}, // hnd -> Arab
- {0x91A70000u, 18u}, // hne -> Deva
+ {0x8DA70000u, 2u}, // hnd -> Arab
+ {0x91A70000u, 19u}, // hne -> Deva
{0xA5A70000u, 33u}, // hnj -> Hmng
{0xB5A70000u, 46u}, // hnn -> Latn
- {0xB9A70000u, 1u}, // hno -> Arab
+ {0xB9A70000u, 2u}, // hno -> Arab
{0x686F0000u, 46u}, // ho -> Latn
- {0x89C70000u, 18u}, // hoc -> Deva
- {0xA5C70000u, 18u}, // hoj -> Deva
+ {0x89C70000u, 19u}, // hoc -> Deva
+ {0xA5C70000u, 19u}, // hoj -> Deva
{0xCDC70000u, 46u}, // hot -> Latn
{0x68720000u, 46u}, // hr -> Latn
{0x86470000u, 46u}, // hsb -> Latn
- {0xB6470000u, 28u}, // hsn -> Hans
+ {0xB6470000u, 29u}, // hsn -> Hans
{0x68740000u, 46u}, // ht -> Latn
{0x68750000u, 46u}, // hu -> Latn
{0xA2870000u, 46u}, // hui -> Latn
- {0x68790000u, 3u}, // hy -> Armn
+ {0x68790000u, 4u}, // hy -> Armn
{0x687A0000u, 46u}, // hz -> Latn
{0x69610000u, 46u}, // ia -> Latn
{0xB4080000u, 46u}, // ian -> Latn
@@ -604,7 +606,7 @@
{0x69670000u, 46u}, // ig -> Latn
{0x84C80000u, 46u}, // igb -> Latn
{0x90C80000u, 46u}, // ige -> Latn
- {0x69690000u, 97u}, // ii -> Yiii
+ {0x69690000u, 98u}, // ii -> Yiii
{0xA5280000u, 46u}, // ijj -> Latn
{0x696B0000u, 46u}, // ik -> Latn
{0xA9480000u, 46u}, // ikk -> Latn
@@ -614,13 +616,13 @@
{0xB9680000u, 46u}, // ilo -> Latn
{0xB9880000u, 46u}, // imo -> Latn
{0x696E0000u, 46u}, // in -> Latn
- {0x9DA80000u, 17u}, // inh -> Cyrl
+ {0x9DA80000u, 18u}, // inh -> Cyrl
{0x696F0000u, 46u}, // io -> Latn
{0xD1C80000u, 46u}, // iou -> Latn
{0xA2280000u, 46u}, // iri -> Latn
{0x69730000u, 46u}, // is -> Latn
{0x69740000u, 46u}, // it -> Latn
- {0x69750000u, 10u}, // iu -> Cans
+ {0x69750000u, 11u}, // iu -> Cans
{0x69770000u, 31u}, // iw -> Hebr
{0xB2C80000u, 46u}, // iwm -> Latn
{0xCAC80000u, 46u}, // iws -> Latn
@@ -638,13 +640,13 @@
{0x6A690000u, 31u}, // ji -> Hebr
{0x85090000u, 46u}, // jib -> Latn
{0x89890000u, 46u}, // jmc -> Latn
- {0xAD890000u, 18u}, // jml -> Deva
+ {0xAD890000u, 19u}, // jml -> Deva
{0x82290000u, 46u}, // jra -> Latn
{0xCE890000u, 46u}, // jut -> Latn
{0x6A760000u, 46u}, // jv -> Latn
{0x6A770000u, 46u}, // jw -> Latn
- {0x6B610000u, 21u}, // ka -> Geor
- {0x800A0000u, 17u}, // kaa -> Cyrl
+ {0x6B610000u, 22u}, // ka -> Geor
+ {0x800A0000u, 18u}, // kaa -> Cyrl
{0x840A0000u, 46u}, // kab -> Latn
{0x880A0000u, 46u}, // kac -> Latn
{0x8C0A0000u, 46u}, // kad -> Latn
@@ -652,37 +654,37 @@
{0xA40A0000u, 46u}, // kaj -> Latn
{0xB00A0000u, 46u}, // kam -> Latn
{0xB80A0000u, 46u}, // kao -> Latn
- {0x8C2A0000u, 17u}, // kbd -> Cyrl
+ {0x8C2A0000u, 18u}, // kbd -> Cyrl
{0xB02A0000u, 46u}, // kbm -> Latn
{0xBC2A0000u, 46u}, // kbp -> Latn
{0xC02A0000u, 46u}, // kbq -> Latn
{0xDC2A0000u, 46u}, // kbx -> Latn
- {0xE02A0000u, 1u}, // kby -> Arab
+ {0xE02A0000u, 2u}, // kby -> Arab
{0x984A0000u, 46u}, // kcg -> Latn
{0xA84A0000u, 46u}, // kck -> Latn
{0xAC4A0000u, 46u}, // kcl -> Latn
{0xCC4A0000u, 46u}, // kct -> Latn
{0x906A0000u, 46u}, // kde -> Latn
- {0x9C6A0000u, 1u}, // kdh -> Arab
+ {0x9C6A0000u, 2u}, // kdh -> Arab
{0xAC6A0000u, 46u}, // kdl -> Latn
- {0xCC6A0000u, 90u}, // kdt -> Thai
+ {0xCC6A0000u, 91u}, // kdt -> Thai
{0x808A0000u, 46u}, // kea -> Latn
{0xB48A0000u, 46u}, // ken -> Latn
{0xE48A0000u, 46u}, // kez -> Latn
{0xB8AA0000u, 46u}, // kfo -> Latn
- {0xC4AA0000u, 18u}, // kfr -> Deva
- {0xE0AA0000u, 18u}, // kfy -> Deva
+ {0xC4AA0000u, 19u}, // kfr -> Deva
+ {0xE0AA0000u, 19u}, // kfy -> Deva
{0x6B670000u, 46u}, // kg -> Latn
{0x90CA0000u, 46u}, // kge -> Latn
{0x94CA0000u, 46u}, // kgf -> Latn
{0xBCCA0000u, 46u}, // kgp -> Latn
{0x80EA0000u, 46u}, // kha -> Latn
- {0x84EA0000u, 83u}, // khb -> Talu
- {0xB4EA0000u, 18u}, // khn -> Deva
+ {0x84EA0000u, 84u}, // khb -> Talu
+ {0xB4EA0000u, 19u}, // khn -> Deva
{0xC0EA0000u, 46u}, // khq -> Latn
{0xC8EA0000u, 46u}, // khs -> Latn
- {0xCCEA0000u, 58u}, // kht -> Mymr
- {0xD8EA0000u, 1u}, // khw -> Arab
+ {0xCCEA0000u, 59u}, // kht -> Mymr
+ {0xD8EA0000u, 2u}, // khw -> Arab
{0xE4EA0000u, 46u}, // khz -> Latn
{0x6B690000u, 46u}, // ki -> Latn
{0xA50A0000u, 46u}, // kij -> Latn
@@ -693,11 +695,11 @@
{0x992A0000u, 45u}, // kjg -> Laoo
{0xC92A0000u, 46u}, // kjs -> Latn
{0xE12A0000u, 46u}, // kjy -> Latn
- {0x6B6B0000u, 17u}, // kk -> Cyrl
- {0x6B6B4146u, 1u}, // kk-AF -> Arab
- {0x6B6B434Eu, 1u}, // kk-CN -> Arab
- {0x6B6B4952u, 1u}, // kk-IR -> Arab
- {0x6B6B4D4Eu, 1u}, // kk-MN -> Arab
+ {0x6B6B0000u, 18u}, // kk -> Cyrl
+ {0x6B6B4146u, 2u}, // kk-AF -> Arab
+ {0x6B6B434Eu, 2u}, // kk-CN -> Arab
+ {0x6B6B4952u, 2u}, // kk-IR -> Arab
+ {0x6B6B4D4Eu, 2u}, // kk-MN -> Arab
{0x894A0000u, 46u}, // kkc -> Latn
{0xA54A0000u, 46u}, // kkj -> Latn
{0x6B6C0000u, 46u}, // kl -> Latn
@@ -716,8 +718,8 @@
{0x95AA0000u, 46u}, // knf -> Latn
{0xBDAA0000u, 46u}, // knp -> Latn
{0x6B6F0000u, 43u}, // ko -> Kore
- {0xA1CA0000u, 17u}, // koi -> Cyrl
- {0xA9CA0000u, 18u}, // kok -> Deva
+ {0xA1CA0000u, 18u}, // koi -> Cyrl
+ {0xA9CA0000u, 19u}, // kok -> Deva
{0xADCA0000u, 46u}, // kol -> Latn
{0xC9CA0000u, 46u}, // kos -> Latn
{0xE5CA0000u, 46u}, // koz -> Latn
@@ -729,58 +731,58 @@
{0x860A0000u, 46u}, // kqb -> Latn
{0x960A0000u, 46u}, // kqf -> Latn
{0xCA0A0000u, 46u}, // kqs -> Latn
- {0xE20A0000u, 20u}, // kqy -> Ethi
+ {0xE20A0000u, 21u}, // kqy -> Ethi
{0x6B720000u, 46u}, // kr -> Latn
- {0x8A2A0000u, 17u}, // krc -> Cyrl
+ {0x8A2A0000u, 18u}, // krc -> Cyrl
{0xA22A0000u, 46u}, // kri -> Latn
{0xA62A0000u, 46u}, // krj -> Latn
{0xAE2A0000u, 46u}, // krl -> Latn
{0xCA2A0000u, 46u}, // krs -> Latn
- {0xD22A0000u, 18u}, // kru -> Deva
- {0x6B730000u, 1u}, // ks -> Arab
+ {0xD22A0000u, 19u}, // kru -> Deva
+ {0x6B730000u, 2u}, // ks -> Arab
{0x864A0000u, 46u}, // ksb -> Latn
{0x8E4A0000u, 46u}, // ksd -> Latn
{0x964A0000u, 46u}, // ksf -> Latn
{0x9E4A0000u, 46u}, // ksh -> Latn
{0xA64A0000u, 46u}, // ksj -> Latn
{0xC64A0000u, 46u}, // ksr -> Latn
- {0x866A0000u, 20u}, // ktb -> Ethi
+ {0x866A0000u, 21u}, // ktb -> Ethi
{0xB26A0000u, 46u}, // ktm -> Latn
{0xBA6A0000u, 46u}, // kto -> Latn
{0xC66A0000u, 46u}, // ktr -> Latn
{0x6B750000u, 46u}, // ku -> Latn
- {0x6B754952u, 1u}, // ku-IR -> Arab
- {0x6B754C42u, 1u}, // ku-LB -> Arab
+ {0x6B754952u, 2u}, // ku-IR -> Arab
+ {0x6B754C42u, 2u}, // ku-LB -> Arab
{0x868A0000u, 46u}, // kub -> Latn
{0x8E8A0000u, 46u}, // kud -> Latn
{0x928A0000u, 46u}, // kue -> Latn
{0xA68A0000u, 46u}, // kuj -> Latn
- {0xB28A0000u, 17u}, // kum -> Cyrl
+ {0xB28A0000u, 18u}, // kum -> Cyrl
{0xB68A0000u, 46u}, // kun -> Latn
{0xBE8A0000u, 46u}, // kup -> Latn
{0xCA8A0000u, 46u}, // kus -> Latn
- {0x6B760000u, 17u}, // kv -> Cyrl
+ {0x6B760000u, 18u}, // kv -> Cyrl
{0x9AAA0000u, 46u}, // kvg -> Latn
{0xC6AA0000u, 46u}, // kvr -> Latn
- {0xDEAA0000u, 1u}, // kvx -> Arab
+ {0xDEAA0000u, 2u}, // kvx -> Arab
{0x6B770000u, 46u}, // kw -> Latn
{0xA6CA0000u, 46u}, // kwj -> Latn
{0xBACA0000u, 46u}, // kwo -> Latn
{0xC2CA0000u, 46u}, // kwq -> Latn
{0x82EA0000u, 46u}, // kxa -> Latn
- {0x8AEA0000u, 20u}, // kxc -> Ethi
+ {0x8AEA0000u, 21u}, // kxc -> Ethi
{0x92EA0000u, 46u}, // kxe -> Latn
- {0xAEEA0000u, 18u}, // kxl -> Deva
- {0xB2EA0000u, 90u}, // kxm -> Thai
- {0xBEEA0000u, 1u}, // kxp -> Arab
+ {0xAEEA0000u, 19u}, // kxl -> Deva
+ {0xB2EA0000u, 91u}, // kxm -> Thai
+ {0xBEEA0000u, 2u}, // kxp -> Arab
{0xDAEA0000u, 46u}, // kxw -> Latn
{0xE6EA0000u, 46u}, // kxz -> Latn
- {0x6B790000u, 17u}, // ky -> Cyrl
- {0x6B79434Eu, 1u}, // ky-CN -> Arab
+ {0x6B790000u, 18u}, // ky -> Cyrl
+ {0x6B79434Eu, 2u}, // ky-CN -> Arab
{0x6B795452u, 46u}, // ky-TR -> Latn
{0x930A0000u, 46u}, // kye -> Latn
{0xDF0A0000u, 46u}, // kyx -> Latn
- {0x9F2A0000u, 1u}, // kzh -> Arab
+ {0x9F2A0000u, 2u}, // kzh -> Arab
{0xA72A0000u, 46u}, // kzj -> Latn
{0xC72A0000u, 46u}, // kzr -> Latn
{0xCF2A0000u, 46u}, // kzt -> Latn
@@ -788,15 +790,15 @@
{0x840B0000u, 48u}, // lab -> Lina
{0x8C0B0000u, 31u}, // lad -> Hebr
{0x980B0000u, 46u}, // lag -> Latn
- {0x9C0B0000u, 1u}, // lah -> Arab
+ {0x9C0B0000u, 2u}, // lah -> Arab
{0xA40B0000u, 46u}, // laj -> Latn
{0xC80B0000u, 46u}, // las -> Latn
{0x6C620000u, 46u}, // lb -> Latn
- {0x902B0000u, 17u}, // lbe -> Cyrl
+ {0x902B0000u, 18u}, // lbe -> Cyrl
{0xD02B0000u, 46u}, // lbu -> Latn
{0xD82B0000u, 46u}, // lbw -> Latn
{0xB04B0000u, 46u}, // lcm -> Latn
- {0xBC4B0000u, 90u}, // lcp -> Thai
+ {0xBC4B0000u, 91u}, // lcp -> Thai
{0x846B0000u, 46u}, // ldb -> Latn
{0x8C8B0000u, 46u}, // led -> Latn
{0x908B0000u, 46u}, // lee -> Latn
@@ -804,23 +806,23 @@
{0xBC8B0000u, 47u}, // lep -> Lepc
{0xC08B0000u, 46u}, // leq -> Latn
{0xD08B0000u, 46u}, // leu -> Latn
- {0xE48B0000u, 17u}, // lez -> Cyrl
+ {0xE48B0000u, 18u}, // lez -> Cyrl
{0x6C670000u, 46u}, // lg -> Latn
{0x98CB0000u, 46u}, // lgg -> Latn
{0x6C690000u, 46u}, // li -> Latn
{0x810B0000u, 46u}, // lia -> Latn
{0x8D0B0000u, 46u}, // lid -> Latn
- {0x950B0000u, 18u}, // lif -> Deva
+ {0x950B0000u, 19u}, // lif -> Deva
{0x990B0000u, 46u}, // lig -> Latn
{0x9D0B0000u, 46u}, // lih -> Latn
{0xA50B0000u, 46u}, // lij -> Latn
{0xC90B0000u, 49u}, // lis -> Lisu
{0xBD2B0000u, 46u}, // ljp -> Latn
- {0xA14B0000u, 1u}, // lki -> Arab
+ {0xA14B0000u, 2u}, // lki -> Arab
{0xCD4B0000u, 46u}, // lkt -> Latn
{0x916B0000u, 46u}, // lle -> Latn
{0xB56B0000u, 46u}, // lln -> Latn
- {0xB58B0000u, 87u}, // lmn -> Telu
+ {0xB58B0000u, 88u}, // lmn -> Telu
{0xB98B0000u, 46u}, // lmo -> Latn
{0xBD8B0000u, 46u}, // lmp -> Latn
{0x6C6E0000u, 46u}, // ln -> Latn
@@ -833,25 +835,25 @@
{0xC5CB0000u, 46u}, // lor -> Latn
{0xC9CB0000u, 46u}, // los -> Latn
{0xE5CB0000u, 46u}, // loz -> Latn
- {0x8A2B0000u, 1u}, // lrc -> Arab
+ {0x8A2B0000u, 2u}, // lrc -> Arab
{0x6C740000u, 46u}, // lt -> Latn
{0x9A6B0000u, 46u}, // ltg -> Latn
{0x6C750000u, 46u}, // lu -> Latn
{0x828B0000u, 46u}, // lua -> Latn
{0xBA8B0000u, 46u}, // luo -> Latn
{0xE28B0000u, 46u}, // luy -> Latn
- {0xE68B0000u, 1u}, // luz -> Arab
+ {0xE68B0000u, 2u}, // luz -> Arab
{0x6C760000u, 46u}, // lv -> Latn
- {0xAECB0000u, 90u}, // lwl -> Thai
- {0x9F2B0000u, 28u}, // lzh -> Hans
+ {0xAECB0000u, 91u}, // lwl -> Thai
+ {0x9F2B0000u, 29u}, // lzh -> Hans
{0xE72B0000u, 46u}, // lzz -> Latn
{0x8C0C0000u, 46u}, // mad -> Latn
{0x940C0000u, 46u}, // maf -> Latn
- {0x980C0000u, 18u}, // mag -> Deva
- {0xA00C0000u, 18u}, // mai -> Deva
+ {0x980C0000u, 19u}, // mag -> Deva
+ {0xA00C0000u, 19u}, // mai -> Deva
{0xA80C0000u, 46u}, // mak -> Latn
{0xB40C0000u, 46u}, // man -> Latn
- {0xB40C474Eu, 60u}, // man-GN -> Nkoo
+ {0xB40C474Eu, 61u}, // man-GN -> Nkoo
{0xC80C0000u, 46u}, // mas -> Latn
{0xD80C0000u, 46u}, // maw -> Latn
{0xE40C0000u, 46u}, // maz -> Latn
@@ -866,12 +868,12 @@
{0xC44C0000u, 46u}, // mcr -> Latn
{0xD04C0000u, 46u}, // mcu -> Latn
{0x806C0000u, 46u}, // mda -> Latn
- {0x906C0000u, 1u}, // mde -> Arab
- {0x946C0000u, 17u}, // mdf -> Cyrl
+ {0x906C0000u, 2u}, // mde -> Arab
+ {0x946C0000u, 18u}, // mdf -> Cyrl
{0x9C6C0000u, 46u}, // mdh -> Latn
{0xA46C0000u, 46u}, // mdj -> Latn
{0xC46C0000u, 46u}, // mdr -> Latn
- {0xDC6C0000u, 20u}, // mdx -> Ethi
+ {0xDC6C0000u, 21u}, // mdx -> Ethi
{0x8C8C0000u, 46u}, // med -> Latn
{0x908C0000u, 46u}, // mee -> Latn
{0xA88C0000u, 46u}, // mek -> Latn
@@ -879,7 +881,7 @@
{0xC48C0000u, 46u}, // mer -> Latn
{0xCC8C0000u, 46u}, // met -> Latn
{0xD08C0000u, 46u}, // meu -> Latn
- {0x80AC0000u, 1u}, // mfa -> Arab
+ {0x80AC0000u, 2u}, // mfa -> Arab
{0x90AC0000u, 46u}, // mfe -> Latn
{0xB4AC0000u, 46u}, // mfn -> Latn
{0xB8AC0000u, 46u}, // mfo -> Latn
@@ -888,7 +890,7 @@
{0x9CCC0000u, 46u}, // mgh -> Latn
{0xACCC0000u, 46u}, // mgl -> Latn
{0xB8CC0000u, 46u}, // mgo -> Latn
- {0xBCCC0000u, 18u}, // mgp -> Deva
+ {0xBCCC0000u, 19u}, // mgp -> Deva
{0xE0CC0000u, 46u}, // mgy -> Latn
{0x6D680000u, 46u}, // mh -> Latn
{0xA0EC0000u, 46u}, // mhi -> Latn
@@ -896,26 +898,25 @@
{0x6D690000u, 46u}, // mi -> Latn
{0x950C0000u, 46u}, // mif -> Latn
{0xB50C0000u, 46u}, // min -> Latn
- {0xC90C0000u, 30u}, // mis -> Hatr
{0xD90C0000u, 46u}, // miw -> Latn
- {0x6D6B0000u, 17u}, // mk -> Cyrl
- {0xA14C0000u, 1u}, // mki -> Arab
+ {0x6D6B0000u, 18u}, // mk -> Cyrl
+ {0xA14C0000u, 2u}, // mki -> Arab
{0xAD4C0000u, 46u}, // mkl -> Latn
{0xBD4C0000u, 46u}, // mkp -> Latn
{0xD94C0000u, 46u}, // mkw -> Latn
- {0x6D6C0000u, 55u}, // ml -> Mlym
+ {0x6D6C0000u, 56u}, // ml -> Mlym
{0x916C0000u, 46u}, // mle -> Latn
{0xBD6C0000u, 46u}, // mlp -> Latn
{0xC96C0000u, 46u}, // mls -> Latn
{0xB98C0000u, 46u}, // mmo -> Latn
{0xD18C0000u, 46u}, // mmu -> Latn
{0xDD8C0000u, 46u}, // mmx -> Latn
- {0x6D6E0000u, 17u}, // mn -> Cyrl
- {0x6D6E434Eu, 56u}, // mn-CN -> Mong
+ {0x6D6E0000u, 18u}, // mn -> Cyrl
+ {0x6D6E434Eu, 57u}, // mn-CN -> Mong
{0x81AC0000u, 46u}, // mna -> Latn
{0x95AC0000u, 46u}, // mnf -> Latn
- {0xA1AC0000u, 7u}, // mni -> Beng
- {0xD9AC0000u, 58u}, // mnw -> Mymr
+ {0xA1AC0000u, 8u}, // mni -> Beng
+ {0xD9AC0000u, 59u}, // mnw -> Mymr
{0x6D6F0000u, 46u}, // mo -> Latn
{0x81CC0000u, 46u}, // moa -> Latn
{0x91CC0000u, 46u}, // moe -> Latn
@@ -927,39 +928,39 @@
{0xCDEC0000u, 46u}, // mpt -> Latn
{0xDDEC0000u, 46u}, // mpx -> Latn
{0xAE0C0000u, 46u}, // mql -> Latn
- {0x6D720000u, 18u}, // mr -> Deva
- {0x8E2C0000u, 18u}, // mrd -> Deva
- {0xA62C0000u, 17u}, // mrj -> Cyrl
- {0xBA2C0000u, 57u}, // mro -> Mroo
+ {0x6D720000u, 19u}, // mr -> Deva
+ {0x8E2C0000u, 19u}, // mrd -> Deva
+ {0xA62C0000u, 18u}, // mrj -> Cyrl
+ {0xBA2C0000u, 58u}, // mro -> Mroo
{0x6D730000u, 46u}, // ms -> Latn
- {0x6D734343u, 1u}, // ms-CC -> Arab
+ {0x6D734343u, 2u}, // ms-CC -> Arab
{0x6D740000u, 46u}, // mt -> Latn
{0x8A6C0000u, 46u}, // mtc -> Latn
{0x966C0000u, 46u}, // mtf -> Latn
{0xA26C0000u, 46u}, // mti -> Latn
- {0xC66C0000u, 18u}, // mtr -> Deva
+ {0xC66C0000u, 19u}, // mtr -> Deva
{0x828C0000u, 46u}, // mua -> Latn
{0xC68C0000u, 46u}, // mur -> Latn
{0xCA8C0000u, 46u}, // mus -> Latn
{0x82AC0000u, 46u}, // mva -> Latn
{0xB6AC0000u, 46u}, // mvn -> Latn
- {0xE2AC0000u, 1u}, // mvy -> Arab
+ {0xE2AC0000u, 2u}, // mvy -> Arab
{0xAACC0000u, 46u}, // mwk -> Latn
- {0xC6CC0000u, 18u}, // mwr -> Deva
+ {0xC6CC0000u, 19u}, // mwr -> Deva
{0xD6CC0000u, 46u}, // mwv -> Latn
{0xDACC0000u, 34u}, // mww -> Hmnp
{0x8AEC0000u, 46u}, // mxc -> Latn
{0xB2EC0000u, 46u}, // mxm -> Latn
- {0x6D790000u, 58u}, // my -> Mymr
+ {0x6D790000u, 59u}, // my -> Mymr
{0xAB0C0000u, 46u}, // myk -> Latn
- {0xB30C0000u, 20u}, // mym -> Ethi
- {0xD70C0000u, 17u}, // myv -> Cyrl
+ {0xB30C0000u, 21u}, // mym -> Ethi
+ {0xD70C0000u, 18u}, // myv -> Cyrl
{0xDB0C0000u, 46u}, // myw -> Latn
{0xDF0C0000u, 46u}, // myx -> Latn
{0xE70C0000u, 52u}, // myz -> Mand
{0xAB2C0000u, 46u}, // mzk -> Latn
{0xB32C0000u, 46u}, // mzm -> Latn
- {0xB72C0000u, 1u}, // mzn -> Arab
+ {0xB72C0000u, 2u}, // mzn -> Arab
{0xBF2C0000u, 46u}, // mzp -> Latn
{0xDB2C0000u, 46u}, // mzw -> Latn
{0xE72C0000u, 46u}, // mzz -> Latn
@@ -967,7 +968,7 @@
{0x880D0000u, 46u}, // nac -> Latn
{0x940D0000u, 46u}, // naf -> Latn
{0xA80D0000u, 46u}, // nak -> Latn
- {0xB40D0000u, 28u}, // nan -> Hans
+ {0xB40D0000u, 29u}, // nan -> Hans
{0xBC0D0000u, 46u}, // nap -> Latn
{0xC00D0000u, 46u}, // naq -> Latn
{0xC80D0000u, 46u}, // nas -> Latn
@@ -981,9 +982,9 @@
{0x6E640000u, 46u}, // nd -> Latn
{0x886D0000u, 46u}, // ndc -> Latn
{0xC86D0000u, 46u}, // nds -> Latn
- {0x6E650000u, 18u}, // ne -> Deva
+ {0x6E650000u, 19u}, // ne -> Deva
{0x848D0000u, 46u}, // neb -> Latn
- {0xD88D0000u, 18u}, // new -> Deva
+ {0xD88D0000u, 19u}, // new -> Deva
{0xDC8D0000u, 46u}, // nex -> Latn
{0xC4AD0000u, 46u}, // nfr -> Latn
{0x6E670000u, 46u}, // ng -> Latn
@@ -1011,17 +1012,17 @@
{0x9DAD0000u, 46u}, // nnh -> Latn
{0xA9AD0000u, 46u}, // nnk -> Latn
{0xB1AD0000u, 46u}, // nnm -> Latn
- {0xBDAD0000u, 94u}, // nnp -> Wcho
+ {0xBDAD0000u, 95u}, // nnp -> Wcho
{0x6E6F0000u, 46u}, // no -> Latn
{0x8DCD0000u, 44u}, // nod -> Lana
- {0x91CD0000u, 18u}, // noe -> Deva
- {0xB5CD0000u, 72u}, // non -> Runr
+ {0x91CD0000u, 19u}, // noe -> Deva
+ {0xB5CD0000u, 73u}, // non -> Runr
{0xBDCD0000u, 46u}, // nop -> Latn
{0xD1CD0000u, 46u}, // nou -> Latn
- {0xBA0D0000u, 60u}, // nqo -> Nkoo
+ {0xBA0D0000u, 61u}, // nqo -> Nkoo
{0x6E720000u, 46u}, // nr -> Latn
{0x862D0000u, 46u}, // nrb -> Latn
- {0xAA4D0000u, 10u}, // nsk -> Cans
+ {0xAA4D0000u, 11u}, // nsk -> Cans
{0xB64D0000u, 46u}, // nsn -> Latn
{0xBA4D0000u, 46u}, // nso -> Latn
{0xCA4D0000u, 46u}, // nss -> Latn
@@ -1049,18 +1050,18 @@
{0xB5AE0000u, 46u}, // onn -> Latn
{0xC9AE0000u, 46u}, // ons -> Latn
{0xB1EE0000u, 46u}, // opm -> Latn
- {0x6F720000u, 65u}, // or -> Orya
+ {0x6F720000u, 66u}, // or -> Orya
{0xBA2E0000u, 46u}, // oro -> Latn
- {0xD22E0000u, 1u}, // oru -> Arab
- {0x6F730000u, 17u}, // os -> Cyrl
- {0x824E0000u, 66u}, // osa -> Osge
- {0x826E0000u, 1u}, // ota -> Arab
- {0xAA6E0000u, 64u}, // otk -> Orkh
+ {0xD22E0000u, 2u}, // oru -> Arab
+ {0x6F730000u, 18u}, // os -> Cyrl
+ {0x824E0000u, 67u}, // osa -> Osge
+ {0x826E0000u, 2u}, // ota -> Arab
+ {0xAA6E0000u, 65u}, // otk -> Orkh
{0xB32E0000u, 46u}, // ozm -> Latn
- {0x70610000u, 27u}, // pa -> Guru
- {0x7061504Bu, 1u}, // pa-PK -> Arab
+ {0x70610000u, 28u}, // pa -> Guru
+ {0x7061504Bu, 2u}, // pa-PK -> Arab
{0x980F0000u, 46u}, // pag -> Latn
- {0xAC0F0000u, 68u}, // pal -> Phli
+ {0xAC0F0000u, 69u}, // pal -> Phli
{0xB00F0000u, 46u}, // pam -> Latn
{0xBC0F0000u, 46u}, // pap -> Latn
{0xD00F0000u, 46u}, // pau -> Latn
@@ -1070,28 +1071,28 @@
{0x886F0000u, 46u}, // pdc -> Latn
{0xCC6F0000u, 46u}, // pdt -> Latn
{0x8C8F0000u, 46u}, // ped -> Latn
- {0xB88F0000u, 95u}, // peo -> Xpeo
+ {0xB88F0000u, 96u}, // peo -> Xpeo
{0xDC8F0000u, 46u}, // pex -> Latn
{0xACAF0000u, 46u}, // pfl -> Latn
- {0xACEF0000u, 1u}, // phl -> Arab
- {0xB4EF0000u, 69u}, // phn -> Phnx
+ {0xACEF0000u, 2u}, // phl -> Arab
+ {0xB4EF0000u, 70u}, // phn -> Phnx
{0xAD0F0000u, 46u}, // pil -> Latn
{0xBD0F0000u, 46u}, // pip -> Latn
- {0x814F0000u, 8u}, // pka -> Brah
+ {0x814F0000u, 9u}, // pka -> Brah
{0xB94F0000u, 46u}, // pko -> Latn
{0x706C0000u, 46u}, // pl -> Latn
{0x816F0000u, 46u}, // pla -> Latn
{0xC98F0000u, 46u}, // pms -> Latn
{0x99AF0000u, 46u}, // png -> Latn
{0xB5AF0000u, 46u}, // pnn -> Latn
- {0xCDAF0000u, 25u}, // pnt -> Grek
+ {0xCDAF0000u, 26u}, // pnt -> Grek
{0xB5CF0000u, 46u}, // pon -> Latn
- {0x81EF0000u, 18u}, // ppa -> Deva
+ {0x81EF0000u, 19u}, // ppa -> Deva
{0xB9EF0000u, 46u}, // ppo -> Latn
{0x822F0000u, 39u}, // pra -> Khar
- {0x8E2F0000u, 1u}, // prd -> Arab
+ {0x8E2F0000u, 2u}, // prd -> Arab
{0x9A2F0000u, 46u}, // prg -> Latn
- {0x70730000u, 1u}, // ps -> Arab
+ {0x70730000u, 2u}, // ps -> Arab
{0xCA4F0000u, 46u}, // pss -> Latn
{0x70740000u, 46u}, // pt -> Latn
{0xBE6F0000u, 46u}, // ptp -> Latn
@@ -1101,23 +1102,23 @@
{0x8A900000u, 46u}, // quc -> Latn
{0x9A900000u, 46u}, // qug -> Latn
{0xA0110000u, 46u}, // rai -> Latn
- {0xA4110000u, 18u}, // raj -> Deva
+ {0xA4110000u, 19u}, // raj -> Deva
{0xB8110000u, 46u}, // rao -> Latn
{0x94510000u, 46u}, // rcf -> Latn
{0xA4910000u, 46u}, // rej -> Latn
{0xAC910000u, 46u}, // rel -> Latn
{0xC8910000u, 46u}, // res -> Latn
{0xB4D10000u, 46u}, // rgn -> Latn
- {0x98F10000u, 1u}, // rhg -> Arab
+ {0x98F10000u, 2u}, // rhg -> Arab
{0x81110000u, 46u}, // ria -> Latn
- {0x95110000u, 88u}, // rif -> Tfng
+ {0x95110000u, 89u}, // rif -> Tfng
{0x95114E4Cu, 46u}, // rif-NL -> Latn
- {0xC9310000u, 18u}, // rjs -> Deva
- {0xCD510000u, 7u}, // rkt -> Beng
+ {0xC9310000u, 19u}, // rjs -> Deva
+ {0xCD510000u, 8u}, // rkt -> Beng
{0x726D0000u, 46u}, // rm -> Latn
{0x95910000u, 46u}, // rmf -> Latn
{0xB9910000u, 46u}, // rmo -> Latn
- {0xCD910000u, 1u}, // rmt -> Arab
+ {0xCD910000u, 2u}, // rmt -> Arab
{0xD1910000u, 46u}, // rmu -> Latn
{0x726E0000u, 46u}, // rn -> Latn
{0x81B10000u, 46u}, // rna -> Latn
@@ -1128,49 +1129,49 @@
{0xB9D10000u, 46u}, // roo -> Latn
{0xBA310000u, 46u}, // rro -> Latn
{0xB2710000u, 46u}, // rtm -> Latn
- {0x72750000u, 17u}, // ru -> Cyrl
- {0x92910000u, 17u}, // rue -> Cyrl
+ {0x72750000u, 18u}, // ru -> Cyrl
+ {0x92910000u, 18u}, // rue -> Cyrl
{0x9A910000u, 46u}, // rug -> Latn
{0x72770000u, 46u}, // rw -> Latn
{0xAAD10000u, 46u}, // rwk -> Latn
{0xBAD10000u, 46u}, // rwo -> Latn
{0xD3110000u, 38u}, // ryu -> Kana
- {0x73610000u, 18u}, // sa -> Deva
+ {0x73610000u, 19u}, // sa -> Deva
{0x94120000u, 46u}, // saf -> Latn
- {0x9C120000u, 17u}, // sah -> Cyrl
+ {0x9C120000u, 18u}, // sah -> Cyrl
{0xC0120000u, 46u}, // saq -> Latn
{0xC8120000u, 46u}, // sas -> Latn
- {0xCC120000u, 63u}, // sat -> Olck
+ {0xCC120000u, 64u}, // sat -> Olck
{0xD4120000u, 46u}, // sav -> Latn
- {0xE4120000u, 75u}, // saz -> Saur
+ {0xE4120000u, 76u}, // saz -> Saur
{0x80320000u, 46u}, // sba -> Latn
{0x90320000u, 46u}, // sbe -> Latn
{0xBC320000u, 46u}, // sbp -> Latn
{0x73630000u, 46u}, // sc -> Latn
- {0xA8520000u, 18u}, // sck -> Deva
- {0xAC520000u, 1u}, // scl -> Arab
+ {0xA8520000u, 19u}, // sck -> Deva
+ {0xAC520000u, 2u}, // scl -> Arab
{0xB4520000u, 46u}, // scn -> Latn
{0xB8520000u, 46u}, // sco -> Latn
{0xC8520000u, 46u}, // scs -> Latn
- {0x73640000u, 1u}, // sd -> Arab
+ {0x73640000u, 2u}, // sd -> Arab
{0x88720000u, 46u}, // sdc -> Latn
- {0x9C720000u, 1u}, // sdh -> Arab
+ {0x9C720000u, 2u}, // sdh -> Arab
{0x73650000u, 46u}, // se -> Latn
{0x94920000u, 46u}, // sef -> Latn
{0x9C920000u, 46u}, // seh -> Latn
{0xA0920000u, 46u}, // sei -> Latn
{0xC8920000u, 46u}, // ses -> Latn
{0x73670000u, 46u}, // sg -> Latn
- {0x80D20000u, 62u}, // sga -> Ogam
+ {0x80D20000u, 63u}, // sga -> Ogam
{0xC8D20000u, 46u}, // sgs -> Latn
- {0xD8D20000u, 20u}, // sgw -> Ethi
+ {0xD8D20000u, 21u}, // sgw -> Ethi
{0xE4D20000u, 46u}, // sgz -> Latn
{0x73680000u, 46u}, // sh -> Latn
- {0xA0F20000u, 88u}, // shi -> Tfng
+ {0xA0F20000u, 89u}, // shi -> Tfng
{0xA8F20000u, 46u}, // shk -> Latn
- {0xB4F20000u, 58u}, // shn -> Mymr
- {0xD0F20000u, 1u}, // shu -> Arab
- {0x73690000u, 77u}, // si -> Sinh
+ {0xB4F20000u, 59u}, // shn -> Mymr
+ {0xD0F20000u, 2u}, // shu -> Arab
+ {0x73690000u, 78u}, // si -> Sinh
{0x8D120000u, 46u}, // sid -> Latn
{0x99120000u, 46u}, // sig -> Latn
{0xAD120000u, 46u}, // sil -> Latn
@@ -1178,7 +1179,7 @@
{0xC5320000u, 46u}, // sjr -> Latn
{0x736B0000u, 46u}, // sk -> Latn
{0x89520000u, 46u}, // skc -> Latn
- {0xC5520000u, 1u}, // skr -> Arab
+ {0xC5520000u, 2u}, // skr -> Arab
{0xC9520000u, 46u}, // sks -> Latn
{0x736C0000u, 46u}, // sl -> Latn
{0x8D720000u, 46u}, // sld -> Latn
@@ -1189,7 +1190,7 @@
{0x81920000u, 46u}, // sma -> Latn
{0xA5920000u, 46u}, // smj -> Latn
{0xB5920000u, 46u}, // smn -> Latn
- {0xBD920000u, 73u}, // smp -> Samr
+ {0xBD920000u, 74u}, // smp -> Samr
{0xC1920000u, 46u}, // smq -> Latn
{0xC9920000u, 46u}, // sms -> Latn
{0x736E0000u, 46u}, // sn -> Latn
@@ -1199,24 +1200,24 @@
{0xDDB20000u, 46u}, // snx -> Latn
{0xE1B20000u, 46u}, // sny -> Latn
{0x736F0000u, 46u}, // so -> Latn
- {0x99D20000u, 78u}, // sog -> Sogd
+ {0x99D20000u, 79u}, // sog -> Sogd
{0xA9D20000u, 46u}, // sok -> Latn
{0xC1D20000u, 46u}, // soq -> Latn
- {0xD1D20000u, 90u}, // sou -> Thai
+ {0xD1D20000u, 91u}, // sou -> Thai
{0xE1D20000u, 46u}, // soy -> Latn
{0x8DF20000u, 46u}, // spd -> Latn
{0xADF20000u, 46u}, // spl -> Latn
{0xC9F20000u, 46u}, // sps -> Latn
{0x73710000u, 46u}, // sq -> Latn
- {0x73720000u, 17u}, // sr -> Cyrl
+ {0x73720000u, 18u}, // sr -> Cyrl
{0x73724D45u, 46u}, // sr-ME -> Latn
{0x7372524Fu, 46u}, // sr-RO -> Latn
{0x73725255u, 46u}, // sr-RU -> Latn
{0x73725452u, 46u}, // sr-TR -> Latn
- {0x86320000u, 79u}, // srb -> Sora
+ {0x86320000u, 80u}, // srb -> Sora
{0xB6320000u, 46u}, // srn -> Latn
{0xC6320000u, 46u}, // srr -> Latn
- {0xDE320000u, 18u}, // srx -> Deva
+ {0xDE320000u, 19u}, // srx -> Deva
{0x73730000u, 46u}, // ss -> Latn
{0x8E520000u, 46u}, // ssd -> Latn
{0x9A520000u, 46u}, // ssg -> Latn
@@ -1232,18 +1233,18 @@
{0xCA920000u, 46u}, // sus -> Latn
{0x73760000u, 46u}, // sv -> Latn
{0x73770000u, 46u}, // sw -> Latn
- {0x86D20000u, 1u}, // swb -> Arab
+ {0x86D20000u, 2u}, // swb -> Arab
{0x8AD20000u, 46u}, // swc -> Latn
{0x9AD20000u, 46u}, // swg -> Latn
{0xBED20000u, 46u}, // swp -> Latn
- {0xD6D20000u, 18u}, // swv -> Deva
+ {0xD6D20000u, 19u}, // swv -> Deva
{0xB6F20000u, 46u}, // sxn -> Latn
{0xDAF20000u, 46u}, // sxw -> Latn
- {0xAF120000u, 7u}, // syl -> Beng
- {0xC7120000u, 81u}, // syr -> Syrc
+ {0xAF120000u, 8u}, // syl -> Beng
+ {0xC7120000u, 82u}, // syr -> Syrc
{0xAF320000u, 46u}, // szl -> Latn
- {0x74610000u, 84u}, // ta -> Taml
- {0xA4130000u, 18u}, // taj -> Deva
+ {0x74610000u, 85u}, // ta -> Taml
+ {0xA4130000u, 19u}, // taj -> Deva
{0xAC130000u, 46u}, // tal -> Latn
{0xB4130000u, 46u}, // tan -> Latn
{0xC0130000u, 46u}, // taq -> Latn
@@ -1256,28 +1257,28 @@
{0xE4330000u, 46u}, // tbz -> Latn
{0xA0530000u, 46u}, // tci -> Latn
{0xE0530000u, 42u}, // tcy -> Knda
- {0x8C730000u, 82u}, // tdd -> Tale
- {0x98730000u, 18u}, // tdg -> Deva
- {0x9C730000u, 18u}, // tdh -> Deva
+ {0x8C730000u, 83u}, // tdd -> Tale
+ {0x98730000u, 19u}, // tdg -> Deva
+ {0x9C730000u, 19u}, // tdh -> Deva
{0xD0730000u, 46u}, // tdu -> Latn
- {0x74650000u, 87u}, // te -> Telu
+ {0x74650000u, 88u}, // te -> Telu
{0x8C930000u, 46u}, // ted -> Latn
{0xB0930000u, 46u}, // tem -> Latn
{0xB8930000u, 46u}, // teo -> Latn
{0xCC930000u, 46u}, // tet -> Latn
{0xA0B30000u, 46u}, // tfi -> Latn
- {0x74670000u, 17u}, // tg -> Cyrl
- {0x7467504Bu, 1u}, // tg-PK -> Arab
+ {0x74670000u, 18u}, // tg -> Cyrl
+ {0x7467504Bu, 2u}, // tg-PK -> Arab
{0x88D30000u, 46u}, // tgc -> Latn
{0xB8D30000u, 46u}, // tgo -> Latn
{0xD0D30000u, 46u}, // tgu -> Latn
- {0x74680000u, 90u}, // th -> Thai
- {0xACF30000u, 18u}, // thl -> Deva
- {0xC0F30000u, 18u}, // thq -> Deva
- {0xC4F30000u, 18u}, // thr -> Deva
- {0x74690000u, 20u}, // ti -> Ethi
+ {0x74680000u, 91u}, // th -> Thai
+ {0xACF30000u, 19u}, // thl -> Deva
+ {0xC0F30000u, 19u}, // thq -> Deva
+ {0xC4F30000u, 19u}, // thr -> Deva
+ {0x74690000u, 21u}, // ti -> Ethi
{0x95130000u, 46u}, // tif -> Latn
- {0x99130000u, 20u}, // tig -> Ethi
+ {0x99130000u, 21u}, // tig -> Ethi
{0xA9130000u, 46u}, // tik -> Latn
{0xB1130000u, 46u}, // tim -> Latn
{0xB9130000u, 46u}, // tio -> Latn
@@ -1285,7 +1286,7 @@
{0x746B0000u, 46u}, // tk -> Latn
{0xAD530000u, 46u}, // tkl -> Latn
{0xC5530000u, 46u}, // tkr -> Latn
- {0xCD530000u, 18u}, // tkt -> Deva
+ {0xCD530000u, 19u}, // tkt -> Deva
{0x746C0000u, 46u}, // tl -> Latn
{0x95730000u, 46u}, // tlf -> Latn
{0xDD730000u, 46u}, // tlx -> Latn
@@ -1305,19 +1306,19 @@
{0x74720000u, 46u}, // tr -> Latn
{0xD2330000u, 46u}, // tru -> Latn
{0xD6330000u, 46u}, // trv -> Latn
- {0xDA330000u, 1u}, // trw -> Arab
+ {0xDA330000u, 2u}, // trw -> Arab
{0x74730000u, 46u}, // ts -> Latn
- {0x8E530000u, 25u}, // tsd -> Grek
- {0x96530000u, 18u}, // tsf -> Deva
+ {0x8E530000u, 26u}, // tsd -> Grek
+ {0x96530000u, 19u}, // tsf -> Deva
{0x9A530000u, 46u}, // tsg -> Latn
- {0xA6530000u, 91u}, // tsj -> Tibt
+ {0xA6530000u, 92u}, // tsj -> Tibt
{0xDA530000u, 46u}, // tsw -> Latn
- {0x74740000u, 17u}, // tt -> Cyrl
+ {0x74740000u, 18u}, // tt -> Cyrl
{0x8E730000u, 46u}, // ttd -> Latn
{0x92730000u, 46u}, // tte -> Latn
{0xA6730000u, 46u}, // ttj -> Latn
{0xC6730000u, 46u}, // ttr -> Latn
- {0xCA730000u, 90u}, // tts -> Thai
+ {0xCA730000u, 91u}, // tts -> Thai
{0xCE730000u, 46u}, // ttt -> Latn
{0x9E930000u, 46u}, // tuh -> Latn
{0xAE930000u, 46u}, // tul -> Latn
@@ -1328,25 +1329,26 @@
{0xD2B30000u, 46u}, // tvu -> Latn
{0x9ED30000u, 46u}, // twh -> Latn
{0xC2D30000u, 46u}, // twq -> Latn
- {0x9AF30000u, 85u}, // txg -> Tang
+ {0x9AF30000u, 86u}, // txg -> Tang
{0x74790000u, 46u}, // ty -> Latn
{0x83130000u, 46u}, // tya -> Latn
- {0xD7130000u, 17u}, // tyv -> Cyrl
+ {0xD7130000u, 18u}, // tyv -> Cyrl
{0xB3330000u, 46u}, // tzm -> Latn
{0xD0340000u, 46u}, // ubu -> Latn
- {0xB0740000u, 17u}, // udm -> Cyrl
- {0x75670000u, 1u}, // ug -> Arab
- {0x75674B5Au, 17u}, // ug-KZ -> Cyrl
- {0x75674D4Eu, 17u}, // ug-MN -> Cyrl
- {0x80D40000u, 92u}, // uga -> Ugar
- {0x756B0000u, 17u}, // uk -> Cyrl
+ {0xA0740000u, 0u}, // udi -> Aghb
+ {0xB0740000u, 18u}, // udm -> Cyrl
+ {0x75670000u, 2u}, // ug -> Arab
+ {0x75674B5Au, 18u}, // ug-KZ -> Cyrl
+ {0x75674D4Eu, 18u}, // ug-MN -> Cyrl
+ {0x80D40000u, 93u}, // uga -> Ugar
+ {0x756B0000u, 18u}, // uk -> Cyrl
{0xA1740000u, 46u}, // uli -> Latn
{0x85940000u, 46u}, // umb -> Latn
- {0xC5B40000u, 7u}, // unr -> Beng
- {0xC5B44E50u, 18u}, // unr-NP -> Deva
- {0xDDB40000u, 7u}, // unx -> Beng
+ {0xC5B40000u, 8u}, // unr -> Beng
+ {0xC5B44E50u, 19u}, // unr-NP -> Deva
+ {0xDDB40000u, 8u}, // unx -> Beng
{0xA9D40000u, 46u}, // uok -> Latn
- {0x75720000u, 1u}, // ur -> Arab
+ {0x75720000u, 2u}, // ur -> Arab
{0xA2340000u, 46u}, // uri -> Latn
{0xCE340000u, 46u}, // urt -> Latn
{0xDA340000u, 46u}, // urw -> Latn
@@ -1356,10 +1358,10 @@
{0x9EB40000u, 46u}, // uvh -> Latn
{0xAEB40000u, 46u}, // uvl -> Latn
{0x757A0000u, 46u}, // uz -> Latn
- {0x757A4146u, 1u}, // uz-AF -> Arab
- {0x757A434Eu, 17u}, // uz-CN -> Cyrl
+ {0x757A4146u, 2u}, // uz-AF -> Arab
+ {0x757A434Eu, 18u}, // uz-CN -> Cyrl
{0x98150000u, 46u}, // vag -> Latn
- {0xA0150000u, 93u}, // vai -> Vaii
+ {0xA0150000u, 94u}, // vai -> Vaii
{0xB4150000u, 46u}, // van -> Latn
{0x76650000u, 46u}, // ve -> Latn
{0x88950000u, 46u}, // vec -> Latn
@@ -1378,12 +1380,12 @@
{0x77610000u, 46u}, // wa -> Latn
{0x90160000u, 46u}, // wae -> Latn
{0xA4160000u, 46u}, // waj -> Latn
- {0xAC160000u, 20u}, // wal -> Ethi
+ {0xAC160000u, 21u}, // wal -> Ethi
{0xB4160000u, 46u}, // wan -> Latn
{0xC4160000u, 46u}, // war -> Latn
{0xBC360000u, 46u}, // wbp -> Latn
- {0xC0360000u, 87u}, // wbq -> Telu
- {0xC4360000u, 18u}, // wbr -> Deva
+ {0xC0360000u, 88u}, // wbq -> Telu
+ {0xC4360000u, 19u}, // wbr -> Deva
{0xA0560000u, 46u}, // wci -> Latn
{0xC4960000u, 46u}, // wer -> Latn
{0xA0D60000u, 46u}, // wgi -> Latn
@@ -1396,40 +1398,40 @@
{0xC9760000u, 46u}, // wls -> Latn
{0xB9960000u, 46u}, // wmo -> Latn
{0x89B60000u, 46u}, // wnc -> Latn
- {0xA1B60000u, 1u}, // wni -> Arab
+ {0xA1B60000u, 2u}, // wni -> Arab
{0xD1B60000u, 46u}, // wnu -> Latn
{0x776F0000u, 46u}, // wo -> Latn
{0x85D60000u, 46u}, // wob -> Latn
{0xC9D60000u, 46u}, // wos -> Latn
{0xCA360000u, 46u}, // wrs -> Latn
- {0x9A560000u, 22u}, // wsg -> Gong
+ {0x9A560000u, 23u}, // wsg -> Gong
{0xAA560000u, 46u}, // wsk -> Latn
- {0xB2760000u, 18u}, // wtm -> Deva
- {0xD2960000u, 28u}, // wuu -> Hans
+ {0xB2760000u, 19u}, // wtm -> Deva
+ {0xD2960000u, 29u}, // wuu -> Hans
{0xD6960000u, 46u}, // wuv -> Latn
{0x82D60000u, 46u}, // wwa -> Latn
{0xD4170000u, 46u}, // xav -> Latn
{0xA0370000u, 46u}, // xbi -> Latn
- {0xB8570000u, 14u}, // xco -> Chrs
- {0xC4570000u, 11u}, // xcr -> Cari
+ {0xB8570000u, 15u}, // xco -> Chrs
+ {0xC4570000u, 12u}, // xcr -> Cari
{0xC8970000u, 46u}, // xes -> Latn
{0x78680000u, 46u}, // xh -> Latn
{0x81770000u, 46u}, // xla -> Latn
{0x89770000u, 50u}, // xlc -> Lyci
{0x8D770000u, 51u}, // xld -> Lydi
- {0x95970000u, 21u}, // xmf -> Geor
+ {0x95970000u, 22u}, // xmf -> Geor
{0xB5970000u, 53u}, // xmn -> Mani
- {0xC5970000u, 54u}, // xmr -> Merc
- {0x81B70000u, 59u}, // xna -> Narb
- {0xC5B70000u, 18u}, // xnr -> Deva
+ {0xC5970000u, 55u}, // xmr -> Merc
+ {0x81B70000u, 60u}, // xna -> Narb
+ {0xC5B70000u, 19u}, // xnr -> Deva
{0x99D70000u, 46u}, // xog -> Latn
{0xB5D70000u, 46u}, // xon -> Latn
- {0xC5F70000u, 71u}, // xpr -> Prti
+ {0xC5F70000u, 72u}, // xpr -> Prti
{0x86370000u, 46u}, // xrb -> Latn
- {0x82570000u, 74u}, // xsa -> Sarb
+ {0x82570000u, 75u}, // xsa -> Sarb
{0xA2570000u, 46u}, // xsi -> Latn
{0xB2570000u, 46u}, // xsm -> Latn
- {0xC6570000u, 18u}, // xsr -> Deva
+ {0xC6570000u, 19u}, // xsr -> Deva
{0x92D70000u, 46u}, // xwe -> Latn
{0xB0180000u, 46u}, // yam -> Latn
{0xB8180000u, 46u}, // yao -> Latn
@@ -1458,33 +1460,33 @@
{0xAE380000u, 46u}, // yrl -> Latn
{0xCA580000u, 46u}, // yss -> Latn
{0x82980000u, 46u}, // yua -> Latn
- {0x92980000u, 29u}, // yue -> Hant
- {0x9298434Eu, 28u}, // yue-CN -> Hans
+ {0x92980000u, 30u}, // yue -> Hant
+ {0x9298434Eu, 29u}, // yue-CN -> Hans
{0xA6980000u, 46u}, // yuj -> Latn
{0xCE980000u, 46u}, // yut -> Latn
{0xDA980000u, 46u}, // yuw -> Latn
{0x7A610000u, 46u}, // za -> Latn
{0x98190000u, 46u}, // zag -> Latn
- {0xA4790000u, 1u}, // zdj -> Arab
+ {0xA4790000u, 2u}, // zdj -> Arab
{0x80990000u, 46u}, // zea -> Latn
- {0x9CD90000u, 88u}, // zgh -> Tfng
- {0x7A680000u, 28u}, // zh -> Hans
- {0x7A684155u, 29u}, // zh-AU -> Hant
- {0x7A68424Eu, 29u}, // zh-BN -> Hant
- {0x7A684742u, 29u}, // zh-GB -> Hant
- {0x7A684746u, 29u}, // zh-GF -> Hant
- {0x7A68484Bu, 29u}, // zh-HK -> Hant
- {0x7A684944u, 29u}, // zh-ID -> Hant
- {0x7A684D4Fu, 29u}, // zh-MO -> Hant
- {0x7A685041u, 29u}, // zh-PA -> Hant
- {0x7A685046u, 29u}, // zh-PF -> Hant
- {0x7A685048u, 29u}, // zh-PH -> Hant
- {0x7A685352u, 29u}, // zh-SR -> Hant
- {0x7A685448u, 29u}, // zh-TH -> Hant
- {0x7A685457u, 29u}, // zh-TW -> Hant
- {0x7A685553u, 29u}, // zh-US -> Hant
- {0x7A68564Eu, 29u}, // zh-VN -> Hant
- {0xDCF90000u, 61u}, // zhx -> Nshu
+ {0x9CD90000u, 89u}, // zgh -> Tfng
+ {0x7A680000u, 29u}, // zh -> Hans
+ {0x7A684155u, 30u}, // zh-AU -> Hant
+ {0x7A68424Eu, 30u}, // zh-BN -> Hant
+ {0x7A684742u, 30u}, // zh-GB -> Hant
+ {0x7A684746u, 30u}, // zh-GF -> Hant
+ {0x7A68484Bu, 30u}, // zh-HK -> Hant
+ {0x7A684944u, 30u}, // zh-ID -> Hant
+ {0x7A684D4Fu, 30u}, // zh-MO -> Hant
+ {0x7A685041u, 30u}, // zh-PA -> Hant
+ {0x7A685046u, 30u}, // zh-PF -> Hant
+ {0x7A685048u, 30u}, // zh-PH -> Hant
+ {0x7A685352u, 30u}, // zh-SR -> Hant
+ {0x7A685448u, 30u}, // zh-TH -> Hant
+ {0x7A685457u, 30u}, // zh-TW -> Hant
+ {0x7A685553u, 30u}, // zh-US -> Hant
+ {0x7A68564Eu, 30u}, // zh-VN -> Hant
+ {0xDCF90000u, 62u}, // zhx -> Nshu
{0x81190000u, 46u}, // zia -> Latn
{0xCD590000u, 41u}, // zkt -> Kits
{0xB1790000u, 46u}, // zlm -> Latn
@@ -1642,6 +1644,7 @@
0xB48343414C61746ELLU, // den_Latn_CA
0xC4C343414C61746ELLU, // dgr_Latn_CA
0x91234E454C61746ELLU, // dje_Latn_NE
+ 0x95834E474D656466LLU, // dmf_Medf_NG
0xA5A343494C61746ELLU, // dnj_Latn_CI
0xA1C3494E44657661LLU, // doi_Deva_IN
0x9E23434E4D6F6E67LLU, // drh_Mong_CN
@@ -1917,8 +1920,6 @@
0x6D684D484C61746ELLU, // mh_Latn_MH
0x6D694E5A4C61746ELLU, // mi_Latn_NZ
0xB50C49444C61746ELLU, // min_Latn_ID
- 0xC90C495148617472LLU, // mis_Hatr_IQ
- 0xC90C4E474D656466LLU, // mis_Medf_NG
0x6D6B4D4B4379726CLLU, // mk_Cyrl_MK
0x6D6C494E4D6C796DLLU, // ml_Mlym_IN
0xC96C53444C61746ELLU, // mls_Latn_SD
@@ -2174,6 +2175,7 @@
0x747950464C61746ELLU, // ty_Latn_PF
0xD71352554379726CLLU, // tyv_Cyrl_RU
0xB3334D414C61746ELLU, // tzm_Latn_MA
+ 0xA074525541676862LLU, // udi_Aghb_RU
0xB07452554379726CLLU, // udm_Cyrl_RU
0x7567434E41726162LLU, // ug_Arab_CN
0x75674B5A4379726CLLU, // ug_Cyrl_KZ
@@ -2382,6 +2384,8 @@
{0x65735553u, 0x6573A424u}, // es-US -> es-419
{0x65735559u, 0x6573A424u}, // es-UY -> es-419
{0x65735645u, 0x6573A424u}, // es-VE -> es-419
+ {0x6E620000u, 0x6E6F0000u}, // nb -> no
+ {0x6E6E0000u, 0x6E6F0000u}, // nn -> no
{0x7074414Fu, 0x70745054u}, // pt-AO -> pt-PT
{0x70744348u, 0x70745054u}, // pt-CH -> pt-PT
{0x70744356u, 0x70745054u}, // pt-CV -> pt-PT
diff --git a/libs/androidfw/PosixUtils.cpp b/libs/androidfw/PosixUtils.cpp
index 4ec525a..0269128 100644
--- a/libs/androidfw/PosixUtils.cpp
+++ b/libs/androidfw/PosixUtils.cpp
@@ -114,10 +114,10 @@
std::unique_ptr<ProcResult> result(new ProcResult());
result->status = status;
const auto out = ReadFile(stdout[0]);
- result->stdout = out ? *out : "";
+ result->stdout_str = out ? *out : "";
close(stdout[0]);
const auto err = ReadFile(stderr[0]);
- result->stderr = err ? *err : "";
+ result->stderr_str = err ? *err : "";
close(stderr[0]);
return result;
}
diff --git a/libs/androidfw/include/androidfw/PosixUtils.h b/libs/androidfw/include/androidfw/PosixUtils.h
index 8fc3ee2..bb20847 100644
--- a/libs/androidfw/include/androidfw/PosixUtils.h
+++ b/libs/androidfw/include/androidfw/PosixUtils.h
@@ -23,8 +23,8 @@
struct ProcResult {
int status;
- std::string stdout;
- std::string stderr;
+ std::string stdout_str;
+ std::string stderr_str;
};
// Fork, exec and wait for an external process. Return nullptr if the process could not be launched,
diff --git a/libs/androidfw/tests/PosixUtils_test.cpp b/libs/androidfw/tests/PosixUtils_test.cpp
index cf97f87..c7b3eba 100644
--- a/libs/androidfw/tests/PosixUtils_test.cpp
+++ b/libs/androidfw/tests/PosixUtils_test.cpp
@@ -30,14 +30,14 @@
const auto result = ExecuteBinary({"/bin/date", "--help"});
ASSERT_THAT(result, NotNull());
ASSERT_EQ(result->status, 0);
- ASSERT_EQ(result->stdout.find("usage: date "), 0);
+ ASSERT_EQ(result->stdout_str.find("usage: date "), 0);
}
TEST(PosixUtilsTest, RelativePathToBinary) {
const auto result = ExecuteBinary({"date", "--help"});
ASSERT_THAT(result, NotNull());
ASSERT_EQ(result->status, 0);
- ASSERT_EQ(result->stdout.find("usage: date "), 0);
+ ASSERT_EQ(result->stdout_str.find("usage: date "), 0);
}
TEST(PosixUtilsTest, BadParameters) {
diff --git a/libs/hwui/jni/PaintFilter.cpp b/libs/hwui/jni/PaintFilter.cpp
index ec115b4..86d4742 100644
--- a/libs/hwui/jni/PaintFilter.cpp
+++ b/libs/hwui/jni/PaintFilter.cpp
@@ -74,7 +74,7 @@
result |= RegisterMethodsOrDie(env, "android/graphics/PaintFlagsDrawFilter", paintflags_methods,
NELEM(paintflags_methods));
- return 0;
+ return result;
}
}
diff --git a/media/OWNERS b/media/OWNERS
index abfc8bf..0aff43e 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -1,8 +1,7 @@
-chz@google.com
+# Bug component: 1344
elaurent@google.com
essick@google.com
etalvala@google.com
-gkasten@google.com
hdmoon@google.com
hkuang@google.com
hunga@google.com
@@ -13,16 +12,13 @@
jsharkey@android.com
klhyun@google.com
lajos@google.com
-marcone@google.com
nchalko@google.com
philburk@google.com
quxiangfang@google.com
wonsik@google.com
-# LON
-andrewlewis@google.com
-aquilescanta@google.com
-olly@google.com
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
# SEO
sungsoo@google.com
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d22e97c..8390ae4 100755
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -5273,6 +5273,40 @@
}
}
+ /**
+ * Indicate Le Audio output device connection state change and eventually suppress
+ * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
+ * @param device Bluetooth device connected/disconnected
+ * @param state new connection state (BluetoothProfile.STATE_xxx)
+ * @param suppressNoisyIntent if true the
+ * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
+ * {@hide}
+ */
+ public void setBluetoothLeAudioOutDeviceConnectionState(BluetoothDevice device, int state,
+ boolean suppressNoisyIntent) {
+ final IAudioService service = getService();
+ try {
+ service.setBluetoothLeAudioOutDeviceConnectionState(device, state, suppressNoisyIntent);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Indicate Le Audio input connection state change.
+ * @param device Bluetooth device connected/disconnected
+ * @param state new connection state (BluetoothProfile.STATE_xxx)
+ * {@hide}
+ */
+ public void setBluetoothLeAudioInDeviceConnectionState(BluetoothDevice device, int state) {
+ final IAudioService service = getService();
+ try {
+ service.setBluetoothLeAudioInDeviceConnectionState(device, state);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Indicate A2DP source or sink connection state change and eventually suppress
* the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index ed48b56..73bc428 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -256,6 +256,11 @@
void setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device,
int state, boolean suppressNoisyIntent, int musicDevice);
+ void setBluetoothLeAudioOutDeviceConnectionState(in BluetoothDevice device, int state,
+ boolean suppressNoisyIntent);
+
+ void setBluetoothLeAudioInDeviceConnectionState(in BluetoothDevice device, int state);
+
void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 9657b25e..c7c503d 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -2178,12 +2178,6 @@
if (size == null || size.getWidth() * size.getHeight() <= 0) {
continue;
}
- if (size.getWidth() > SIZE_RANGE.getUpper()
- || size.getHeight() > SIZE_RANGE.getUpper()) {
- size = new Size(
- Math.min(size.getWidth(), SIZE_RANGE.getUpper()),
- Math.min(size.getHeight(), SIZE_RANGE.getUpper()));
- }
Range<Long> range = Utils.parseLongRange(map.get(key), null);
if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
continue;
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 559a61d..0f9e89a 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -900,7 +900,7 @@
private @NonNull List<Bitmap> getFramesAtIndexInternal(
int frameIndex, int numFrames, @Nullable BitmapParams params) {
if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO))) {
- throw new IllegalStateException("Does not contail video or image sequences");
+ throw new IllegalStateException("Does not contain video or image sequences");
}
int frameCount = Integer.parseInt(
extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT));
@@ -1018,7 +1018,7 @@
private Bitmap getImageAtIndexInternal(int imageIndex, @Nullable BitmapParams params) {
if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE))) {
- throw new IllegalStateException("Does not contail still images");
+ throw new IllegalStateException("Does not contain still images");
}
String imageCount = extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT);
diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS
index cf06fad..813dee3 100644
--- a/media/java/android/media/OWNERS
+++ b/media/java/android/media/OWNERS
@@ -1,9 +1,9 @@
# Bug component: 1344
-
fgoldfain@google.com
elaurent@google.com
lajos@google.com
-olly@google.com
-andrewlewis@google.com
sungsoo@google.com
jmtrivi@google.com
+
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/media/jni/OWNERS b/media/jni/OWNERS
index f1b0237..445672b 100644
--- a/media/jni/OWNERS
+++ b/media/jni/OWNERS
@@ -2,4 +2,4 @@
per-file android_mtp_*.cpp=marcone@google.com,jsharkey@android.com,jameswei@google.com,rmojumder@google.com
# extra for TV related files
-per-file android_media_tv_*=nchalko@google.com,quxiangfang@google.com
+per-file android_media_tv_*=hgchen@google.com,quxiangfang@google.com
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 0d53ab1..2691983 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-
#include <stdio.h>
+#include <unordered_set>
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioEffects-JNI"
@@ -58,21 +58,14 @@
struct effect_callback_cookie {
jclass audioEffect_class; // AudioEffect class
jobject audioEffect_ref; // AudioEffect object instance
- };
-
-// ----------------------------------------------------------------------------
-class AudioEffectJniStorage {
- public:
- effect_callback_cookie mCallbackData;
-
- AudioEffectJniStorage() {
- }
-
- ~AudioEffectJniStorage() {
- }
-
+ bool busy;
+ Condition cond;
};
+// ----------------------------------------------------------------------------
+struct AudioEffectJniStorage {
+ effect_callback_cookie mCallbackData{};
+};
jint AudioEffectJni::translateNativeErrorToJava(int code) {
switch(code) {
@@ -101,6 +94,7 @@
}
static Mutex sLock;
+static std::unordered_set<effect_callback_cookie*> sAudioEffectCallBackCookies;
// ----------------------------------------------------------------------------
static void effectCallback(int event, void* user, void *info) {
@@ -121,7 +115,13 @@
ALOGW("effectCallback error user %p, env %p", user, env);
return;
}
-
+ {
+ Mutex::Autolock l(sLock);
+ if (sAudioEffectCallBackCookies.count(callbackInfo) == 0) {
+ return;
+ }
+ callbackInfo->busy = true;
+ }
ALOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
callbackInfo,
callbackInfo->audioEffect_ref,
@@ -188,6 +188,11 @@
env->ExceptionDescribe();
env->ExceptionClear();
}
+ {
+ Mutex::Autolock l(sLock);
+ callbackInfo->busy = false;
+ callbackInfo->cond.broadcast();
+ }
}
// ----------------------------------------------------------------------------
@@ -396,6 +401,10 @@
setAudioEffect(env, thiz, lpAudioEffect);
}
+ {
+ Mutex::Autolock l(sLock);
+ sAudioEffectCallBackCookies.insert(&lpJniStorage->mCallbackData);
+ }
env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
return (jint) AUDIOEFFECT_SUCCESS;
@@ -427,6 +436,7 @@
// ----------------------------------------------------------------------------
+#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz) {
sp<AudioEffect> lpAudioEffect = setAudioEffect(env, thiz, 0);
if (lpAudioEffect == 0) {
@@ -442,7 +452,17 @@
env->SetLongField(thiz, fields.fidJniData, 0);
if (lpJniStorage) {
- ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
+ Mutex::Autolock l(sLock);
+ effect_callback_cookie *lpCookie = &lpJniStorage->mCallbackData;
+ ALOGV("deleting lpJniStorage: %p\n", lpJniStorage);
+ sAudioEffectCallBackCookies.erase(lpCookie);
+ while (lpCookie->busy) {
+ if (lpCookie->cond.waitRelative(sLock,
+ milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
+ NO_ERROR) {
+ break;
+ }
+ }
env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
delete lpJniStorage;
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 4c5970a..609fafe 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -15,6 +15,7 @@
*/
#include <stdio.h>
+#include <unordered_set>
//#define LOG_NDEBUG 0
#define LOG_TAG "visualizers-JNI"
@@ -63,6 +64,12 @@
jclass visualizer_class; // Visualizer class
jobject visualizer_ref; // Visualizer object instance
+ // 'busy_count' and 'cond' together with 'sLock' are used to serialize
+ // concurrent access to the callback cookie from 'setup'/'release'
+ // and the callback.
+ int busy_count;
+ Condition cond;
+
// Lazily allocated arrays used to hold callback data provided to java
// applications. These arrays are allocated during the first callback and
// reallocated when the size of the callback data changes. Allocating on
@@ -70,14 +77,12 @@
// reference to the provided data (they need to make a copy if they want to
// hold onto outside of the callback scope), but it avoids GC thrash caused
// by constantly allocating and releasing arrays to hold callback data.
+ // 'callback_data_lock' must never be held at the same time with 'sLock'.
Mutex callback_data_lock;
jbyteArray waveform_data;
jbyteArray fft_data;
- visualizer_callback_cookie() {
- waveform_data = NULL;
- fft_data = NULL;
- }
+ // Assumes use of default initialization by the client.
~visualizer_callback_cookie() {
cleanupBuffers();
@@ -102,15 +107,8 @@
};
// ----------------------------------------------------------------------------
-class VisualizerJniStorage {
- public:
- visualizer_callback_cookie mCallbackData;
-
- VisualizerJniStorage() {
- }
-
- ~VisualizerJniStorage() {
- }
+struct VisualizerJniStorage {
+ visualizer_callback_cookie mCallbackData{};
};
@@ -136,6 +134,7 @@
}
static Mutex sLock;
+static std::unordered_set<visualizer_callback_cookie*> sVisualizerCallBackCookies;
// ----------------------------------------------------------------------------
static void ensureArraySize(JNIEnv *env, jbyteArray *array, uint32_t size) {
@@ -173,11 +172,19 @@
return;
}
+ {
+ Mutex::Autolock l(sLock);
+ if (sVisualizerCallBackCookies.count(callbackInfo) == 0) {
+ return;
+ }
+ callbackInfo->busy_count++;
+ }
ALOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
callbackInfo,
callbackInfo->visualizer_ref,
callbackInfo->visualizer_class);
+ {
AutoMutex lock(&callbackInfo->callback_data_lock);
if (waveformSize != 0 && waveform != NULL) {
@@ -219,11 +226,17 @@
jArray);
}
}
+ } // callback_data_lock scope
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
+ {
+ Mutex::Autolock l(sLock);
+ callbackInfo->busy_count--;
+ callbackInfo->cond.broadcast();
+ }
}
// ----------------------------------------------------------------------------
@@ -332,16 +345,41 @@
void *info) {
if ((event == AudioEffect::EVENT_ERROR) &&
(*((status_t*)info) == DEAD_OBJECT)) {
- VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage*)user;
- visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData;
+ visualizer_callback_cookie* callbackInfo =
+ (visualizer_callback_cookie *)user;
JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (!user || !env) {
+ ALOGW("effectCallback error user %p, env %p", user, env);
+ return;
+ }
+ {
+ Mutex::Autolock l(sLock);
+ if (sVisualizerCallBackCookies.count(callbackInfo) == 0) {
+ return;
+ }
+ callbackInfo->busy_count++;
+ }
+ ALOGV("effectCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
+ callbackInfo,
+ callbackInfo->visualizer_ref,
+ callbackInfo->visualizer_class);
+
env->CallStaticVoidMethod(
callbackInfo->visualizer_class,
fields.midPostNativeEvent,
callbackInfo->visualizer_ref,
NATIVE_EVENT_SERVER_DIED,
0, NULL);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ {
+ Mutex::Autolock l(sLock);
+ callbackInfo->busy_count--;
+ callbackInfo->cond.broadcast();
+ }
}
}
@@ -389,7 +427,7 @@
}
lpVisualizer->set(0,
android_media_visualizer_effect_callback,
- lpJniStorage,
+ &lpJniStorage->mCallbackData,
(audio_session_t) sessionId);
lStatus = translateError(lpVisualizer->initCheck());
@@ -410,6 +448,10 @@
setVisualizer(env, thiz, lpVisualizer);
+ {
+ Mutex::Autolock l(sLock);
+ sVisualizerCallBackCookies.insert(&lpJniStorage->mCallbackData);
+ }
env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
return VISUALIZER_SUCCESS;
@@ -432,13 +474,15 @@
}
// ----------------------------------------------------------------------------
+#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
static void android_media_visualizer_native_release(JNIEnv *env, jobject thiz) {
- { //limit scope so that lpVisualizer is deleted before JNI storage data.
+ {
sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
if (lpVisualizer == 0) {
return;
}
lpVisualizer->release();
+ // Visualizer can still can be held by AudioEffect::EffectClient
}
// delete the JNI data
VisualizerJniStorage* lpJniStorage =
@@ -449,9 +493,22 @@
env->SetLongField(thiz, fields.fidJniData, 0);
if (lpJniStorage) {
+ {
+ Mutex::Autolock l(sLock);
+ visualizer_callback_cookie *lpCookie = &lpJniStorage->mCallbackData;
ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
+ sVisualizerCallBackCookies.erase(lpCookie);
+ while (lpCookie->busy_count > 0) {
+ if (lpCookie->cond.waitRelative(sLock,
+ milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
+ NO_ERROR) {
+ break;
+ }
+ }
+ ALOG_ASSERT(lpCookie->busy_count == 0, "Unbalanced busy_count inc/dec");
env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_class);
env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_ref);
+ } // sLock scope
delete lpJniStorage;
}
}
@@ -707,4 +764,3 @@
{
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
}
-
diff --git a/media/tests/EffectsTest/AndroidManifest.xml b/media/tests/EffectsTest/AndroidManifest.xml
index 9b59891..ad0c10e 100644
--- a/media/tests/EffectsTest/AndroidManifest.xml
+++ b/media/tests/EffectsTest/AndroidManifest.xml
@@ -13,6 +13,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<!--
+Make sure to enable access to the mic in settings and run:
+adb shell am compat enable ALLOW_TEST_API_ACCESS com.android.effectstest
+-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.effectstest">
diff --git a/media/tests/EffectsTest/res/layout/bassboosttest.xml b/media/tests/EffectsTest/res/layout/bassboosttest.xml
index ac912c8..5f9132c 100644
--- a/media/tests/EffectsTest/res/layout/bassboosttest.xml
+++ b/media/tests/EffectsTest/res/layout/bassboosttest.xml
@@ -187,6 +187,11 @@
android:layout_height="wrap_content"
android:scaleType="fitXY"/>
+ <Button android:id="@+id/hammer_on_release_bug"
+ android:layout_width="fill_parent" android:layout_height="wrap_content"
+ android:text="@string/hammer_on_release_bug_name">
+ </Button>
+
</LinearLayout>
</ScrollView>
diff --git a/media/tests/EffectsTest/res/layout/visualizertest.xml b/media/tests/EffectsTest/res/layout/visualizertest.xml
index 18d7a36..85dabbc 100644
--- a/media/tests/EffectsTest/res/layout/visualizertest.xml
+++ b/media/tests/EffectsTest/res/layout/visualizertest.xml
@@ -175,6 +175,11 @@
</LinearLayout>
+ <Button android:id="@+id/hammer_on_release_bug"
+ android:layout_width="fill_parent" android:layout_height="wrap_content"
+ android:text="@string/hammer_on_release_bug_name">
+ </Button>
+
<ImageView
android:src="@android:drawable/divider_horizontal_dark"
android:layout_width="fill_parent"
diff --git a/media/tests/EffectsTest/res/values/strings.xml b/media/tests/EffectsTest/res/values/strings.xml
index 7c12da1..a44c7e9 100644
--- a/media/tests/EffectsTest/res/values/strings.xml
+++ b/media/tests/EffectsTest/res/values/strings.xml
@@ -37,4 +37,6 @@
<string name="send_level_name">Send Level</string>
<!-- Toggles use of a multi-threaded client for an effect [CHAR LIMIT=24] -->
<string name="effect_multithreaded">Multithreaded Use</string>
+ <!-- Runs a stress test for a bug related to simultaneous release of multiple effect instances [CHAR LIMIT=24] -->
+ <string name="hammer_on_release_bug_name">Hammer on release()</string>
</resources>
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
index cce2acc..a207bf1 100644
--- a/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
+++ b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
@@ -17,29 +17,24 @@
package com.android.effectstest;
import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
+import android.media.audiofx.AudioEffect;
+import android.media.audiofx.BassBoost;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.View.OnClickListener;
import android.view.View;
-import android.view.ViewGroup;
+import android.view.View.OnClickListener;
import android.widget.Button;
-import android.widget.TextView;
-import android.widget.EditText;
-import android.widget.SeekBar;
-import android.widget.ToggleButton;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
-import java.nio.ByteOrder;
-import java.nio.ByteBuffer;
-import java.util.HashMap;
-import java.util.Map;
+import android.widget.EditText;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.ToggleButton;
-import android.media.audiofx.BassBoost;
-import android.media.audiofx.AudioEffect;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.HashMap;
public class BassBoostTest extends Activity implements OnCheckedChangeListener {
@@ -78,6 +73,9 @@
mReleaseButton = (ToggleButton)findViewById(R.id.bbReleaseButton);
mOnOffButton = (ToggleButton)findViewById(R.id.bassboostOnOff);
+ final Button hammerReleaseTest = (Button) findViewById(R.id.hammer_on_release_bug);
+ hammerReleaseTest.setEnabled(false);
+
getEffect(sSession);
if (mBassBoost != null) {
@@ -93,6 +91,14 @@
mStrength = new BassBoostParam(mBassBoost, 0, 1000, seekBar, textView);
seekBar.setOnSeekBarChangeListener(mStrength);
mStrength.setEnabled(mBassBoost.getStrengthSupported());
+
+ hammerReleaseTest.setEnabled(true);
+ hammerReleaseTest.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ runHammerReleaseTest(hammerReleaseTest);
+ }
+ });
}
}
@@ -273,4 +279,52 @@
}
}
+ // Stress-tests releasing of AudioEffect by doing repeated creation
+ // and subsequent releasing. Also forces emission of callbacks from
+ // the AudioFlinger by setting a control status listener. Since all
+ // effect instances are bound to the same session, the AF will
+ // notify them about the change in their status. This can reveal racy
+ // behavior w.r.t. releasing.
+ class HammerReleaseTest extends Thread {
+ private static final int NUM_EFFECTS = 10;
+ private static final int NUM_ITERATIONS = 100;
+ private final int mSession;
+ private final Runnable mOnComplete;
+
+ HammerReleaseTest(int session, Runnable onComplete) {
+ mSession = session;
+ mOnComplete = onComplete;
+ }
+
+ @Override
+ public void run() {
+ Log.w(TAG, "HammerReleaseTest started");
+ BassBoost[] effects = new BassBoost[NUM_EFFECTS];
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ for (int j = 0; j < NUM_EFFECTS; j++) {
+ effects[j] = new BassBoost(0, mSession);
+ effects[j].setControlStatusListener(mEffectListener);
+ yield();
+ }
+ for (int j = NUM_EFFECTS - 1; j >= 0; j--) {
+ Log.w(TAG, "HammerReleaseTest releasing effect " + (Object) effects[j]);
+ effects[j].release();
+ effects[j] = null;
+ yield();
+ }
+ }
+ Log.w(TAG, "HammerReleaseTest ended");
+ runOnUiThread(mOnComplete);
+ }
+ }
+
+ private void runHammerReleaseTest(Button controlButton) {
+ controlButton.setEnabled(false);
+ HammerReleaseTest thread = new HammerReleaseTest(sSession,
+ () -> {
+ controlButton.setEnabled(true);
+ });
+ thread.start();
+ }
+
}
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
index 2e141c5..dcfe11a 100644
--- a/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
+++ b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
@@ -17,6 +17,7 @@
package com.android.effectstest;
import android.app.Activity;
+import android.media.audiofx.Visualizer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -24,6 +25,8 @@
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
@@ -74,11 +77,22 @@
mCallbackOn = false;
mCallbackButton.setChecked(mCallbackOn);
+ final Button hammerReleaseTest = (Button) findViewById(R.id.hammer_on_release_bug);
+ hammerReleaseTest.setEnabled(false);
+
mMultithreadedButton.setOnCheckedChangeListener(this);
if (getEffect(sSession) != null) {
mReleaseButton.setOnCheckedChangeListener(this);
mOnOffButton.setOnCheckedChangeListener(this);
mCallbackButton.setOnCheckedChangeListener(this);
+
+ hammerReleaseTest.setEnabled(true);
+ hammerReleaseTest.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ runHammerReleaseTest(hammerReleaseTest);
+ }
+ });
}
}
@@ -214,4 +228,50 @@
}
}
+ // Stress-tests releasing of AudioEffect by doing repeated creation
+ // and subsequent releasing. Unlike a similar class in BassBoostTest,
+ // this one doesn't sets a control status listener because Visualizer
+ // doesn't inherit from AudioEffect and doesn't implement this method
+ // by itself.
+ class HammerReleaseTest extends Thread {
+ private static final int NUM_EFFECTS = 10;
+ private static final int NUM_ITERATIONS = 100;
+ private final int mSession;
+ private final Runnable mOnComplete;
+
+ HammerReleaseTest(int session, Runnable onComplete) {
+ mSession = session;
+ mOnComplete = onComplete;
+ }
+
+ @Override
+ public void run() {
+ Log.w(TAG, "HammerReleaseTest started");
+ Visualizer[] effects = new Visualizer[NUM_EFFECTS];
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ for (int j = 0; j < NUM_EFFECTS; j++) {
+ effects[j] = new Visualizer(mSession);
+ yield();
+ }
+ for (int j = NUM_EFFECTS - 1; j >= 0; j--) {
+ Log.w(TAG, "HammerReleaseTest releasing effect " + (Object) effects[j]);
+ effects[j].release();
+ effects[j] = null;
+ yield();
+ }
+ }
+ Log.w(TAG, "HammerReleaseTest ended");
+ runOnUiThread(mOnComplete);
+ }
+ }
+
+ private void runHammerReleaseTest(Button controlButton) {
+ controlButton.setEnabled(false);
+ HammerReleaseTest thread = new HammerReleaseTest(sSession,
+ () -> {
+ controlButton.setEnabled(true);
+ });
+ thread.start();
+ }
+
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 59d8acb..70baf1d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -18,6 +18,7 @@
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
@@ -125,6 +126,9 @@
addHandler(BluetoothDevice.ACTION_ACL_CONNECTED, new AclStateChangedHandler());
addHandler(BluetoothDevice.ACTION_ACL_DISCONNECTED, new AclStateChangedHandler());
+ addHandler(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE,
+ new SetMemberAvailableHandler());
+
registerAdapterIntentReceiver();
}
@@ -293,6 +297,8 @@
BluetoothDevice device) {
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
+ final boolean isCoordinatedSetMember =
+ intent.getBooleanExtra(BluetoothDevice.EXTRA_IS_COORDINATED_SET_MEMBER, false);
// TODO Pick up UUID. They should be available for 2.1 devices.
// Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
@@ -307,6 +313,7 @@
}
cachedDevice.setRssi(rssi);
cachedDevice.setJustDiscovered(true);
+ cachedDevice.setIsCoordinatedSetMember(isCoordinatedSetMember);
}
}
@@ -335,6 +342,12 @@
}
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
BluetoothDevice.ERROR);
+
+ if (mDeviceManager.onBondStateChangedIfProcess(device, bondState)) {
+ Log.d(TAG, "Should not update UI for the set member");
+ return;
+ }
+
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
Log.w(TAG, "Got bonding state changed for " + device +
@@ -348,8 +361,10 @@
cachedDevice.onBondingStateChanged(bondState);
if (bondState == BluetoothDevice.BOND_NONE) {
- /* Check if we need to remove other Hearing Aid devices */
- if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
+ // Check if we need to remove other Coordinated set member devices / Hearing Aid
+ // devices
+ if (cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
+ || cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
mDeviceManager.onDeviceUnpaired(cachedDevice);
}
int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
@@ -496,4 +511,29 @@
dispatchAudioModeChanged();
}
}
+
+ private class SetMemberAvailableHandler implements Handler {
+ @Override
+ public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+ final String action = intent.getAction();
+ if (device == null) {
+ Log.e(TAG, "SetMemberAvailableHandler: device is null");
+ return;
+ }
+
+ if (action == null) {
+ Log.e(TAG, "SetMemberAvailableHandler: action is null");
+ return;
+ }
+
+ final int groupId = intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID,
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ Log.e(TAG, "SetMemberAvailableHandler: Invalid group id");
+ return;
+ }
+
+ mDeviceManager.onSetMemberAppear(device, groupId);
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 4c80b91..78fc139 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -18,6 +18,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
@@ -41,7 +42,9 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
/**
@@ -66,6 +69,7 @@
private final Object mProfileLock = new Object();
BluetoothDevice mDevice;
private long mHiSyncId;
+ private int mGroupId;
// Need this since there is no method for getting RSSI
short mRssi;
// mProfiles and mRemovedProfiles does not do swap() between main and sub device. It is
@@ -80,6 +84,8 @@
boolean mJustDiscovered;
+ boolean mIsCoordinatedSetMember = false;
+
private final Collection<Callback> mCallbacks = new CopyOnWriteArrayList<>();
/**
@@ -98,6 +104,8 @@
private boolean mIsA2dpProfileConnectedFail = false;
private boolean mIsHeadsetProfileConnectedFail = false;
private boolean mIsHearingAidProfileConnectedFail = false;
+ // Group member devices for the coordinated set
+ private Set<CachedBluetoothDevice> mMemberDevices = new HashSet<CachedBluetoothDevice>();
// Group second device for Hearing Aid
private CachedBluetoothDevice mSubDevice;
@@ -131,6 +139,7 @@
mDevice = device;
fillData();
mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
+ mGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
}
/**
@@ -297,6 +306,42 @@
return mHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID;
}
+ /**
+ * Mark the discovered device as member of coordinated set.
+ *
+ * @param isCoordinatedSetMember {@code true}, if the device is a member of a coordinated set.
+ */
+ public void setIsCoordinatedSetMember(boolean isCoordinatedSetMember) {
+ mIsCoordinatedSetMember = isCoordinatedSetMember;
+ }
+
+ /**
+ * Check if the device is a CSIP member device.
+ *
+ * @return {@code true}, if this device supports CSIP, otherwise returns {@code false}.
+ */
+ public boolean isCoordinatedSetMemberDevice() {
+ return mIsCoordinatedSetMember;
+ }
+
+ /**
+ * Get the coordinated set group id.
+ *
+ * @return the group id.
+ */
+ public int getGroupId() {
+ return mGroupId;
+ }
+
+ /**
+ * Set the coordinated set group id.
+ *
+ * @param id the group id from the CSIP.
+ */
+ public void setGroupId(int id) {
+ mGroupId = id;
+ }
+
void onBondingDockConnect() {
// Attempt to connect if UUIDs are available. Otherwise,
// we will connect when the ACTION_UUID intent arrives.
@@ -1171,4 +1216,52 @@
mSubDevice.mJustDiscovered = tmpJustDiscovered;
fetchActiveDevices();
}
+
+ /**
+ * @return a set of member devices that are in the same coordinated set with this device.
+ */
+ public Set<CachedBluetoothDevice> getMemberDevice() {
+ return mMemberDevices;
+ }
+
+ /**
+ * Store the member devices that are in the same coordinated set.
+ */
+ public void setMemberDevice(CachedBluetoothDevice memberDevice) {
+ mMemberDevices.add(memberDevice);
+ }
+
+ /**
+ * Remove a device from the member device sets.
+ */
+ public void removeMemberDevice(CachedBluetoothDevice memberDevice) {
+ mMemberDevices.remove(memberDevice);
+ }
+
+ /**
+ * In order to show the preference for the whole group, we always set the main device as the
+ * first connected device in the coordinated set, and then switch the content of the main
+ * device and member devices.
+ *
+ * @param prevMainDevice the previous Main device, it will be added into the member device set.
+ * @param newMainDevie the new Main device, it will be removed from the member device set.
+ */
+ public void switchMemberDeviceContent(CachedBluetoothDevice prevMainDevice,
+ CachedBluetoothDevice newMainDevie) {
+ // Backup from main device
+ final BluetoothDevice tmpDevice = mDevice;
+ final short tmpRssi = mRssi;
+ final boolean tmpJustDiscovered = mJustDiscovered;
+ // Set main device from sub device
+ mDevice = newMainDevie.mDevice;
+ mRssi = newMainDevie.mRssi;
+ mJustDiscovered = newMainDevie.mJustDiscovered;
+ setMemberDevice(prevMainDevice);
+ mMemberDevices.remove(newMainDevie);
+ // Set sub device from backup
+ newMainDevie.mDevice = tmpDevice;
+ newMainDevie.mRssi = tmpRssi;
+ newMainDevie.mJustDiscovered = tmpJustDiscovered;
+ fetchActiveDevices();
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index cca9cfa..0256615 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -18,6 +18,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;
@@ -26,6 +27,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
/**
* CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
@@ -41,11 +43,15 @@
final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
@VisibleForTesting
HearingAidDeviceManager mHearingAidDeviceManager;
+ @VisibleForTesting
+ CsipDeviceManager mCsipDeviceManager;
+ BluetoothDevice mOngoingSetMemberPair;
CachedBluetoothDeviceManager(Context context, LocalBluetoothManager localBtManager) {
mContext = context;
mBtManager = localBtManager;
mHearingAidDeviceManager = new HearingAidDeviceManager(localBtManager, mCachedDevices);
+ mCsipDeviceManager = new CsipDeviceManager(localBtManager, mCachedDevices);
}
public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
@@ -79,7 +85,16 @@
if (cachedDevice.getDevice().equals(device)) {
return cachedDevice;
}
- // Check sub devices if it exists
+ // Check the member devices for the coordinated set if it exists
+ final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ if (memberDevice.getDevice().equals(device)) {
+ return memberDevice;
+ }
+ }
+ }
+ // Check sub devices for hearing aid if it exists
CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
if (subDevice != null && subDevice.getDevice().equals(device)) {
return subDevice;
@@ -102,8 +117,10 @@
newDevice = findDevice(device);
if (newDevice == null) {
newDevice = new CachedBluetoothDevice(mContext, profileManager, device);
+ mCsipDeviceManager.initCsipDeviceIfNeeded(newDevice);
mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(newDevice);
- if (!mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
+ if (!mCsipDeviceManager.setMemberDeviceIfNeeded(newDevice)
+ && !mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
mCachedDevices.add(newDevice);
mBtManager.getEventManager().dispatchDeviceAdded(newDevice);
}
@@ -114,13 +131,23 @@
}
/**
- * Returns device summary of the pair of the hearing aid passed as the parameter.
+ * Returns device summary of the pair of the hearing aid / CSIP passed as the parameter.
*
* @param CachedBluetoothDevice device
- * @return Device summary, or if the pair does not exist or if it is not a hearing aid,
- * then {@code null}.
+ * @return Device summary, or if the pair does not exist or if it is not a hearing aid or
+ * a CSIP set member, then {@code null}.
*/
public synchronized String getSubDeviceSummary(CachedBluetoothDevice device) {
+ final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ if (!memberDevice.isConnected()) {
+ return null;
+ }
+ }
+
+ return device.getConnectionSummary();
+ }
CachedBluetoothDevice subDevice = device.getSubDevice();
if (subDevice != null && subDevice.isConnected()) {
return subDevice.getConnectionSummary();
@@ -132,12 +159,22 @@
* Search for existing sub device {@link CachedBluetoothDevice}.
*
* @param device the address of the Bluetooth device
- * @return true for found sub device or false.
+ * @return true for found sub / member device or false.
*/
public synchronized boolean isSubDevice(BluetoothDevice device) {
for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
if (!cachedDevice.getDevice().equals(device)) {
- // Check sub devices if it exists
+ // Check the member devices of the coordinated set if it exists
+ Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ if (memberDevice.getDevice().equals(device)) {
+ return true;
+ }
+ }
+ continue;
+ }
+ // Check sub devices of hearing aid if it exists
CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
if (subDevice != null && subDevice.getDevice().equals(device)) {
return true;
@@ -157,6 +194,14 @@
}
/**
+ * Updates the Csip devices; specifically the GroupId's. This routine is called when the
+ * CSIS is connected and the GroupId's are now available.
+ */
+ public synchronized void updateCsipDevices() {
+ mCsipDeviceManager.updateCsipDevices();
+ }
+
+ /**
* Attempts to get the name of a remote device, otherwise returns the address.
*
* @param device The remote device.
@@ -185,6 +230,16 @@
private void clearNonBondedSubDevices() {
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+ final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ // Member device exists and it is not bonded
+ if (memberDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
+ cachedDevice.removeMemberDevice(memberDevice);
+ }
+ }
+ return;
+ }
CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
if (subDevice != null
&& subDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
@@ -201,6 +256,13 @@
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
cachedDevice.setJustDiscovered(false);
+ final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ memberDevice.setJustDiscovered(false);
+ }
+ return;
+ }
final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
if (subDevice != null) {
subDevice.setJustDiscovered(false);
@@ -214,10 +276,19 @@
if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
- CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
- if (subDevice != null) {
- if (subDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
- cachedDevice.setSubDevice(null);
+ final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ if (memberDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+ cachedDevice.removeMemberDevice(memberDevice);
+ }
+ }
+ } else {
+ CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
+ if (subDevice != null) {
+ if (subDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+ cachedDevice.setSubDevice(null);
+ }
}
}
if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
@@ -229,13 +300,32 @@
}
public synchronized boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice
- cachedDevice, int state) {
- return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
+ cachedDevice, int state, int profileId) {
+ if (profileId == BluetoothProfile.HEARING_AID) {
+ return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
state);
+ }
+ if (profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
+ return mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
+ state);
+ }
+ return false;
}
public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) {
- CachedBluetoothDevice mainDevice = mHearingAidDeviceManager.findMainDevice(device);
+ CachedBluetoothDevice mainDevice = mCsipDeviceManager.findMainDevice(device);
+ final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
+ if (memberDevices != null) {
+ // Main device is unpaired, to unpair the member device
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ memberDevice.unpair();
+ device.removeMemberDevice(memberDevice);
+ }
+ } else if (mainDevice != null) {
+ // the member device unpaired, to unpair main device
+ mainDevice.unpair();
+ }
+ mainDevice = mHearingAidDeviceManager.findMainDevice(device);
CachedBluetoothDevice subDevice = device.getSubDevice();
if (subDevice != null) {
// Main device is unpaired, to unpair sub device
@@ -248,6 +338,74 @@
}
}
+ /**
+ * Called when we found a set member of a group. The function will check the {@code groupId} if
+ * it exists and if there is a ongoing pair, the device would be ignored.
+ *
+ * @param device The found device
+ * @param groupId The group id of the found device
+ */
+ public synchronized void onSetMemberAppear(BluetoothDevice device, int groupId) {
+ Log.d(TAG, "onSetMemberAppear, groupId: " + groupId + " device: " + device.toString());
+
+ if (mOngoingSetMemberPair != null) {
+ Log.d(TAG, "Ongoing set memberPairing in process, drop it!");
+ return;
+ }
+
+ if (mCsipDeviceManager.onSetMemberAppear(device, groupId)) {
+ mOngoingSetMemberPair = device;
+ }
+ }
+
+ /**
+ * Called when the bond state change. If the bond state change is related with the
+ * ongoing set member pair, the cachedBluetoothDevice will be created but the UI
+ * would not be updated. For the other case, return {@code false} to go through the normal
+ * flow.
+ *
+ * @param device The device
+ * @param bondState The new bond state
+ *
+ * @return {@code true}, if the bond state change for the device is handled inside this
+ * function, and would not like to update the UI. If not, return {@code false}.
+ */
+ public synchronized boolean onBondStateChangedIfProcess(BluetoothDevice device, int bondState) {
+ if (mOngoingSetMemberPair == null || !mOngoingSetMemberPair.equals(device)) {
+ return false;
+ }
+
+ if (bondState == BluetoothDevice.BOND_BONDING) {
+ return true;
+ }
+
+ mOngoingSetMemberPair = null;
+ if (bondState != BluetoothDevice.BOND_NONE) {
+ if (findDevice(device) == null) {
+ final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+ CachedBluetoothDevice newDevice =
+ new CachedBluetoothDevice(mContext, profileManager, device);
+ mCachedDevices.add(newDevice);
+ findDevice(device).connect();
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if the device is the one which is initial paired locally by CSIP. The setting
+ * would depned on it to accept the pairing request automatically
+ *
+ * @param device The device
+ *
+ * @return {@code true}, if the device is ongoing pair by CSIP. Otherwise, return
+ * {@code false}.
+ */
+ public boolean isOngoingPairByCsip(BluetoothDevice device) {
+ return !(mOngoingSetMemberPair == null) && mOngoingSetMemberPair.equals(device);
+ }
+
private void log(String msg) {
if (DEBUG) {
Log.d(TAG, msg);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
new file mode 100644
index 0000000..347e14b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * CsipDeviceManager manages the set of remote CSIP Bluetooth devices.
+ */
+public class CsipDeviceManager {
+ private static final String TAG = "CsipDeviceManager";
+ private static final boolean DEBUG = BluetoothUtils.D;
+
+ private final LocalBluetoothManager mBtManager;
+ private final List<CachedBluetoothDevice> mCachedDevices;
+
+ CsipDeviceManager(LocalBluetoothManager localBtManager,
+ List<CachedBluetoothDevice> cachedDevices) {
+ mBtManager = localBtManager;
+ mCachedDevices = cachedDevices;
+ };
+
+ void initCsipDeviceIfNeeded(CachedBluetoothDevice newDevice) {
+ // Current it only supports the base uuid for CSIP and group this set in UI.
+ final int groupId = getBaseGroupId(newDevice.getDevice());
+ if (isValidGroupId(groupId)) {
+ log("initCsipDeviceIfNeeded: " + newDevice + " (group: " + groupId + ")");
+ // Once groupId is valid, assign groupId
+ newDevice.setGroupId(groupId);
+ }
+ }
+
+ private int getBaseGroupId(BluetoothDevice device) {
+ final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+ final CsipSetCoordinatorProfile profileProxy = profileManager
+ .getCsipSetCoordinatorProfile();
+ if (profileProxy != null) {
+ final Map<Integer, ParcelUuid> groupIdMap = profileProxy
+ .getGroupUuidMapByDevice(device);
+ if (groupIdMap == null) {
+ return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+ }
+
+ for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
+ if (entry.getValue().equals(BluetoothUuid.BASE_UUID)) {
+ return entry.getKey();
+ }
+ }
+ }
+ return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+ }
+
+ boolean setMemberDeviceIfNeeded(CachedBluetoothDevice newDevice) {
+ final int groupId = newDevice.getGroupId();
+ if (isValidGroupId(groupId)) {
+ final CachedBluetoothDevice CsipDevice = getCachedDevice(groupId);
+ log("setMemberDeviceIfNeeded, main: " + CsipDevice + ", member: " + newDevice);
+ // Just add one of the coordinated set from a pair in the list that is shown in the UI.
+ // Once there is other devices with the same groupId, to add new device as member
+ // devices.
+ if (CsipDevice != null) {
+ CsipDevice.setMemberDevice(newDevice);
+ newDevice.setName(CsipDevice.getName());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isValidGroupId(int groupId) {
+ return groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+ }
+
+ private CachedBluetoothDevice getCachedDevice(int groupId) {
+ for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+ CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+ if (cachedDevice.getGroupId() == groupId) {
+ return cachedDevice;
+ }
+ }
+ return null;
+ }
+
+ // To collect all set member devices and call #onGroupIdChanged to group device by GroupId
+ void updateCsipDevices() {
+ final Set<Integer> newGroupIdSet = new HashSet<Integer>();
+ for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
+ // Do nothing if GroupId has been assigned
+ if (!isValidGroupId(cachedDevice.getGroupId())) {
+ final int newGroupId = getBaseGroupId(cachedDevice.getDevice());
+ // Do nothing if there is no GroupId on Bluetooth device
+ if (isValidGroupId(newGroupId)) {
+ cachedDevice.setGroupId(newGroupId);
+ newGroupIdSet.add(newGroupId);
+ }
+ }
+ }
+ for (int groupId : newGroupIdSet) {
+ onGroupIdChanged(groupId);
+ }
+ }
+
+ // Group devices by groupId
+ @VisibleForTesting
+ void onGroupIdChanged(int groupId) {
+ int firstMatchedIndex = -1;
+ CachedBluetoothDevice mainDevice = null;
+
+ for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+ final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+ if (cachedDevice.getGroupId() != groupId) {
+ continue;
+ }
+
+ if (firstMatchedIndex == -1) {
+ // Found the first one
+ firstMatchedIndex = i;
+ mainDevice = cachedDevice;
+ continue;
+ }
+
+ log("onGroupIdChanged: removed from UI device =" + cachedDevice
+ + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex);
+
+ mainDevice.setMemberDevice(cachedDevice);
+ mCachedDevices.remove(i);
+ mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
+ break;
+ }
+ }
+
+ // @return {@code true}, the event is processed inside the method. It is for updating
+ // le audio device on group relationship when receiving connected or disconnected.
+ // @return {@code false}, it is not le audio device or to process it same as other profiles
+ boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice cachedDevice,
+ int state) {
+ log("onProfileConnectionStateChangedIfProcessed: " + cachedDevice + ", state: " + state);
+ switch (state) {
+ case BluetoothProfile.STATE_CONNECTED:
+ onGroupIdChanged(cachedDevice.getGroupId());
+ CachedBluetoothDevice mainDevice = findMainDevice(cachedDevice);
+ if (mainDevice != null) {
+ if (mainDevice.isConnected()) {
+ // When main device exists and in connected state, receiving member device
+ // connection. To refresh main device UI
+ mainDevice.refresh();
+ return true;
+ } else {
+ // When both LE Audio devices are disconnected, receiving member device
+ // connection. To switch content and dispatch to notify UI change
+ mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice);
+ mainDevice.switchMemberDeviceContent(mainDevice, cachedDevice);
+ mainDevice.refresh();
+ // It is necessary to do remove and add for updating the mapping on
+ // preference and device
+ mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
+ return true;
+ }
+ }
+ break;
+ case BluetoothProfile.STATE_DISCONNECTED:
+ mainDevice = findMainDevice(cachedDevice);
+ if (mainDevice != null) {
+ // When main device exists, receiving sub device disconnection
+ // To update main device UI
+ mainDevice.refresh();
+ return true;
+ }
+ final Set<CachedBluetoothDevice> memberSet = cachedDevice.getMemberDevice();
+ if (memberSet == null) {
+ break;
+ }
+
+ for (CachedBluetoothDevice device: memberSet) {
+ if (device.isConnected()) {
+ // Main device is disconnected and sub device is connected
+ // To copy data from sub device to main device
+ mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
+ cachedDevice.switchMemberDeviceContent(device, cachedDevice);
+ cachedDevice.refresh();
+ // It is necessary to do remove and add for updating the mapping on
+ // preference and device
+ mBtManager.getEventManager().dispatchDeviceAdded(cachedDevice);
+ return true;
+ }
+ }
+ break;
+ default:
+ // Do not handle this state.
+ }
+ return false;
+ }
+
+ CachedBluetoothDevice findMainDevice(CachedBluetoothDevice device) {
+ if (device == null || mCachedDevices == null) {
+ return null;
+ }
+
+ for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
+ if (isValidGroupId(cachedDevice.getGroupId())) {
+ Set<CachedBluetoothDevice> memberSet = cachedDevice.getMemberDevice();
+ if (memberSet == null) {
+ continue;
+ }
+
+ for (CachedBluetoothDevice memberDevice: memberSet) {
+ if (memberDevice != null && memberDevice.equals(device)) {
+ return cachedDevice;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Called when we found a set member of a group. The function will check bond state, and
+ * the {@code groupId} if it exists, and then create the bond.
+ *
+ * @param device The found device
+ * @param groupId The group id of the found device
+ *
+ * @return {@code true}, if the we create bond with the device. Otherwise, return
+ * {@code false}.
+ */
+ public boolean onSetMemberAppear(BluetoothDevice device, int groupId) {
+ if (device.getBondState() != BluetoothDevice.BOND_NONE) {
+ return false;
+ }
+
+ if (getCachedDevice(groupId) != null) {
+ device.createBond(BluetoothDevice.TRANSPORT_LE);
+ return true;
+ }
+
+ return false;
+ }
+
+ private void log(String msg) {
+ if (DEBUG) {
+ Log.d(TAG, msg);
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java
new file mode 100644
index 0000000..6da249c
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2021 HIMSA II K/S - www.himsa.com.
+ * Represented by EHIMA - www.ehima.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * CSIP Set Coordinator handles Bluetooth CSIP Set Coordinator role profile.
+ */
+public class CsipSetCoordinatorProfile implements LocalBluetoothProfile {
+ private static final String TAG = "CsipSetCoordinatorProfile";
+ private static final boolean VDBG = true;
+
+ private Context mContext;
+
+ private BluetoothCsipSetCoordinator mService;
+ private boolean mIsProfileReady;
+
+ private final CachedBluetoothDeviceManager mDeviceManager;
+
+ static final String NAME = "CSIP Set Coordinator";
+ private final LocalBluetoothProfileManager mProfileManager;
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 1;
+
+ // These callbacks run on the main thread.
+ private final class CoordinatedSetServiceListener implements BluetoothProfile.ServiceListener {
+ @RequiresApi(32)
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (VDBG) {
+ Log.d(TAG, "Bluetooth service connected");
+ }
+ mService = (BluetoothCsipSetCoordinator) proxy;
+ // We just bound to the service, so refresh the UI for any connected CSIP devices.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ while (!deviceList.isEmpty()) {
+ BluetoothDevice nextDevice = deviceList.remove(0);
+ CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ if (VDBG) {
+ Log.d(TAG, "CsipSetCoordinatorProfile found new device: " + nextDevice);
+ }
+ device = mDeviceManager.addDevice(nextDevice);
+ }
+ device.onProfileStateChanged(
+ CsipSetCoordinatorProfile.this, BluetoothProfile.STATE_CONNECTED);
+ device.refresh();
+ }
+
+ mDeviceManager.updateCsipDevices();
+ mProfileManager.callServiceConnectedListeners();
+ mIsProfileReady = true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (VDBG) {
+ Log.d(TAG, "Bluetooth service disconnected");
+ }
+ mProfileManager.callServiceDisconnectedListeners();
+ mIsProfileReady = false;
+ }
+ }
+
+ CsipSetCoordinatorProfile(Context context, CachedBluetoothDeviceManager deviceManager,
+ LocalBluetoothProfileManager profileManager) {
+ mContext = context;
+ mDeviceManager = deviceManager;
+ mProfileManager = profileManager;
+
+ BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
+ new CoordinatedSetServiceListener(), BluetoothProfile.CSIP_SET_COORDINATOR);
+ }
+
+ /**
+ * Get CSIP devices matching connection states{
+ *
+ * @code BluetoothProfile.STATE_CONNECTED,
+ * @code BluetoothProfile.STATE_CONNECTING,
+ * @code BluetoothProfile.STATE_DISCONNECTING}
+ *
+ * @return Matching device list
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (mService == null) {
+ return new ArrayList<BluetoothDevice>(0);
+ }
+ return mService.getDevicesMatchingConnectionStates(
+ new int[] {BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING});
+ }
+
+ /**
+ * Gets the connection status of the device.
+ *
+ * @code BluetoothProfile.STATE_CONNECTED,
+ * @code BluetoothProfile.STATE_CONNECTING,
+ * @code BluetoothProfile.STATE_DISCONNECTING}
+ *
+ * @return Connection status, {@code BluetoothProfile.STATE_DISCONNECTED} if unknown.
+ */
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ @Override
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ @Override
+ public int getProfileId() {
+ return BluetoothProfile.CSIP_SET_COORDINATOR;
+ }
+
+ @Override
+ public boolean accessProfileEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
+ if (mService == null || device == null) {
+ return false;
+ }
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
+ }
+
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
+ if (mService == null || device == null) {
+ return CONNECTION_POLICY_FORBIDDEN;
+ }
+ return mService.getConnectionPolicy(device);
+ }
+
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
+ if (mService == null || device == null) {
+ return false;
+ }
+ if (enabled) {
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ }
+ } else {
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ }
+
+ return isEnabled;
+ }
+
+ @Override
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ @Override
+ public int getNameResource(BluetoothDevice device) {
+ return R.string.summary_empty;
+ }
+
+ @Override
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = getConnectionStatus(device);
+ return BluetoothUtils.getConnectionStateSummary(state);
+ }
+
+ @Override
+ public int getDrawableResource(BluetoothClass btClass) {
+ return 0;
+ }
+
+ /**
+ * Get the device's groups and correspondsing uuids map.
+ * @param device the bluetooth device
+ * @return Map of groups ids and related UUIDs
+ */
+ public Map<Integer, ParcelUuid> getGroupUuidMapByDevice(BluetoothDevice device) {
+ if (mService == null || device == null) {
+ return null;
+ }
+ return mService.getGroupUuidMapByDevice(device);
+ }
+
+ /**
+ * Return the profile name as a string.
+ */
+ public String toString() {
+ return NAME;
+ }
+
+ @RequiresApi(32)
+ protected void finalize() {
+ if (VDBG) {
+ Log.d(TAG, "finalize()");
+ }
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
+ BluetoothProfile.CSIP_SET_COORDINATOR, mService);
+ mService = null;
+ } catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up CSIP Set Coordinator proxy", t);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 34fdc1e..24113c5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -19,6 +19,7 @@
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothA2dpSink;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
@@ -100,7 +101,9 @@
private PbapClientProfile mPbapClientProfile;
private PbapServerProfile mPbapProfile;
private HearingAidProfile mHearingAidProfile;
+ private CsipSetCoordinatorProfile mCsipSetCoordinatorProfile;
private SapProfile mSapProfile;
+ private VolumeControlProfile mVolumeControlProfile;
/**
* Mapping from profile name, e.g. "HEADSET" to profile object.
@@ -220,6 +223,25 @@
mSapProfile = new SapProfile(mContext, mDeviceManager, this);
addProfile(mSapProfile, SapProfile.NAME, BluetoothSap.ACTION_CONNECTION_STATE_CHANGED);
}
+ if (mVolumeControlProfile == null
+ && supportedList.contains(BluetoothProfile.VOLUME_CONTROL)) {
+ if (DEBUG) {
+ Log.d(TAG, "Adding local Volume Control profile");
+ }
+ mVolumeControlProfile = new VolumeControlProfile();
+ // Note: no event handler for VCP, only for being connectable.
+ mProfileNameMap.put(VolumeControlProfile.NAME, mVolumeControlProfile);
+ }
+ if (mCsipSetCoordinatorProfile == null
+ && supportedList.contains(BluetoothProfile.CSIP_SET_COORDINATOR)) {
+ if (DEBUG) {
+ Log.d(TAG, "Adding local CSIP set coordinator profile");
+ }
+ mCsipSetCoordinatorProfile =
+ new CsipSetCoordinatorProfile(mContext, mDeviceManager, this);
+ addProfile(mCsipSetCoordinatorProfile, mCsipSetCoordinatorProfile.NAME,
+ BluetoothCsipSetCoordinator.ACTION_CSIS_CONNECTION_STATE_CHANGED);
+ }
mEventManager.registerProfileIntentReceiver();
}
@@ -296,11 +318,35 @@
}
}
}
+
+ if (getCsipSetCoordinatorProfile() != null
+ && mProfile instanceof CsipSetCoordinatorProfile
+ && newState == BluetoothProfile.STATE_CONNECTED) {
+ // Check if the GroupID has being initialized
+ if (cachedDevice.getGroupId() == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ final Map<Integer, ParcelUuid> groupIdMap = getCsipSetCoordinatorProfile()
+ .getGroupUuidMapByDevice(cachedDevice.getDevice());
+ if (groupIdMap != null) {
+ for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
+ if (entry.getValue().equals(BluetoothUuid.BASE_UUID)) {
+ cachedDevice.setGroupId(entry.getKey());
+ break;
+ }
+ }
+ }
+ }
+ }
+
cachedDevice.onProfileStateChanged(mProfile, newState);
// Dispatch profile changed after device update
- if (!(cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
- && mDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
- newState))) {
+ boolean needDispatchProfileConnectionState = true;
+ if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
+ || cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ needDispatchProfileConnectionState = !mDeviceManager
+ .onProfileConnectionStateChangedIfProcessed(cachedDevice, newState,
+ mProfile.getProfileId());
+ }
+ if (needDispatchProfileConnectionState) {
cachedDevice.refresh();
mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
mProfile.getProfileId());
@@ -451,6 +497,10 @@
return mHidDeviceProfile;
}
+ public CsipSetCoordinatorProfile getCsipSetCoordinatorProfile() {
+ return mCsipSetCoordinatorProfile;
+ }
+
/**
* Fill in a list of LocalBluetoothProfile objects that are supported by
* the local device and the remote device.
@@ -565,6 +615,18 @@
removedProfiles.remove(mSapProfile);
}
+ if (mVolumeControlProfile != null
+ && ArrayUtils.contains(uuids, BluetoothUuid.VOLUME_CONTROL)) {
+ profiles.add(mVolumeControlProfile);
+ removedProfiles.remove(mVolumeControlProfile);
+ }
+
+ if (mCsipSetCoordinatorProfile != null
+ && ArrayUtils.contains(uuids, BluetoothUuid.COORDINATED_SET)) {
+ profiles.add(mCsipSetCoordinatorProfile);
+ removedProfiles.remove(mCsipSetCoordinatorProfile);
+ }
+
if (DEBUG) {
Log.d(TAG,"New Profiles" + profiles.toString());
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java
new file mode 100644
index 0000000..511df28
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+
+/**
+ * VolumeControlProfile handles Bluetooth Volume Control Controller role
+ */
+public class VolumeControlProfile implements LocalBluetoothProfile {
+ private static final String TAG = "VolumeControlProfile";
+ static final String NAME = "VCP";
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 23;
+
+ @Override
+ public boolean accessProfileEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ @Override
+ public int getConnectionStatus(BluetoothDevice device) {
+ return BluetoothProfile.STATE_DISCONNECTED; // Settings app doesn't handle VCP
+ }
+
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
+ return false;
+ }
+
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; // Settings app doesn't handle VCP
+ }
+
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ return false;
+ }
+
+ @Override
+ public boolean isProfileReady() {
+ return true;
+ }
+
+ @Override
+ public int getProfileId() {
+ return BluetoothProfile.VOLUME_CONTROL;
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ @Override
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ @Override
+ public int getNameResource(BluetoothDevice device) {
+ return 0; // VCP profile not displayed in UI
+ }
+
+ @Override
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ return 0; // VCP profile not displayed in UI
+ }
+
+ @Override
+ public int getDrawableResource(BluetoothClass btClass) {
+ // no icon for VCP
+ return 0;
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index fd5b053..4f8fa2f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -206,7 +206,7 @@
mContext.sendBroadcast(mIntent);
verify(mDeviceManager).onProfileConnectionStateChangedIfProcessed(mCachedBluetoothDevice,
- BluetoothProfile.STATE_CONNECTED);
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
}
/**
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 10600e3..0e9a51d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -513,7 +513,7 @@
<provider android:name=".HeapDumpProvider"
android:authorities="com.android.shell.heapdump"
android:grantUriPermissions="true"
- android:exported="true" />
+ android:exported="false" />
<activity
android:name=".BugreportWarningActivity"
diff --git a/services/OWNERS b/services/OWNERS
index b7128a3..a083319 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -4,3 +4,4 @@
per-file art-profile* = calin@google.com, ngeoffray@google.com, vmarko@google.com
per-file java/com/android/server/* = toddke@google.com,patb@google.com
+per-file tests/servicestests/src/com/android/server/systemconfig/* = patb@google.com
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index bf28603..bdeb4d5 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -81,7 +81,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
@@ -176,8 +175,6 @@
private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock();
private boolean mBinding;
private boolean mUnbinding;
- private int mWaitForEnableRetry;
- private int mWaitForDisableRetry;
private BluetoothModeChangeHelper mBluetoothModeChangeHelper;
@@ -786,35 +783,6 @@
return mIsHearingAidProfileSupported;
}
- @Override
- /** @hide */
- public java.util.List<String> getSystemConfigEnabledProfilesForPackage(String packageName) {
- if (Binder.getCallingUid() != Process.BLUETOOTH_UID) {
- Slog.w(TAG, "getSystemConfigEnabledProfilesForPackage(): not allowed for non-bluetooth");
- return null;
- }
-
- SystemConfig systemConfig = SystemConfig.getInstance();
- if (systemConfig == null) {
- return null;
- }
-
- android.util.ArrayMap<String, Boolean> componentEnabledStates =
- systemConfig.getComponentsEnabledStates(packageName);
- if (componentEnabledStates == null) {
- return null;
- }
-
- ArrayList enabledProfiles = new ArrayList<String>();
- for (Map.Entry<String, Boolean> entry : componentEnabledStates.entrySet()) {
- if (entry.getValue()) {
- enabledProfiles.add(entry.getKey());
- }
- }
-
- return enabledProfiles;
- }
-
private boolean isDeviceProvisioned() {
return Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED,
0) != 0;
@@ -963,14 +931,15 @@
if (mState == BluetoothAdapter.STATE_ON
|| mState == BluetoothAdapter.STATE_BLE_ON
|| mState == BluetoothAdapter.STATE_TURNING_ON
- || mState == BluetoothAdapter.STATE_TURNING_OFF) {
- Log.d(TAG, "enableBLE(): Bluetooth already enabled");
+ || mState == BluetoothAdapter.STATE_TURNING_OFF
+ || mState == BluetoothAdapter.STATE_BLE_TURNING_ON) {
+ Log.d(TAG, "enableBLE(): Bluetooth is already enabled or is turning on");
return true;
}
synchronized (mReceiver) {
// waive WRITE_SECURE_SETTINGS permission check
- sendEnableMsg(false,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
+ sendEnableMsg(false, BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
+ packageName, true);
}
return true;
}
@@ -1764,6 +1733,8 @@
private class BluetoothHandler extends Handler {
boolean mGetNameAddressOnly = false;
+ private int mWaitForEnableRetry;
+ private int mWaitForDisableRetry;
BluetoothHandler(Looper looper) {
super(looper);
@@ -1811,11 +1782,12 @@
case MESSAGE_ENABLE:
int quietEnable = msg.arg1;
+ int isBle = msg.arg2;
if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED)
|| mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
// We are handling enable or disable right now, wait for it.
mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ENABLE,
- quietEnable, 0), ENABLE_DISABLE_DELAY_MS);
+ quietEnable, isBle), ENABLE_DISABLE_DELAY_MS);
break;
}
@@ -1830,13 +1802,28 @@
try {
mBluetoothLock.readLock().lock();
if (mBluetooth != null) {
+ boolean isHandled = true;
int state = mBluetooth.getState();
- if (state == BluetoothAdapter.STATE_BLE_ON) {
- Slog.w(TAG, "BT Enable in BLE_ON State, going to ON");
- mBluetooth.onLeServiceUp();
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- break;
+ switch (state) {
+ case BluetoothAdapter.STATE_BLE_ON:
+ if (isBle == 1) {
+ Slog.i(TAG, "Already at BLE_ON State");
+ } else {
+ Slog.w(TAG, "BT Enable in BLE_ON State, going to ON");
+ mBluetooth.onLeServiceUp();
+ persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
+ }
+ break;
+ case BluetoothAdapter.STATE_BLE_TURNING_ON:
+ case BluetoothAdapter.STATE_TURNING_ON:
+ case BluetoothAdapter.STATE_ON:
+ Slog.i(TAG, "MESSAGE_ENABLE: already enabled");
+ break;
+ default:
+ isHandled = false;
+ break;
}
+ if (isHandled) break;
}
} catch (RemoteException e) {
Slog.e(TAG, "", e);
@@ -2589,7 +2576,12 @@
}
private void sendEnableMsg(boolean quietMode, int reason, String packageName) {
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0));
+ sendEnableMsg(quietMode, reason, packageName, false);
+ }
+
+ private void sendEnableMsg(boolean quietMode, int reason, String packageName, boolean isBle) {
+ mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0,
+ isBle ? 1 : 0));
addActiveLog(reason, packageName, true);
mLastEnabledTime = SystemClock.elapsedRealtime();
}
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index a9f3a1b..462ed5c 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -82,6 +82,8 @@
private static final int INVALID_ID = 0;
private int mUniqueId = 1;
+ // The count of the connected legacy clients.
+ private int mLegacyClientCount = 0;
private class NsdStateMachine extends StateMachine {
@@ -107,7 +109,9 @@
sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs);
}
private void maybeScheduleStop() {
- if (!isAnyRequestActive()) {
+ // The native daemon should stay alive and can't be cleanup
+ // if any legacy client connected.
+ if (!isAnyRequestActive() && mLegacyClientCount == 0) {
scheduleStop();
}
}
@@ -175,11 +179,11 @@
if (cInfo != null) {
cInfo.expungeAllRequests();
mClients.remove(msg.replyTo);
+ if (cInfo.isLegacy()) {
+ mLegacyClientCount -= 1;
+ }
}
- //Last client
- if (mClients.size() == 0) {
- scheduleStop();
- }
+ maybeScheduleStop();
break;
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
AsyncChannel ac = new AsyncChannel();
@@ -208,6 +212,17 @@
case NsdManager.DAEMON_CLEANUP:
mDaemon.maybeStop();
break;
+ // This event should be only sent by the legacy (target SDK < S) clients.
+ // Mark the sending client as legacy.
+ case NsdManager.DAEMON_STARTUP:
+ cInfo = mClients.get(msg.replyTo);
+ if (cInfo != null) {
+ cancelStop();
+ cInfo.setLegacy();
+ mLegacyClientCount += 1;
+ maybeStartDaemon();
+ }
+ break;
case NsdManager.NATIVE_DAEMON_EVENT:
default:
Slog.e(TAG, "Unhandled " + msg);
@@ -863,6 +878,9 @@
/* A map from client id to the type of the request we had received */
private final SparseIntArray mClientRequests = new SparseIntArray();
+ // The target SDK of this client < Build.VERSION_CODES.S
+ private boolean mIsLegacy = false;
+
private ClientInfo(AsyncChannel c, Messenger m) {
mChannel = c;
mMessenger = m;
@@ -875,6 +893,7 @@
sb.append("mChannel ").append(mChannel).append("\n");
sb.append("mMessenger ").append(mMessenger).append("\n");
sb.append("mResolvedService ").append(mResolvedService).append("\n");
+ sb.append("mIsLegacy ").append(mIsLegacy).append("\n");
for(int i = 0; i< mClientIds.size(); i++) {
int clientID = mClientIds.keyAt(i);
sb.append("clientId ").append(clientID).
@@ -884,6 +903,14 @@
return sb.toString();
}
+ private boolean isLegacy() {
+ return mIsLegacy;
+ }
+
+ private void setLegacy() {
+ mIsLegacy = true;
+ }
+
// Remove any pending requests from the global map when we get rid of a client,
// and send cancellations to the daemon.
private void expungeAllRequests() {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index b1ffaeb..6d85273 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -734,11 +734,8 @@
}
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
- if (!r.mAllowWhileInUsePermissionInFgs) {
- r.mAllowWhileInUsePermissionInFgs =
- shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
- callingUid, service, r, allowBackgroundActivityStarts);
- }
+ setFgsRestrictionLocked(callingPackage, callingPid, callingUid, r,
+ allowBackgroundActivityStarts);
return cmp;
}
@@ -1411,14 +1408,6 @@
+ String.format("0x%08X", manifestType)
+ " in service element of manifest file");
}
- // If the foreground service is not started from TOP process, do not allow it to
- // have while-in-use location/camera/microphone access.
- if (!r.mAllowWhileInUsePermissionInFgs) {
- Slog.w(TAG,
- "Foreground service started from background can not have "
- + "location/camera/microphone access: service "
- + r.shortInstanceName);
- }
}
boolean alreadyStartedOp = false;
boolean stopProcStatsOp = false;
@@ -1466,6 +1455,57 @@
ignoreForeground = true;
}
+ if (!ignoreForeground) {
+ if (r.mStartForegroundCount == 0) {
+ /*
+ If the service was started with startService(), not
+ startForegroundService(), and if startForeground() isn't called within
+ mFgsStartForegroundTimeoutMs, then we check the state of the app
+ (who owns the service, which is the app that called startForeground())
+ again. If the app is in the foreground, or in any other cases where
+ FGS-starts are allowed, then we still allow the FGS to be started.
+ Otherwise, startForeground() would fail.
+
+ If the service was started with startForegroundService(), then the service
+ must call startForeground() within a timeout anyway, so we don't need this
+ check.
+ */
+ if (!r.fgRequired) {
+ final long delayMs = SystemClock.elapsedRealtime() - r.createRealTime;
+ if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
+ resetFgsRestrictionLocked(r);
+ setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.pid,
+ r.appInfo.uid, r, false);
+ EventLog.writeEvent(0x534e4554, "183147114",
+ r.appInfo.uid,
+ "call setFgsRestrictionLocked again due to "
+ + "startForegroundTimeout");
+ }
+ }
+ } else if (r.mStartForegroundCount >= 1) {
+ // The second or later time startForeground() is called after service is
+ // started. Check for app state again.
+ final long delayMs = SystemClock.elapsedRealtime() -
+ r.mLastSetFgsRestrictionTime;
+ if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
+ resetFgsRestrictionLocked(r);
+ setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.pid,
+ r.appInfo.uid, r, false);
+ EventLog.writeEvent(0x534e4554, "183147114", r.appInfo.uid,
+ "call setFgsRestrictionLocked for "
+ + (r.mStartForegroundCount + 1) + "th startForeground");
+ }
+ }
+ // If the foreground service is not started from TOP process, do not allow it to
+ // have while-in-use location/camera/microphone access.
+ if (!r.mAllowWhileInUsePermissionInFgs) {
+ Slog.w(TAG,
+ "Foreground service started from background can not have "
+ + "location/camera/microphone access: service "
+ + r.shortInstanceName);
+ }
+ }
+
// Apps under strict background restrictions simply don't get to have foreground
// services, so now that we've enforced the startForegroundService() contract
// we only do the machinery of making the service foreground when the app
@@ -1501,6 +1541,7 @@
active.mNumActive++;
}
r.isForeground = true;
+ r.mStartForegroundCount++;
if (!stopProcStatsOp) {
ServiceState stracker = r.getTracker();
if (stracker != null) {
@@ -1559,6 +1600,7 @@
decActiveForegroundAppLocked(smap, r);
}
r.isForeground = false;
+ resetFgsRestrictionLocked(r);
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -2118,12 +2160,7 @@
}
}
- if (!s.mAllowWhileInUsePermissionInFgs) {
- s.mAllowWhileInUsePermissionInFgs =
- shouldAllowWhileInUsePermissionInFgsLocked(callingPackage,
- callingPid, callingUid,
- service, s, false);
- }
+ setFgsRestrictionLocked(callingPackage, callingPid, callingUid, s, false);
if (s.app != null) {
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
@@ -3419,7 +3456,7 @@
r.isForeground = false;
r.foregroundId = 0;
r.foregroundNoti = null;
- r.mAllowWhileInUsePermissionInFgs = false;
+ resetFgsRestrictionLocked(r);
// Clear start entries.
r.clearDeliveredStartsLocked();
@@ -4900,7 +4937,7 @@
* @return true if allow, false otherwise.
*/
private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage,
- int callingPid, int callingUid, Intent intent, ServiceRecord r,
+ int callingPid, int callingUid, ServiceRecord r,
boolean allowBackgroundActivityStarts) {
// Is the background FGS start restriction turned on?
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
@@ -4986,6 +5023,28 @@
boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid,
String callingPackage) {
return shouldAllowWhileInUsePermissionInFgsLocked(
- callingPackage, callingPid, callingUid, null, null, false);
+ callingPackage, callingPid, callingUid, null, false);
+ }
+
+ /**
+ * In R, mAllowWhileInUsePermissionInFgs is to allow while-in-use permissions in foreground
+ * service or not. while-in-use permissions in FGS started from background might be restricted.
+ * @param callingPackage caller app's package name.
+ * @param callingUid caller app's uid.
+ * @param r the service to start.
+ * @return true if allow, false otherwise.
+ */
+ private void setFgsRestrictionLocked(String callingPackage,
+ int callingPid, int callingUid, ServiceRecord r,
+ boolean allowBackgroundActivityStarts) {
+ r.mLastSetFgsRestrictionTime = SystemClock.elapsedRealtime();
+ if (!r.mAllowWhileInUsePermissionInFgs) {
+ r.mAllowWhileInUsePermissionInFgs = shouldAllowWhileInUsePermissionInFgsLocked(
+ callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts);
+ }
+ }
+
+ private void resetFgsRestrictionLocked(ServiceRecord r) {
+ r.mAllowWhileInUsePermissionInFgs = false;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 7be843f..00d8208e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -88,6 +88,7 @@
static final String KEY_PROCESS_START_ASYNC = "process_start_async";
static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
+ static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
@@ -121,6 +122,7 @@
private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
+ private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000;
private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
// Flag stored in the DeviceConfig API.
@@ -273,6 +275,12 @@
// this long.
public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;
+ /**
+ * When service started from background, before the timeout it can be promoted to FGS by calling
+ * Service.startForeground().
+ */
+ volatile long mFgsStartForegroundTimeoutMs = DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS;
+
// Indicates whether the activity starts logging is enabled.
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -421,6 +429,9 @@
case KEY_MIN_ASSOC_LOG_DURATION:
updateMinAssocLogDuration();
break;
+ case KEY_FGS_START_FOREGROUND_TIMEOUT:
+ updateFgsStartForegroundTimeout();
+ break;
default:
break;
}
@@ -697,6 +708,13 @@
/* defaultValue */ DEFAULT_MIN_ASSOC_LOG_DURATION);
}
+ private void updateFgsStartForegroundTimeout() {
+ mFgsStartForegroundTimeoutMs = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_FGS_START_FOREGROUND_TIMEOUT,
+ DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS);
+ }
+
void dump(PrintWriter pw) {
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS + ":");
@@ -769,6 +787,8 @@
pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.toArray()));
pw.print(" "); pw.print(KEY_MIN_ASSOC_LOG_DURATION); pw.print("=");
pw.println(MIN_ASSOC_LOG_DURATION);
+ pw.print(" "); pw.print(KEY_FGS_START_FOREGROUND_TIMEOUT); pw.print("=");
+ pw.println(mFgsStartForegroundTimeoutMs);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index af89907..50f3520 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -94,7 +94,6 @@
import com.android.server.compat.PlatformCompat;
import java.io.BufferedReader;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -787,8 +786,7 @@
return -1;
}
- File file = new File(filename);
- file.delete();
+ // Writes an error message to stderr on failure
ParcelFileDescriptor fd = openFileForSystem(filename, "w");
if (fd == null) {
return -1;
@@ -942,16 +940,16 @@
String logNameTimeString = LOG_NAME_TIME_FORMATTER.format(localDateTime);
heapFile = "/data/local/tmp/heapdump-" + logNameTimeString + ".prof";
}
- pw.println("File: " + heapFile);
- pw.flush();
- File file = new File(heapFile);
- file.delete();
+ // Writes an error message to stderr on failure
ParcelFileDescriptor fd = openFileForSystem(heapFile, "w");
if (fd == null) {
return -1;
}
+ pw.println("File: " + heapFile);
+ pw.flush();
+
final CountDownLatch latch = new CountDownLatch(1);
final RemoteCallback finishCallback = new RemoteCallback(new OnResultListener() {
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 39f79ca..ef47b1e 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -22,6 +22,7 @@
import android.net.wifi.WifiManager;
import android.os.BatteryStats;
import android.os.Bundle;
+import android.os.OutcomeReceiver;
import android.os.Parcelable;
import android.os.Process;
import android.os.ServiceManager;
@@ -40,6 +41,7 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.function.pooled.PooledLambda;
+import java.util.concurrent.ExecutionException;
import libcore.util.EmptyArray;
import java.util.concurrent.CompletableFuture;
@@ -405,7 +407,7 @@
// We will request data from external processes asynchronously, and wait on a timeout.
SynchronousResultReceiver wifiReceiver = null;
SynchronousResultReceiver bluetoothReceiver = null;
- SynchronousResultReceiver modemReceiver = null;
+ CompletableFuture<ModemActivityInfo> modemFuture = CompletableFuture.completedFuture(null);
boolean railUpdated = false;
if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
@@ -460,8 +462,22 @@
}
if (mTelephony != null) {
- modemReceiver = new SynchronousResultReceiver("telephony");
- mTelephony.requestModemActivityInfo(modemReceiver);
+ CompletableFuture<ModemActivityInfo> temp = new CompletableFuture<>();
+ mTelephony.requestModemActivityInfo(Runnable::run,
+ new OutcomeReceiver<ModemActivityInfo,
+ TelephonyManager.ModemActivityInfoException>() {
+ @Override
+ public void onResult(ModemActivityInfo result) {
+ temp.complete(result);
+ }
+
+ @Override
+ public void onError(TelephonyManager.ModemActivityInfoException e) {
+ Slog.w(TAG, "error reading modem stats:" + e);
+ temp.complete(null);
+ }
+ });
+ modemFuture = temp;
}
if (!railUpdated) {
synchronized (mStats) {
@@ -472,7 +488,17 @@
final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
final BluetoothActivityEnergyInfo bluetoothInfo = awaitControllerInfo(bluetoothReceiver);
- final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
+ ModemActivityInfo modemInfo = null;
+ try {
+ modemInfo = modemFuture.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS);
+ } catch (TimeoutException | InterruptedException e) {
+ Slog.w(TAG, "timeout or interrupt reading modem stats: " + e);
+ } catch (ExecutionException e) {
+ Slog.w(TAG, "exception reading modem stats: " + e.getCause());
+ }
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
synchronized (mStats) {
mStats.addHistoryEventLocked(
@@ -519,11 +545,7 @@
}
if (modemInfo != null) {
- if (modemInfo.isValid()) {
- mStats.updateMobileRadioState(modemInfo);
- } else {
- Slog.w(TAG, "modem info is invalid: " + modemInfo);
- }
+ mStats.updateMobileRadioState(modemInfo);
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 580ceca..34ba3e0 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1208,7 +1208,7 @@
public void noteModemControllerActivity(ModemActivityInfo info) {
enforceCallingPermission();
- if (info == null || !info.isValid()) {
+ if (info == null) {
Slog.e(TAG, "invalid modem data given: " + info);
return;
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 1b65dba..0e62828 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -142,6 +142,10 @@
// allow while-in-use permissions in foreground service or not.
// while-in-use permissions in FGS started from background might be restricted.
boolean mAllowWhileInUsePermissionInFgs;
+ // The number of times Service.startForeground() is called;
+ int mStartForegroundCount;
+ // Last time mAllowWhileInUsePermissionInFgs is set.
+ long mLastSetFgsRestrictionTime;
// the most recent package that start/bind this service.
String mRecentCallingPackage;
@@ -406,6 +410,8 @@
}
pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
pw.println(mAllowWhileInUsePermissionInFgs);
+ pw.print(prefix); pw.print("startForegroundCount=");
+ pw.println(mStartForegroundCount);
pw.print(prefix); pw.print("recentCallingPackage=");
pw.println(mRecentCallingPackage);
if (delayed) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 26f5c4c..b5e6c11 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -563,6 +563,37 @@
sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
}
+ private static final class LeAudioDeviceConnectionInfo {
+ final @NonNull BluetoothDevice mDevice;
+ final @AudioService.BtProfileConnectionState int mState;
+ final boolean mSupprNoisy;
+ final @NonNull String mEventSource;
+
+ LeAudioDeviceConnectionInfo(@NonNull BluetoothDevice device,
+ @AudioService.BtProfileConnectionState int state,
+ boolean suppressNoisyIntent, @NonNull String eventSource) {
+ mDevice = device;
+ mState = state;
+ mSupprNoisy = suppressNoisyIntent;
+ mEventSource = eventSource;
+ }
+ }
+
+ /*package*/ void postBluetoothLeAudioOutDeviceConnectionState(
+ @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
+ boolean suppressNoisyIntent, @NonNull String eventSource) {
+ final LeAudioDeviceConnectionInfo info = new LeAudioDeviceConnectionInfo(
+ device, state, suppressNoisyIntent, eventSource);
+ sendLMsgNoDelay(MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
+ }
+
+ /*package*/ void postBluetoothLeAudioInDeviceConnectionState(
+ @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
+ @NonNull String eventSource) {
+ final LeAudioDeviceConnectionInfo info = new LeAudioDeviceConnectionInfo(
+ device, state, false, eventSource);
+ sendLMsgNoDelay(MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
+ }
/**
* Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn().
@@ -849,6 +880,23 @@
delay);
}
+ /*package*/ void postSetLeAudioOutConnectionState(
+ @AudioService.BtProfileConnectionState int state,
+ @NonNull BluetoothDevice device, int delay) {
+ sendILMsg(MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE, SENDMSG_QUEUE,
+ state,
+ device,
+ delay);
+ }
+
+ /*package*/ void postSetLeAudioInConnectionState(
+ @AudioService.BtProfileConnectionState int state,
+ @NonNull BluetoothDevice device) {
+ sendILMsgNoDelay(MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE, SENDMSG_QUEUE,
+ state,
+ device);
+ }
+
/*package*/ void postDisconnectA2dp() {
sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE);
}
@@ -1154,7 +1202,20 @@
synchronized (mDeviceStateLock) {
mDeviceInventory.onSetHearingAidConnectionState(
(BluetoothDevice) msg.obj, msg.arg1,
- mAudioService.getHearingAidStreamType());
+ mAudioService.getBluetoothContextualVolumeStream());
+ }
+ break;
+ case MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE:
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onSetLeAudioOutConnectionState(
+ (BluetoothDevice) msg.obj, msg.arg1,
+ mAudioService.getBluetoothContextualVolumeStream());
+ }
+ break;
+ case MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE:
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onSetLeAudioInConnectionState(
+ (BluetoothDevice) msg.obj, msg.arg1);
}
break;
case MSG_BT_HEADSET_CNCT_FAILED:
@@ -1343,6 +1404,31 @@
final int capturePreset = msg.arg1;
mDeviceInventory.onSaveClearPreferredDevicesForCapturePreset(capturePreset);
} break;
+ case MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT: {
+ final LeAudioDeviceConnectionInfo info =
+ (LeAudioDeviceConnectionInfo) msg.obj;
+ AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "setLeAudioDeviceOutConnectionState state=" + info.mState
+ + " addr=" + info.mDevice.getAddress()
+ + " supprNoisy=" + info.mSupprNoisy
+ + " src=" + info.mEventSource)).printLog(TAG));
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.setBluetoothLeAudioOutDeviceConnectionState(
+ info.mDevice, info.mState, info.mSupprNoisy);
+ }
+ } break;
+ case MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT: {
+ final LeAudioDeviceConnectionInfo info =
+ (LeAudioDeviceConnectionInfo) msg.obj;
+ AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "setLeAudioDeviceInConnectionState state=" + info.mState
+ + " addr=" + info.mDevice.getAddress()
+ + " src=" + info.mEventSource)).printLog(TAG));
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.setBluetoothLeAudioInDeviceConnectionState(info.mDevice,
+ info.mState);
+ }
+ } break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -1424,6 +1510,11 @@
private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
+ private static final int MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE = 42;
+ private static final int MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE = 43;
+ private static final int MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT = 44;
+ private static final int MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT = 45;
+
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
@@ -1439,6 +1530,8 @@
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
case MSG_CHECK_MUTE_MUSIC:
+ case MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT:
+ case MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT:
return true;
default:
return false;
@@ -1648,10 +1741,9 @@
return;
}
Log.w(TAG, "Speaker client died");
- if (removeCommunicationRouteClient(client.getBinder(), false)
- != null) {
- onUpdateCommunicationRoute("onCommunicationRouteClientDied");
- }
+ setCommunicationRouteForClient(
+ client.getBinder(), client.getPid(), null,
+ BtHelper.SCO_MODE_UNDEFINED, "onCommunicationRouteClientDied");
}
/**
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 82586b8..78daabc 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -21,6 +21,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.media.AudioDeviceAttributes;
@@ -423,6 +424,45 @@
}
}
+ /*package*/ void onSetLeAudioConnectionState(BluetoothDevice btDevice,
+ @AudioService.BtProfileConnectionState int state, int streamType, int device) {
+ String address = btDevice.getAddress();
+ if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+ address = "";
+ }
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+ "onSetLeAudioConnectionState addr=" + address));
+
+ synchronized (mDevicesLock) {
+ DeviceInfo di = null;
+ boolean isConnected = false;
+
+ String key = DeviceInfo.makeDeviceListKey(device, btDevice.getAddress());
+ di = mConnectedDevices.get(key);
+ isConnected = di != null;
+
+ if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
+ makeLeAudioDeviceUnavailable(address, device);
+ } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
+ makeLeAudioDeviceAvailable(address, BtHelper.getName(btDevice), streamType,
+ device, "onSetLeAudioConnectionState");
+ }
+ }
+ }
+
+ /*package*/ void onSetLeAudioOutConnectionState(BluetoothDevice btDevice,
+ @AudioService.BtProfileConnectionState int state, int streamType) {
+ // TODO: b/198610537 clarify DEVICE_OUT_BLE_HEADSET vs DEVICE_OUT_BLE_SPEAKER criteria
+ onSetLeAudioConnectionState(btDevice, state, streamType,
+ AudioSystem.DEVICE_OUT_BLE_HEADSET);
+ }
+
+ /*package*/ void onSetLeAudioInConnectionState(BluetoothDevice btDevice,
+ @AudioService.BtProfileConnectionState int state) {
+ onSetLeAudioConnectionState(btDevice, state, AudioSystem.STREAM_DEFAULT,
+ AudioSystem.DEVICE_IN_BLE_HEADSET);
+ }
+
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ void onBluetoothA2dpActiveDeviceChange(
@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) {
@@ -943,6 +983,28 @@
}
}
+ /*package*/ int setBluetoothLeAudioOutDeviceConnectionState(
+ @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
+ boolean suppressNoisyIntent) {
+ synchronized (mDevicesLock) {
+ /* Active device become null and it's previous device is not connected anymore */
+ int delay = 0;
+ if (!suppressNoisyIntent) {
+ int intState = (state == BluetoothLeAudio.STATE_CONNECTED) ? 1 : 0;
+ delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_BLE_HEADSET,
+ intState, AudioSystem.DEVICE_NONE);
+ }
+ mDeviceBroker.postSetLeAudioOutConnectionState(state, device, delay);
+ return delay;
+ }
+ }
+
+ /*package*/ void setBluetoothLeAudioInDeviceConnectionState(
+ @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state) {
+ synchronized (mDevicesLock) {
+ mDeviceBroker.postSetLeAudioInConnectionState(state, device);
+ }
+ }
//-------------------------------------------------------------------
// Internal utilities
@@ -1115,6 +1177,36 @@
}
@GuardedBy("mDevicesLock")
+ private void makeLeAudioDeviceAvailable(String address, String name, int streamType, int device,
+ String eventSource) {
+ if (device != AudioSystem.DEVICE_NONE) {
+ AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
+ address, name, AudioSystem.AUDIO_FORMAT_DEFAULT);
+ mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
+ new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
+ mDeviceBroker.postAccessoryPlugMediaUnmute(device);
+ }
+
+ if (streamType == AudioSystem.STREAM_DEFAULT) {
+ // No need to update volume for input devices
+ return;
+ }
+
+ mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "makeLeAudioDeviceAvailable");
+ }
+
+ @GuardedBy("mDevicesLock")
+ private void makeLeAudioDeviceUnavailable(String address, int device) {
+ if (device != AudioSystem.DEVICE_NONE) {
+ AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ address, "", AudioSystem.AUDIO_FORMAT_DEFAULT);
+ mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address));
+ }
+
+ setCurrentAudioRouteNameIfPossible(null, false /*fromA2dp*/);
+ }
+
+ @GuardedBy("mDevicesLock")
private void setCurrentAudioRouteNameIfPossible(String name, boolean fromA2dp) {
synchronized (mCurAudioRoutes) {
if (TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
@@ -1150,6 +1242,7 @@
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID);
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
+ BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
}
// must be called before removing the device from mConnectedDevices
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d0a3079..97a20c4 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -163,6 +163,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -307,6 +308,12 @@
// retry delay in case of failure to indicate system ready to AudioFlinger
private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
+ // Bits representing connected devices to monitor playback monitor voice activity
+ private static final int CONNECTED_STATE_HEARING_AID_BIT = 0;
+ private static final int CONNECTED_STATE_LE_AUDIO_BIT = 1;
+
+ private BitSet mConnectedStateBitset = new BitSet(2);
+
/** @see AudioSystemThread */
private AudioSystemThread mAudioSystemThread;
/** @see AudioHandler */
@@ -2529,7 +2536,7 @@
if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
// only modify the hearing aid attenuation when the stream to modify matches
// the one expected by the hearing aid
- if (streamType == getHearingAidStreamType()) {
+ if (streamType == getBluetoothContextualVolumeStream()) {
if (DEBUG_VOL) {
Log.d(TAG, "adjustSreamVolume postSetHearingAidVolumeIndex index="
+ newIndex + " stream=" + streamType);
@@ -2872,11 +2879,11 @@
}
}
- /*package*/ int getHearingAidStreamType() {
- return getHearingAidStreamType(mMode);
+ /*package*/ int getBluetoothContextualVolumeStream() {
+ return getBluetoothContextualVolumeStream(mMode);
}
- private int getHearingAidStreamType(int mode) {
+ private int getBluetoothContextualVolumeStream(int mode) {
switch (mode) {
case AudioSystem.MODE_IN_COMMUNICATION:
case AudioSystem.MODE_IN_CALL:
@@ -2922,7 +2929,7 @@
}
private void updateHearingAidVolumeOnVoiceActivityUpdate() {
- final int streamType = getHearingAidStreamType();
+ final int streamType = getBluetoothContextualVolumeStream();
final int index = getStreamVolume(streamType);
sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_HEARING_AID,
mVoiceActive.get(), streamType, index));
@@ -2954,7 +2961,7 @@
return;
}
- int streamType = getHearingAidStreamType(newMode);
+ int streamType = getBluetoothContextualVolumeStream(newMode);
final Set<Integer> deviceTypes = AudioSystem.generateAudioDeviceTypesSet(
AudioSystem.getDevicesForStream(streamType));
@@ -3036,7 +3043,7 @@
}
if (device == AudioSystem.DEVICE_OUT_HEARING_AID
- && streamType == getHearingAidStreamType()) {
+ && streamType == getBluetoothContextualVolumeStream()) {
Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
+ " stream=" + streamType);
mDeviceBroker.postSetHearingAidVolumeIndex(index, streamType);
@@ -5496,15 +5503,68 @@
throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
+ " (dis)connection, got " + state);
}
- if (state == BluetoothProfile.STATE_CONNECTED) {
- mPlaybackMonitor.registerPlaybackCallback(mVoiceActivityMonitor, true);
- } else {
- mPlaybackMonitor.unregisterPlaybackCallback(mVoiceActivityMonitor);
+ synchronized (mConnectedStateBitset) {
+ if (state == BluetoothProfile.STATE_CONNECTED) {
+ if (mConnectedStateBitset.isEmpty()) {
+ mPlaybackMonitor.registerPlaybackCallback(mVoiceActivityMonitor, true);
+ }
+ mConnectedStateBitset.set(CONNECTED_STATE_HEARING_AID_BIT);
+ } else {
+ mConnectedStateBitset.clear(CONNECTED_STATE_HEARING_AID_BIT);
+ if (mConnectedStateBitset.isEmpty()) {
+ mPlaybackMonitor.unregisterPlaybackCallback(mVoiceActivityMonitor);
+ }
+ }
}
mDeviceBroker.postBluetoothHearingAidDeviceConnectionState(
device, state, suppressNoisyIntent, musicDevice, "AudioService");
}
+ private void setBluetoothLeAudioDeviceConnectionState(@NonNull BluetoothDevice device,
+ @BtProfileConnectionState int state) {
+ if (device == null) {
+ throw new IllegalArgumentException("Illegal null device");
+ }
+ if (state != BluetoothProfile.STATE_CONNECTED
+ && state != BluetoothProfile.STATE_DISCONNECTED) {
+ throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
+ + " (dis)connection, got " + state);
+ }
+ synchronized (mConnectedStateBitset) {
+ if (state == BluetoothProfile.STATE_CONNECTED) {
+ if (mConnectedStateBitset.isEmpty()) {
+ mPlaybackMonitor.registerPlaybackCallback(mVoiceActivityMonitor, true);
+ }
+ mConnectedStateBitset.set(CONNECTED_STATE_LE_AUDIO_BIT);
+ } else {
+ mConnectedStateBitset.clear(CONNECTED_STATE_LE_AUDIO_BIT);
+ if (mConnectedStateBitset.isEmpty()) {
+ mPlaybackMonitor.unregisterPlaybackCallback(mVoiceActivityMonitor);
+ }
+ }
+ }
+ }
+
+ /**
+ * See AudioManager.setBluetoothLeAudioOutDeviceConnectionState()
+ */
+ public void setBluetoothLeAudioOutDeviceConnectionState(
+ @NonNull BluetoothDevice device, @BtProfileConnectionState int state,
+ boolean suppressNoisyIntent) {
+ setBluetoothLeAudioDeviceConnectionState(device, state);
+ mDeviceBroker.postBluetoothLeAudioOutDeviceConnectionState(device, state,
+ suppressNoisyIntent, "AudioService");
+ }
+
+ /**
+ * See AudioManager.setBluetoothLeAudioInDeviceConnectionState()
+ */
+ public void setBluetoothLeAudioInDeviceConnectionState(
+ @NonNull BluetoothDevice device, @BtProfileConnectionState int state) {
+ setBluetoothLeAudioDeviceConnectionState(device, state);
+ mDeviceBroker.postBluetoothLeAudioInDeviceConnectionState(device, state, "AudioService");
+ }
+
/**
* See AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent()
*/
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
index f2e44ee..e7118ad 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
@@ -28,10 +28,8 @@
import android.os.RemoteException;
import android.util.Slog;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
class Tuner extends ITuner.Stub {
private static final String TAG = "BroadcastRadioService.Tuner";
@@ -292,12 +290,12 @@
}
@Override
- public Map setParameters(Map parameters) {
+ public Map<String, String> setParameters(Map<String, String> parameters) {
throw new UnsupportedOperationException("Not supported by HAL 1.x");
}
@Override
- public Map getParameters(List<String> keys) {
+ public Map<String, String> getParameters(List<String> keys) {
throw new UnsupportedOperationException("Not supported by HAL 1.x");
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
index 7a6d964..867d5b4 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
@@ -18,12 +18,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.radio.ITuner;
import android.hardware.radio.ITunerCallback;
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
-import android.hardware.radio.RadioMetadata;
import android.hardware.radio.RadioTuner;
import android.os.IBinder;
import android.os.RemoteException;
@@ -31,7 +29,6 @@
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@@ -176,7 +173,7 @@
}
@Override
- public void onParametersUpdated(Map parameters) {
+ public void onParametersUpdated(Map<String, String> parameters) {
Slog.e(TAG, "Not applicable for HAL 1.x");
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 7ab3bdd..7d8c6a4 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -299,7 +299,7 @@
}
@Override
- public Map setParameters(Map parameters) {
+ public Map<String, String> setParameters(Map<String, String> parameters) {
synchronized (mLock) {
checkNotClosedLocked();
return Convert.vendorInfoFromHal(Utils.maybeRethrow(
@@ -308,7 +308,7 @@
}
@Override
- public Map getParameters(List<String> keys) {
+ public Map<String, String> getParameters(List<String> keys) {
synchronized (mLock) {
checkNotClosedLocked();
return Convert.vendorInfoFromHal(Utils.maybeRethrow(
diff --git a/services/core/java/com/android/server/connectivity/PacProxyService.java b/services/core/java/com/android/server/connectivity/PacProxyService.java
index 0070339..3a97765 100644
--- a/services/core/java/com/android/server/connectivity/PacProxyService.java
+++ b/services/core/java/com/android/server/connectivity/PacProxyService.java
@@ -34,7 +34,6 @@
import android.net.TrafficStats;
import android.net.Uri;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteCallbackList;
@@ -42,6 +41,7 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -192,7 +192,7 @@
}
/**
- * Updates the PAC Proxy Installer with current Proxy information. This is called by
+ * Updates the PAC Proxy Service with current Proxy information. This is called by
* the ProxyTracker through PacProxyManager before a broadcast takes place to allow
* the PacProxyService to indicate that the broadcast should not be sent and the
* PacProxyService will trigger a new broadcast when it is ready.
@@ -357,8 +357,9 @@
}
}
};
- mContext.bindService(intent, mConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE);
+ mContext.bindServiceAsUser(intent, mConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
+ UserHandle.SYSTEM);
intent = new Intent();
intent.setClassName(PROXY_PACKAGE, PROXY_SERVICE);
@@ -398,9 +399,9 @@
}
}
};
- mContext.bindService(intent,
+ mContext.bindServiceAsUser(intent, mProxyConnection,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
- new HandlerExecutor(mNetThreadHandler), mProxyConnection);
+ mNetThreadHandler, UserHandle.SYSTEM);
}
private void unbind() {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index c24973d..8926e20 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -242,7 +242,7 @@
mValidationInfo.append(opcode, new ValidationInfo(validator, addrType));
}
- int isValid(HdmiCecMessage message) {
+ int isValid(HdmiCecMessage message, boolean isMessageReceived) {
int opcode = message.getOpcode();
ValidationInfo info = mValidationInfo.get(opcode);
if (info == null) {
@@ -256,6 +256,22 @@
HdmiLogger.warning("Unexpected source: " + message);
return ERROR_SOURCE;
}
+
+ if (isMessageReceived) {
+ // Check if the source's logical address and local device's logical
+ // address are the same.
+ for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
+ synchronized (device.mLock) {
+ if (message.getSource() == device.getDeviceInfo().getLogicalAddress()
+ && message.getSource() != Constants.ADDR_UNREGISTERED) {
+ HdmiLogger.warning(
+ "Unexpected source: message sent from device itself, " + message);
+ return ERROR_SOURCE;
+ }
+ }
+ }
+ }
+
// Check the destination field.
if (message.getDestination() == Constants.ADDR_BROADCAST) {
if ((info.addressType & DEST_BROADCAST) == 0) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index cca8be8..b049d01 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -556,6 +556,12 @@
// on boot, if device is interactive, set HDMI CEC state as powered on as well
if (mPowerManager.isInteractive() && isPowerStandbyOrTransient()) {
mPowerStatus = HdmiControlManager.POWER_STATUS_ON;
+ // Start all actions that were queued because the device was in standby
+ if (mAddressAllocated) {
+ for (HdmiCecLocalDevice localDevice : getAllLocalDevices()) {
+ localDevice.startQueuedActions();
+ }
+ }
}
}
@@ -1122,7 +1128,7 @@
@ServiceThreadOnly
void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) {
assertRunOnServiceThread();
- if (mMessageValidator.isValid(command) == HdmiCecMessageValidator.OK) {
+ if (mMessageValidator.isValid(command, false) == HdmiCecMessageValidator.OK) {
mCecController.sendCommand(command, callback);
} else {
HdmiLogger.error("Invalid message type:" + command);
@@ -1153,7 +1159,7 @@
@ServiceThreadOnly
boolean handleCecCommand(HdmiCecMessage message) {
assertRunOnServiceThread();
- int errorCode = mMessageValidator.isValid(message);
+ int errorCode = mMessageValidator.isValid(message, true);
if (errorCode != HdmiCecMessageValidator.OK) {
// We'll not response on the messages with the invalid source or destination
// or with parameter length shorter than specified in the standard.
@@ -3353,8 +3359,8 @@
invokeInputChangeListener(info);
}
- void setMhlInputChangeEnabled(boolean enabled) {
- mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled));
+ void setMhlInputChangeEnabled(boolean enabled) {
+ mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled));
synchronized (mLock) {
mMhlInputChangeEnabled = enabled;
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 6aefe41..a090c1a 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -285,7 +285,8 @@
combined.getValues(augmentStart, augmentEnd, entry);
}
- final long rawBytes = entry.rxBytes + entry.txBytes;
+ final long rawBytes = (entry.rxBytes + entry.txBytes) == 0 ? 1 :
+ (entry.rxBytes + entry.txBytes);
final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes;
final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes;
final long targetBytes = augmentPlan.getDataUsageBytes();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5babfeb..f83d059 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -123,6 +123,7 @@
import android.app.ITransientNotification;
import android.app.ITransientNotificationCallback;
import android.app.IUriGrantsManager;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -479,6 +480,8 @@
final ArrayMap<NotificationRecord, ArrayList<CancelNotificationRunnable>> mDelayedCancelations =
new ArrayMap<>();
+ private KeyguardManager mKeyguardManager;
+
// The last key in this list owns the hardware.
ArrayList<String> mLights = new ArrayList<>();
@@ -1726,6 +1729,11 @@
}
@VisibleForTesting
+ void setKeyguardManager(KeyguardManager keyguardManager) {
+ mKeyguardManager = keyguardManager;
+ }
+
+ @VisibleForTesting
ShortcutHelper getShortcutHelper() {
return mShortcutHelper;
}
@@ -2330,6 +2338,7 @@
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+ mKeyguardManager = getContext().getSystemService(KeyguardManager.class);
mZenModeHelper.onSystemReady();
mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class),
mPackageManager, getContext().getMainExecutor());
@@ -6902,7 +6911,6 @@
boolean beep = false;
boolean blink = false;
- final Notification notification = record.getSbn().getNotification();
final String key = record.getKey();
// Should this notification make noise, vibe, or use the LED?
@@ -6924,7 +6932,7 @@
if (!record.isUpdate
&& record.getImportance() > IMPORTANCE_MIN
&& !suppressedByDnd) {
- sendAccessibilityEvent(notification, record.getSbn().getPackageName());
+ sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
@@ -6946,7 +6954,7 @@
boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
if (!sentAccessibilityEvent) {
- sendAccessibilityEvent(notification, record.getSbn().getPackageName());
+ sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
if (DBG) Slog.v(TAG, "Interrupting!");
@@ -7663,17 +7671,30 @@
return (x < low) ? low : ((x > high) ? high : x);
}
- void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
+ void sendAccessibilityEvent(NotificationRecord record) {
if (!mAccessibilityManager.isEnabled()) {
return;
}
- AccessibilityEvent event =
+ final Notification notification = record.getNotification();
+ final CharSequence packageName = record.getSbn().getPackageName();
+ final AccessibilityEvent event =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
event.setPackageName(packageName);
event.setClassName(Notification.class.getName());
- event.setParcelableData(notification);
- CharSequence tickerText = notification.tickerText;
+ final int visibilityOverride = record.getPackageVisibilityOverride();
+ final int notifVisibility = visibilityOverride == NotificationManager.VISIBILITY_NO_OVERRIDE
+ ? notification.visibility : visibilityOverride;
+ final int userId = record.getUser().getIdentifier();
+ final boolean needPublic = userId >= 0 && mKeyguardManager.isDeviceLocked(userId);
+ if (needPublic && notifVisibility != Notification.VISIBILITY_PUBLIC) {
+ // Emit the public version if we're on the lockscreen and this notification isn't
+ // publicly visible.
+ event.setParcelableData(notification.publicVersion);
+ } else {
+ event.setParcelableData(notification);
+ }
+ final CharSequence tickerText = notification.tickerText;
if (!TextUtils.isEmpty(tickerText)) {
event.getText().add(tickerText);
}
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 378405f..f6f3db3 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -238,6 +238,14 @@
throws PackageManagerException;
/**
+ * Returns {@code ApeInfo} about apex sessions that have been marked ready via
+ * {@link #markStagedSessionReady(int)}
+ *
+ * Returns empty array if there is no staged apex session or if there is any error.
+ */
+ abstract ApexInfo[] getStagedApexInfos(ApexSessionParams params);
+
+ /**
* Mark a staged session previously submitted using {@code submitStagedSession} as ready to be
* applied at next reboot.
*
@@ -707,6 +715,19 @@
}
@Override
+ ApexInfo[] getStagedApexInfos(ApexSessionParams params) {
+ try {
+ return waitForApexService().getStagedApexInfos(params);
+ } catch (RemoteException re) {
+ Slog.w(TAG, "Unable to contact apexservice" + re.getMessage());
+ throw new RuntimeException(re);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to collect staged apex infos" + e.getMessage());
+ return new ApexInfo[0];
+ }
+ }
+
+ @Override
void markStagedSessionReady(int sessionId) throws PackageManagerException {
try {
waitForApexService().markStagedSessionReady(sessionId);
@@ -1100,6 +1121,11 @@
}
@Override
+ ApexInfo[] getStagedApexInfos(ApexSessionParams params) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
void markStagedSessionReady(int sessionId) {
throw new UnsupportedOperationException();
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index f8115d3..0b07bb6 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -224,6 +224,10 @@
mStagingManager = new StagingManager(this, context, apexParserSupplier);
}
+ StagingManager getStagingManager() {
+ return mStagingManager;
+ }
+
boolean okToSendBroadcasts() {
return mOkToSendBroadcasts;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e4723ad..4767823 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21,14 +21,12 @@
import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
import static android.Manifest.permission.QUERY_ALL_PACKAGES;
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.content.Intent.ACTION_MAIN;
-import static android.content.Intent.CATEGORY_BROWSABLE;
import static android.content.Intent.CATEGORY_DEFAULT;
import static android.content.Intent.CATEGORY_HOME;
import static android.content.Intent.EXTRA_LONG_VERSION_CODE;
@@ -36,8 +34,6 @@
import static android.content.Intent.EXTRA_VERSION_CODE;
import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
-import static android.content.Intent.CATEGORY_BROWSABLE;
-import static android.content.Intent.CATEGORY_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
@@ -181,6 +177,7 @@
import android.content.pm.IPackageManagerNative;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
+import android.content.pm.IStagedApexObserver;
import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.InstantAppRequest;
@@ -220,6 +217,7 @@
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
+import android.content.pm.StagedApexInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
@@ -14291,9 +14289,15 @@
return new ParceledListSlice<IntentFilter>(result) {
@Override
protected void writeElement(IntentFilter parcelable, Parcel dest, int callFlags) {
- // IntentFilter has final Parcelable methods, so redirect to the subclass
- ((ParsedIntentInfo) parcelable).writeIntentInfoToParcel(dest,
- callFlags);
+ parcelable.writeToParcel(dest, callFlags);
+ }
+
+ @Override
+ protected void writeParcelableCreator(IntentFilter parcelable, Parcel dest) {
+ // All Parcel#writeParcelableCreator does is serialize the class name to
+ // access via reflection to grab its CREATOR. This does that manually, pointing
+ // to the parent IntentFilter so that all of the subclass fields are ignored.
+ dest.writeString(IntentFilter.class.getName());
}
};
}
@@ -24119,6 +24123,28 @@
public String getModuleMetadataPackageName() throws RemoteException {
return PackageManagerService.this.mModuleInfoProvider.getPackageName();
}
+
+ @Override
+ public void registerStagedApexObserver(IStagedApexObserver observer) {
+ mInstallerService.getStagingManager().registerStagedApexObserver(observer);
+ }
+
+ @Override
+ public void unregisterStagedApexObserver(IStagedApexObserver observer) {
+ mInstallerService.getStagingManager().unregisterStagedApexObserver(observer);
+ }
+
+ @Override
+ public String[] getStagedApexModuleNames() {
+ return mInstallerService.getStagingManager()
+ .getStagedApexModuleNames().toArray(new String[0]);
+ }
+
+ @Override
+ @Nullable
+ public StagedApexInfo getStagedApexInfo(String moduleName) {
+ return mInstallerService.getStagingManager().getStagedApexInfo(moduleName);
+ }
}
private class PackageManagerInternalImpl extends PackageManagerInternal {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 4038bf2..02397da 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -29,7 +29,9 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.pm.ApexStagedEvent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
@@ -38,6 +40,7 @@
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
+import android.content.pm.StagedApexInfo;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.content.rollback.IRollbackManager;
import android.content.rollback.RollbackInfo;
@@ -58,6 +61,7 @@
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -66,8 +70,10 @@
import android.util.apk.ApkSignatureVerifier;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageHelper;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
@@ -84,7 +90,9 @@
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
@@ -103,7 +111,8 @@
private final ApexManager mApexManager;
private final PowerManager mPowerManager;
private final Context mContext;
- private final PreRebootVerificationHandler mPreRebootVerificationHandler;
+ @VisibleForTesting
+ final PreRebootVerificationHandler mPreRebootVerificationHandler;
private final Supplier<PackageParser2> mPackageParserSupplier;
private final File mFailureReasonFile = new File("/metadata/staged-install/failure_reason.txt");
@@ -122,6 +131,9 @@
@GuardedBy("mSuccessfulStagedSessionIds")
private final List<Integer> mSuccessfulStagedSessionIds = new ArrayList<>();
+ @GuardedBy("mStagedApexObservers")
+ private final List<IStagedApexObserver> mStagedApexObservers = new ArrayList<>();
+
StagingManager(PackageInstallerService pi, Context context,
Supplier<PackageParser2> packageParserSupplier) {
mPi = pi;
@@ -184,6 +196,35 @@
mApexManager.markBootCompleted();
}
+ void registerStagedApexObserver(IStagedApexObserver observer) {
+ if (observer == null) {
+ return;
+ }
+ if (observer.asBinder() != null) {
+ try {
+ observer.asBinder().linkToDeath(new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (mStagedApexObservers) {
+ mStagedApexObservers.remove(observer);
+ }
+ }
+ }, 0);
+ } catch (RemoteException re) {
+ Slog.w(TAG, re.getMessage());
+ }
+ }
+ synchronized (mStagedApexObservers) {
+ mStagedApexObservers.add(observer);
+ }
+ }
+
+ void unregisterStagedApexObserver(IStagedApexObserver observer) {
+ synchronized (mStagedApexObservers) {
+ mStagedApexObservers.remove(observer);
+ }
+ }
+
/**
* Validates the signature used to sign the container of the new apex package
*
@@ -1075,6 +1116,9 @@
Slog.w(TAG, "Could not contact apexd to abort staged session " + sessionId);
}
}
+ if (sessionContainsApex(session)) {
+ notifyStagedApexObservers();
+ }
}
// Session was successfully aborted from apexd (if required) and pre-reboot verification
@@ -1299,7 +1343,107 @@
return session;
}
- private final class PreRebootVerificationHandler extends Handler {
+ /**
+ * Returns ApexInfo about APEX contained inside the session as a {@code Map<String, ApexInfo>},
+ * where the key of the map is the module name of the ApexInfo.
+ *
+ * Returns an empty map if there is any error.
+ */
+ @VisibleForTesting
+ @NonNull
+ Map<String, ApexInfo> getStagedApexInfos(@NonNull PackageInstallerSession session) {
+ Preconditions.checkArgument(session != null, "Session is null");
+ Preconditions.checkArgument(!session.hasParentSessionId(),
+ session.sessionId + " session has parent session");
+ Preconditions.checkArgument(sessionContainsApex(session),
+ session.sessionId + " session does not contain apex");
+
+ // Even if caller calls this method on ready session, the session could be abandoned
+ // right after this method is called.
+ if (!session.isStagedSessionReady() || session.isDestroyed()) {
+ return Collections.emptyMap();
+ }
+
+ ApexSessionParams params = new ApexSessionParams();
+ params.sessionId = session.sessionId;
+ final IntArray childSessionIds = new IntArray();
+ if (session.isMultiPackage()) {
+ for (int id : session.getChildSessionIds()) {
+ if (isApexSession(getStagedSession(id))) {
+ childSessionIds.add(id);
+ }
+ }
+ }
+ params.childSessionIds = childSessionIds.toArray();
+
+ ApexInfo[] infos = mApexManager.getStagedApexInfos(params);
+ Map<String, ApexInfo> result = new ArrayMap<>();
+ for (ApexInfo info : infos) {
+ result.put(info.moduleName, info);
+ }
+ return result;
+ }
+
+ /**
+ * Returns apex module names of all packages that are staged ready
+ */
+ List<String> getStagedApexModuleNames() {
+ List<String> result = new ArrayList<>();
+ synchronized (mStagedSessions) {
+ for (int i = 0; i < mStagedSessions.size(); i++) {
+ final PackageInstallerSession session = mStagedSessions.valueAt(i);
+ if (!session.isStagedSessionReady() || session.isDestroyed()
+ || session.hasParentSessionId() || !sessionContainsApex(session)) {
+ continue;
+ }
+ result.addAll(getStagedApexInfos(session).keySet());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns ApexInfo of the {@code moduleInfo} provided if it is staged, otherwise returns null.
+ */
+ @Nullable
+ StagedApexInfo getStagedApexInfo(String moduleName) {
+ synchronized (mStagedSessions) {
+ for (int i = 0; i < mStagedSessions.size(); i++) {
+ final PackageInstallerSession session = mStagedSessions.valueAt(i);
+ if (!session.isStagedSessionReady() || session.isDestroyed()
+ || session.hasParentSessionId() || !sessionContainsApex(session)) {
+ continue;
+ }
+ ApexInfo ai = getStagedApexInfos(session).get(moduleName);
+ if (ai != null) {
+ StagedApexInfo info = new StagedApexInfo();
+ info.moduleName = ai.moduleName;
+ info.diskImagePath = ai.modulePath;
+ info.versionCode = ai.versionCode;
+ info.versionName = ai.versionName;
+ return info;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void notifyStagedApexObservers() {
+ synchronized (mStagedApexObservers) {
+ for (IStagedApexObserver observer : mStagedApexObservers) {
+ ApexStagedEvent event = new ApexStagedEvent();
+ event.stagedApexModuleNames = getStagedApexModuleNames().toArray(new String[0]);
+ try {
+ observer.onApexStaged(event);
+ } catch (RemoteException re) {
+ Slog.w(TAG, "Failed to contact the observer " + re.getMessage());
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ final class PreRebootVerificationHandler extends Handler {
// Hold session ids before handler gets ready to do the verification.
private IntArray mPendingSessionIds;
private boolean mIsReady;
@@ -1327,7 +1471,8 @@
private static final int MSG_PRE_REBOOT_VERIFICATION_START = 1;
private static final int MSG_PRE_REBOOT_VERIFICATION_APEX = 2;
private static final int MSG_PRE_REBOOT_VERIFICATION_APK = 3;
- private static final int MSG_PRE_REBOOT_VERIFICATION_END = 4;
+ @VisibleForTesting
+ static final int MSG_PRE_REBOOT_VERIFICATION_END = 4;
@Override
public void handleMessage(Message msg) {
@@ -1579,6 +1724,7 @@
if (hasApex) {
try {
mApexManager.markStagedSessionReady(session.sessionId);
+ notifyStagedApexObservers();
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
return;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 836e615..ae940d0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -608,6 +608,8 @@
private int mPowerButtonSuppressionDelayMillis = POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS;
+ private boolean mLockNowPending = false;
+
private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5;
@@ -4941,6 +4943,7 @@
mKeyguardDelegate.doKeyguardTimeout(options);
}
mLockScreenTimerActive = false;
+ mLockNowPending = false;
options = null;
}
}
@@ -4950,7 +4953,7 @@
}
}
- ScreenLockTimeout mScreenLockTimeout = new ScreenLockTimeout();
+ final ScreenLockTimeout mScreenLockTimeout = new ScreenLockTimeout();
@Override
public void lockNow(Bundle options) {
@@ -4962,6 +4965,9 @@
mScreenLockTimeout.setLockOptions(options);
}
mHandler.post(mScreenLockTimeout);
+ synchronized (mScreenLockTimeout) {
+ mLockNowPending = true;
+ }
}
// TODO (b/113840485): Move this logic to DisplayPolicy when lockscreen supports multi-display.
@@ -4977,6 +4983,10 @@
private void updateLockScreenTimeout() {
synchronized (mScreenLockTimeout) {
+ if (mLockNowPending) {
+ Log.w(TAG, "lockNow pending, ignore updating lockscreen timeout");
+ return;
+ }
final boolean enable = !mAllowLockscreenWhenOnDisplays.isEmpty()
&& mDefaultDisplayPolicy.isAwake()
&& mKeyguardDelegate != null && mKeyguardDelegate.isSecure(mCurrentUserId);
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 392792d..b75bce8 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -662,6 +662,12 @@
@Override
public String getDefaultSmsPackage(int userId) {
+ userId = handleIncomingUser(userId, false, "getDefaultSmsPackage");
+ if (!mUserManagerInternal.exists(userId)) {
+ Slog.e(LOG_TAG, "user " + userId + " does not exist");
+ return null;
+ }
+
long identity = Binder.clearCallingIdentity();
try {
return CollectionUtils.firstOrNull(
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 0390015..71b3e61 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -102,6 +102,7 @@
import android.os.IStoraged;
import android.os.IThermalEventListener;
import android.os.IThermalService;
+import android.os.OutcomeReceiver;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -172,6 +173,7 @@
import com.android.server.storage.DiskStatsFileLogger;
import com.android.server.storage.DiskStatsLoggingService;
+import java.util.concurrent.ExecutionException;
import libcore.io.IoUtils;
import org.json.JSONArray;
@@ -1731,22 +1733,47 @@
int pullModemActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) {
long token = Binder.clearCallingIdentity();
try {
- SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
- mTelephony.requestModemActivityInfo(modemReceiver);
- final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
+ CompletableFuture<ModemActivityInfo> modemFuture = new CompletableFuture<>();
+ mTelephony.requestModemActivityInfo(Runnable::run,
+ new OutcomeReceiver<ModemActivityInfo,
+ TelephonyManager.ModemActivityInfoException>() {
+ @Override
+ public void onResult(ModemActivityInfo result) {
+ modemFuture.complete(result);
+ }
+
+ @Override
+ public void onError(TelephonyManager.ModemActivityInfoException e) {
+ Slog.w(TAG, "error reading modem stats:" + e);
+ modemFuture.complete(null);
+ }
+ });
+
+ ModemActivityInfo modemInfo;
+ try {
+ modemInfo = modemFuture.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS);
+ } catch (TimeoutException | InterruptedException e) {
+ Slog.w(TAG, "timeout or interrupt reading modem stats: " + e);
+ return StatsManager.PULL_SKIP;
+ } catch (ExecutionException e) {
+ Slog.w(TAG, "exception reading modem stats: " + e.getCause());
+ return StatsManager.PULL_SKIP;
+ }
+
if (modemInfo == null) {
return StatsManager.PULL_SKIP;
}
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
- .writeLong(modemInfo.getTimestamp())
+ .writeLong(modemInfo.getTimestampMillis())
.writeLong(modemInfo.getSleepTimeMillis())
.writeLong(modemInfo.getIdleTimeMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(0).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(1).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(2).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(3).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(4).getTimeInMillis())
+ .writeLong(modemInfo.getTransmitDurationMillisAtPowerLevel(0))
+ .writeLong(modemInfo.getTransmitDurationMillisAtPowerLevel(1))
+ .writeLong(modemInfo.getTransmitDurationMillisAtPowerLevel(2))
+ .writeLong(modemInfo.getTransmitDurationMillisAtPowerLevel(3))
+ .writeLong(modemInfo.getTransmitDurationMillisAtPowerLevel(4))
.writeLong(modemInfo.getReceiveTimeMillis())
.build();
pulledData.add(e);
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index bba5dcb..630317a 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -114,6 +114,8 @@
private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>();
+ private final List<Message> mPendingTvinputInfoEvents = new LinkedList<>();
+
// Calls to mListener should happen here.
private final Handler mHandler = new ListenerHandler();
@@ -229,7 +231,16 @@
connection.getInputStateLocked(), 0, inputId).sendToTarget();
}
}
- }
+ } else {
+ Message msg = mHandler.obtainMessage(ListenerHandler.TVINPUT_INFO_ADDED,
+ deviceId, cableConnectionStatus, connection);
+ for (Iterator<Message> it = mPendingTvinputInfoEvents.iterator(); it.hasNext();) {
+ if (it.next().arg1 == deviceId) {
+ it.remove();
+ }
+ }
+ mPendingTvinputInfoEvents.add(msg);
+ }
ITvInputHardwareCallback callback = connection.getCallbackLocked();
if (callback != null) {
try {
@@ -288,6 +299,8 @@
}
mHardwareInputIdMap.put(deviceId, info.getId());
mInputMap.put(info.getId(), info);
+ processPendingTvInputInfoEventsLocked();
+ Slog.d(TAG,"deviceId ="+ deviceId+", tvinputinfo = "+info);
// Process pending state changes
@@ -529,6 +542,20 @@
}
}
+
+ private void processPendingTvInputInfoEventsLocked() {
+ for (Iterator<Message> it = mPendingTvinputInfoEvents.iterator(); it.hasNext(); ) {
+ Message msg = it.next();
+ int deviceId = msg.arg1;
+ String inputId = mHardwareInputIdMap.get(deviceId);
+ if (inputId != null) {
+ msg.sendToTarget();
+ it.remove();
+ }
+ }
+ }
+
+
private void updateVolume() {
mCurrentMaxIndex = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
mCurrentIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
@@ -1181,6 +1208,7 @@
private static final int HDMI_DEVICE_ADDED = 4;
private static final int HDMI_DEVICE_REMOVED = 5;
private static final int HDMI_DEVICE_UPDATED = 6;
+ private static final int TVINPUT_INFO_ADDED = 7;
@Override
public final void handleMessage(Message msg) {
@@ -1225,6 +1253,31 @@
}
break;
}
+ case TVINPUT_INFO_ADDED: {
+ int deviceId = msg.arg1;
+ int cableConnectionStatus = msg.arg2;
+ Connection connection =(Connection)msg.obj;
+
+ int previousConfigsLength = connection.getConfigsLengthLocked();
+ int previousCableConnectionStatus = connection.getInputStateLocked();
+ String inputId = mHardwareInputIdMap.get(deviceId);
+
+ if (inputId != null) {
+ if (connection.updateCableConnectionStatusLocked(cableConnectionStatus)) {
+ if (previousCableConnectionStatus != connection.getInputStateLocked()) {
+ mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+ connection.getInputStateLocked(), 0, inputId).sendToTarget();
+ }
+ } else {
+ if ((previousConfigsLength == 0)
+ != (connection.getConfigsLengthLocked() == 0)) {
+ mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+ connection.getInputStateLocked(), 0, inputId).sendToTarget();
+ }
+ }
+ }
+ break;
+ }
default: {
Slog.w(TAG, "Unhandled message: " + msg);
break;
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 382398a..e0cc8e1 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -352,7 +352,7 @@
}
private void handleSafeModeStatusChanged() {
- logDbg("VcnGatewayConnection safe mode status changed");
+ logVdbg("VcnGatewayConnection safe mode status changed");
boolean hasSafeModeGatewayConnection = false;
// If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode
@@ -368,7 +368,7 @@
hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
if (oldStatus != mCurrentStatus) {
mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection);
- logDbg(
+ logInfo(
"Safe mode "
+ (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE ? "entered" : "exited"));
}
@@ -539,6 +539,16 @@
Slog.d(TAG, getLogPrefix() + msg, tr);
}
+ private void logInfo(String msg) {
+ Slog.i(TAG, getLogPrefix() + msg);
+ LOCAL_LOG.log(getLogPrefix() + "INFO: " + msg);
+ }
+
+ private void logInfo(String msg, Throwable tr) {
+ Slog.i(TAG, getLogPrefix() + msg, tr);
+ LOCAL_LOG.log(getLogPrefix() + "INFO: " + msg + tr);
+ }
+
private void logErr(String msg) {
Slog.e(TAG, getLogPrefix() + msg);
LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg);
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 450257f..7dec4e7 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -1677,10 +1677,8 @@
mFailedAttempts = 0;
cancelSafeModeAlarm();
- if (mIsInSafeMode) {
- mIsInSafeMode = false;
- mGatewayStatusCallback.onSafeModeStatusChanged();
- }
+ mIsInSafeMode = false;
+ mGatewayStatusCallback.onSafeModeStatusChanged();
}
protected void applyTransform(
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 113797c..419a7fa 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1468,7 +1468,7 @@
final Task targetTask = r.getTask() != null
? r.getTask()
: mTargetTask;
- if (startedActivityStack == null || targetTask == null) {
+ if (startedActivityStack == null || targetTask == null || !targetTask.isAttached()) {
return;
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index a0c96f0..f2f6b1d 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -158,7 +158,7 @@
"android.hardware.input.classifier@1.0",
"android.hardware.ir@1.0",
"android.hardware.light@2.0",
- "android.hardware.memtrack-V1-ndk_platform",
+ "android.hardware.memtrack-V1-ndk",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
"android.hardware.power-V1-cpp",
@@ -176,7 +176,7 @@
"android.frameworks.stats@1.0",
"android.system.suspend.control-V1-cpp",
"android.system.suspend.control.internal-cpp",
- "android.system.suspend@1.0",
+ "android.system.suspend-V1-ndk",
"service.incremental",
],
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 7a6d310..4922b2c 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -18,11 +18,12 @@
//#define LOG_NDEBUG 0
+#include <aidl/android/system/suspend/ISystemSuspend.h>
+#include <aidl/android/system/suspend/IWakeLock.h>
#include <android/hardware/power/1.1/IPower.h>
#include <android/hardware/power/Boost.h>
#include <android/hardware/power/IPower.h>
#include <android/hardware/power/Mode.h>
-#include <android/system/suspend/1.0/ISystemSuspend.h>
#include <android/system/suspend/ISuspendControlService.h>
#include <android/system/suspend/internal/ISuspendControlServiceInternal.h>
#include <nativehelper/JNIHelp.h>
@@ -33,6 +34,7 @@
#include <limits.h>
#include <android-base/chrono_utils.h>
+#include <android/binder_manager.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <binder/IServiceManager.h>
@@ -40,23 +42,23 @@
#include <hardware/power.h>
#include <hardware_legacy/power.h>
#include <hidl/ServiceManagement.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/misc.h>
-#include <utils/String8.h>
-#include <utils/Log.h>
#include "com_android_server_power_PowerManagerService.h"
+using aidl::android::system::suspend::ISystemSuspend;
+using aidl::android::system::suspend::IWakeLock;
+using aidl::android::system::suspend::WakeLockType;
+using android::String8;
using android::hardware::Return;
using android::hardware::Void;
using android::hardware::power::Boost;
using android::hardware::power::Mode;
-using android::hardware::power::V1_0::PowerHint;
using android::hardware::power::V1_0::Feature;
-using android::String8;
-using android::system::suspend::V1_0::ISystemSuspend;
-using android::system::suspend::V1_0::IWakeLock;
-using android::system::suspend::V1_0::WakeLockType;
+using android::hardware::power::V1_0::PowerHint;
using android::system::suspend::ISuspendControlService;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
@@ -352,20 +354,21 @@
}
}
-static sp<ISystemSuspend> gSuspendHal = nullptr;
+static std::shared_ptr<ISystemSuspend> gSuspendHal = nullptr;
static sp<ISuspendControlService> gSuspendControl = nullptr;
static sp<system::suspend::internal::ISuspendControlServiceInternal> gSuspendControlInternal =
nullptr;
-static sp<IWakeLock> gSuspendBlocker = nullptr;
+static std::shared_ptr<IWakeLock> gSuspendBlocker = nullptr;
static std::mutex gSuspendMutex;
// Assume SystemSuspend HAL is always alive.
// TODO: Force device to restart if SystemSuspend HAL dies.
-sp<ISystemSuspend> getSuspendHal() {
+std::shared_ptr<ISystemSuspend> getSuspendHal() {
static std::once_flag suspendHalFlag;
- std::call_once(suspendHalFlag, [](){
- ::android::hardware::details::waitForHwService(ISystemSuspend::descriptor, "default");
- gSuspendHal = ISystemSuspend::getService();
+ std::call_once(suspendHalFlag, []() {
+ const std::string suspendInstance = std::string() + ISystemSuspend::descriptor + "/default";
+ gSuspendHal = ISystemSuspend::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(suspendInstance.c_str())));
assert(gSuspendHal != nullptr);
});
return gSuspendHal;
@@ -403,7 +406,7 @@
std::lock_guard<std::mutex> lock(gSuspendMutex);
if (gSuspendBlocker) {
gSuspendBlocker->release();
- gSuspendBlocker.clear();
+ gSuspendBlocker = nullptr;
}
}
}
@@ -411,9 +414,10 @@
void disableAutoSuspend() {
std::lock_guard<std::mutex> lock(gSuspendMutex);
if (!gSuspendBlocker) {
- sp<ISystemSuspend> suspendHal = getSuspendHal();
- gSuspendBlocker = suspendHal->acquireWakeLock(WakeLockType::PARTIAL,
- "PowerManager.SuspendLockout");
+ std::shared_ptr<ISystemSuspend> suspendHal = getSuspendHal();
+ suspendHal->acquireWakeLock(WakeLockType::PARTIAL, "PowerManager.SuspendLockout",
+ &gSuspendBlocker);
+ assert(gSuspendBlocker != nullptr);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d908945..5dfa86e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -10314,7 +10314,7 @@
}
@Override
- public boolean setPermittedAccessibilityServices(ComponentName who, List packageList) {
+ public boolean setPermittedAccessibilityServices(ComponentName who, List<String> packageList) {
if (!mHasFeature) {
return false;
}
@@ -10367,7 +10367,7 @@
}
@Override
- public List getPermittedAccessibilityServices(ComponentName who) {
+ public List<String> getPermittedAccessibilityServices(ComponentName who) {
if (!mHasFeature) {
return null;
}
@@ -10381,7 +10381,7 @@
}
@Override
- public List getPermittedAccessibilityServicesForUser(int userId) {
+ public List<String> getPermittedAccessibilityServicesForUser(int userId) {
if (!mHasFeature) {
return null;
}
@@ -10465,7 +10465,7 @@
}
@Override
- public boolean setPermittedInputMethods(ComponentName who, List packageList) {
+ public boolean setPermittedInputMethods(ComponentName who, List<String> packageList) {
if (!mHasFeature) {
return false;
}
@@ -10505,7 +10505,7 @@
}
@Override
- public List getPermittedInputMethods(ComponentName who) {
+ public List<String> getPermittedInputMethods(ComponentName who) {
if (!mHasFeature) {
return null;
}
@@ -10519,7 +10519,7 @@
}
@Override
- public List getPermittedInputMethodsForCurrentUser() {
+ public List<String> getPermittedInputMethodsForCurrentUser() {
enforceManageUsers();
final int callingUserId = mInjector.userHandleGetCallingUserId();
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp
index 1a96048..bf1a64e 100644
--- a/services/incremental/Android.bp
+++ b/services/incremental/Android.bp
@@ -65,7 +65,6 @@
"libincremental_manager_aidl-cpp",
"libprotobuf-cpp-lite",
"service.incremental.proto",
- "libutils",
"libvold_binder",
"libc++fs",
],
@@ -77,6 +76,7 @@
"libincfs",
"liblog",
"libpermission",
+ "libutils",
"libz",
"libziparchive",
],
diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java
index a2768c6..3a9b2dc 100644
--- a/services/java/com/android/server/SystemConfigService.java
+++ b/services/java/com/android/server/SystemConfigService.java
@@ -21,6 +21,7 @@
import android.Manifest;
import android.content.Context;
import android.os.ISystemConfig;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -84,6 +85,21 @@
}
return ArrayUtils.convertToIntArray(uids);
}
+
+ @Override
+ public List<String> getEnabledComponentOverrides(String packageName) {
+ ArrayMap<String, Boolean> systemComponents = SystemConfig.getInstance()
+ .getComponentsEnabledStates(packageName);
+ List<String> enabledComponent = new ArrayList<>();
+ if (systemComponents != null) {
+ for (Map.Entry<String, Boolean> entry : systemComponents.entrySet()) {
+ if (Boolean.TRUE.equals(entry.getValue())) {
+ enabledComponent.add(entry.getKey());
+ }
+ }
+ }
+ return enabledComponent;
+ }
};
public SystemConfigService(Context context) {
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 5ecf6bb..6e01f69 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -79,7 +79,6 @@
// These are not normally accessible from apps so they must be explicitly included.
jni_libs: [
- "libbacktrace",
"libbase",
"libbinder",
"libc++",
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 3e5cbea..c45d084 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -125,7 +125,7 @@
mMessageValidator =
new HdmiCecMessageValidator(mHdmiControlService) {
@Override
- int isValid(HdmiCecMessage message) {
+ int isValid(HdmiCecMessage message, boolean isMessageReceived) {
return HdmiCecMessageValidator.OK;
}
};
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index ae7f422..ae99dab 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -629,7 +629,7 @@
}
private IntegerSubject assertMessageValidity(String message) {
- return assertThat(mHdmiCecMessageValidator.isValid(buildMessage(message)));
+ return assertThat(mHdmiCecMessageValidator.isValid(buildMessage(message), false));
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 72afca0..b6f7922 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -37,6 +37,7 @@
import android.content.Context;
import android.content.pm.PackageInfo;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -228,6 +229,21 @@
}
@Test
+ public void testGetStagedApexInfos_throwRunTimeException() throws RemoteException {
+ doThrow(RemoteException.class).when(mApexService).getStagedApexInfos(any());
+
+ assertThrows(RuntimeException.class,
+ () -> mApexManager.getStagedApexInfos(testParamsWithChildren()));
+ }
+
+ @Test
+ public void testGetStagedApexInfos_returnsEmptyArrayOnError() throws RemoteException {
+ doThrow(ServiceSpecificException.class).when(mApexService).getStagedApexInfos(any());
+
+ assertThat(mApexManager.getStagedApexInfos(testParamsWithChildren())).hasLength(0);
+ }
+
+ @Test
public void testMarkStagedSessionReady_throwPackageManagerException() throws RemoteException {
doAnswer(invocation -> {
throw new Exception();
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 541fc63..2448026 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -55,7 +55,6 @@
jni_libs: [
"libdexmakerjvmtiagent",
"libmultiplejvmtiagentsinterferenceagent",
- "libbacktrace",
"libbase",
"libbinder",
"libc++",
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index ad15a99..11ea4a4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -46,6 +46,7 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
@@ -103,6 +104,8 @@
NotificationUsageStats mUsageStats;
@Mock
IAccessibilityManager mAccessibilityService;
+ @Mock
+ KeyguardManager mKeyguardManager;
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30);
@@ -147,6 +150,7 @@
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
long serviceReturnValue = IntPair.of(
AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
@@ -168,6 +172,7 @@
mService.setFallbackVibrationPattern(FALLBACK_VIBRATION_PATTERN);
mService.setUsageStats(mUsageStats);
mService.setAccessibilityManager(accessibilityManager);
+ mService.setKeyguardManager(mKeyguardManager);
mService.mScreenOn = false;
mService.mInCallStateOffHook = false;
mService.mNotificationPulseEnabled = true;
@@ -484,6 +489,94 @@
}
@Test
+ public void testLockedPrivateA11yRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification().publicVersion, event.getParcelableData());
+ }
+
+ @Test
+ public void testLockedOverridePrivateA11yRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(Notification.VISIBILITY_PRIVATE);
+ r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification().publicVersion, event.getParcelableData());
+ }
+
+ @Test
+ public void testLockedPublicA11yNoRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification(), event.getParcelableData());
+ }
+
+ @Test
+ public void testUnlockedPrivateA11yNoRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification(), event.getParcelableData());
+ }
+
+ @Test
public void testBeepInsistently() throws Exception {
NotificationRecord r = getInsistentBeepyNotification();
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 5e3d26a..705b491 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -81,7 +81,8 @@
* <pre>
* {@code
* <service android:name="your.package.YourInCallServiceImplementation"
- * android:permission="android.permission.BIND_INCALL_SERVICE">
+ * android:permission="android.permission.BIND_INCALL_SERVICE"
+ * android:exported="true">
* <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
* <meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
* android:value="true" />
@@ -91,6 +92,10 @@
* </service>
* }
* </pre>
+ *
+ * <em>Note: You should NOT mark your {@link InCallService} with the attribute
+ * {@code android:exported="false"}; doing so can result in a failure to bind to your implementation
+ * during calls.</em>
* <p>
* In addition to implementing the {@link InCallService} API, you must also declare an activity in
* your manifest which handles the {@link Intent#ACTION_DIAL} intent. The example below illustrates
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index 6b82045..b5d97ab 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -567,6 +567,10 @@
*/
public static int getFrequencyFromNrArfcn(int nrArfcn) {
+ if (nrArfcn == PhysicalChannelConfig.CHANNEL_NUMBER_UNKNOWN) {
+ return PhysicalChannelConfig.FREQUENCY_UNKNOWN;
+ }
+
int globalKhz = 0;
int rangeOffset = 0;
int arfcnOffset = 0;
@@ -632,6 +636,10 @@
*/
public static int getFrequencyFromUarfcn(int band, int uarfcn, boolean isUplink) {
+ if (uarfcn == PhysicalChannelConfig.CHANNEL_NUMBER_UNKNOWN) {
+ return PhysicalChannelConfig.FREQUENCY_UNKNOWN;
+ }
+
int offsetKhz = 0;
for (UtranBandArfcnFrequency uarfcnFrequency : AccessNetworkConstants.
UtranBandArfcnFrequency.values()) {
@@ -702,6 +710,10 @@
*/
public static int getFrequencyFromArfcn(int band, int arfcn, boolean isUplink) {
+ if (arfcn == PhysicalChannelConfig.CHANNEL_NUMBER_UNKNOWN) {
+ return PhysicalChannelConfig.FREQUENCY_UNKNOWN;
+ }
+
int uplinkFrequencyFirst = 0;
int arfcnOffset = 0;
int downlinkOffset = 0;
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index debb119..0bf8ce6 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -16,8 +16,12 @@
package android.telephony;
+import android.annotation.DurationMillisLong;
+import android.annotation.ElapsedRealtimeLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -25,46 +29,50 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
+import java.util.Objects;
/**
- * Reports modem activity information.
+ * Contains information about the modem's activity. May be useful for power stats reporting.
* @hide
*/
+@SystemApi
+@TestApi
public final class ModemActivityInfo implements Parcelable {
+ private static final int TX_POWER_LEVELS = 5;
+
/**
- * Tx(transmit) power level. see power index below
- * <ul>
- * <li> index 0 = tx_power < 0dBm. </li>
- * <li> index 1 = 0dBm < tx_power < 5dBm. </li>
- * <li> index 2 = 5dBm < tx_power < 15dBm. </li>
- * <li> index 3 = 15dBm < tx_power < 20dBm. </li>
- * <li> index 4 = tx_power > 20dBm. </li>
- * </ul>
- */
- public static final int TX_POWER_LEVELS = 5;
- /**
- * Tx(transmit) power level 0: tx_power < 0dBm
+ * Corresponds to transmit power of less than 0dBm.
*/
public static final int TX_POWER_LEVEL_0 = 0;
+
/**
- * Tx(transmit) power level 1: 0dBm < tx_power < 5dBm
+ * Corresponds to transmit power between 0dBm and 5dBm.
*/
public static final int TX_POWER_LEVEL_1 = 1;
+
/**
- * Tx(transmit) power level 2: 5dBm < tx_power < 15dBm
+ * Corresponds to transmit power between 5dBm and 15dBm.
*/
public static final int TX_POWER_LEVEL_2 = 2;
+
/**
- * Tx(transmit) power level 3: 15dBm < tx_power < 20dBm.
+ * Corresponds to transmit power between 15dBm and 20dBm.
*/
public static final int TX_POWER_LEVEL_3 = 3;
+
/**
- * Tx(transmit) power level 4: tx_power > 20dBm
+ * Corresponds to transmit power above 20dBm.
*/
public static final int TX_POWER_LEVEL_4 = 4;
+ /**
+ * The number of transmit power levels. Fixed by HAL definition.
+ */
+ public static int getNumTxPowerLevels() {
+ return TX_POWER_LEVELS;
+ }
+
/** @hide */
@IntDef(prefix = {"TX_POWER_LEVEL_"}, value = {
TX_POWER_LEVEL_0,
@@ -82,34 +90,39 @@
new Range<>(5, 15),
new Range<>(15, 20),
new Range<>(20, Integer.MAX_VALUE)
-
};
private long mTimestamp;
private int mSleepTimeMs;
private int mIdleTimeMs;
- private List<TransmitPower> mTransmitPowerInfo = new ArrayList<>(TX_POWER_LEVELS);
+ private int[] mTxTimeMs;
private int mRxTimeMs;
+ /**
+ * @hide
+ */
+ @TestApi
public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs,
@NonNull int[] txTimeMs, int rxTimeMs) {
+ Objects.requireNonNull(txTimeMs);
+ if (txTimeMs.length != TX_POWER_LEVELS) {
+ throw new IllegalArgumentException("txTimeMs must have length == TX_POWER_LEVELS");
+ }
mTimestamp = timestamp;
mSleepTimeMs = sleepTimeMs;
mIdleTimeMs = idleTimeMs;
- populateTransmitPowerRange(txTimeMs);
+ mTxTimeMs = txTimeMs;
mRxTimeMs = rxTimeMs;
}
- /** helper API to populate tx power range for each bucket **/
- private void populateTransmitPowerRange(@NonNull int[] transmitPowerMs) {
- int i = 0;
- for ( ; i < Math.min(transmitPowerMs.length, TX_POWER_LEVELS); i++) {
- mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], transmitPowerMs[i]));
- }
- // Make sure that mTransmitPowerInfo is fully initialized.
- for ( ; i < TX_POWER_LEVELS; i++) {
- mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], 0));
- }
+ /**
+ * Provided for convenience in manipulation since the API exposes long values but internal
+ * representations are ints.
+ * @hide
+ */
+ public ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs,
+ @NonNull int[] txTimeMs, long rxTimeMs) {
+ this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, txTimeMs, (int) rxTimeMs);
}
@Override
@@ -118,7 +131,7 @@
+ " mTimestamp=" + mTimestamp
+ " mSleepTimeMs=" + mSleepTimeMs
+ " mIdleTimeMs=" + mIdleTimeMs
- + " mTransmitPowerInfo[]=" + mTransmitPowerInfo.toString()
+ + " mTxTimeMs[]=" + Arrays.toString(mTxTimeMs)
+ " mRxTimeMs=" + mRxTimeMs
+ "}";
}
@@ -129,14 +142,12 @@
public static final @android.annotation.NonNull Parcelable.Creator<ModemActivityInfo> CREATOR =
new Parcelable.Creator<ModemActivityInfo>() {
- public ModemActivityInfo createFromParcel(Parcel in) {
+ public ModemActivityInfo createFromParcel(@NonNull Parcel in) {
long timestamp = in.readLong();
int sleepTimeMs = in.readInt();
int idleTimeMs = in.readInt();
int[] txTimeMs = new int[TX_POWER_LEVELS];
- for (int i = 0; i < TX_POWER_LEVELS; i++) {
- txTimeMs[i] = in.readInt();
- }
+ in.readIntArray(txTimeMs);
int rxTimeMs = in.readInt();
return new ModemActivityInfo(timestamp, sleepTimeMs, idleTimeMs,
txTimeMs, rxTimeMs);
@@ -147,21 +158,25 @@
}
};
- public void writeToParcel(Parcel dest, int flags) {
+ /**
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeLong(mTimestamp);
dest.writeInt(mSleepTimeMs);
dest.writeInt(mIdleTimeMs);
- for (int i = 0; i < TX_POWER_LEVELS; i++) {
- dest.writeInt(mTransmitPowerInfo.get(i).getTimeInMillis());
- }
+ dest.writeIntArray(mTxTimeMs);
dest.writeInt(mRxTimeMs);
}
/**
- * @return milliseconds since boot, including mTimeInMillis spent in sleep.
- * @see SystemClock#elapsedRealtime()
+ * Gets the timestamp at which this modem activity info was recorded.
+ *
+ * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this
+ * {@link ModemActivityInfo} was recorded.
*/
- public long getTimestamp() {
+ public @ElapsedRealtimeLong long getTimestampMillis() {
return mTimestamp;
}
@@ -171,35 +186,48 @@
}
/**
- * @return an arrayList of {@link TransmitPower} with each element representing the total time where
- * transmitter is awake time (in ms) for a given power range (in dbm).
+ * Gets the amount of time the modem spent transmitting at a certain power level.
*
- * @see #TX_POWER_LEVELS
+ * @param powerLevel The power level to query.
+ * @return The amount of time, in milliseconds, that the modem spent transmitting at the
+ * given power level.
*/
- @NonNull
- public List<TransmitPower> getTransmitPowerInfo() {
- return mTransmitPowerInfo;
+ public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
+ @TxPowerLevel int powerLevel) {
+ return mTxTimeMs[powerLevel];
+ }
+
+ /**
+ * Gets the range of transmit powers corresponding to a certain power level.
+ *
+ * @param powerLevel The power level to query
+ * @return A {@link Range} object representing the range of intensities (in dBm) to which this
+ * power level corresponds.
+ */
+ public @NonNull Range<Integer> getTransmitPowerRange(@TxPowerLevel int powerLevel) {
+ return TX_POWER_RANGES[powerLevel];
}
/** @hide */
public void setTransmitTimeMillis(int[] txTimeMs) {
- populateTransmitPowerRange(txTimeMs);
- }
-
- /** @hide */
- @NonNull
- public int[] getTransmitTimeMillis() {
- int[] transmitTimeMillis = new int[TX_POWER_LEVELS];
- for (int i = 0; i < transmitTimeMillis.length; i++) {
- transmitTimeMillis[i] = mTransmitPowerInfo.get(i).getTimeInMillis();
- }
- return transmitTimeMillis;
+ mTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
}
/**
- * @return total mTimeInMillis (in ms) when modem is in a low power or sleep state.
+ * @return The raw array of transmit power durations
+ * @hide
*/
- public int getSleepTimeMillis() {
+ @NonNull
+ public int[] getTransmitTimeMillis() {
+ return mTxTimeMs;
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is in a low power or sleep state.
+ *
+ * @return Time in milliseconds.
+ */
+ public @DurationMillisLong long getSleepTimeMillis() {
return mSleepTimeMs;
}
@@ -209,10 +237,44 @@
}
/**
- * @return total mTimeInMillis (in ms) when modem is awake but neither the transmitter nor receiver are
- * active.
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
*/
- public int getIdleTimeMillis() {
+ public void setSleepTimeMillis(long sleepTimeMillis) {
+ mSleepTimeMs = (int) sleepTimeMillis;
+ }
+
+ /**
+ * Computes the difference between this instance of {@link ModemActivityInfo} and another
+ * instance.
+ *
+ * This method should be used to compute the amount of activity that has happened between two
+ * samples of modem activity taken at separate times. The sample passed in as an argument to
+ * this method should be the one that's taken later in time (and therefore has more activity).
+ * @param other The other instance of {@link ModemActivityInfo} to diff against.
+ * @return An instance of {@link ModemActivityInfo} representing the difference in modem
+ * activity.
+ */
+ public @NonNull ModemActivityInfo getDelta(@NonNull ModemActivityInfo other) {
+ int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
+ for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
+ txTimeMs[i] = other.mTxTimeMs[i] - mTxTimeMs[i];
+ }
+ return new ModemActivityInfo(other.getTimestampMillis(),
+ other.getSleepTimeMillis() - getSleepTimeMillis(),
+ other.getIdleTimeMillis() - getIdleTimeMillis(),
+ txTimeMs,
+ other.getReceiveTimeMillis() - getReceiveTimeMillis());
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is awake but neither transmitting
+ * nor receiving.
+ *
+ * @return Time in milliseconds.
+ */
+ public @DurationMillisLong long getIdleTimeMillis() {
return mIdleTimeMs;
}
@@ -222,9 +284,20 @@
}
/**
- * @return rx(receive) mTimeInMillis in ms.
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
*/
- public int getReceiveTimeMillis() {
+ public void setIdleTimeMillis(long idleTimeMillis) {
+ mIdleTimeMs = (int) idleTimeMillis;
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is awake and receiving data.
+ *
+ * @return Time in milliseconds.
+ */
+ public @DurationMillisLong long getReceiveTimeMillis() {
return mRxTimeMs;
}
@@ -234,71 +307,56 @@
}
/**
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
+ */
+ public void setReceiveTimeMillis(long receiveTimeMillis) {
+ mRxTimeMs = (int) receiveTimeMillis;
+ }
+
+ /**
* Indicates if the modem has reported valid {@link ModemActivityInfo}.
*
* @return {@code true} if this {@link ModemActivityInfo} record is valid,
* {@code false} otherwise.
+ * @hide
*/
+ @TestApi
public boolean isValid() {
- for (TransmitPower powerInfo : getTransmitPowerInfo()) {
- if(powerInfo.getTimeInMillis() < 0) {
- return false;
- }
- }
+ boolean isTxPowerValid = Arrays.stream(mTxTimeMs).allMatch((i) -> i >= 0);
- return ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
+ return isTxPowerValid && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
&& (getReceiveTimeMillis() >= 0) && !isEmpty());
}
- private boolean isEmpty() {
- for (TransmitPower txVal : getTransmitPowerInfo()) {
- if(txVal.getTimeInMillis() != 0) {
- return false;
- }
- }
+ /** @hide */
+ @TestApi
+ public boolean isEmpty() {
+ boolean isTxPowerEmpty = mTxTimeMs == null || mTxTimeMs.length == 0
+ || Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0);
- return ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
+ return isTxPowerEmpty && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
&& (getReceiveTimeMillis() == 0));
}
- /**
- * Transmit power Information, including the power range in dbm and the total time (in ms) where
- * the transmitter is active/awake for this power range.
- * e.g, range: 0dbm(lower) ~ 5dbm(upper)
- * time: 5ms
- */
- public class TransmitPower {
- private int mTimeInMillis;
- private Range<Integer> mPowerRangeInDbm;
- /** @hide */
- public TransmitPower(@NonNull Range<Integer> range, int time) {
- this.mTimeInMillis = time;
- this.mPowerRangeInDbm = range;
- }
- /**
- * @return the total time in ms where the transmitter is active/wake for this power range
- * {@link #getPowerRangeInDbm()}.
- */
- public int getTimeInMillis() {
- return mTimeInMillis;
- }
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ModemActivityInfo that = (ModemActivityInfo) o;
+ return mTimestamp == that.mTimestamp
+ && mSleepTimeMs == that.mSleepTimeMs
+ && mIdleTimeMs == that.mIdleTimeMs
+ && mRxTimeMs == that.mRxTimeMs
+ && Arrays.equals(mTxTimeMs, that.mTxTimeMs);
+ }
- /**
- * @return the power range in dbm. e.g, range: 0dbm(lower) ~ 5dbm(upper)
- */
- @NonNull
- public Range<Integer> getPowerRangeInDbm() {
- return mPowerRangeInDbm;
- }
-
- @Override
- public String toString() {
- return "TransmitPower{"
- + " mTimeInMillis=" + mTimeInMillis
- + " mPowerRangeInDbm={" + mPowerRangeInDbm.getLower()
- + "," + mPowerRangeInDbm.getUpper()
- + "}}";
- }
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mRxTimeMs);
+ result = 31 * result + Arrays.hashCode(mTxTimeMs);
+ return result;
}
}
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index 8a4bb46..59eac6a 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -337,7 +337,8 @@
private void setUplinkFrequency() {
switch (mNetworkType){
case TelephonyManager.NETWORK_TYPE_NR:
- mUplinkFrequency = mDownlinkFrequency;
+ mUplinkFrequency = AccessNetworkUtils.getFrequencyFromNrArfcn(
+ mUplinkChannelNumber);
break;
case TelephonyManager.NETWORK_TYPE_LTE:
mUplinkFrequency = AccessNetworkUtils.getFrequencyFromEarfcn(
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 6da61b7..1677c61 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -444,7 +444,9 @@
mArfcnRsrpBoost = s.mArfcnRsrpBoost;
synchronized (mNetworkRegistrationInfos) {
mNetworkRegistrationInfos.clear();
- mNetworkRegistrationInfos.addAll(s.getNetworkRegistrationInfoList());
+ for (NetworkRegistrationInfo nri : s.getNetworkRegistrationInfoList()) {
+ mNetworkRegistrationInfos.add(new NetworkRegistrationInfo(nri));
+ }
}
mNrFrequencyRange = s.mNrFrequencyRange;
mOperatorAlphaLongRaw = s.mOperatorAlphaLongRaw;
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
index fe7e5976..41e24dd 100644
--- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -26,8 +26,10 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -101,9 +103,11 @@
}
mSignalThresholdInfos = new ArrayList<>(signalThresholdInfos);
- // Sort the collection with RAN ascending order, make the ordering not matter for equals
+ // Sort the collection with RAN and then SignalMeasurementType ascending order, make the
+ // ordering not matter for equals
mSignalThresholdInfos.sort(
- Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType));
+ Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType)
+ .thenComparing(SignalThresholdInfo::getSignalMeasurementType));
return this;
}
@@ -144,7 +148,7 @@
* @return the SignalStrengthUpdateRequest object
*
* @throws IllegalArgumentException if the SignalThresholdInfo collection is empty size, the
- * radio access network type in the collection is not unique
+ * signal measurement type for the same RAN in the collection is not unique
*/
public @NonNull SignalStrengthUpdateRequest build() {
return new SignalStrengthUpdateRequest(mSignalThresholdInfos,
@@ -258,14 +262,23 @@
}
/**
- * Throw IAE when the RAN in the collection is not unique.
+ * Throw IAE if SignalThresholdInfo collection is null or empty,
+ * or the SignalMeasurementType for the same RAN in the collection is not unique.
*/
private static void validate(Collection<SignalThresholdInfo> infos) {
- Set<Integer> uniqueRan = new HashSet<>(infos.size());
+ if (infos == null || infos.isEmpty()) {
+ throw new IllegalArgumentException("SignalThresholdInfo collection is null or empty");
+ }
+
+ // Map from RAN to set of SignalMeasurementTypes
+ Map<Integer, Set<Integer>> ranToTypes = new HashMap<>(infos.size());
for (SignalThresholdInfo info : infos) {
final int ran = info.getRadioAccessNetworkType();
- if (!uniqueRan.add(ran)) {
- throw new IllegalArgumentException("RAN: " + ran + " is not unique");
+ final int type = info.getSignalMeasurementType();
+ ranToTypes.putIfAbsent(ran, new HashSet<>());
+ if (!ranToTypes.get(ran).add(type)) {
+ throw new IllegalArgumentException(
+ "SignalMeasurementType " + type + " for RAN " + ran + " is not unique");
}
}
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 9d4db17..98f9dfd 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1827,8 +1827,9 @@
* @param subscriptionType the {@link #SUBSCRIPTION_TYPE}
* @hide
*/
- public void addSubscriptionInfoRecord(String uniqueId, String displayName, int slotIndex,
- int subscriptionType) {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void addSubscriptionInfoRecord(@NonNull String uniqueId, @Nullable String displayName,
+ int slotIndex, int subscriptionType) {
if (VDBG) {
logd("[addSubscriptionInfoRecord]+ uniqueId:" + uniqueId
+ ", displayName:" + displayName + ", slotIndex:" + slotIndex
@@ -1863,7 +1864,8 @@
* @param subscriptionType the {@link #SUBSCRIPTION_TYPE}
* @hide
*/
- public void removeSubscriptionInfoRecord(String uniqueId, int subscriptionType) {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void removeSubscriptionInfoRecord(@NonNull String uniqueId, int subscriptionType) {
if (VDBG) {
logd("[removeSubscriptionInfoRecord]+ uniqueId:" + uniqueId
+ ", subscriptionType: " + subscriptionType);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4189784..f55dc8b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -57,7 +57,9 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.OutcomeReceiver;
import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -84,6 +86,7 @@
import android.telephony.VisualVoicemailService.VisualVoicemailTask;
import android.telephony.data.ApnSetting;
import android.telephony.data.ApnSetting.MvnoType;
+import android.telephony.data.SlicingConfig;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
import android.telephony.gba.UaSecurityProtocolIdentifier;
@@ -176,6 +179,9 @@
*/
public static final String MODEM_ACTIVITY_RESULT_KEY = "controller_activity";
+ /** @hide */
+ public static final String EXCEPTION_RESULT_KEY = "exception";
+
/**
* The process name of the Phone app as well as many other apps that use this process name, such
* as settings and vendor components.
@@ -10855,26 +10861,149 @@
return null;
}
-
/**
- * Requests the modem activity info. The recipient will place the result
- * in `result`.
- * @param result The object on which the recipient will send the resulting
- * {@link android.telephony.ModemActivityInfo} object with key of
- * {@link #MODEM_ACTIVITY_RESULT_KEY}.
+ * Exception that may be supplied to the callback provided in {@link #requestModemActivityInfo}.
* @hide
*/
- public void requestModemActivityInfo(@NonNull ResultReceiver result) {
+ @SystemApi
+ public static class ModemActivityInfoException extends Exception {
+ /** Indicates that an unknown error occurred */
+ public static final int ERROR_UNKNOWN = 0;
+
+ /**
+ * Indicates that the modem or phone processes are not available (such as when the device
+ * is in airplane mode).
+ */
+ public static final int ERROR_PHONE_NOT_AVAILABLE = 1;
+
+ /**
+ * Indicates that the modem supplied an invalid instance of {@link ModemActivityInfo}
+ */
+ public static final int ERROR_INVALID_INFO_RECEIVED = 2;
+
+ /**
+ * Indicates that the modem encountered an internal failure when processing the request
+ * for activity info.
+ */
+ public static final int ERROR_MODEM_RESPONSE_ERROR = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"ERROR_"},
+ value = {
+ ERROR_UNKNOWN,
+ ERROR_PHONE_NOT_AVAILABLE,
+ ERROR_INVALID_INFO_RECEIVED,
+ ERROR_MODEM_RESPONSE_ERROR,
+ })
+ public @interface ModemActivityInfoError {}
+
+ private final int mErrorCode;
+
+ /** @hide */
+ public ModemActivityInfoException(@ModemActivityInfoError int errorCode) {
+ mErrorCode = errorCode;
+ }
+
+ public @ModemActivityInfoError int getErrorCode() {
+ return mErrorCode;
+ }
+
+ @Override
+ public String toString() {
+ switch (mErrorCode) {
+ case ERROR_UNKNOWN: return "ERROR_UNKNOWN";
+ case ERROR_PHONE_NOT_AVAILABLE: return "ERROR_PHONE_NOT_AVAILABLE";
+ case ERROR_INVALID_INFO_RECEIVED: return "ERROR_INVALID_INFO_RECEIVED";
+ case ERROR_MODEM_RESPONSE_ERROR: return "ERROR_MODEM_RESPONSE_ERROR";
+ default: return "UNDEFINED";
+ }
+ }
+ }
+
+ /**
+ * Requests the current modem activity info.
+ *
+ * The provided instance of {@link ModemActivityInfo} represents the cumulative activity since
+ * the last restart of the phone process.
+ *
+ * @param callback A callback object to which the result will be delivered. If there was an
+ * error processing the request, {@link OutcomeReceiver#onError} will be called
+ * with more details about the error.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void requestModemActivityInfo(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<ModemActivityInfo, ModemActivityInfoException> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ // Pass no handler into the receiver, since we're going to be trampolining the call to the
+ // listener onto the provided executor.
+ ResultReceiver wrapperResultReceiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle data) {
+ if (data == null) {
+ Log.w(TAG, "requestModemActivityInfo: received null bundle");
+ sendErrorToListener(ModemActivityInfoException.ERROR_UNKNOWN);
+ return;
+ }
+ data.setDefusable(true);
+ if (data.containsKey(EXCEPTION_RESULT_KEY)) {
+ int receivedErrorCode = data.getInt(EXCEPTION_RESULT_KEY);
+ sendErrorToListener(receivedErrorCode);
+ return;
+ }
+
+ if (!data.containsKey(MODEM_ACTIVITY_RESULT_KEY)) {
+ Log.w(TAG, "requestModemActivityInfo: Bundle did not contain expected key");
+ sendErrorToListener(ModemActivityInfoException.ERROR_UNKNOWN);
+ return;
+ }
+ Parcelable receivedResult = data.getParcelable(MODEM_ACTIVITY_RESULT_KEY);
+ if (!(receivedResult instanceof ModemActivityInfo)) {
+ Log.w(TAG, "requestModemActivityInfo: Bundle contained something that wasn't "
+ + "a ModemActivityInfo.");
+ sendErrorToListener(ModemActivityInfoException.ERROR_UNKNOWN);
+ return;
+ }
+ ModemActivityInfo modemActivityInfo = (ModemActivityInfo) receivedResult;
+ if (!modemActivityInfo.isValid()) {
+ Log.w(TAG, "requestModemActivityInfo: Received an invalid ModemActivityInfo");
+ sendErrorToListener(ModemActivityInfoException.ERROR_INVALID_INFO_RECEIVED);
+ return;
+ }
+ Log.d(TAG, "requestModemActivityInfo: Sending result to app: " + modemActivityInfo);
+ sendResultToListener(modemActivityInfo);
+ }
+
+ private void sendResultToListener(ModemActivityInfo info) {
+ Binder.withCleanCallingIdentity(() ->
+ executor.execute(() ->
+ callback.onResult(info)));
+ }
+
+ private void sendErrorToListener(int code) {
+ ModemActivityInfoException e = new ModemActivityInfoException(code);
+ Binder.withCleanCallingIdentity(() ->
+ executor.execute(() ->
+ callback.onError(e)));
+ }
+ };
+
try {
ITelephony service = getITelephony();
if (service != null) {
- service.requestModemActivityInfo(result);
+ service.requestModemActivityInfo(wrapperResultReceiver);
return;
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#getModemActivityInfo", e);
}
- result.send(0, null);
+ executor.execute(() -> callback.onError(
+ new ModemActivityInfoException(
+ ModemActivityInfoException.ERROR_PHONE_NOT_AVAILABLE)));
}
/**
@@ -15093,4 +15222,96 @@
return PhoneCapability.DEFAULT_SSSS_CAPABILITY;
}
}
+
+ /**
+ * Exception that may be supplied to the callback in {@link #getNetworkSlicingConfiguration} if
+ * something goes awry.
+ */
+ public static class SlicingException extends Exception {
+ /**
+ * Getting the current slicing configuration successfully. Used internally only.
+ * @hide
+ */
+ public static final int SUCCESS = 0;
+
+ /**
+ * The system timed out waiting for a response from the Radio.
+ */
+ public static final int ERROR_TIMEOUT = 1;
+
+ /**
+ * The modem returned a failure.
+ */
+ public static final int ERROR_MODEM_ERROR = 2;
+
+ /** @hide */
+ @IntDef(prefix = {"ERROR_"}, value = {
+ ERROR_TIMEOUT,
+ ERROR_MODEM_ERROR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SlicingError {}
+
+ private final int mErrorCode;
+
+ public SlicingException(@SlicingError int errorCode) {
+ mErrorCode = errorCode;
+ }
+
+ /**
+ * Fetches the error code associated with this exception.
+ * @return An error code.
+ */
+ public @SlicingError int getErrorCode() {
+ return mErrorCode;
+ }
+ }
+
+ /** @hide */
+ public static final String KEY_SLICING_CONFIG_HANDLE = "slicing_config_handle";
+
+ /**
+ * Request to get the current slicing configuration including URSP rules and
+ * NSSAIs (configured, allowed and rejected).
+ *
+ * This method can be invoked if one of the following requirements is met:
+ * <ul>
+ * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
+ * is a privileged permission that can only be granted to apps preloaded on the device.
+ * <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * </ul>
+ *
+ * @param executor the executor on which callback will be invoked.
+ * @param callback a callback to receive the current slicing configuration.
+ */
+ @SuppressAutoDoc // No support for carrier privileges (b/72967236).
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void getNetworkSlicingConfiguration(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<SlicingConfig, SlicingException> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ telephony.getSlicingConfig(new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle result) {
+ if (resultCode != SlicingException.SUCCESS) {
+ executor.execute(() -> callback.onError(
+ new SlicingException(resultCode)));
+ return;
+ }
+ SlicingConfig slicingConfig =
+ result.getParcelable(KEY_SLICING_CONFIG_HANDLE);
+ executor.execute(() -> callback.onResult(slicingConfig));
+ }
+ });
+ } catch (RemoteException ex) {
+ ex.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index ad57b91..5008307 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -138,7 +138,7 @@
private final int mPduSessionId;
private final Qos mDefaultQos;
private final List<QosBearerSession> mQosBearerSessions;
- private final SliceInfo mSliceInfo;
+ private final NetworkSliceInfo mSliceInfo;
private final List<TrafficDescriptor> mTrafficDescriptors;
/**
@@ -201,7 +201,8 @@
@Nullable List<InetAddress> pcscfAddresses, int mtu, int mtuV4, int mtuV6,
@HandoverFailureMode int handoverFailureMode, int pduSessionId,
@Nullable Qos defaultQos, @Nullable List<QosBearerSession> qosBearerSessions,
- @Nullable SliceInfo sliceInfo, @Nullable List<TrafficDescriptor> trafficDescriptors) {
+ @Nullable NetworkSliceInfo sliceInfo,
+ @Nullable List<TrafficDescriptor> trafficDescriptors) {
mCause = cause;
mSuggestedRetryTime = suggestedRetryTime;
mId = id;
@@ -254,7 +255,7 @@
mDefaultQos = source.readParcelable(Qos.class.getClassLoader());
mQosBearerSessions = new ArrayList<>();
source.readList(mQosBearerSessions, QosBearerSession.class.getClassLoader());
- mSliceInfo = source.readParcelable(SliceInfo.class.getClassLoader());
+ mSliceInfo = source.readParcelable(NetworkSliceInfo.class.getClassLoader());
mTrafficDescriptors = new ArrayList<>();
source.readList(mTrafficDescriptors, TrafficDescriptor.class.getClassLoader());
}
@@ -408,7 +409,7 @@
* @return The slice info related to this data connection.
*/
@Nullable
- public SliceInfo getSliceInfo() {
+ public NetworkSliceInfo getSliceInfo() {
return mSliceInfo;
}
@@ -620,7 +621,7 @@
private List<QosBearerSession> mQosBearerSessions = new ArrayList<>();
- private SliceInfo mSliceInfo;
+ private NetworkSliceInfo mSliceInfo;
private List<TrafficDescriptor> mTrafficDescriptors = new ArrayList<>();
@@ -851,13 +852,13 @@
* The Slice used for this data connection.
* <p/>
* If a handover occurs from EPDG to 5G,
- * this is the {@link SliceInfo} used in {@link DataService#setupDataCall}.
+ * this is the {@link NetworkSliceInfo} used in {@link DataService#setupDataCall}.
*
* @param sliceInfo the slice info for the data call
*
* @return The same instance of the builder.
*/
- public @NonNull Builder setSliceInfo(@Nullable SliceInfo sliceInfo) {
+ public @NonNull Builder setSliceInfo(@Nullable NetworkSliceInfo sliceInfo) {
mSliceInfo = sliceInfo;
return this;
}
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index f5f29c6..17e6f32 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -217,7 +217,7 @@
boolean isRoaming, boolean allowRoaming,
@SetupDataReason int reason,
@Nullable LinkProperties linkProperties,
- @IntRange(from = 0, to = 15) int pduSessionId, @Nullable SliceInfo sliceInfo,
+ @IntRange(from = 0, to = 15) int pduSessionId, @Nullable NetworkSliceInfo sliceInfo,
@Nullable TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
@NonNull DataServiceCallback callback) {
/* Call the old version since the new version isn't supported */
@@ -414,13 +414,13 @@
public final int reason;
public final LinkProperties linkProperties;
public final int pduSessionId;
- public final SliceInfo sliceInfo;
+ public final NetworkSliceInfo sliceInfo;
public final TrafficDescriptor trafficDescriptor;
public final boolean matchAllRuleAllowed;
public final IDataServiceCallback callback;
SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId,
- SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
+ NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
boolean matchAllRuleAllowed, IDataServiceCallback callback) {
this.accessNetworkType = accessNetworkType;
this.dataProfile = dataProfile;
@@ -707,7 +707,7 @@
@Override
public void setupDataCall(int slotIndex, int accessNetworkType, DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming, int reason,
- LinkProperties linkProperties, int pduSessionId, SliceInfo sliceInfo,
+ LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo,
TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
IDataServiceCallback callback) {
mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, slotIndex, 0,
diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl
index 81f5fd3..1346946 100644
--- a/telephony/java/android/telephony/data/IDataService.aidl
+++ b/telephony/java/android/telephony/data/IDataService.aidl
@@ -19,7 +19,7 @@
import android.net.LinkProperties;
import android.telephony.data.DataProfile;
import android.telephony.data.IDataServiceCallback;
-import android.telephony.data.SliceInfo;
+import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.TrafficDescriptor;
/**
@@ -31,7 +31,7 @@
void removeDataServiceProvider(int slotId);
void setupDataCall(int slotId, int accessNetwork, in DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, in LinkProperties linkProperties,
- int pduSessionId, in SliceInfo sliceInfo,
+ int pduSessionId, in NetworkSliceInfo sliceInfo,
in TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
IDataServiceCallback callback);
void deactivateDataCall(int slotId, int cid, int reason, IDataServiceCallback callback);
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/telephony/java/android/telephony/data/NetworkSliceInfo.aidl
similarity index 95%
rename from telephony/java/android/telephony/data/SliceInfo.aidl
rename to telephony/java/android/telephony/data/NetworkSliceInfo.aidl
index 286ea5e..e1a11f2 100644
--- a/telephony/java/android/telephony/data/SliceInfo.aidl
+++ b/telephony/java/android/telephony/data/NetworkSliceInfo.aidl
@@ -17,4 +17,4 @@
/** @hide */
package android.telephony.data;
-parcelable SliceInfo;
+parcelable NetworkSliceInfo;
diff --git a/telephony/java/android/telephony/data/SliceInfo.java b/telephony/java/android/telephony/data/NetworkSliceInfo.java
similarity index 68%
rename from telephony/java/android/telephony/data/SliceInfo.java
rename to telephony/java/android/telephony/data/NetworkSliceInfo.java
index 609d111..232a930 100644
--- a/telephony/java/android/telephony/data/SliceInfo.java
+++ b/telephony/java/android/telephony/data/NetworkSliceInfo.java
@@ -19,8 +19,6 @@
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -35,11 +33,8 @@
* SliceServiceType defines the type of service provided by the slice, and SliceDifferentiator is
* used to differentiate between multiple slices of the same type. If the devices is not on HPLMN,
* the mappedHplmn versions of these 2 fields indicate the corresponding values in HPLMN.
- *
- * @hide
*/
-@SystemApi
-public final class SliceInfo implements Parcelable {
+public final class NetworkSliceInfo implements Parcelable {
/**
* When set on a Slice Differentiator, this value indicates that there is no corresponding
* Slice.
@@ -68,14 +63,14 @@
/**
* The min acceptable value for a Slice Differentiator
+ * @hide
*/
- @SuppressLint("MinMaxConstant")
public static final int MIN_SLICE_DIFFERENTIATOR = -1;
/**
* The max acceptable value for a Slice Differentiator
+ * @hide
*/
- @SuppressLint("MinMaxConstant")
public static final int MAX_SLICE_DIFFERENTIATOR = 0xFFFFFE;
/** @hide */
@@ -88,6 +83,62 @@
@Retention(RetentionPolicy.SOURCE)
public @interface SliceServiceType {}
+ /**
+ * The slice status is unknown. This can happen during IWLAN->cellular handover when the
+ * NetworkSliceInfo is received over IWLAN.
+ */
+ public static final int SLICE_STATUS_UNKNOWN = 0;
+
+ /**
+ * The slice is configured but not allowed or rejected yet.
+ */
+ public static final int SLICE_STATUS_CONFIGURED = 1;
+
+ /**
+ * The slice is allowed to be used.
+ */
+ public static final int SLICE_STATUS_ALLOWED = 2;
+
+ /**
+ * The slice is rejected because not available in PLMN.
+ */
+ public static final int SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_PLMN = 3;
+
+ /**
+ * The slice is rejected because not available in registered area.
+ */
+ public static final int SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_REGISTERED_AREA = 4;
+
+ /**
+ * The slice is configured by home operator(HPLMN) in default and is used if configured/allowed
+ * slices are not available for the serving PLMN.
+ */
+ public static final int SLICE_STATUS_DEFAULT_CONFIGURED = 5;
+
+ /**
+ * The min acceptable value for a slice status.
+ * @hide
+ */
+ public static final int MIN_SLICE_STATUS = SLICE_STATUS_UNKNOWN;
+
+ /**
+ * The max acceptable value for a slice status.
+ * @hide
+ */
+ public static final int MAX_SLICE_STATUS = SLICE_STATUS_DEFAULT_CONFIGURED;
+
+ /** @hide */
+ @IntDef(prefix = { "SLICE_STATUS_" }, value = {
+ SLICE_STATUS_UNKNOWN,
+ SLICE_STATUS_CONFIGURED,
+ SLICE_STATUS_ALLOWED,
+ SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_PLMN,
+ SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_REGISTERED_AREA,
+ SLICE_STATUS_DEFAULT_CONFIGURED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SliceStatus {}
+
@SliceServiceType
private final int mSliceServiceType;
@@ -97,14 +148,18 @@
private final int mMappedHplmnSliceServiceType;
@IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
private final int mMappedHplmnSliceDifferentiator;
+ @SliceStatus
+ @IntRange(from = MIN_SLICE_STATUS, to = MAX_SLICE_STATUS)
+ private final int mStatus;
- private SliceInfo(@SliceServiceType int sliceServiceType,
+ private NetworkSliceInfo(@SliceServiceType int sliceServiceType,
int sliceDifferentiator, int mappedHplmnSliceServiceType,
- int mappedHplmnSliceDifferentiator) {
+ int mappedHplmnSliceDifferentiator, int status) {
mSliceServiceType = sliceServiceType;
mSliceDifferentiator = sliceDifferentiator;
mMappedHplmnSliceDifferentiator = mappedHplmnSliceDifferentiator;
mMappedHplmnSliceServiceType = mappedHplmnSliceServiceType;
+ mStatus = status;
}
/**
@@ -141,7 +196,7 @@
}
/**
- * This Slice Differentiator corresponds to a {@link SliceInfo} (S-NSSAI) of the HPLMN;
+ * This Slice Differentiator corresponds to a {@link NetworkSliceInfo} (S-NSSAI) of the HPLMN;
* {@link #getSliceDifferentiator()} is mapped to this value.
* <p/>
* Returns {@link #SLICE_DIFFERENTIATOR_NO_SLICE} if either of the following are true:
@@ -157,11 +212,21 @@
return mMappedHplmnSliceDifferentiator;
}
- private SliceInfo(@NonNull Parcel in) {
+ /**
+ * Field to indicate the current status of the slice.
+ * @return the current status for this slice info.
+ */
+ @SliceStatus
+ public int getStatus() {
+ return mStatus;
+ }
+
+ private NetworkSliceInfo(@NonNull Parcel in) {
mSliceServiceType = in.readInt();
mSliceDifferentiator = in.readInt();
mMappedHplmnSliceServiceType = in.readInt();
mMappedHplmnSliceDifferentiator = in.readInt();
+ mStatus = in.readInt();
}
@Override
@@ -175,20 +240,21 @@
dest.writeInt(mSliceDifferentiator);
dest.writeInt(mMappedHplmnSliceServiceType);
dest.writeInt(mMappedHplmnSliceDifferentiator);
+ dest.writeInt(mStatus);
}
- public static final @android.annotation.NonNull Parcelable.Creator<SliceInfo> CREATOR =
- new Parcelable.Creator<SliceInfo>() {
+ public static final @android.annotation.NonNull Parcelable.Creator<NetworkSliceInfo> CREATOR =
+ new Parcelable.Creator<NetworkSliceInfo>() {
@Override
@NonNull
- public SliceInfo createFromParcel(@NonNull Parcel source) {
- return new SliceInfo(source);
+ public NetworkSliceInfo createFromParcel(@NonNull Parcel source) {
+ return new NetworkSliceInfo(source);
}
@Override
@NonNull
- public SliceInfo[] newArray(int size) {
- return new SliceInfo[size];
+ public NetworkSliceInfo[] newArray(int size) {
+ return new NetworkSliceInfo[size];
}
};
@@ -200,6 +266,7 @@
+ ", mMappedHplmnSliceServiceType="
+ sliceServiceTypeToString(mMappedHplmnSliceServiceType)
+ ", mMappedHplmnSliceDifferentiator=" + mMappedHplmnSliceDifferentiator
+ + ", mStatus=" + sliceStatusToString(mStatus)
+ '}';
}
@@ -218,25 +285,45 @@
}
}
+ private static String sliceStatusToString(@SliceStatus int sliceStatus) {
+ switch(sliceStatus) {
+ case SLICE_STATUS_UNKNOWN:
+ return "UNKNOWN";
+ case SLICE_STATUS_CONFIGURED:
+ return "CONFIGURED";
+ case SLICE_STATUS_ALLOWED:
+ return "ALLOWED";
+ case SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_PLMN:
+ return "REJECTED_NOT_AVAILABLE_IN_PLMN";
+ case SLICE_STATUS_REJECTED_NOT_AVAILABLE_IN_REGISTERED_AREA:
+ return "REJECTED_NOT_AVAILABLE_IN_REGISTERED_AREA";
+ case SLICE_STATUS_DEFAULT_CONFIGURED:
+ return "DEFAULT_CONFIGURED";
+ default:
+ return Integer.toString(sliceStatus);
+ }
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- SliceInfo sliceInfo = (SliceInfo) o;
+ NetworkSliceInfo sliceInfo = (NetworkSliceInfo) o;
return mSliceServiceType == sliceInfo.mSliceServiceType
&& mSliceDifferentiator == sliceInfo.mSliceDifferentiator
&& mMappedHplmnSliceServiceType == sliceInfo.mMappedHplmnSliceServiceType
- && mMappedHplmnSliceDifferentiator == sliceInfo.mMappedHplmnSliceDifferentiator;
+ && mMappedHplmnSliceDifferentiator == sliceInfo.mMappedHplmnSliceDifferentiator
+ && mStatus == sliceInfo.mStatus;
}
@Override
public int hashCode() {
return Objects.hash(mSliceServiceType, mSliceDifferentiator, mMappedHplmnSliceServiceType,
- mMappedHplmnSliceDifferentiator);
+ mMappedHplmnSliceDifferentiator, mStatus);
}
/**
- * Provides a convenient way to set the fields of a {@link SliceInfo} when creating a
+ * Provides a convenient way to set the fields of a {@link NetworkSliceInfo} when creating a
* new instance.
*
* <p>The example below shows how you might create a new {@code SliceInfo}:
@@ -257,6 +344,9 @@
private int mMappedHplmnSliceServiceType = SLICE_SERVICE_TYPE_NONE;
@IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
private int mMappedHplmnSliceDifferentiator = SLICE_DIFFERENTIATOR_NO_SLICE;
+ @SliceStatus
+ @IntRange(from = MIN_SLICE_STATUS, to = MAX_SLICE_STATUS)
+ private int mStatus = SLICE_STATUS_UNKNOWN;
/**
* Default constructor for Builder.
@@ -281,8 +371,7 @@
* A value of {@link #SLICE_DIFFERENTIATOR_NO_SLICE} indicates that there is no
* corresponding Slice.
*
- * @throws IllegalArgumentException if the parameter is not between
- * {@link #MIN_SLICE_DIFFERENTIATOR} and {@link #MAX_SLICE_DIFFERENTIATOR}.
+ * @throws IllegalArgumentException if the parameter is not in the expected range.
*
* @return The same instance of the builder.
*/
@@ -316,8 +405,7 @@
* A value of {@link #SLICE_DIFFERENTIATOR_NO_SLICE} indicates that there is no
* corresponding Slice of the HPLMN.
*
- * @throws IllegalArgumentException if the parameter is not between
- * {@link #MIN_SLICE_DIFFERENTIATOR} and {@link #MAX_SLICE_DIFFERENTIATOR}.
+ * @throws IllegalArgumentException if the parameter is not in the expected range.
*
* @return The same instance of the builder.
*/
@@ -334,14 +422,31 @@
}
/**
- * Build the {@link SliceInfo}.
+ * Set the slice status.
*
- * @return the {@link SliceInfo} object.
+ * @throws IllegalArgumentException if the status is invalid.
+ *
+ * @return The same instance of the builder.
*/
@NonNull
- public SliceInfo build() {
- return new SliceInfo(this.mSliceServiceType, this.mSliceDifferentiator,
- this.mMappedHplmnSliceServiceType, this.mMappedHplmnSliceDifferentiator);
+ public Builder setStatus(@SliceStatus int status) {
+ if (status < MIN_SLICE_STATUS || status > MAX_SLICE_STATUS) {
+ throw new IllegalArgumentException("The slice status is not valid");
+ }
+ this.mStatus = status;
+ return this;
+ }
+
+ /**
+ * Build the {@link NetworkSliceInfo}.
+ *
+ * @return the {@link NetworkSliceInfo} object.
+ */
+ @NonNull
+ public NetworkSliceInfo build() {
+ return new NetworkSliceInfo(this.mSliceServiceType, this.mSliceDifferentiator,
+ this.mMappedHplmnSliceServiceType, this.mMappedHplmnSliceDifferentiator,
+ this.mStatus);
}
}
}
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/telephony/java/android/telephony/data/RouteSelectionDescriptor.aidl
similarity index 87%
copy from telephony/java/android/telephony/data/SliceInfo.aidl
copy to telephony/java/android/telephony/data/RouteSelectionDescriptor.aidl
index 286ea5e..563a00e 100644
--- a/telephony/java/android/telephony/data/SliceInfo.aidl
+++ b/telephony/java/android/telephony/data/RouteSelectionDescriptor.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
package android.telephony.data;
-parcelable SliceInfo;
+parcelable RouteSelectionDescriptor;
diff --git a/telephony/java/android/telephony/data/RouteSelectionDescriptor.java b/telephony/java/android/telephony/data/RouteSelectionDescriptor.java
new file mode 100644
index 0000000..c2457f2
--- /dev/null
+++ b/telephony/java/android/telephony/data/RouteSelectionDescriptor.java
@@ -0,0 +1,263 @@
+/**
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents a single route selection descriptor as defined in
+ * 3GPP TS 24.526.
+ */
+public final class RouteSelectionDescriptor implements Parcelable {
+ /**
+ * The min acceptable value for the precedence of a route selection descriptor.
+ * @hide
+ */
+ public static final int MIN_ROUTE_PRECEDENCE = 0;
+
+ /**
+ * The max acceptable value for the precedence of a route selection descriptor.
+ * @hide
+ */
+ public static final int MAX_ROUTE_PRECEDENCE = 255;
+
+ /**
+ * The route selection descriptor is for the session with IPV4 type.
+ */
+ public static final int SESSION_TYPE_IPV4 = 0;
+
+ /**
+ * The route selection descriptor is for the session with IPV6 type.
+ */
+ public static final int SESSION_TYPE_IPV6 = 1;
+
+ /**
+ * The route selection descriptor is for the session with both IP and IPV6 types.
+ */
+ public static final int SESSION_TYPE_IPV4V6 = 2;
+
+ /** @hide */
+ @IntDef(prefix = { "SESSION_TYPE_" }, value = {
+ SESSION_TYPE_IPV4,
+ SESSION_TYPE_IPV6,
+ SESSION_TYPE_IPV4V6,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RouteSessionType {}
+
+ /**
+ * The route selection descriptor is using SSC mode 1. The session will provide continual
+ * support when UE's location is updated.
+ */
+ public static final int ROUTE_SSC_MODE_1 = 1;
+
+ /**
+ * The route selection descriptor is using SSC mode 2. The new session for the same network
+ * will be established after releasing the old session when UE's location is updated.
+ */
+ public static final int ROUTE_SSC_MODE_2 = 2;
+
+ /**
+ * The route selection descriptor is using SSC mode 3. The new session for the same network is
+ * allowed to be established before releasing the old session when UE's location is updated.
+ */
+ public static final int ROUTE_SSC_MODE_3 = 3;
+
+ /**
+ * The min acceptable value for the SSC mode of a route selection descriptor.
+ * @hide
+ */
+ public static final int MIN_ROUTE_SSC_MODE = ROUTE_SSC_MODE_1;
+
+ /**
+ * The max acceptable value for the SSC mode of a route selection descriptor.
+ * @hide
+ */
+ public static final int MAX_ROUTE_SSC_MODE = ROUTE_SSC_MODE_3;
+
+ /** @hide */
+ @IntDef(prefix = { "ROUTE_SSC_MODE_" }, value = {
+ ROUTE_SSC_MODE_1,
+ ROUTE_SSC_MODE_2,
+ ROUTE_SSC_MODE_3,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RouteSscMode {}
+
+ @IntRange(from = MIN_ROUTE_PRECEDENCE, to = MAX_ROUTE_PRECEDENCE)
+ private final int mPrecedence;
+ @RouteSessionType
+ private final int mSessionType;
+ @RouteSscMode
+ @IntRange(from = MIN_ROUTE_SSC_MODE, to = MAX_ROUTE_SSC_MODE)
+ private final int mSscMode;
+ private final List<NetworkSliceInfo> mSliceInfo;
+ private final List<String> mDnn;
+
+ /** @hide */
+ RouteSelectionDescriptor(android.hardware.radio.V1_6.RouteSelectionDescriptor rsd) {
+ this(rsd.precedence, rsd.sessionType.value(), rsd.sscMode.value(), rsd.sliceInfo,
+ rsd.dnn);
+ }
+
+ /** @hide */
+ public RouteSelectionDescriptor(int precedence, int sessionType, int sscMode,
+ List<android.hardware.radio.V1_6.SliceInfo> sliceInfo, List<String> dnn) {
+ mPrecedence = precedence;
+ mSessionType = sessionType;
+ mSscMode = sscMode;
+ mSliceInfo = new ArrayList<NetworkSliceInfo>();
+ for (android.hardware.radio.V1_6.SliceInfo si : sliceInfo) {
+ mSliceInfo.add(sliceInfoBuilder(si));
+ }
+ mDnn = new ArrayList<String>();
+ mDnn.addAll(dnn);
+ }
+
+ private NetworkSliceInfo sliceInfoBuilder(android.hardware.radio.V1_6.SliceInfo si) {
+ NetworkSliceInfo.Builder builder = new NetworkSliceInfo.Builder()
+ .setSliceServiceType(si.sst)
+ .setMappedHplmnSliceServiceType(si.mappedHplmnSst);
+ if (si.sliceDifferentiator != NetworkSliceInfo.SLICE_DIFFERENTIATOR_NO_SLICE) {
+ builder
+ .setSliceDifferentiator(si.sliceDifferentiator)
+ .setMappedHplmnSliceDifferentiator(si.mappedHplmnSD);
+ }
+ return builder.build();
+ }
+
+ private RouteSelectionDescriptor(Parcel p) {
+ mPrecedence = p.readInt();
+ mSessionType = p.readInt();
+ mSscMode = p.readInt();
+ mSliceInfo = p.createTypedArrayList(NetworkSliceInfo.CREATOR);
+ mDnn = new ArrayList<String>();
+ p.readStringList(mDnn);
+ }
+
+ /**
+ * Precedence value in the range of 0 to 255. Higher value has lower precedence.
+ * @return the precedence value for this route selection descriptor.
+ */
+ @IntRange(from = MIN_ROUTE_PRECEDENCE, to = MAX_ROUTE_PRECEDENCE)
+ public int getPrecedence() {
+ return mPrecedence;
+ }
+
+ /**
+ * This is used for checking which session type defined in 3GPP TS 23.501 is allowed for the
+ * route in a route selection descriptor.
+ * @return the session type for this route selection descriptor.
+ */
+ @RouteSessionType
+ public int getSessionType() {
+ return mSessionType;
+ }
+
+ /**
+ * SSC mode stands for Session and Service Continuity mode (which specifies the IP continuity
+ * mode) as defined in 3GPP TS 23.501.
+ * @return the SSC mode for this route selection descriptor.
+ */
+ @RouteSscMode
+ public int getSscMode() {
+ return mSscMode;
+ }
+
+ /**
+ * This is the list of all the slices available in the route selection descriptor as indicated
+ * by the network. These are the slices that can be used by the device if this route selection
+ * descriptor is used based the traffic (see 3GPP TS 23.501 for details).
+ * @return the list of all the slices available in the route selection descriptor.
+ */
+ public @NonNull List<NetworkSliceInfo> getSliceInfo() {
+ return mSliceInfo;
+ }
+
+ /**
+ * DNN stands for Data Network Name and represents an APN as defined in 3GPP TS 23.003. There
+ * can be 0 or more DNNs specified in a route selection descriptor.
+ * @return the list of DNN for this route selection descriptor.
+ */
+ public @NonNull List<String> getDataNetworkName() {
+ return mDnn;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mPrecedence);
+ dest.writeInt(mSessionType);
+ dest.writeInt(mSscMode);
+ dest.writeTypedList(mSliceInfo, flags);
+ dest.writeStringList(mDnn);
+ }
+
+ public static final @NonNull Parcelable.Creator<RouteSelectionDescriptor> CREATOR =
+ new Parcelable.Creator<RouteSelectionDescriptor>() {
+ @Override
+ public RouteSelectionDescriptor createFromParcel(Parcel source) {
+ return new RouteSelectionDescriptor(source);
+ }
+
+ @Override
+ public RouteSelectionDescriptor[] newArray(int size) {
+ return new RouteSelectionDescriptor[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RouteSelectionDescriptor that = (RouteSelectionDescriptor) o;
+ return mPrecedence == that.mPrecedence
+ && mSessionType == that.mSessionType
+ && mSscMode == that.mSscMode
+ && mSliceInfo.size() == that.mSliceInfo.size()
+ && mSliceInfo.containsAll(that.mSliceInfo)
+ && mDnn.size() == that.mDnn.size()
+ && mDnn.containsAll(that.mDnn);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPrecedence, mSessionType, mSscMode, mSliceInfo, mDnn);
+ }
+
+ @Override
+ public String toString() {
+ return "{.precedence = " + mPrecedence + ", .sessionType = " + mSessionType
+ + ", .sscMode = " + mSscMode + ", .sliceInfo = " + mSliceInfo
+ + ", .dnn = " + mDnn + "}";
+ }
+}
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/telephony/java/android/telephony/data/SlicingConfig.aidl
similarity index 87%
copy from telephony/java/android/telephony/data/SliceInfo.aidl
copy to telephony/java/android/telephony/data/SlicingConfig.aidl
index 286ea5e..ad93d8c 100644
--- a/telephony/java/android/telephony/data/SliceInfo.aidl
+++ b/telephony/java/android/telephony/data/SlicingConfig.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
package android.telephony.data;
-parcelable SliceInfo;
+parcelable SlicingConfig;
diff --git a/telephony/java/android/telephony/data/SlicingConfig.java b/telephony/java/android/telephony/data/SlicingConfig.java
new file mode 100644
index 0000000..990e4d2
--- /dev/null
+++ b/telephony/java/android/telephony/data/SlicingConfig.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents a slicing configuration
+ */
+public final class SlicingConfig implements Parcelable {
+ private final List<UrspRule> mUrspRules;
+ private final List<NetworkSliceInfo> mSliceInfo;
+
+ public SlicingConfig() {
+ mUrspRules = new ArrayList<UrspRule>();
+ mSliceInfo = new ArrayList<NetworkSliceInfo>();
+ }
+
+ /** @hide */
+ public SlicingConfig(android.hardware.radio.V1_6.SlicingConfig sc) {
+ this(sc.urspRules, sc.sliceInfo);
+ }
+
+ /** @hide */
+ public SlicingConfig(List<android.hardware.radio.V1_6.UrspRule> urspRules,
+ List<android.hardware.radio.V1_6.SliceInfo> sliceInfo) {
+ mUrspRules = new ArrayList<UrspRule>();
+ for (android.hardware.radio.V1_6.UrspRule ur : urspRules) {
+ mUrspRules.add(new UrspRule(ur.precedence, ur.trafficDescriptors,
+ ur.routeSelectionDescriptor));
+ }
+ mSliceInfo = new ArrayList<NetworkSliceInfo>();
+ for (android.hardware.radio.V1_6.SliceInfo si : sliceInfo) {
+ mSliceInfo.add(sliceInfoBuilder(si));
+ }
+ }
+
+ private NetworkSliceInfo sliceInfoBuilder(android.hardware.radio.V1_6.SliceInfo si) {
+ NetworkSliceInfo.Builder builder = new NetworkSliceInfo.Builder()
+ .setSliceServiceType(si.sst)
+ .setMappedHplmnSliceServiceType(si.mappedHplmnSst);
+ if (si.sliceDifferentiator != NetworkSliceInfo.SLICE_DIFFERENTIATOR_NO_SLICE) {
+ builder
+ .setSliceDifferentiator(si.sliceDifferentiator)
+ .setMappedHplmnSliceDifferentiator(si.mappedHplmnSD);
+ }
+ return builder.build();
+ }
+
+ /** @hide */
+ public SlicingConfig(Parcel p) {
+ mUrspRules = p.createTypedArrayList(UrspRule.CREATOR);
+ mSliceInfo = p.createTypedArrayList(NetworkSliceInfo.CREATOR);
+ }
+
+ /**
+ * This list contains the current URSP rules. Empty list represents that no rules are
+ * configured.
+ * @return the current URSP rules for this slicing configuration.
+ */
+ public @NonNull List<UrspRule> getUrspRules() {
+ return mUrspRules;
+ }
+
+ /**
+ * @return the list of all slices for this slicing configuration.
+ */
+ public @NonNull List<NetworkSliceInfo> getSliceInfo() {
+ return mSliceInfo;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeTypedList(mUrspRules, flags);
+ dest.writeTypedList(mSliceInfo, flags);
+ }
+
+ public static final @NonNull Parcelable.Creator<SlicingConfig> CREATOR =
+ new Parcelable.Creator<SlicingConfig>() {
+ @Override
+ public SlicingConfig createFromParcel(Parcel source) {
+ return new SlicingConfig(source);
+ }
+
+ @Override
+ public SlicingConfig[] newArray(int size) {
+ return new SlicingConfig[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SlicingConfig that = (SlicingConfig) o;
+ return mUrspRules.size() == that.mUrspRules.size()
+ && mUrspRules.containsAll(that.mUrspRules)
+ && mSliceInfo.size() == that.mSliceInfo.size()
+ && mSliceInfo.containsAll(that.mSliceInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUrspRules, mSliceInfo);
+ }
+
+ @Override
+ public String toString() {
+ return "{.urspRules = " + mUrspRules + ", .sliceInfo = " + mSliceInfo + "}";
+ }
+}
diff --git a/telephony/java/android/telephony/data/TrafficDescriptor.java b/telephony/java/android/telephony/data/TrafficDescriptor.java
index 480379d..d813bc5 100644
--- a/telephony/java/android/telephony/data/TrafficDescriptor.java
+++ b/telephony/java/android/telephony/data/TrafficDescriptor.java
@@ -18,20 +18,17 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
- * A traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2. It is used for URSP traffic
- * matching as described in 3GPP TS 24.526 Section 4.2.2. It includes an optional DNN, which,
- * if present, must be used for traffic matching; it does not specify the end point to be used for
- * the data call.
- * @hide
+ * A traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2. It is used for UE Route Selection
+ * Policy(URSP) traffic matching as described in 3GPP TS 24.526 Section 4.2.2. It includes an
+ * optional Data Network Name(DNN), which, if present, must be used for traffic matching; it does
+ * not specify the end point to be used for the data call.
*/
-@SystemApi
public final class TrafficDescriptor implements Parcelable {
private final String mDnn;
private final String mOsAppId;
@@ -45,8 +42,10 @@
* Create a traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2
* @param dnn optional DNN, which must be used for traffic matching, if present
* @param osAppId OsId + osAppId of the traffic descriptor
+ *
+ * @hide
*/
- public TrafficDescriptor(@Nullable String dnn, @Nullable String osAppId) {
+ public TrafficDescriptor(String dnn, String osAppId) {
mDnn = dnn;
mOsAppId = osAppId;
}
@@ -55,12 +54,13 @@
* DNN stands for Data Network Name and represents an APN as defined in 3GPP TS 23.003.
* @return the DNN of this traffic descriptor.
*/
- public @Nullable String getDnn() {
+ public @Nullable String getDataNetworkName() {
return mDnn;
}
/**
- * OsAppId represents the OsId + OsAppId as defined in 3GPP TS 24.526 Section 5.2.
+ * OsAppId is the app id as defined in 3GPP TS 24.526 Section 5.2, and it identifies a traffic
+ * category.
* @return the OS App ID of this traffic descriptor.
*/
public @Nullable String getOsAppId() {
@@ -108,4 +108,65 @@
public int hashCode() {
return Objects.hash(mDnn, mOsAppId);
}
+
+ /**
+ * Provides a convenient way to set the fields of a {@link TrafficDescriptor} when creating a
+ * new instance.
+ *
+ * <p>The example below shows how you might create a new {@code TrafficDescriptor}:
+ *
+ * <pre><code>
+ *
+ * TrafficDescriptor response = new TrafficDescriptor.Builder()
+ * .setDnn("")
+ * .build();
+ * </code></pre>
+ */
+ public static final class Builder {
+ private String mDnn = null;
+ private String mOsAppId = null;
+
+ /**
+ * Default constructor for Builder.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Set the Data Network Name(DNN).
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setDataNetworkName(@NonNull String dnn) {
+ this.mDnn = dnn;
+ return this;
+ }
+
+ /**
+ * Set the OS App ID.
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setOsAppId(@NonNull String osAppId) {
+ this.mOsAppId = osAppId;
+ return this;
+ }
+
+ /**
+ * Build the {@link TrafficDescriptor}.
+ *
+ * @throws IllegalArgumentException if DNN and OS App ID are null.
+ *
+ * @return the {@link TrafficDescriptor} object.
+ */
+ @NonNull
+ public TrafficDescriptor build() {
+ if (this.mDnn == null && this.mOsAppId == null) {
+ throw new IllegalArgumentException("DNN and OS App ID are null");
+ }
+ return new TrafficDescriptor(this.mDnn, this.mOsAppId);
+ }
+ }
}
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/telephony/java/android/telephony/data/UrspRule.aidl
similarity index 87%
copy from telephony/java/android/telephony/data/SliceInfo.aidl
copy to telephony/java/android/telephony/data/UrspRule.aidl
index 286ea5e..2bed583 100644
--- a/telephony/java/android/telephony/data/SliceInfo.aidl
+++ b/telephony/java/android/telephony/data/UrspRule.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** @hide */
package android.telephony.data;
-parcelable SliceInfo;
+parcelable UrspRule;
diff --git a/telephony/java/android/telephony/data/UrspRule.java b/telephony/java/android/telephony/data/UrspRule.java
new file mode 100644
index 0000000..e2c47fd
--- /dev/null
+++ b/telephony/java/android/telephony/data/UrspRule.java
@@ -0,0 +1,178 @@
+/**
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.radio.V1_6.OptionalDnn;
+import android.hardware.radio.V1_6.OptionalOsAppId;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents a single URSP rule as defined in 3GPP TS 24.526. URSP stands for UE Route Selection
+ * Policy. In 5G, network can provide URSP information to devices which provides information on
+ * what connection parameters should be used for what traffic.
+ */
+public final class UrspRule implements Parcelable {
+ /**
+ * The min acceptable value for the precedence of a URSP rule.
+ * @hide
+ */
+ public static final int MIN_URSP_PRECEDENCE = 0;
+
+ /**
+ * The max acceptable value for the precedence of a URSP rule.
+ * @hide
+ */
+ public static final int MAX_URSP_PRECEDENCE = 255;
+
+ @IntRange(from = MIN_URSP_PRECEDENCE, to = MAX_URSP_PRECEDENCE)
+ private final int mPrecedence;
+ private final List<TrafficDescriptor> mTrafficDescriptors;
+ private final List<RouteSelectionDescriptor> mRouteSelectionDescriptor;
+
+ UrspRule(android.hardware.radio.V1_6.UrspRule ur) {
+ this(ur.precedence, ur.trafficDescriptors, ur.routeSelectionDescriptor);
+ }
+
+ /** @hide */
+ public UrspRule(int precedence,
+ List<android.hardware.radio.V1_6.TrafficDescriptor> trafficDescriptors,
+ List<android.hardware.radio.V1_6.RouteSelectionDescriptor> routeSelectionDescriptor) {
+ mPrecedence = precedence;
+ mTrafficDescriptors = new ArrayList<TrafficDescriptor>();
+ for (android.hardware.radio.V1_6.TrafficDescriptor td : trafficDescriptors) {
+ mTrafficDescriptors.add(convertToTrafficDescriptor(td));
+ }
+ mRouteSelectionDescriptor = new ArrayList<RouteSelectionDescriptor>();
+ for (android.hardware.radio.V1_6.RouteSelectionDescriptor rsd : routeSelectionDescriptor) {
+ mRouteSelectionDescriptor.add(new RouteSelectionDescriptor(rsd));
+ }
+ }
+
+ /** Convert an ArrayList of Bytes to an exactly-sized primitive array */
+ private byte[] arrayListToPrimitiveArray(ArrayList<Byte> bytes) {
+ byte[] ret = new byte[bytes.size()];
+ for (int i = 0; i < ret.length; i++) {
+ ret[i] = bytes.get(i);
+ }
+ return ret;
+ }
+
+ private TrafficDescriptor convertToTrafficDescriptor(
+ android.hardware.radio.V1_6.TrafficDescriptor td) {
+ String dnn = td.dnn.getDiscriminator() == OptionalDnn.hidl_discriminator.noinit
+ ? null : td.dnn.value();
+ String osAppId = td.osAppId.getDiscriminator() == OptionalOsAppId.hidl_discriminator.noinit
+ ? null : new String(arrayListToPrimitiveArray(td.osAppId.value().osAppId));
+ TrafficDescriptor.Builder builder = new TrafficDescriptor.Builder();
+ if (dnn != null) {
+ builder.setDataNetworkName(dnn);
+ }
+ if (osAppId != null) {
+ builder.setOsAppId(osAppId);
+ }
+ return builder.build();
+ }
+
+ private UrspRule(Parcel p) {
+ mPrecedence = p.readInt();
+ mTrafficDescriptors = p.createTypedArrayList(TrafficDescriptor.CREATOR);
+ mRouteSelectionDescriptor = p.createTypedArrayList(RouteSelectionDescriptor.CREATOR);
+ }
+
+ /**
+ * Precedence value in the range of 0 to 255. Higher value has lower precedence.
+ * @return the precedence value for this URSP rule.
+ */
+ @IntRange(from = MIN_URSP_PRECEDENCE, to = MAX_URSP_PRECEDENCE)
+ public int getPrecedence() {
+ return mPrecedence;
+ }
+
+ /**
+ * These traffic descriptors are used as a matcher for network requests.
+ * @return the traffic descriptors which are associated to this URSP rule.
+ */
+ public @NonNull List<TrafficDescriptor> getTrafficDescriptors() {
+ return mTrafficDescriptors;
+ }
+
+ /**
+ * List of routes (connection parameters) that must be used by the device for requests matching
+ * a traffic descriptor.
+ * @return the route selection descriptors which are associated to this URSP rule.
+ */
+ public @NonNull List<RouteSelectionDescriptor> getRouteSelectionDescriptor() {
+ return mRouteSelectionDescriptor;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mPrecedence);
+ dest.writeTypedList(mTrafficDescriptors, flags);
+ dest.writeTypedList(mRouteSelectionDescriptor, flags);
+ }
+
+ public static final @NonNull Parcelable.Creator<UrspRule> CREATOR =
+ new Parcelable.Creator<UrspRule>() {
+ @Override
+ public UrspRule createFromParcel(Parcel source) {
+ return new UrspRule(source);
+ }
+
+ @Override
+ public UrspRule[] newArray(int size) {
+ return new UrspRule[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UrspRule that = (UrspRule) o;
+ return mPrecedence == that.mPrecedence
+ && mTrafficDescriptors.size() == that.mTrafficDescriptors.size()
+ && mTrafficDescriptors.containsAll(that.mTrafficDescriptors)
+ && mRouteSelectionDescriptor.size() == that.mRouteSelectionDescriptor.size()
+ && mRouteSelectionDescriptor.containsAll(that.mRouteSelectionDescriptor);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPrecedence, mTrafficDescriptors, mRouteSelectionDescriptor);
+ }
+
+ @Override
+ public String toString() {
+ return "{.precedence = " + mPrecedence + ", .trafficDescriptors = " + mTrafficDescriptors
+ + ", .routeSelectionDescriptor = " + mRouteSelectionDescriptor + "}";
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index 0aff997..dfe5e6c9 100755
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -766,7 +766,10 @@
* The method is only valid to call when the session state is in
* {@link ImsCallSession.State#IDLE}.
*
- * @param callee dialed string to make the call to
+ * @param callee dial string to make the call to. The platform passes the dialed number
+ * entered by the user as-is. The {@link ImsService} should ensure that the
+ * number is formatted in SIP messages appropriately (e.g. using
+ * {@link android.telephony.PhoneNumberUtils#formatNumberToE164(String, String)}).
* @param profile call profile to make the call with the specified service type,
* call type and media information
* @see Listener#callSessionStarted, Listener#callSessionStartFailed
@@ -788,7 +791,10 @@
* The method is only valid to call when the session state is in
* {@link ImsCallSession.State#IDLE}.
*
- * @param participants participant list to initiate an IMS conference call
+ * @param participants participant list to initiate an IMS conference call. The platform passes
+ * the dialed numbers entered by the user as-is. The {@link ImsService} should
+ * ensure that the number is formatted in SIP messages appropriately (e.g. using
+ * {@link android.telephony.PhoneNumberUtils#formatNumberToE164(String, String)}).
* @param profile call profile to make the call with the specified service type,
* call type and media information
* @see Listener#callSessionStarted, Listener#callSessionStartFailed
diff --git a/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
index 1a1c7f8..43273a4 100755
--- a/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
@@ -25,6 +25,7 @@
{
void onError(int errorCode, String message);
+ @SuppressWarnings(value={"untyped-collection"})
void onAvailableSaisUpdated(in List currentSai, in List availableSais);
void onServiceInterfaceAvailable(String interfaceName, int index);
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
index 44cc24a..6e139ac 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
@@ -29,9 +29,11 @@
void stopGroupCall(int subId, long tmgi);
+ @SuppressWarnings(value={"untyped-collection"})
void updateGroupCall(int subscriptionId, long tmgi, in List saiList,
in List frequencyList);
+ @SuppressWarnings(value={"untyped-collection"})
int startGroupCall(int subscriptionId, long tmgi, in List saiList,
in List frequencyList, IGroupCallCallback callback);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 9b2f119..d812b46 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1961,6 +1961,7 @@
/**
* Return the emergency number list from all the active subscriptions.
*/
+ @SuppressWarnings(value={"untyped-collection"})
Map getEmergencyNumberList(String callingPackage, String callingFeatureId);
/**
@@ -2446,4 +2447,10 @@
* Gets the current phone capability.
*/
PhoneCapability getPhoneCapability();
+
+ /**
+ * Request to get the current slicing configuration including URSP rules and
+ * NSSAIs (configured, allowed and rejected).
+ */
+ void getSlicingConfig(in ResultReceiver callback);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 822fc44..fe8e671 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -527,6 +527,7 @@
int RIL_REQUEST_SET_DATA_THROTTLING = 221;
int RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP = 222;
int RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP = 223;
+ int RIL_REQUEST_GET_SLICING_CONFIG = 224;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 460a26d..0bb6198 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -32,7 +32,9 @@
":android-test-mock-sources",
// Note: Below are NOT APIs of this library. We only take APIs under
// the android.test.mock package. They however provide private APIs that
- // android.test.mock APIs references to.
+ // android.test.mock APIs references to. We need to have the classes in
+ // source code form to have access to the @hide comment which disappears
+ // when the classes are compiled into a Jar library.
":framework-core-sources-for-test-mock",
":framework_native_aidl",
],
@@ -46,6 +48,14 @@
api_packages: [
"android.test.mock",
],
+ // Only include android.test.mock.* classes. Jarjar rules below removes
+ // classes in other packages like android.content. In order to keep the
+ // list up-to-date, permitted_packages ensures that the library contains
+ // clases under android.test.mock after the jarjar rules are applied.
+ jarjar_rules: "jarjar-rules.txt",
+ permitted_packages: [
+ "android.test.mock",
+ ],
compile_dex: true,
default_to_stubs: true,
dist_group: "android",
diff --git a/test-mock/jarjar-rules.txt b/test-mock/jarjar-rules.txt
new file mode 100644
index 0000000..4420a44
--- /dev/null
+++ b/test-mock/jarjar-rules.txt
@@ -0,0 +1,7 @@
+zap android.accounts.**
+zap android.app.**
+zap android.content.**
+zap android.database.**
+zap android.os.**
+zap android.util.**
+zap android.view.**
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 243c301..086ef95 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -25,14 +25,24 @@
name: "StagedInstallInternalTestApp",
manifest: "app/AndroidManifest.xml",
srcs: ["app/src/**/*.java"],
- static_libs: ["androidx.test.rules", "cts-install-lib"],
+ static_libs: [
+ "androidx.test.rules",
+ "cts-install-lib",
+ ],
test_suites: ["general-tests"],
+ java_resources: [
+ ":StagedInstallTestApexV2",
+ ],
+ platform_apis: true,
}
java_test_host {
name: "StagedInstallInternalTest",
srcs: ["src/**/*.java"],
- libs: ["tradefed", "cts-shim-host-lib"],
+ libs: [
+ "tradefed",
+ "cts-shim-host-lib",
+ ],
static_libs: [
"testng",
"compatibility-tradefed",
@@ -40,7 +50,7 @@
"cts-install-lib-host",
],
data: [
- ":com.android.apex.cts.shim.v2_prebuilt",
+ ":StagedInstallTestApexV2",
":TestAppAv1",
],
test_suites: ["general-tests"],
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index e673549..a0f4e0a 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -17,12 +17,24 @@
package com.android.tests.stagedinstallinternal;
import static com.android.cts.install.lib.InstallUtils.getPackageInstaller;
+import static com.android.cts.install.lib.InstallUtils.waitForSessionReady;
+import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
import android.Manifest;
+import android.content.pm.ApexStagedEvent;
+import android.content.pm.IPackageManagerNative;
+import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInstaller;
+import android.content.pm.StagedApexInfo;
+import android.os.IBinder;
+import android.os.ServiceManager;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -35,6 +47,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -50,6 +64,10 @@
private static final String TAG = StagedInstallInternalTest.class.getSimpleName();
+ private static final TestApp APEX_V2 = new TestApp(
+ "ApexV2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true,
+ "com.android.apex.cts.shim.v2.apex");
+
private File mTestStateFile = new File(
InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(),
"stagedinstall_state");
@@ -109,6 +127,72 @@
Install.multi(TestApp.AIncompleteSplit, TestApp.B1, TestApp.Apex1).setStaged());
}
+ @Test
+ public void testGetStagedModuleNames() throws Exception {
+ // Before staging a session
+ String[] result = getPackageManagerNative().getStagedApexModuleNames();
+ assertThat(result).hasLength(0);
+ // Stage an apex
+ int sessionId = Install.single(APEX_V2).setStaged().commit();
+ waitForSessionReady(sessionId);
+ result = getPackageManagerNative().getStagedApexModuleNames();
+ assertThat(result).hasLength(1);
+ assertThat(result).isEqualTo(new String[]{SHIM_APEX_PACKAGE_NAME});
+ // Abandon the session
+ InstallUtils.openPackageInstallerSession(sessionId).abandon();
+ result = getPackageManagerNative().getStagedApexModuleNames();
+ assertThat(result).hasLength(0);
+ }
+
+ @Test
+ public void testGetStagedApexInfo() throws Exception {
+ // Ask for non-existing module
+ StagedApexInfo result = getPackageManagerNative().getStagedApexInfo("not found");
+ assertThat(result).isNull();
+ // Stage an apex
+ int sessionId = Install.single(APEX_V2).setStaged().commit();
+ waitForSessionReady(sessionId);
+ // Query proper module name
+ result = getPackageManagerNative().getStagedApexInfo(SHIM_APEX_PACKAGE_NAME);
+ assertThat(result.moduleName).isEqualTo(SHIM_APEX_PACKAGE_NAME);
+ InstallUtils.openPackageInstallerSession(sessionId).abandon();
+ }
+
+ public static class MockStagedApexObserver extends IStagedApexObserver.Stub {
+ @Override
+ public void onApexStaged(ApexStagedEvent event) {
+ assertThat(event).isNotNull();
+ }
+ }
+
+ @Test
+ public void testStagedApexObserver() throws Exception {
+ MockStagedApexObserver realObserver = new MockStagedApexObserver();
+ IStagedApexObserver observer = spy(realObserver);
+ assertThat(observer).isNotNull();
+ getPackageManagerNative().registerStagedApexObserver(observer);
+
+ // Stage an apex and verify observer was called
+ int sessionId = Install.single(APEX_V2).setStaged().commit();
+ waitForSessionReady(sessionId);
+ ArgumentCaptor<ApexStagedEvent> captor = ArgumentCaptor.forClass(ApexStagedEvent.class);
+ verify(observer, timeout(5000)).onApexStaged(captor.capture());
+ assertThat(captor.getValue().stagedApexModuleNames).isEqualTo(
+ new String[] {SHIM_APEX_PACKAGE_NAME});
+
+ // Abandon and verify observer is called
+ Mockito.clearInvocations(observer);
+ InstallUtils.openPackageInstallerSession(sessionId).abandon();
+ verify(observer, timeout(5000)).onApexStaged(captor.capture());
+ assertThat(captor.getValue().stagedApexModuleNames).hasLength(0);
+ }
+
+ private IPackageManagerNative getPackageManagerNative() {
+ IBinder binder = ServiceManager.waitForService("package_native");
+ assertThat(binder).isNotNull();
+ return IPackageManagerNative.Stub.asInterface(binder);
+ }
+
private static void assertSessionReady(int sessionId) {
assertSessionState(sessionId,
(session) -> assertThat(session.isStagedSessionReady()).isTrue());
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index dddb317..f92c31c 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -216,6 +216,21 @@
assertThat(getStagingDirectories()).isEmpty();
}
+ @Test
+ public void testGetStagedModuleNames() throws Exception {
+ runPhase("testGetStagedModuleNames");
+ }
+
+ @Test
+ public void testGetStagedApexInfo() throws Exception {
+ runPhase("testGetStagedApexInfo");
+ }
+
+ @Test
+ public void testStagedApexObserver() throws Exception {
+ runPhase("testStagedApexObserver");
+ }
+
private List<String> getStagingDirectories() throws DeviceNotAvailableException {
String baseDir = "/data/app-staging";
try {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 0f84f6e..c9a8947a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -322,6 +322,7 @@
triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
verify(mSafeModeTimeoutAlarm).cancel();
assertFalse(mGatewayConnection.isInSafeMode());
+ verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */);
}
@Test
@@ -391,6 +392,7 @@
triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
+ verifySafeModeStateAndCallbackFired(2 /* invocationCount */, false /* isInSafeMode */);
assertFalse(mGatewayConnection.isInSafeMode());
}
@@ -400,7 +402,7 @@
mTestLooper.dispatchAll();
triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
- assertFalse(mGatewayConnection.isInSafeMode());
+ verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */);
// Trigger a failed validation, and the subsequent safemode timeout.
triggerValidation(NetworkAgent.VALIDATION_STATUS_NOT_VALID);
@@ -416,7 +418,7 @@
runnableCaptor.getValue().run();
mTestLooper.dispatchAll();
- assertTrue(mGatewayConnection.isInSafeMode());
+ verifySafeModeStateAndCallbackFired(2 /* invocationCount */, true /* isInSafeMode */);
}
private Consumer<VcnNetworkAgent> setupNetworkAndGetUnwantedCallback() {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index a696b3a..64d0bca 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -23,7 +23,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
@@ -301,6 +300,11 @@
expectCanceled);
}
+ protected void verifySafeModeStateAndCallbackFired(int invocationCount, boolean isInSafeMode) {
+ verify(mGatewayStatusCallback, times(invocationCount)).onSafeModeStatusChanged();
+ assertEquals(isInSafeMode, mGatewayConnection.isInSafeMode());
+ }
+
protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
@NonNull State expectedState) {
// Set a VcnNetworkAgent, and expect it to be unregistered and cleared
@@ -314,9 +318,8 @@
delayedEvent.run();
mTestLooper.dispatchAll();
- verify(mGatewayStatusCallback).onSafeModeStatusChanged();
assertEquals(expectedState, mGatewayConnection.getCurrentState());
- assertTrue(mGatewayConnection.isInSafeMode());
+ verifySafeModeStateAndCallbackFired(1, true);
verify(mockNetworkAgent).unregister();
assertNull(mGatewayConnection.getNetworkAgent());
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 672731c..899d268 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -319,12 +319,10 @@
// The second subtag can either be a script or a region code.
// If its size is 4, it's a script code, else it's a region code.
- bool hasRegion = false;
if (subtags[1].size() == 4) {
setScript(subtags[1]);
} else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
setRegion(subtags[1]);
- hasRegion = true;
} else {
fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n", part.string());
return -1;
diff --git a/tools/aapt/Android.bp b/tools/aapt/Android.bp
index c75ba71..cf5f313 100644
--- a/tools/aapt/Android.bp
+++ b/tools/aapt/Android.bp
@@ -50,7 +50,6 @@
"libbase",
"libz",
],
- group_static_libs: true,
cflags: [
"-Wall",
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 257e96b..b9de11b 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2475,11 +2475,10 @@
{
if (accessorCookie != NULL && fmt != NULL) {
AccessorCookie* ac = (AccessorCookie*)accessorCookie;
- int retval=0;
char buf[1024];
va_list ap;
va_start(ap, fmt);
- retval = vsnprintf(buf, sizeof(buf), fmt, ap);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
ac->sourcePos.error("Error: %s (at '%s' with value '%s').\n",
buf, ac->attr.string(), ac->value.string());
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 5c5b3c3..5de0a63 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -72,7 +72,6 @@
"libidmap2_policies",
],
stl: "libc++_static",
- group_static_libs: true,
}
// ==========================================================
@@ -196,9 +195,9 @@
],
defaults: ["aapt2_defaults"],
data: [
- "integration-tests/CompileTest/**/*",
- "integration-tests/CommandTests/**/*",
- "integration-tests/ConvertTest/**/*"
+ "integration-tests/CompileTest/**/*",
+ "integration-tests/CommandTests/**/*",
+ "integration-tests/ConvertTest/**/*",
],
}
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index d56994e..97e4436 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -148,7 +148,7 @@
diff = true;
}
}
- return false;
+ return diff;
}
static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index 3960856f..d345422 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -35,6 +35,7 @@
echo
echo "If your change contains no confidential details (such as security fixes), please"
echo "upload and merge this change at https://android-review.googlesource.com/."
+ echo "Else add a tag 'Ignore-AOSP-First:' with the reason to bypass AOSP."
echo
exit 1
fi
diff --git a/tools/bit/print.cpp b/tools/bit/print.cpp
index 35feda1..8bc6f16 100644
--- a/tools/bit/print.cpp
+++ b/tools/bit/print.cpp
@@ -17,6 +17,7 @@
#include "print.h"
#include <sys/ioctl.h>
+#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/tools/bit/util.h b/tools/bit/util.h
index 7ccdab1..8c66911 100644
--- a/tools/bit/util.h
+++ b/tools/bit/util.h
@@ -17,6 +17,8 @@
#ifndef UTIL_H
#define UTIL_H
+#include <sys/types.h>
+
#include <map>
#include <string>
#include <vector>
diff --git a/tools/lint/OWNERS b/tools/lint/OWNERS
new file mode 100644
index 0000000..7c04519
--- /dev/null
+++ b/tools/lint/OWNERS
@@ -0,0 +1,5 @@
+brufino@google.com
+jsharkey@google.com
+
+per-file *CallingSettingsNonUserGetterMethods* = file:/packages/SettingsProvider/OWNERS
+
diff --git a/tools/split-select/Android.bp b/tools/split-select/Android.bp
index c12fc6a..5402657 100644
--- a/tools/split-select/Android.bp
+++ b/tools/split-select/Android.bp
@@ -48,7 +48,6 @@
"libbase",
"libz",
],
- group_static_libs: true,
target: {
windows: {
diff --git a/tools/streaming_proto/Errors.cpp b/tools/streaming_proto/Errors.cpp
index 0cd9037..6890d99 100644
--- a/tools/streaming_proto/Errors.cpp
+++ b/tools/streaming_proto/Errors.cpp
@@ -1,5 +1,6 @@
#include "Errors.h"
+#include <stdarg.h>
#include <stdlib.h>
namespace android {