Merge "Update constructors for IRadioData classes"
diff --git a/.gitignore b/.gitignore
index c47cc8b..2dffb7a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.idea
+.project
*.iml
*.sw*
gen/
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 1ea269f..d5a81c4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -118,7 +118,6 @@
":libbluetooth-binder-aidl",
":libcamera_client_aidl",
":libcamera_client_framework_aidl",
- ":packagemanager_aidl",
":libupdate_engine_aidl",
":resourcemanager_aidl",
":storaged_aidl",
@@ -209,6 +208,7 @@
name: "framework-internal-utils",
static_libs: [
"apex_aidl_interface-java",
+ "packagemanager_aidl-java",
"framework-protos",
"updatable-driver-protos",
"ota_metadata_proto_java",
diff --git a/OWNERS b/OWNERS
index ab5bd18..47d8c83 100644
--- a/OWNERS
+++ b/OWNERS
@@ -29,10 +29,7 @@
# Support bulk translation updates
per-file */res*/values*/*.xml = byi@google.com, delphij@google.com
-per-file Android.bp = file:platform/build/soong:/OWNERS
-per-file Android.mk = file:platform/build/soong:/OWNERS
-per-file ApiDocs.bp = file:platform/build/soong:/OWNERS
-per-file StubLibraries.bp = file:platform/build/soong:/OWNERS
-per-file ProtoLibraries.bp = file:platform/build/soong:/OWNERS
+per-file *.bp = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION}
+per-file Android.mk = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION}
per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS
per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS
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/api/Android.bp b/api/Android.bp
index 8dff60af..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,17 +50,28 @@
"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,
},
}
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/core/api/current.txt b/core/api/current.txt
index e4e7d4e..4d89cdf 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10253,6 +10253,8 @@
field public static final String NSD_SERVICE = "servicediscovery";
field public static final String POWER_SERVICE = "power";
field public static final String PRINT_SERVICE = "print";
+ field public static final int RECEIVER_EXPORTED = 2; // 0x2
+ field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
field public static final String RESTRICTIONS_SERVICE = "restrictions";
field public static final String ROLE_SERVICE = "role";
@@ -29976,6 +29978,7 @@
method public boolean hasFileDescriptors();
method public byte[] marshall();
method @NonNull public static android.os.Parcel obtain();
+ method @NonNull public static android.os.Parcel obtain(@NonNull android.os.IBinder);
method @Nullable public Object[] readArray(@Nullable ClassLoader);
method @Nullable public java.util.ArrayList readArrayList(@Nullable ClassLoader);
method public void readBinderArray(@NonNull android.os.IBinder[]);
@@ -29998,12 +30001,15 @@
method public int readInt();
method public void readIntArray(@NonNull int[]);
method public void readList(@NonNull java.util.List, @Nullable ClassLoader);
+ method public <T> void readList(@NonNull java.util.List<? super T>, @Nullable ClassLoader, @NonNull Class<T>);
method public long readLong();
method public void readLongArray(@NonNull long[]);
method public void readMap(@NonNull java.util.Map, @Nullable ClassLoader);
method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
+ method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader, @NonNull Class<T>);
method @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader);
method @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader);
+ method @Nullable public <T> android.os.Parcelable.Creator<T> readParcelableCreator(@Nullable ClassLoader, @NonNull Class<T>);
method @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader);
method @Nullable public android.os.PersistableBundle readPersistableBundle();
method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
@@ -30142,7 +30148,7 @@
public interface Parcelable {
method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int CONTENTS_FILE_DESCRIPTOR = 1; // 0x1
field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index e601583..a61851d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1861,6 +1861,7 @@
method @Nullable public abstract java.io.File getPreloadsFileCache();
method public abstract boolean isCredentialProtectedStorage();
method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler);
+ method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
method public abstract void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 949ba6a..3b2d883 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -332,12 +332,7 @@
filegroup {
name: "framework-cellbroadcast-shared-srcs",
srcs: [
- "android/os/HandlerExecutor.java",
"android/util/LocalLog.java",
- "com/android/internal/util/IState.java",
- "com/android/internal/util/Preconditions.java",
- "com/android/internal/util/State.java",
- "com/android/internal/util/StateMachine.java",
],
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 749e8f5..7c140d6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3724,7 +3724,6 @@
Intent intent = new Intent(activityIntent);
intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
- intent.removeUnsafeExtras();
content.setDefaultIntent(intent);
}
} else {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 12c9cd9..14fb245 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1635,12 +1635,26 @@
}
@Override
+ public Intent registerReceiverForAllUsers(BroadcastReceiver receiver,
+ IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+ return registerReceiverAsUser(receiver, UserHandle.ALL,
+ filter, broadcastPermission, scheduler, flags);
+ }
+
+ @Override
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
IntentFilter filter, String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, user.getIdentifier(),
filter, broadcastPermission, scheduler, getOuterContext(), 0);
}
+ @Override
+ public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+ IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+ return registerReceiverInternal(receiver, user.getIdentifier(),
+ filter, broadcastPermission, scheduler, getOuterContext(), flags);
+ }
+
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 4293ab0..b4a4c90 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -483,8 +483,8 @@
| Context.BIND_NOT_PERCEPTIBLE | Context.BIND_NOT_VISIBLE;
/** @hide */
- @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE_" }, value = {
- RECEIVER_VISIBLE_TO_INSTANT_APPS
+ @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE" }, value = {
+ RECEIVER_VISIBLE_TO_INSTANT_APPS, RECEIVER_EXPORTED, RECEIVER_NOT_EXPORTED
})
@Retention(RetentionPolicy.SOURCE)
public @interface RegisterReceiverFlags {}
@@ -495,6 +495,18 @@
public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 0x1;
/**
+ * Flag for {@link #registerReceiver}: The receiver can receive broadcasts from other Apps.
+ * Has the same behavior as marking a statically registered receiver with "exported=true"
+ */
+ public static final int RECEIVER_EXPORTED = 0x2;
+
+ /**
+ * Flag for {@link #registerReceiver}: The receiver cannot receive broadcasts from other Apps.
+ * Has the same behavior as marking a statically registered receiver with "exported=false"
+ */
+ public static final int RECEIVER_NOT_EXPORTED = 0x4;
+
+ /**
* Returns an AssetManager instance for the application's package.
* <p>
* <strong>Note:</strong> Implementations of this method should return
@@ -2881,8 +2893,12 @@
*
* @param receiver The BroadcastReceiver to handle the broadcast.
* @param filter Selects the Intent broadcasts to be received.
- * @param flags Additional options for the receiver. May be 0 or
- * {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
+ * @param flags Additional options for the receiver. As of
+ * Android T, either {@link #RECEIVER_EXPORTED} or
+ * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
+ * for protected broadcasts, and may additionally specify
+ * {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
+ * specified.
*
* @return The first sticky intent found that matches <var>filter</var>,
* or null if there are none.
@@ -2954,8 +2970,12 @@
* no permission is required.
* @param scheduler Handler identifying the thread that will receive
* the Intent. If null, the main thread of the process will be used.
- * @param flags Additional options for the receiver. May be 0 or
- * {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
+ * @param flags Additional options for the receiver. As of
+ * Android T, either {@link #RECEIVER_EXPORTED} or
+ * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
+ * for protected broadcasts, and may additionally specify
+ * {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
+ * specified.
*
* @return The first sticky intent found that matches <var>filter</var>,
* or null if there are none.
@@ -3002,6 +3022,42 @@
}
/**
+ * Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler, int)}
+ * but this receiver will receive broadcasts that are sent to all users. The receiver can
+ * use {@link BroadcastReceiver#getSendingUser} to determine on which user the broadcast
+ * was sent.
+ *
+ * @param receiver The BroadcastReceiver to handle the broadcast.
+ * @param filter Selects the Intent broadcasts to be received.
+ * @param broadcastPermission String naming a permissions that a
+ * broadcaster must hold in order to send an Intent to you. If {@code null},
+ * no permission is required.
+ * @param scheduler Handler identifying the thread that will receive
+ * the Intent. If {@code null}, the main thread of the process will be used.
+ * @param flags Additional options for the receiver. As of
+ * Android T, either {@link #RECEIVER_EXPORTED} or
+ * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being
+ * registered for protected broadcasts
+ *
+ * @return The first sticky intent found that matches <var>filter</var>,
+ * or {@code null} if there are none.
+ *
+ * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler, int)
+ * @see #sendBroadcast
+ * @see #unregisterReceiver
+ * @hide
+ */
+ @SuppressLint("IntentBuilderName")
+ @Nullable
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ @SystemApi
+ public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
+ @NonNull IntentFilter filter, @Nullable String broadcastPermission,
+ @Nullable Handler scheduler, @RegisterReceiverFlags int flags) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* @hide
* Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
* but for a specific user. This receiver will receiver broadcasts that
@@ -3032,6 +3088,41 @@
@Nullable Handler scheduler);
/**
+ * @hide
+ * Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler, int)
+ * but for a specific user. This receiver will receiver broadcasts that
+ * are sent to the requested user.
+ *
+ * @param receiver The BroadcastReceiver to handle the broadcast.
+ * @param user UserHandle to send the intent to.
+ * @param filter Selects the Intent broadcasts to be received.
+ * @param broadcastPermission String naming a permissions that a
+ * broadcaster must hold in order to send an Intent to you. If null,
+ * no permission is required.
+ * @param scheduler Handler identifying the thread that will receive
+ * the Intent. If null, the main thread of the process will be used.
+ * @param flags Additional options for the receiver. As of
+ * Android T, either {@link #RECEIVER_EXPORTED} or
+ * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being
+ * registered for protected broadcasts
+ *
+ * @return The first sticky intent found that matches <var>filter</var>,
+ * or null if there are none.
+ *
+ * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler, int)
+ * @see #sendBroadcast
+ * @see #unregisterReceiver
+ */
+ @SuppressWarnings("HiddenAbstractMethod")
+ @SuppressLint("IntentBuilderName")
+ @Nullable
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ @UnsupportedAppUsage
+ public abstract Intent registerReceiverAsUser(BroadcastReceiver receiver,
+ UserHandle user, IntentFilter filter, @Nullable String broadcastPermission,
+ @Nullable Handler scheduler, @RegisterReceiverFlags int flags);
+
+ /**
* Unregister a previously registered BroadcastReceiver. <em>All</em>
* filters that have been registered for this BroadcastReceiver will be
* removed.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index e351c244..28c8664 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -732,14 +732,34 @@
/** @hide */
@Override
+ @Nullable
+ public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
+ @NonNull IntentFilter filter, @Nullable String broadcastPermission,
+ @Nullable Handler scheduler, int flags) {
+ return mBase.registerReceiverForAllUsers(receiver, filter, broadcastPermission,
+ scheduler, flags);
+ }
+
+ /** @hide */
+ @Override
@UnsupportedAppUsage
- public Intent registerReceiverAsUser(
- BroadcastReceiver receiver, UserHandle user, IntentFilter filter,
- String broadcastPermission, Handler scheduler) {
+ public Intent registerReceiverAsUser(@Nullable BroadcastReceiver receiver, UserHandle user,
+ IntentFilter filter, @Nullable String broadcastPermission,
+ @Nullable Handler scheduler) {
return mBase.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
scheduler);
}
+ /** @hide */
+ @Override
+ @UnsupportedAppUsage
+ public Intent registerReceiverAsUser(@Nullable BroadcastReceiver receiver, UserHandle user,
+ IntentFilter filter, @Nullable String broadcastPermission,
+ @Nullable Handler scheduler, int flags) {
+ return mBase.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
+ scheduler, flags);
+ }
+
@Override
public void unregisterReceiver(BroadcastReceiver receiver) {
mBase.unregisterReceiver(receiver);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0fad63f..9746066 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -8568,16 +8568,6 @@
}
/**
- * Filter extras to only basic types.
- * @hide
- */
- public void removeUnsafeExtras() {
- if (mExtras != null) {
- mExtras = mExtras.filterValues();
- }
- }
-
- /**
* @return Whether {@link #maybeStripForHistory} will return an lightened intent or
* return itself as-is.
* @hide
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 fb21ce3..2a344f6 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -43,18 +43,22 @@
protected static final String TAG = "Bundle";
static final boolean DEBUG = false;
- // Keep them in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
- private static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
+ /**
+ * Keep them in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
private static final int BUNDLE_MAGIC_NATIVE = 0x4C444E44; // 'B' 'N' 'D' 'N'
/**
- * Flag indicating that this Bundle is okay to "defuse." That is, it's okay
- * for system processes to ignore any {@link BadParcelableException}
- * encountered when unparceling it, leaving an empty bundle in its place.
+ * Flag indicating that this Bundle is okay to "defuse", see {@link #setShouldDefuse(boolean)}
+ * for more details.
* <p>
- * This should <em>only</em> be set when the Bundle reaches its final
- * destination, otherwise a system process may clobber contents that were
- * destined for an app that could have unparceled them.
+ * This should <em>only</em> be set when the Bundle reaches its final destination, otherwise a
+ * system process may clobber contents that were destined for an app that could have unparceled
+ * them.
*/
static final int FLAG_DEFUSABLE = 1 << 0;
@@ -63,10 +67,15 @@
private static volatile boolean sShouldDefuse = false;
/**
- * Set global variable indicating that any Bundles parsed in this process
- * should be "defused." That is, any {@link BadParcelableException}
- * encountered will be suppressed and logged, leaving an empty Bundle
- * instead of crashing.
+ * Set global variable indicating that any Bundles parsed in this process should be "defused".
+ * That is, any {@link BadParcelableException} encountered will be suppressed and logged. Also:
+ * <ul>
+ * <li>If it was the deserialization of a custom item (eg. {@link Parcelable}) that caused the
+ * exception, {@code null} will be returned but the item will be held in the map in its
+ * serialized form (lazy value).
+ * <li>If the exception happened during partial deserialization, that is, during the read of
+ * the map and its basic types (while skipping custom types), the map will be left empty.
+ * </ul>
*
* @hide
*/
@@ -249,6 +258,12 @@
}
}
if (itemwise) {
+ if (LOG_DEFUSABLE && sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
+ Slog.wtf(TAG,
+ "Attempting to unparcel all items in a Bundle while in transit; this "
+ + "may remove elements intended for the final desitination.",
+ new Throwable());
+ }
for (int i = 0, n = mMap.size(); i < n; i++) {
// Triggers deserialization of i-th item, if needed
getValueAt(i);
@@ -281,7 +296,16 @@
final Object getValueAt(int i) {
Object object = mMap.valueAt(i);
if (object instanceof Supplier<?>) {
- object = ((Supplier<?>) object).get();
+ try {
+ object = ((Supplier<?>) object).get();
+ } catch (BadParcelableException e) {
+ if (sShouldDefuse) {
+ Log.w(TAG, "Failed to parse item " + mMap.keyAt(i) + ", returning null.", e);
+ return null;
+ } else {
+ throw e;
+ }
+ }
mMap.setValueAt(i, object);
}
return object;
@@ -289,11 +313,6 @@
private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel,
boolean parcelledByNative) {
- if (LOG_DEFUSABLE && sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
- Slog.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "
- + "clobber all data inside!", new Throwable());
- }
-
if (isEmptyParcel(parcelledData)) {
if (DEBUG) {
Log.d(TAG, "unparcel "
@@ -376,8 +395,16 @@
}
}
- /** @hide */
- ArrayMap<String, Object> getMap() {
+ /**
+ * Returns the backing map of this bundle after deserializing every item.
+ *
+ * <p><b>Warning:</b> This method will deserialize every item on the bundle, including custom
+ * types such as {@link Parcelable} and {@link Serializable}, so only use this when you trust
+ * the source. Specifically don't use this method on app-provided bundles.
+ *
+ * @hide
+ */
+ ArrayMap<String, Object> getItemwiseMap() {
unparcel(/* itemwise */ true);
return mMap;
}
@@ -431,7 +458,7 @@
*
* @hide
*/
- public static boolean kindofEquals(BaseBundle a, BaseBundle b) {
+ public static boolean kindofEquals(@Nullable BaseBundle a, @Nullable BaseBundle b) {
return (a == b) || (a != null && a.kindofEquals(b));
}
@@ -500,7 +527,7 @@
final int N = fromMap.size();
mMap = new ArrayMap<>(N);
for (int i = 0; i < N; i++) {
- mMap.append(fromMap.keyAt(i), deepCopyValue(from.getValueAt(i)));
+ mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
}
}
} else {
@@ -1048,7 +1075,7 @@
*/
char getChar(String key, char defaultValue) {
unparcel();
- Object o = getValue(key);
+ Object o = mMap.get(key);
if (o == null) {
return defaultValue;
}
@@ -1451,7 +1478,7 @@
@Nullable
short[] getShortArray(@Nullable String key) {
unparcel();
- Object o = getValue(key);
+ Object o = mMap.get(key);
if (o == null) {
return null;
}
@@ -1474,7 +1501,7 @@
@Nullable
char[] getCharArray(@Nullable String key) {
unparcel();
- Object o = getValue(key);
+ Object o = mMap.get(key);
if (o == null) {
return null;
}
@@ -1543,7 +1570,7 @@
@Nullable
float[] getFloatArray(@Nullable String key) {
unparcel();
- Object o = getValue(key);
+ Object o = mMap.get(key);
if (o == null) {
return null;
}
@@ -1772,7 +1799,7 @@
pw.println("[null]");
return;
}
- final ArrayMap<String, Object> map = bundle.getMap();
+ final ArrayMap<String, Object> map = bundle.getItemwiseMap();
for (int i = 0; i < map.size(); i++) {
dumpStats(pw, map.keyAt(i), map.valueAt(i));
}
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 5626bde..b3827b3 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -347,56 +347,6 @@
return (mFlags & FLAG_HAS_FDS) != 0;
}
- /**
- * Filter values in Bundle to only basic types.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public Bundle filterValues() {
- unparcel(/* itemwise */ true);
- Bundle bundle = this;
- if (mMap != null) {
- ArrayMap<String, Object> map = mMap;
- for (int i = map.size() - 1; i >= 0; i--) {
- Object value = map.valueAt(i);
- if (PersistableBundle.isValidType(value)) {
- continue;
- }
- if (value instanceof Bundle) {
- Bundle newBundle = ((Bundle)value).filterValues();
- if (newBundle != value) {
- if (map == mMap) {
- // The filter had to generate a new bundle, but we have not yet
- // created a new one here. Do that now.
- bundle = new Bundle(this);
- // Note the ArrayMap<> constructor is guaranteed to generate
- // a new object with items in the same order as the original.
- map = bundle.mMap;
- }
- // Replace this current entry with the new child bundle.
- map.setValueAt(i, newBundle);
- }
- continue;
- }
- if (value.getClass().getName().startsWith("android.")) {
- continue;
- }
- if (map == mMap) {
- // This is the first time we have had to remove something, that means we
- // need to switch to a new Bundle.
- bundle = new Bundle(this);
- // Note the ArrayMap<> constructor is guaranteed to generate
- // a new object with items in the same order as the original.
- map = bundle.mMap;
- }
- map.removeAt(i);
- }
- }
- mFlags |= FLAG_HAS_FDS_KNOWN;
- mFlags &= ~FLAG_HAS_FDS;
- return bundle;
- }
-
/** {@hide} */
@Override
public void putObject(@Nullable String key, @Nullable Object value) {
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 7f2e2b1..e6925cb 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -263,6 +263,10 @@
private static final int VAL_SIZE = 26;
private static final int VAL_SIZEF = 27;
private static final int VAL_DOUBLEARRAY = 28;
+ private static final int VAL_CHAR = 29;
+ private static final int VAL_SHORTARRAY = 30;
+ private static final int VAL_CHARARRAY = 31;
+ private static final int VAL_FLOATARRAY = 32;
// The initial int32 in a Binder call's reply Parcel header:
// Keep these in sync with libbinder's binder/Status.h.
@@ -448,6 +452,21 @@
}
/**
+ * Retrieve a new Parcel object from the pool for use with a specific binder.
+ *
+ * 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. For future compatibility, it is recommended to use this for all
+ * Parcels.
+ */
+ @NonNull
+ public static Parcel obtain(@NonNull IBinder binder) {
+ Parcel parcel = Parcel.obtain();
+ parcel.markForBinder(binder);
+ return parcel;
+ }
+
+ /**
* Put a Parcel object back into the pool. You must not touch
* the object after this call.
*/
@@ -519,16 +538,9 @@
}
/**
- * 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) {
+ private void markForBinder(@NonNull IBinder binder) {
nativeMarkForBinder(mNativePtr, binder);
}
@@ -1309,6 +1321,46 @@
}
}
+ /** @hide */
+ public void writeShortArray(@Nullable short[] val) {
+ if (val != null) {
+ int n = val.length;
+ writeInt(n);
+ for (int i = 0; i < n; i++) {
+ writeInt(val[i]);
+ }
+ } else {
+ writeInt(-1);
+ }
+ }
+
+ /** @hide */
+ @Nullable
+ public short[] createShortArray() {
+ int n = readInt();
+ if (n >= 0 && n <= (dataAvail() >> 2)) {
+ short[] val = new short[n];
+ for (int i = 0; i < n; i++) {
+ val[i] = (short) readInt();
+ }
+ return val;
+ } else {
+ return null;
+ }
+ }
+
+ /** @hide */
+ public void readShortArray(@NonNull short[] val) {
+ int n = readInt();
+ if (n == val.length) {
+ for (int i = 0; i < n; i++) {
+ val[i] = (short) readInt();
+ }
+ } else {
+ throw new RuntimeException("bad array lengths");
+ }
+ }
+
public final void writeCharArray(@Nullable char[] val) {
if (val != null) {
int N = val.length;
@@ -1974,6 +2026,14 @@
return VAL_SIZE;
} else if (v instanceof double[]) {
return VAL_DOUBLEARRAY;
+ } else if (v instanceof Character) {
+ return VAL_CHAR;
+ } else if (v instanceof short[]) {
+ return VAL_SHORTARRAY;
+ } else if (v instanceof char[]) {
+ return VAL_CHARARRAY;
+ } else if (v instanceof float[]) {
+ return VAL_FLOATARRAY;
} else {
Class<?> clazz = v.getClass();
if (clazz.isArray() && clazz.getComponentType() == Object.class) {
@@ -2076,6 +2136,18 @@
case VAL_DOUBLEARRAY:
writeDoubleArray((double[]) v);
break;
+ case VAL_CHAR:
+ writeInt((Character) v);
+ break;
+ case VAL_SHORTARRAY:
+ writeShortArray((short[]) v);
+ break;
+ case VAL_CHARARRAY:
+ writeCharArray((char[]) v);
+ break;
+ case VAL_FLOATARRAY:
+ writeFloatArray((float[]) v);
+ break;
case VAL_OBJECTARRAY:
writeArray((Object[]) v);
break;
@@ -2756,7 +2828,20 @@
*/
public final void readList(@NonNull List outVal, @Nullable ClassLoader loader) {
int N = readInt();
- readListInternal(outVal, N, loader);
+ readListInternal(outVal, N, loader, /* clazz */ null);
+ }
+
+ /**
+ * Same as {@link #readList(List, ClassLoader)} but accepts {@code clazz} parameter as
+ * the type required for each item. If the item to be deserialized is not an instance
+ * of that class or any of its children class
+ * a {@link BadParcelableException} will be thrown.
+ */
+ public <T> void readList(@NonNull List<? super T> outVal,
+ @Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+ Objects.requireNonNull(clazz);
+ int n = readInt();
+ readListInternal(outVal, n, loader, clazz);
}
/**
@@ -2955,7 +3040,7 @@
return null;
}
ArrayList l = new ArrayList(N);
- readListInternal(l, N, loader);
+ readListInternal(l, N, loader, /* clazz */ null);
return l;
}
@@ -3355,20 +3440,29 @@
*/
@Nullable
public final Object readValue(@Nullable ClassLoader loader) {
+ return readValue(loader, /* clazz */ null);
+ }
+
+
+ /**
+ * @param clazz The type of the object expected or {@code null} for performing no checks.
+ */
+ @Nullable
+ private <T> T readValue(@Nullable ClassLoader loader, @Nullable Class<T> clazz) {
int type = readInt();
- final Object object;
+ final T object;
if (isLengthPrefixed(type)) {
int length = readInt();
int start = dataPosition();
- object = readValue(type, loader);
+ object = readValue(type, loader, clazz);
int actual = dataPosition() - start;
if (actual != length) {
- Log.w(TAG,
+ Slog.wtfStack(TAG,
"Unparcelling of " + object + " of type " + Parcel.valueTypeToString(type)
+ " consumed " + actual + " bytes, but " + length + " expected.");
}
} else {
- object = readValue(type, loader);
+ object = readValue(type, loader, clazz);
}
return object;
}
@@ -3405,7 +3499,7 @@
setDataPosition(MathUtils.addOrThrow(dataPosition(), length));
return new LazyValue(this, start, length, type, loader);
} else {
- return readValue(type, loader);
+ return readValue(type, loader, /* clazz */ null);
}
}
@@ -3438,14 +3532,17 @@
Parcel source = mSource;
if (source != null) {
synchronized (source) {
- int restore = source.dataPosition();
- try {
- source.setDataPosition(mPosition);
- mObject = source.readValue(mLoader);
- } finally {
- source.setDataPosition(restore);
+ // Check mSource != null guarantees callers won't ever see different objects.
+ if (mSource != null) {
+ int restore = source.dataPosition();
+ try {
+ source.setDataPosition(mPosition);
+ mObject = source.readValue(mLoader);
+ } finally {
+ source.setDataPosition(restore);
+ }
+ mSource = null;
}
- mSource = null;
}
}
return mObject;
@@ -3537,114 +3634,175 @@
/**
* Reads a value from the parcel of type {@code type}. Does NOT read the int representing the
* type first.
+ * @param clazz The type of the object expected or {@code null} for performing no checks.
*/
+ @SuppressWarnings("unchecked")
@Nullable
- private Object readValue(int type, @Nullable ClassLoader loader) {
+ private <T> T readValue(int type, @Nullable ClassLoader loader, @Nullable Class<T> clazz) {
+ final Object object;
switch (type) {
- case VAL_NULL:
- return null;
+ case VAL_NULL:
+ object = null;
+ break;
- case VAL_STRING:
- return readString();
+ case VAL_STRING:
+ object = readString();
+ break;
- case VAL_INTEGER:
- return readInt();
+ case VAL_INTEGER:
+ object = readInt();
+ break;
- case VAL_MAP:
- return readHashMap(loader);
+ case VAL_MAP:
+ object = readHashMap(loader);
+ break;
- case VAL_PARCELABLE:
- return readParcelable(loader);
+ case VAL_PARCELABLE:
+ object = readParcelableInternal(loader, clazz);
+ break;
- case VAL_SHORT:
- return (short) readInt();
+ case VAL_SHORT:
+ object = (short) readInt();
+ break;
- case VAL_LONG:
- return readLong();
+ case VAL_LONG:
+ object = readLong();
+ break;
- case VAL_FLOAT:
- return readFloat();
+ case VAL_FLOAT:
+ object = readFloat();
+ break;
- case VAL_DOUBLE:
- return readDouble();
+ case VAL_DOUBLE:
+ object = readDouble();
+ break;
- case VAL_BOOLEAN:
- return readInt() == 1;
+ case VAL_BOOLEAN:
+ object = readInt() == 1;
+ break;
- case VAL_CHARSEQUENCE:
- return readCharSequence();
+ case VAL_CHARSEQUENCE:
+ object = readCharSequence();
+ break;
- case VAL_LIST:
- return readArrayList(loader);
+ case VAL_LIST:
+ object = readArrayList(loader);
+ break;
- case VAL_BOOLEANARRAY:
- return createBooleanArray();
+ case VAL_BOOLEANARRAY:
+ object = createBooleanArray();
+ break;
- case VAL_BYTEARRAY:
- return createByteArray();
+ case VAL_BYTEARRAY:
+ object = createByteArray();
+ break;
- case VAL_STRINGARRAY:
- return readStringArray();
+ case VAL_STRINGARRAY:
+ object = readStringArray();
+ break;
- case VAL_CHARSEQUENCEARRAY:
- return readCharSequenceArray();
+ case VAL_CHARSEQUENCEARRAY:
+ object = readCharSequenceArray();
+ break;
- case VAL_IBINDER:
- return readStrongBinder();
+ case VAL_IBINDER:
+ object = readStrongBinder();
+ break;
- case VAL_OBJECTARRAY:
- return readArray(loader);
+ case VAL_OBJECTARRAY:
+ object = readArray(loader);
+ break;
- case VAL_INTARRAY:
- return createIntArray();
+ case VAL_INTARRAY:
+ object = createIntArray();
+ break;
- case VAL_LONGARRAY:
- return createLongArray();
+ case VAL_LONGARRAY:
+ object = createLongArray();
+ break;
- case VAL_BYTE:
- return readByte();
+ case VAL_BYTE:
+ object = readByte();
+ break;
- case VAL_SERIALIZABLE:
- return readSerializable(loader);
+ case VAL_SERIALIZABLE:
+ object = readSerializable(loader);
+ break;
- case VAL_PARCELABLEARRAY:
- return readParcelableArray(loader);
+ case VAL_PARCELABLEARRAY:
+ object = readParcelableArray(loader);
+ break;
- case VAL_SPARSEARRAY:
- return readSparseArray(loader);
+ case VAL_SPARSEARRAY:
+ object = readSparseArray(loader);
+ break;
- case VAL_SPARSEBOOLEANARRAY:
- return readSparseBooleanArray();
+ case VAL_SPARSEBOOLEANARRAY:
+ object = readSparseBooleanArray();
+ break;
- case VAL_BUNDLE:
- return readBundle(loader); // loading will be deferred
+ case VAL_BUNDLE:
+ object = readBundle(loader); // loading will be deferred
+ break;
- case VAL_PERSISTABLEBUNDLE:
- return readPersistableBundle(loader);
+ case VAL_PERSISTABLEBUNDLE:
+ object = readPersistableBundle(loader);
+ break;
- case VAL_SIZE:
- return readSize();
+ case VAL_SIZE:
+ object = readSize();
+ break;
- case VAL_SIZEF:
- return readSizeF();
+ case VAL_SIZEF:
+ object = readSizeF();
+ break;
- case VAL_DOUBLEARRAY:
- return createDoubleArray();
+ case VAL_DOUBLEARRAY:
+ object = createDoubleArray();
+ break;
- default:
- int off = dataPosition() - 4;
- throw new RuntimeException(
- "Parcel " + this + ": Unmarshalling unknown type code " + type + " at offset " + off);
+ case VAL_CHAR:
+ object = (char) readInt();
+ break;
+
+ case VAL_SHORTARRAY:
+ object = createShortArray();
+ break;
+
+ case VAL_CHARARRAY:
+ object = createCharArray();
+ break;
+
+ case VAL_FLOATARRAY:
+ object = createFloatArray();
+ break;
+
+ default:
+ int off = dataPosition() - 4;
+ throw new BadParcelableException(
+ "Parcel " + this + ": Unmarshalling unknown type code " + type
+ + " at offset " + off);
}
+ if (clazz != null && !clazz.isInstance(object)) {
+ throw new BadParcelableException("Unparcelled object " + object
+ + " is not an instance of required class " + clazz.getName()
+ + " provided in the parameter");
+ }
+ return (T) object;
}
private boolean isLengthPrefixed(int type) {
+ // In general, we want custom types and containers of custom types to be length-prefixed,
+ // this allows clients (eg. Bundle) to skip their content during deserialization. The
+ // exception to this is Bundle, since Bundle is already length-prefixed and already copies
+ // the correspondent section of the parcel internally.
switch (type) {
+ case VAL_MAP:
case VAL_PARCELABLE:
- case VAL_PARCELABLEARRAY:
case VAL_LIST:
case VAL_SPARSEARRAY:
- case VAL_BUNDLE:
+ case VAL_PARCELABLEARRAY:
+ case VAL_OBJECTARRAY:
case VAL_SERIALIZABLE:
return true;
default:
@@ -3663,17 +3821,42 @@
* @throws BadParcelableException Throws BadParcelableException if there
* was an error trying to instantiate the Parcelable.
*/
- @SuppressWarnings("unchecked")
@Nullable
public final <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader) {
- Parcelable.Creator<?> creator = readParcelableCreator(loader);
+ return readParcelableInternal(loader, /* clazz */ null);
+ }
+
+ /**
+ * Same as {@link #readParcelable(ClassLoader)} but accepts {@code clazz} parameter as the type
+ * required for each item. If the item to be deserialized is not an instance of that class or
+ * any of its children classes a {@link BadParcelableException} will be thrown.
+ */
+ @Nullable
+ public <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader,
+ @NonNull Class<T> clazz) {
+ Objects.requireNonNull(clazz);
+ return readParcelableInternal(loader, clazz);
+ }
+
+ /**
+ *
+ * @param clazz The type of the parcelable expected or {@code null} for performing no checks.
+ */
+ @SuppressWarnings("unchecked")
+ @Nullable
+ private <T> T readParcelableInternal(@Nullable ClassLoader loader, @Nullable Class<T> clazz) {
+ if (clazz != null && !Parcelable.class.isAssignableFrom(clazz)) {
+ throw new BadParcelableException("About to unparcel a parcelable object "
+ + " but class required " + clazz.getName() + " is not Parcelable");
+ }
+ Parcelable.Creator<?> creator = readParcelableCreatorInternal(loader, clazz);
if (creator == null) {
return null;
}
if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
- Parcelable.ClassLoaderCreator<?> classLoaderCreator =
- (Parcelable.ClassLoaderCreator<?>) creator;
- return (T) classLoaderCreator.createFromParcel(this, loader);
+ Parcelable.ClassLoaderCreator<?> classLoaderCreator =
+ (Parcelable.ClassLoaderCreator<?>) creator;
+ return (T) classLoaderCreator.createFromParcel(this, loader);
}
return (T) creator.createFromParcel(this);
}
@@ -3707,6 +3890,28 @@
*/
@Nullable
public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
+ return readParcelableCreatorInternal(loader, /* clazz */ null);
+ }
+
+ /**
+ * Same as {@link #readParcelableCreator(ClassLoader)} but accepts {@code clazz} parameter
+ * as the required type. If the item to be deserialized is not an instance of that class
+ * or any of its children classes a {@link BadParcelableException} will be thrown.
+ */
+ @Nullable
+ public <T> Parcelable.Creator<T> readParcelableCreator(
+ @Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+ Objects.requireNonNull(clazz);
+ return readParcelableCreatorInternal(loader, clazz);
+ }
+
+ /**
+ * @param clazz The type of the parcelable expected or {@code null} for performing no checks.
+ */
+ @SuppressWarnings("unchecked")
+ @Nullable
+ private <T> Parcelable.Creator<T> readParcelableCreatorInternal(
+ @Nullable ClassLoader loader, @Nullable Class<T> clazz) {
String name = readString();
if (name == null) {
return null;
@@ -3722,7 +3927,15 @@
creator = map.get(name);
}
if (creator != null) {
- return creator;
+ if (clazz != null) {
+ Class<?> parcelableClass = creator.getClass().getEnclosingClass();
+ if (!clazz.isAssignableFrom(parcelableClass)) {
+ throw new BadParcelableException("Parcelable creator " + name + " is not "
+ + "a subclass of required class " + clazz.getName()
+ + " provided in the parameter");
+ }
+ }
+ return (Parcelable.Creator<T>) creator;
}
try {
@@ -3738,6 +3951,14 @@
throw new BadParcelableException("Parcelable protocol requires subclassing "
+ "from Parcelable on class " + name);
}
+ if (clazz != null) {
+ if (!clazz.isAssignableFrom(parcelableClass)) {
+ throw new BadParcelableException("Parcelable creator " + name + " is not "
+ + "a subclass of required class " + clazz.getName()
+ + " provided in the parameter");
+ }
+ }
+
Field f = parcelableClass.getField("CREATOR");
if ((f.getModifiers() & Modifier.STATIC) == 0) {
throw new BadParcelableException("Parcelable protocol requires "
@@ -3775,7 +3996,7 @@
map.put(name, creator);
}
- return creator;
+ return (Parcelable.Creator<T>) creator;
}
/**
@@ -4021,13 +4242,21 @@
return result;
}
- private void readListInternal(@NonNull List outVal, int N,
+ private void readListInternal(@NonNull List outVal, int n,
@Nullable ClassLoader loader) {
- while (N > 0) {
- Object value = readValue(loader);
+ readListInternal(outVal, n, loader, null);
+ }
+
+ /**
+ * @param clazz The type of the object expected or {@code null} for performing no checks.
+ */
+ private <T> void readListInternal(@NonNull List<? super T> outVal, int n,
+ @Nullable ClassLoader loader, @Nullable Class<T> clazz) {
+ while (n > 0) {
+ T value = readValue(loader, clazz);
//Log.d(TAG, "Unmarshalling value=" + value);
outVal.add(value);
- N--;
+ n--;
}
}
@@ -4106,6 +4335,10 @@
case VAL_SIZE: return "VAL_SIZE";
case VAL_SIZEF: return "VAL_SIZEF";
case VAL_DOUBLEARRAY: return "VAL_DOUBLEARRAY";
+ case VAL_CHAR: return "VAL_CHAR";
+ case VAL_SHORTARRAY: return "VAL_SHORTARRAY";
+ case VAL_CHARARRAY: return "VAL_CHARARRAY";
+ case VAL_FLOATARRAY: return "VAL_FLOATARRAY";
case VAL_OBJECTARRAY: return "VAL_OBJECTARRAY";
case VAL_SERIALIZABLE: return "VAL_SERIALIZABLE";
default: return "UNKNOWN(" + type + ")";
diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java
index a537c98..a396211 100644
--- a/core/java/android/os/Parcelable.java
+++ b/core/java/android/os/Parcelable.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.NonNull;
import android.annotation.IntDef;
import android.annotation.SystemApi;
@@ -202,7 +203,7 @@
* @param flags Additional flags about how the object should be written.
* May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
*/
- public void writeToParcel(Parcel dest, @WriteFlags int flags);
+ public void writeToParcel(@NonNull Parcel dest, @WriteFlags int flags);
/**
* Interface that must be implemented and provided as a public CREATOR
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index 339371b..c7edbec 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -34,6 +34,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.Serializable;
import java.util.ArrayList;
/**
@@ -100,6 +101,10 @@
/**
* Constructs a PersistableBundle from a Bundle. Does only a shallow copy of the Bundle.
*
+ * <p><b>Warning:</b> This method will deserialize every item on the bundle, including custom
+ * types such as {@link Parcelable} and {@link Serializable}, so only use this when you trust
+ * the source. Specifically don't use this method on app-provided bundles.
+ *
* @param b a Bundle to be copied.
*
* @throws IllegalArgumentException if any element of {@code b} cannot be persisted.
@@ -107,7 +112,7 @@
* @hide
*/
public PersistableBundle(Bundle b) {
- this(b.getMap());
+ this(b.getItemwiseMap());
}
/**
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/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index 4cf0a36..418d92c 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -645,7 +645,7 @@
e.fillInStackTrace();
Log.w(TAG, "New hash " + hash
+ " is before end of array hash " + mHashes[index-1]
- + " at index " + index + " key " + key, e);
+ + " at index " + index + (DEBUG ? " key " + key : ""), e);
put(key, value);
return;
}
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/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/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index 4cc70ba..ddd0070 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -16,16 +16,24 @@
package android.os;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import android.util.Log;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Objects;
+
/**
* Unit tests for bundle that requires accessing hidden APS. Tests that can be written only with
* public APIs should go in the CTS counterpart.
@@ -35,6 +43,15 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BundleTest {
+ private Log.TerribleFailureHandler mWtfHandler;
+
+ @After
+ public void tearDown() throws Exception {
+ BaseBundle.setShouldDefuse(false);
+ if (mWtfHandler != null) {
+ Log.setWtfHandler(mWtfHandler);
+ }
+ }
/**
* Take a bundle, write it to a parcel and return the parcel.
@@ -217,4 +234,268 @@
// return true
assertTrue(BaseBundle.kindofEquals(bundle1, bundle2));
}
+
+ @Test
+ public void kindofEquals_lazyValues() {
+ Parcelable p1 = new CustomParcelable(13, "Tiramisu");
+ Parcelable p2 = new CustomParcelable(13, "Tiramisu");
+
+ // 2 maps with live objects
+ Bundle a = new Bundle();
+ a.putParcelable("key1", p1);
+ Bundle b = new Bundle();
+ b.putParcelable("key1", p2);
+ assertTrue(Bundle.kindofEquals(a, b));
+
+ // 2 identical parcels
+ a.readFromParcel(getParcelledBundle(a));
+ a.setClassLoader(getClass().getClassLoader());
+ b.readFromParcel(getParcelledBundle(b));
+ b.setClassLoader(getClass().getClassLoader());
+ assertTrue(Bundle.kindofEquals(a, b));
+
+ // 2 lazy values with identical parcels inside
+ a.isEmpty();
+ b.isEmpty();
+ assertTrue(Bundle.kindofEquals(a, b));
+
+ // 1 lazy value vs 1 live object
+ a.getParcelable("key1");
+ assertFalse(Bundle.kindofEquals(a, b));
+
+ // 2 live objects
+ b.getParcelable("key1");
+ assertTrue(Bundle.kindofEquals(a, b));
+ }
+
+ @Test
+ public void kindofEquals_lazyValuesWithIdenticalParcels_returnsTrue() {
+ Parcelable p1 = new CustomParcelable(13, "Tiramisu");
+ Parcelable p2 = new CustomParcelable(13, "Tiramisu");
+ Bundle a = new Bundle();
+ a.putParcelable("key", p1);
+ a.readFromParcel(getParcelledBundle(a));
+ a.setClassLoader(getClass().getClassLoader());
+ Bundle b = new Bundle();
+ b.putParcelable("key", p2);
+ b.readFromParcel(getParcelledBundle(b));
+ b.setClassLoader(getClass().getClassLoader());
+ // 2 lazy values with identical parcels inside
+ a.isEmpty();
+ b.isEmpty();
+
+ assertTrue(Bundle.kindofEquals(a, b));
+ }
+
+ @Test
+ public void kindofEquals_lazyValuesAndDifferentClassLoaders_returnsFalse() {
+ Parcelable p1 = new CustomParcelable(13, "Tiramisu");
+ Parcelable p2 = new CustomParcelable(13, "Tiramisu");
+ Bundle a = new Bundle();
+ a.putParcelable("key", p1);
+ a.readFromParcel(getParcelledBundle(a));
+ a.setClassLoader(getClass().getClassLoader());
+ Bundle b = new Bundle();
+ b.putParcelable("key", p2);
+ b.readFromParcel(getParcelledBundle(b));
+ b.setClassLoader(Bundle.class.getClassLoader()); // BCP
+ // 2 lazy values with identical parcels inside
+ a.isEmpty();
+ b.isEmpty();
+
+ assertFalse(Bundle.kindofEquals(a, b));
+ }
+
+ @Test
+ public void kindofEquals_lazyValuesOfDifferentTypes_returnsFalse() {
+ Parcelable p = new CustomParcelable(13, "Tiramisu");
+ Parcelable[] ps = {p};
+ Bundle a = new Bundle();
+ a.putParcelable("key", p);
+ a.readFromParcel(getParcelledBundle(a));
+ a.setClassLoader(getClass().getClassLoader());
+ Bundle b = new Bundle();
+ b.putParcelableArray("key", ps);
+ b.readFromParcel(getParcelledBundle(b));
+ b.setClassLoader(getClass().getClassLoader());
+ a.isEmpty();
+ b.isEmpty();
+
+ assertFalse(Bundle.kindofEquals(a, b));
+ }
+
+ @Test
+ public void kindofEquals_lazyValuesWithDifferentLengths_returnsFalse() {
+ Parcelable p1 = new CustomParcelable(13, "Tiramisu");
+ Parcelable p2 = new CustomParcelable(13, "Tiramisuuuuuuuu");
+ Bundle a = new Bundle();
+ a.putParcelable("key", p1);
+ a.readFromParcel(getParcelledBundle(a));
+ a.setClassLoader(getClass().getClassLoader());
+ Bundle b = new Bundle();
+ b.putParcelable("key", p2);
+ b.readFromParcel(getParcelledBundle(b));
+ b.setClassLoader(getClass().getClassLoader());
+ a.isEmpty();
+ b.isEmpty();
+
+ assertFalse(Bundle.kindofEquals(a, b));
+ }
+
+ @Test
+ public void readWriteLengthMismatch_logsWtf() throws Exception {
+ mWtfHandler = Log.setWtfHandler((tag, e, system) -> {
+ throw new RuntimeException(e);
+ });
+ Parcelable parcelable = new CustomParcelable(13, "Tiramisu").setHasLengthMismatch(true);
+ Bundle bundle = new Bundle();
+ bundle.putParcelable("p", parcelable);
+ bundle.readFromParcel(getParcelledBundle(bundle));
+ bundle.setClassLoader(getClass().getClassLoader());
+ RuntimeException e = assertThrows(RuntimeException.class, () -> bundle.getParcelable("p"));
+ assertThat(e.getCause()).isInstanceOf(Log.TerribleFailure.class);
+ }
+
+ @Test
+ public void getParcelable_whenThrowingAndNotDefusing_throws() throws Exception {
+ Bundle.setShouldDefuse(false);
+ Bundle bundle = new Bundle();
+ bundle.putParcelable("key", new CustomParcelable(13, "Tiramisu"));
+ bundle.readFromParcel(getParcelledBundle(bundle));
+
+ // Default class-loader is the bootpath class-loader, which doesn't contain
+ // CustomParcelable, so trying to read it will throw BadParcelableException.
+ assertThrows(BadParcelableException.class, () -> bundle.getParcelable("key"));
+ }
+
+ @Test
+ public void getParcelable_whenThrowingAndDefusing_returnsNull() throws Exception {
+ Bundle.setShouldDefuse(true);
+ Bundle bundle = new Bundle();
+ bundle.putParcelable("key", new CustomParcelable(13, "Tiramisu"));
+ bundle.putString("string", "value");
+ bundle.readFromParcel(getParcelledBundle(bundle));
+
+ // Default class-loader is the bootpath class-loader, which doesn't contain
+ // CustomParcelable, so trying to read it will throw BadParcelableException.
+ assertThat(bundle.<Parcelable>getParcelable("key")).isNull();
+ // Doesn't affect other items
+ assertThat(bundle.getString("string")).isEqualTo("value");
+ }
+
+ @Test
+ public void getParcelable_whenThrowingAndDefusing_leavesElement() throws Exception {
+ Bundle.setShouldDefuse(true);
+ Bundle bundle = new Bundle();
+ Parcelable parcelable = new CustomParcelable(13, "Tiramisu");
+ bundle.putParcelable("key", parcelable);
+ bundle.putString("string", "value");
+ bundle.readFromParcel(getParcelledBundle(bundle));
+ assertThat(bundle.<Parcelable>getParcelable("key")).isNull();
+
+ // Now, we simulate reserializing and assign the proper class loader to not throw anymore
+ bundle.readFromParcel(getParcelledBundle(bundle));
+ bundle.setClassLoader(getClass().getClassLoader());
+
+ // We're able to retrieve it even though we failed before
+ assertThat(bundle.<Parcelable>getParcelable("key")).isEqualTo(parcelable);
+ }
+
+ @Test
+ public void partialDeserialization_whenNotDefusing_throws() throws Exception {
+ Bundle.setShouldDefuse(false);
+ Bundle bundle = getMalformedBundle();
+ assertThrows(BadParcelableException.class, bundle::isEmpty);
+ }
+
+ @Test
+ public void partialDeserialization_whenDefusing_emptiesMap() throws Exception {
+ Bundle.setShouldDefuse(true);
+ Bundle bundle = getMalformedBundle();
+ bundle.isEmpty();
+ // Nothing thrown
+ assertThat(bundle.size()).isEqualTo(0);
+ }
+
+ private Bundle getMalformedBundle() {
+ Parcel p = Parcel.obtain();
+ p.writeInt(BaseBundle.BUNDLE_MAGIC);
+ int start = p.dataPosition();
+ p.writeInt(1); // Number of items
+ p.writeString("key");
+ p.writeInt(131313); // Invalid type
+ p.writeInt(0); // Anything, really
+ int end = p.dataPosition();
+ p.setDataPosition(0);
+ return new Bundle(p, end - start);
+ }
+
+
+ private static class CustomParcelable implements Parcelable {
+ public final int integer;
+ public final String string;
+ public boolean hasLengthMismatch;
+
+ CustomParcelable(int integer, String string) {
+ this.integer = integer;
+ this.string = string;
+ }
+
+ protected CustomParcelable(Parcel in) {
+ integer = in.readInt();
+ string = in.readString();
+ hasLengthMismatch = in.readBoolean();
+ }
+
+ public CustomParcelable setHasLengthMismatch(boolean hasLengthMismatch) {
+ this.hasLengthMismatch = hasLengthMismatch;
+ return this;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(integer);
+ out.writeString(string);
+ out.writeBoolean(hasLengthMismatch);
+ if (hasLengthMismatch) {
+ out.writeString("extra-write");
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof CustomParcelable)) {
+ return false;
+ }
+ CustomParcelable
+ that = (CustomParcelable) other;
+ return integer == that.integer
+ && hasLengthMismatch == that.hasLengthMismatch
+ && string.equals(that.string);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(integer, string, hasLengthMismatch);
+ }
+
+ public static final Creator<CustomParcelable> CREATOR = new Creator<CustomParcelable>() {
+ @Override
+ public CustomParcelable createFromParcel(Parcel in) {
+ return new CustomParcelable(in);
+ }
+ @Override
+ public CustomParcelable[] newArray(int size) {
+ return new CustomParcelable[size];
+ }
+ };
+ }
}
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index e08b99d..d897e94f 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -32,6 +32,8 @@
using namespace android::uirenderer::renderthread;
+static constexpr bool sEnableExtraCropInset = true;
+
namespace android {
namespace uirenderer {
@@ -71,6 +73,20 @@
ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
return CopyResult::SourceEmpty;
}
+
+ if (sEnableExtraCropInset &&
+ (cropRect.right - cropRect.left != bitmap->width() ||
+ cropRect.bottom - cropRect.top != bitmap->height())) {
+ /*
+ * When we need use filtering, we should also make border shrink here like gui.
+ * But we could not check format for YUV or RGB here... Just use 1 pix.
+ */
+ cropRect.left += 0.5f;
+ cropRect.top += 0.5f;
+ cropRect.right -= 0.5f;
+ cropRect.bottom -= 0.5f;
+ }
+
UniqueAHardwareBuffer sourceBuffer{rawSourceBuffer};
AHardwareBuffer_Desc description;
AHardwareBuffer_describe(sourceBuffer.get(), &description);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index c7c503d..6fe771a 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -27,6 +27,7 @@
import android.os.Build;
import android.os.Process;
import android.os.SystemProperties;
+import android.sysprop.MediaProperties;
import android.util.Log;
import android.util.Pair;
import android.util.Range;
@@ -195,13 +196,20 @@
private static final Range<Rational> POSITIVE_RATIONALS =
Range.create(new Rational(1, Integer.MAX_VALUE),
new Rational(Integer.MAX_VALUE, 1));
- private static final Range<Integer> SIZE_RANGE =
- Process.is64Bit() ? Range.create(1, 32768) : Range.create(1, 4096);
private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960);
private static final Range<Integer> BITRATE_RANGE = Range.create(0, 500000000);
private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32;
private static final int MAX_SUPPORTED_INSTANCES_LIMIT = 256;
+ private static final class LazyHolder {
+ private static final Range<Integer> SIZE_RANGE = Process.is64Bit()
+ ? Range.create(1, 32768)
+ : Range.create(1, MediaProperties.resolution_limit_32bit().orElse(4096));
+ }
+ private static Range<Integer> getSizeRange() {
+ return LazyHolder.SIZE_RANGE;
+ }
+
// found stuff that is not supported by framework (=> this should not happen)
private static final int ERROR_UNRECOGNIZED = (1 << 0);
// found profile/level for which we don't have capability estimates
@@ -2131,12 +2139,12 @@
private void initWithPlatformLimits() {
mBitrateRange = BITRATE_RANGE;
- mWidthRange = SIZE_RANGE;
- mHeightRange = SIZE_RANGE;
+ mWidthRange = getSizeRange();
+ mHeightRange = getSizeRange();
mFrameRateRange = FRAME_RATE_RANGE;
- mHorizontalBlockRange = SIZE_RANGE;
- mVerticalBlockRange = SIZE_RANGE;
+ mHorizontalBlockRange = getSizeRange();
+ mVerticalBlockRange = getSizeRange();
// full positive ranges are supported as these get calculated
mBlockCountRange = POSITIVE_INTEGERS;
@@ -2150,7 +2158,7 @@
mHeightAlignment = 2;
mBlockWidth = 2;
mBlockHeight = 2;
- mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
+ mSmallerDimensionUpperLimit = getSizeRange().getUpper();
}
private @Nullable List<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
@@ -2391,10 +2399,10 @@
// codec supports profiles that we don't know.
// Use supplied values clipped to platform limits
if (widths != null) {
- mWidthRange = SIZE_RANGE.intersect(widths);
+ mWidthRange = getSizeRange().intersect(widths);
}
if (heights != null) {
- mHeightRange = SIZE_RANGE.intersect(heights);
+ mHeightRange = getSizeRange().intersect(heights);
}
if (counts != null) {
mBlockCountRange = POSITIVE_INTEGERS.intersect(
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 0256615..1f75ae3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -139,14 +139,14 @@
*/
public synchronized String getSubDeviceSummary(CachedBluetoothDevice device) {
final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
- if (memberDevices != null) {
+ // TODO: check the CSIP group size instead of the real member device set size, and adjust
+ // the size restriction.
+ if (memberDevices.size() == 1) {
for (CachedBluetoothDevice memberDevice : memberDevices) {
- if (!memberDevice.isConnected()) {
- return null;
+ if (memberDevice.isConnected()) {
+ return memberDevice.getConnectionSummary();
}
}
-
- return device.getConnectionSummary();
}
CachedBluetoothDevice subDevice = device.getSubDevice();
if (subDevice != null && subDevice.isConnected()) {
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/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 8bb5204..66227d3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -619,10 +619,8 @@
}
}
- if (!mService.isPowerStandbyOrTransient()) {
- addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
- activeSource.physicalAddress, deviceType));
- }
+ addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
+ activeSource.physicalAddress, deviceType));
}
private boolean handleNewDeviceAtTheTailOfActivePath(int path) {
@@ -798,14 +796,12 @@
@ServiceThreadOnly
void onNewAvrAdded(HdmiDeviceInfo avr) {
assertRunOnServiceThread();
- if (!mService.isPowerStandbyOrTransient()) {
- addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
- if (!isDirectConnectAddress(avr.getPhysicalAddress())) {
- startArcAction(false);
- } else if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
- && !hasAction(SetArcTransmissionStateAction.class)) {
- startArcAction(true);
- }
+ addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
+ if (!isDirectConnectAddress(avr.getPhysicalAddress())) {
+ startArcAction(false);
+ } else if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
+ && !hasAction(SetArcTransmissionStateAction.class)) {
+ startArcAction(true);
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index e951053..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();
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
index ed1f5f5..3fc4169 100644
--- a/services/core/java/com/android/server/os/NativeTombstoneManager.java
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -356,7 +356,7 @@
return false;
}
- if (Math.abs(exitInfo.getTimestamp() - mTimestampMs) > 1000) {
+ if (Math.abs(exitInfo.getTimestamp() - mTimestampMs) > 5000) {
return false;
}
diff --git a/services/net/java/android/net/ConnectivityModuleConnector.java b/services/net/java/android/net/ConnectivityModuleConnector.java
index 62f2c35..c6b15c1 100644
--- a/services/net/java/android/net/ConnectivityModuleConnector.java
+++ b/services/net/java/android/net/ConnectivityModuleConnector.java
@@ -278,7 +278,10 @@
// This code path is only run by the system server: only the system server binds
// to the NetworkStack as a service. Other processes get the NetworkStack from
// the ServiceManager.
- maybeCrashWithTerribleFailure("Lost network stack", mPackageName);
+ maybeCrashWithTerribleFailure(
+ "Lost network stack. This is not the root cause of any issue, it is a side "
+ + "effect of a crash that happened earlier. Earlier logs should point to the "
+ + "actual issue.", mPackageName);
}
}
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 6046d78..7b449ce 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -566,11 +566,26 @@
/** @hide */
@Override
+ @SystemApi
+ public Intent registerReceiverForAllUsers(BroadcastReceiver receiver,
+ IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
IntentFilter filter, String broadcastPermission, Handler scheduler) {
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+ IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void unregisterReceiver(BroadcastReceiver receiver) {
throw new UnsupportedOperationException();
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/.project b/tests/Camera2Tests/SmartCamera/SimpleCamera/.project
deleted file mode 100644
index 2517e2d..0000000
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/.project
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>CameraShoot</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>com.android.ide.eclipse.adt.ApkBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
diff --git a/tests/HwAccelerationTest/.project b/tests/HwAccelerationTest/.project
deleted file mode 100644
index 7c04d3c..0000000
--- a/tests/HwAccelerationTest/.project
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>HwAccelerationTest</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>com.android.ide.eclipse.adt.ApkBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 840a588..086ef95 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -50,7 +50,7 @@
"cts-install-lib-host",
],
data: [
- ":com.android.apex.cts.shim.v2_prebuilt",
+ ":StagedInstallTestApexV2",
":TestAppAv1",
],
test_suites: ["general-tests"],