summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/multiuser/Android.bp1
-rw-r--r--apct-tests/perftests/multiuser/AndroidTest.xml37
-rw-r--r--apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto154
-rw-r--r--api/Android.bp38
-rw-r--r--api/api_versions_trimmer_unittests.py2
-rwxr-xr-xapi/merge_annotation_zips.py71
-rw-r--r--api/merge_annotation_zips_test.py124
-rw-r--r--core/java/android/os/BaseBundle.java11
-rw-r--r--core/java/android/os/OWNERS3
-rw-r--r--core/java/android/os/Parcel.java88
-rw-r--r--core/java/android/os/VintfObject.java7
-rw-r--r--core/java/android/permission/OWNERS3
-rw-r--r--core/java/android/widget/QuickContactBadge.java5
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java18
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java2
17 files changed, 512 insertions, 62 deletions
diff --git a/apct-tests/perftests/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp
index 91e207433f3d..c967e51e16f9 100644
--- a/apct-tests/perftests/multiuser/Android.bp
+++ b/apct-tests/perftests/multiuser/Android.bp
@@ -31,5 +31,6 @@ android_test {
],
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 9117561fe1e5..bec3cc9272c3 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 000000000000..93b06e84e130
--- /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 8dff60af8bbd..0acd759bc73e 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -24,9 +24,8 @@ package {
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 {
},
}
+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 @@ python_test_host {
"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 4eb929ea1b5d..d2e5b7d1a07e 100644
--- a/api/api_versions_trimmer_unittests.py
+++ b/api/api_versions_trimmer_unittests.py
@@ -304,4 +304,4 @@ sultCallback;Landroid/os/Handler;)Z" since="24"/>
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 000000000000..9c67d7bded76
--- /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 000000000000..26795c47af9e
--- /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/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 6da02f5c9ff5..fb21ce30415f 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -260,6 +260,9 @@ public class BaseBundle {
/**
* 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) {
@@ -270,15 +273,15 @@ public class BaseBundle {
/**
* 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<?>) {
- Supplier<?> supplier = (Supplier<?>) object;
- synchronized (this) {
- object = supplier.get();
- }
+ object = ((Supplier<?>) object).get();
mMap.setValueAt(i, object);
}
return object;
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index a870c04f9cd3..c575c80e41fc 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -69,3 +69,6 @@ per-file Bugreport* = file:/platform/frameworks/native:/cmds/dumpstate/OWNERS
# 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/Parcel.java b/core/java/android/os/Parcel.java
index a2716d211bbf..7f2e2b115986 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;
@@ -3412,12 +3414,19 @@ public final class Parcel {
private final int mLength;
private final int mType;
@Nullable private final ClassLoader mLoader;
- @Nullable private Parcel mSource;
@Nullable private Object mObject;
- @Nullable private Parcel mValueParcel;
+ @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 = source;
+ mSource = requireNonNull(source);
mPosition = position;
mLength = length;
mType = type;
@@ -3426,38 +3435,41 @@ public final class Parcel {
@Override
public Object get() {
- if (mObject == null) {
- int restore = mSource.dataPosition();
- try {
- mSource.setDataPosition(mPosition);
- mObject = mSource.readValue(mLoader);
- } finally {
- mSource.setDataPosition(restore);
- }
- mSource = null;
- if (mValueParcel != null) {
- mValueParcel.recycle();
- mValueParcel = null;
+ 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) {
- if (mObject == null) {
- out.appendFrom(mSource, mPosition, mLength + 8);
+ Parcel source = mSource;
+ if (source != null) {
+ out.appendFrom(source, mPosition, mLength + 8);
} else {
out.writeValue(mObject);
}
}
public boolean hasFileDescriptors() {
- return getValueParcel().hasFileDescriptors();
+ Parcel source = mSource;
+ return (source != null)
+ ? getValueParcel(source).hasFileDescriptors()
+ : Parcel.hasFileDescriptors(mObject);
}
@Override
public String toString() {
- return mObject == null
+ return (mSource != null)
? "Supplier{" + valueTypeToString(mType) + "@" + mPosition + "+" + mLength + '}'
: "Supplier{" + mObject + "}";
}
@@ -3476,41 +3488,49 @@ public final class Parcel {
return false;
}
LazyValue value = (LazyValue) other;
- // Check if they are either both serialized or both deserialized
- if ((mObject == null) != (value.mObject == null)) {
+ // 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 (mObject != null) {
- return mObject.equals(value.mObject);
+ // 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
+ // 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
+ // Otherwise compare metadata prior to comparing payload.
if (mType != value.mType || mLength != value.mLength) {
return false;
}
- // Finally we compare the payload
- return getValueParcel().compareData(value.getValueParcel()) == 0;
+ // Finally we compare the payload.
+ return getValueParcel(source).compareData(value.getValueParcel(otherSource)) == 0;
}
@Override
public int hashCode() {
- return Objects.hash(mObject, mLoader, mType, mLength);
+ // 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() {
- if (mValueParcel == null) {
- mValueParcel = Parcel.obtain();
+ 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.
- mValueParcel.appendFrom(mSource, mPosition, mLength + 8);
+ parcel.appendFrom(source, mPosition, mLength + 8);
+ mValueParcel = parcel;
}
- return mValueParcel;
+ return parcel;
}
}
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index bf0b655fe574..1f11197afeee 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -97,8 +97,11 @@ public class VintfObject {
* ["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/permission/OWNERS b/core/java/android/permission/OWNERS
index 19a3a8bd514a..b5466b6d3cb5 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/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index ea39f6d71573..fcaeeffe8e99 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -396,8 +396,9 @@ public class QuickContactBadge extends ImageView implements OnClickListener {
// 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/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index c24973d4f2d4..8926e20ae5ea 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 @@ public class HdmiCecMessageValidator {
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 @@ public class HdmiCecMessageValidator {
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 cca8be8a1bea..e951053b6ec7 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1122,7 +1122,7 @@ public class HdmiControlService extends SystemService {
@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 +1153,7 @@ public class HdmiControlService extends SystemService {
@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 +3353,8 @@ public class HdmiControlService extends SystemService {
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/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 3e5cbea6a2a4..c45d084ac7c9 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 @@ public class HdmiCecLocalDeviceTest {
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 ae7f422817e5..ae99dab6ed4e 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 @@ public class HdmiCecMessageValidatorTest {
}
private IntegerSubject assertMessageValidity(String message) {
- return assertThat(mHdmiCecMessageValidator.isValid(buildMessage(message)));
+ return assertThat(mHdmiCecMessageValidator.isValid(buildMessage(message), false));
}
/**