Merge "Add InputDispatcher unit tests for untrusted touches [4/n]" into sc-dev
diff --git a/Android.bp b/Android.bp
index 9829c7f..298c01a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,41 @@
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change filtered out the below license kinds as false-positives:
+// SPDX-license-identifier-LGPL
+// SPDX-license-identifier-LGPL-2.1
+// SPDX-license-identifier-LGPL-3.0
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "SPDX-license-identifier-BSD",
+ "SPDX-license-identifier-MIT",
+ "SPDX-license-identifier-Unicode-DFS",
+ "legacy_notice",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
ndk_headers {
name: "libandroid_headers",
from: "include/android",
@@ -43,3 +81,8 @@
":framework_native_aidl_gui",
],
}
+
+cc_library_headers{
+ name: "libandroid_headers_private",
+ export_include_dirs: ["include/private"],
+}
\ No newline at end of file
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index e7d0ad0..aa0ef25 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -1,5 +1,22 @@
// Copyright 2012 The Android Open Source Project
+package {
+ default_applicable_licenses: ["frameworks_native_cmds_atrace_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_cmds_atrace_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_binary {
name: "atrace",
srcs: ["atrace.cpp"],
diff --git a/cmds/bugreport/Android.bp b/cmds/bugreport/Android.bp
index 24044a6..8262aed 100644
--- a/cmds/bugreport/Android.bp
+++ b/cmds/bugreport/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "bugreport",
srcs: ["bugreport.cpp"],
diff --git a/cmds/bugreportz/Android.bp b/cmds/bugreportz/Android.bp
index 924a3a3..332f858 100644
--- a/cmds/bugreportz/Android.bp
+++ b/cmds/bugreportz/Android.bp
@@ -1,5 +1,14 @@
// bugreportz
// ==========
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "bugreportz",
diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp
index 8ea71cd..c900a24 100644
--- a/cmds/cmd/Android.bp
+++ b/cmds/cmd/Android.bp
@@ -1,3 +1,20 @@
+package {
+ default_applicable_licenses: ["frameworks_native_cmds_cmd_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_cmds_cmd_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_library_static {
name: "libcmd",
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 34e9a85..f48f1fb 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -13,6 +13,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "dumpstate_cflag_defaults",
cflags: [
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index f99588f..91aa018 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -1,3 +1,20 @@
+package {
+ default_applicable_licenses: ["frameworks_native_cmds_dumpsys_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_cmds_dumpsys_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_defaults {
name: "dumpsys_defaults",
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index e182b9d..6854c75 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -1,4 +1,13 @@
// Build the unit tests for dumpsys
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_cmds_dumpsys_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_cmds_dumpsys_license"],
+}
+
cc_test {
name: "dumpsys_test",
test_suites: ["device-tests"],
diff --git a/cmds/flatland/Android.mk b/cmds/flatland/Android.mk
index 7aa111c..754a99c 100644
--- a/cmds/flatland/Android.mk
+++ b/cmds/flatland/Android.mk
@@ -11,6 +11,9 @@
LOCAL_CFLAGS := -Wall -Werror
LOCAL_MODULE:= flatland
+LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS:= notice
+LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE
LOCAL_MODULE_TAGS := tests
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 72ffc94..c537fed 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "idlcli-defaults",
shared_libs: [
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index cbe857a..5c2211f 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "installd_defaults",
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 7c9e3b2..f67ab81 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -1,4 +1,13 @@
// Build the unit tests for installd
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "installd_utils_test",
test_suites: ["device-tests"],
@@ -157,4 +166,3 @@
"libotapreoptparameters"
],
}
-
diff --git a/cmds/ip-up-vpn/Android.mk b/cmds/ip-up-vpn/Android.mk
index e1e2204..396ae9d 100644
--- a/cmds/ip-up-vpn/Android.mk
+++ b/cmds/ip-up-vpn/Android.mk
@@ -21,6 +21,9 @@
LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_MODULE := ip-up-vpn
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp
LOCAL_MODULE_TAGS := optional
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 0cbb80f..649e53a 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "liblshal",
shared_libs: [
diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp
index 9592111..cbfbdc9 100644
--- a/cmds/lshal/libprocpartition/Android.bp
+++ b/cmds/lshal/libprocpartition/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libprocpartition",
shared_libs: [
diff --git a/cmds/rawbu/Android.bp b/cmds/rawbu/Android.bp
index 363ffc1..e34119d 100644
--- a/cmds/rawbu/Android.bp
+++ b/cmds/rawbu/Android.bp
@@ -1,5 +1,22 @@
// Copyright 2009 The Android Open Source Project
+package {
+ default_applicable_licenses: ["frameworks_native_cmds_rawbu_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_cmds_rawbu_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_binary {
name: "rawbu",
diff --git a/cmds/rss_hwm_reset/Android.bp b/cmds/rss_hwm_reset/Android.bp
index 15f10ef..cd335d4 100644
--- a/cmds/rss_hwm_reset/Android.bp
+++ b/cmds/rss_hwm_reset/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "rss_hwm_reset",
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
index a5b1ac5..3e8e3f6 100644
--- a/cmds/service/Android.bp
+++ b/cmds/service/Android.bp
@@ -1,3 +1,20 @@
+package {
+ default_applicable_licenses: ["frameworks_native_cmds_service_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_cmds_service_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_binary {
name: "service",
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index b139251..9de344a 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "servicemanager_defaults",
diff --git a/cmds/surfacereplayer/Android.bp b/cmds/surfacereplayer/Android.bp
index d4c037a..34fc8b1 100644
--- a/cmds/surfacereplayer/Android.bp
+++ b/cmds/surfacereplayer/Android.bp
@@ -1,4 +1,13 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
subdirs = [
"proto",
"replayer",
-]
\ No newline at end of file
+]
diff --git a/cmds/surfacereplayer/proto/Android.bp b/cmds/surfacereplayer/proto/Android.bp
index 71a5e23..dae976e 100644
--- a/cmds/surfacereplayer/proto/Android.bp
+++ b/cmds/surfacereplayer/proto/Android.bp
@@ -1,3 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libtrace_proto",
srcs: [
diff --git a/cmds/surfacereplayer/replayer/Android.bp b/cmds/surfacereplayer/replayer/Android.bp
index 7632311..3985230 100644
--- a/cmds/surfacereplayer/replayer/Android.bp
+++ b/cmds/surfacereplayer/replayer/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libsurfacereplayer",
srcs: [
diff --git a/data/etc/android.hardware.keystore.app_attest_key.xml b/data/etc/android.hardware.keystore.app_attest_key.xml
new file mode 100644
index 0000000..8adc439
--- /dev/null
+++ b/data/etc/android.hardware.keystore.app_attest_key.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Feature for devices that support app attestation keys (i.e. KeyMint 1.0). -->
+<permissions>
+ <feature name="android.hardware.keystore.app_attest_key" />
+</permissions>
diff --git a/headers/Android.bp b/headers/Android.bp
index 8f41c2b..7481a23 100644
--- a/headers/Android.bp
+++ b/headers/Android.bp
@@ -1,3 +1,13 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "media_plugin_headers",
vendor_available: true,
diff --git a/include/android/permission_manager.h b/include/android/permission_manager.h
index 2d5d060..753b6d1 100644
--- a/include/android/permission_manager.h
+++ b/include/android/permission_manager.h
@@ -14,6 +14,17 @@
* limitations under the License.
*/
+/**
+ * Structures and functions related to permission checks in native code.
+ *
+ * @addtogroup Permission
+ * @{
+ */
+
+/**
+ * @file permission_manager.h
+ */
+
#ifndef ANDROID_PERMISSION_MANAGER_H
#define ANDROID_PERMISSION_MANAGER_H
@@ -48,8 +59,8 @@
enum {
/**
* This is returned if the permission check completed without errors.
- * The output result is valid and contains one of {PERMISSION_MANAGER_PERMISSION_GRANTED,
- * PERMISSION_MANAGER_PERMISSION_DENIED}.
+ * The output result is valid and contains one of {::PERMISSION_MANAGER_PERMISSION_GRANTED,
+ * ::PERMISSION_MANAGER_PERMISSION_DENIED}.
*/
PERMISSION_MANAGER_STATUS_OK = 0,
/**
@@ -85,3 +96,5 @@
__END_DECLS
#endif // ANDROID_PERMISSION_MANAGER_H
+
+/** @} */
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 98fd875..b836581 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -67,9 +67,21 @@
__INTRODUCED_IN(29);
/**
- * Releases the \a surface_control object. After releasing the ASurfaceControl the caller no longer
- * has ownership of the AsurfaceControl. The surface and it's children may remain on display as long
- * as their parent remains on display.
+ * Acquires a reference on the given ASurfaceControl object. This prevents the object
+ * from being deleted until the reference is removed.
+ *
+ * To release the reference, use the ASurfaceControl_release function.
+ *
+ * Available since API level 31.
+ */
+void ASurfaceControl_acquire(ASurfaceControl* surface_control) __INTRODUCED_IN(31);
+
+/**
+ * Removes a reference that was previously acquired with one of the following functions:
+ * ASurfaceControl_createFromWindow
+ * ASurfaceControl_create
+ * ANativeWindow_acquire
+ * The surface and its children may remain on display as long as their parent remains on display.
*
* Available since API level 29.
*/
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 8744ef7..11b714f 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -30,6 +30,7 @@
*/
#include <string>
+#include <unordered_map>
#include <android-base/chrono_utils.h>
@@ -155,6 +156,7 @@
struct Finished {
uint32_t empty1;
uint32_t handled; // actually a bool, but we must maintain 8-byte alignment
+ nsecs_t consumeTime; // The time when the event was consumed by the receiving end
inline size_t size() const { return sizeof(Finished); }
} finished;
@@ -362,7 +364,8 @@
/* Receives the finished signal from the consumer in reply to the original dispatch signal.
* If a signal was received, returns the message sequence number,
- * and whether the consumer handled the message.
+ * whether the consumer handled the message, and the time the event was first read by the
+ * consumer.
*
* The returned sequence number is never 0 unless the operation failed.
*
@@ -371,7 +374,8 @@
* Returns DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
+ status_t receiveFinishedSignal(
+ const std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)>& callback);
private:
std::shared_ptr<InputChannel> mChannel;
@@ -577,6 +581,13 @@
};
std::vector<SeqChain> mSeqChains;
+ // The time at which each event with the sequence number 'seq' was consumed.
+ // This data is provided in 'finishInputEvent' so that the receiving end can measure the latency
+ // This collection is populated when the event is received, and the entries are erased when the
+ // events are finished. It should not grow infinitely because if an event is not ack'd, ANR
+ // will be raised for that connection, and no further events will be posted to that channel.
+ std::unordered_map<uint32_t /*seq*/, nsecs_t /*consumeTime*/> mConsumeTimes;
+
status_t consumeBatch(InputEventFactoryInterface* factory,
nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
status_t consumeSamples(InputEventFactoryInterface* factory,
@@ -589,6 +600,8 @@
ssize_t findBatch(int32_t deviceId, int32_t source) const;
ssize_t findTouchState(int32_t deviceId, int32_t source) const;
+ nsecs_t getConsumeTime(uint32_t seq) const;
+ void popConsumeTime(uint32_t seq);
status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
static void rewriteMessage(TouchState& state, InputMessage& msg);
diff --git a/include/private/surface_control_private.h b/include/private/surface_control_private.h
new file mode 100644
index 0000000..37a476e
--- /dev/null
+++ b/include/private/surface_control_private.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_PRIVATE_NATIVE_SURFACE_CONTROL_H
+#define ANDROID_PRIVATE_NATIVE_SURFACE_CONTROL_H
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+struct ASurfaceControl;
+struct ASurfaceControlStats;
+
+typedef struct ASurfaceControlStats ASurfaceControlStats;
+
+/**
+ * Callback to be notified when surface stats for a specific surface control are available.
+ */
+typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context,
+ ASurfaceControl* control, ASurfaceControlStats* stats);
+
+/**
+ * Registers a callback to be invoked when surface stats from a specific surface are available.
+ *
+ * \param context Optional context provided by the client that is passed into
+ * the callback.
+ *
+ * \param control The surface to retrieve callbacks for.
+ *
+ * \param func The callback to be invoked when surface stats are available.
+ */
+void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, void* context,
+ ASurfaceControl_SurfaceStatsListener func);
+
+/**
+ * Unregisters a callback to be invoked when surface stats from a specific surface are available.
+ *
+ * \param context The context passed into ASurfaceControl_registerSurfaceStatsListener
+ *
+ * \param func The callback passed into ASurfaceControl_registerSurfaceStatsListener
+ */
+void ASurfaceControl_unregisterSurfaceStatsListener(void* context,
+ ASurfaceControl_SurfaceStatsListener func);
+
+/**
+ * Returns the timestamp of when the buffer was acquired for a specific frame with frame number
+ * obtained from ASurfaceControlStats_getFrameNumber.
+ */
+int64_t ASurfaceControlStats_getAcquireTime(ASurfaceControlStats* stats);
+
+/**
+ * Returns the frame number of the surface stats object passed into the callback.
+ */
+uint64_t ASurfaceControlStats_getFrameNumber(ASurfaceControlStats* stats);
+
+__END_DECLS
+
+#endif //ANDROID_PRIVATE_NATIVE_SURFACE_CONTROL_H
diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp
index 8883c04..16cded8 100644
--- a/libs/adbd_auth/Android.bp
+++ b/libs/adbd_auth/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libadbd_auth",
cflags: [
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index cdd7764..b74923c 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -30,6 +30,15 @@
// instead of libandroid_runtime. When they are used by a vendor process,
// depending on libandroid_runtime is meaningless. In this case,
// they can depend on libandroid_runtime_lazy.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libandroid_runtime_lazy",
vendor_available: true,
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 80aa891..bb40f51 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -12,6 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_libs_arect_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_arect_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
ndk_headers {
name: "libarect_headers_for_ndk",
from: "include/android",
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b585ad2..e9d866b 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libbinder_headers",
export_include_dirs: ["include"],
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index bf4387a..ddda024 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -228,8 +228,9 @@
: Stability::getLocalLevel();
if (CC_UNLIKELY(!Stability::check(category, required))) {
- ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
+ ALOGE("Cannot do a user transaction on a %s binder (%s) in a %s context.",
category.debugString().c_str(),
+ String8(getInterfaceDescriptor()).c_str(),
Stability::levelString(required).c_str());
return BAD_TYPE;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b9d00fe..3773760 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -520,7 +520,7 @@
}
}
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID_VNDK__)
constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
#else
constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
@@ -769,200 +769,116 @@
return NO_ERROR;
}
-status_t Parcel::writeUtf8AsUtf16(const std::optional<std::string>& str) {
- if (!str) {
- return writeInt32(-1);
- }
- return writeUtf8AsUtf16(*str);
-}
-status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) {
- if (!str) {
- return writeInt32(-1);
- }
- return writeUtf8AsUtf16(*str);
-}
+status_t Parcel::writeUtf8AsUtf16(const std::optional<std::string>& str) { return writeData(str); }
+status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) { return writeData(str); }
-status_t Parcel::writeByteVectorInternal(const int8_t* data, size_t size) {
- if (size > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
+status_t Parcel::writeString16(const std::optional<String16>& str) { return writeData(str); }
+status_t Parcel::writeString16(const std::unique_ptr<String16>& str) { return writeData(str); }
- status_t status = writeInt32(size);
- if (status != OK) {
- return status;
- }
+status_t Parcel::writeByteVector(const std::vector<int8_t>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::optional<std::vector<int8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::vector<uint8_t>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::optional<std::vector<uint8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val){ return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val) { return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::optional<std::vector<int32_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::optional<std::vector<int64_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::vector<uint64_t>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::optional<std::vector<uint64_t>>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::vector<float>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::optional<std::vector<float>>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::unique_ptr<std::vector<float>>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::vector<double>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::optional<std::vector<double>>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::unique_ptr<std::vector<double>>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::vector<bool>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::optional<std::vector<bool>>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::unique_ptr<std::vector<bool>>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::vector<char16_t>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::optional<std::vector<char16_t>>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val) { return writeData(val); }
- return write(data, size);
-}
-
-status_t Parcel::writeByteVector(const std::vector<int8_t>& val) {
- return writeByteVectorInternal(val.data(), val.size());
-}
-
-status_t Parcel::writeByteVector(const std::optional<std::vector<int8_t>>& val)
-{
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(val->data(), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val)
-{
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(val->data(), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::vector<uint8_t>& val) {
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
-}
-
-status_t Parcel::writeByteVector(const std::optional<std::vector<uint8_t>>& val)
-{
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val)
-{
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-
-status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val)
-{
- return writeTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt32Vector(const std::optional<std::vector<int32_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val)
-{
- return writeTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeInt64Vector(const std::optional<std::vector<int64_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeUint64Vector(const std::vector<uint64_t>& val)
-{
- return writeTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeUint64Vector(const std::optional<std::vector<uint64_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeFloatVector(const std::vector<float>& val)
-{
- return writeTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeFloatVector(const std::optional<std::vector<float>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeFloatVector(const std::unique_ptr<std::vector<float>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeDoubleVector(const std::vector<double>& val)
-{
- return writeTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeDoubleVector(const std::optional<std::vector<double>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeDoubleVector(const std::unique_ptr<std::vector<double>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeBoolVector(const std::vector<bool>& val)
-{
- return writeTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeBoolVector(const std::optional<std::vector<bool>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeBoolVector(const std::unique_ptr<std::vector<bool>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeCharVector(const std::vector<char16_t>& val)
-{
- return writeTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeCharVector(const std::optional<std::vector<char16_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeString16Vector(const std::vector<String16>& val)
-{
- return writeTypedVector(val, &Parcel::writeString16);
-}
-
+status_t Parcel::writeString16Vector(const std::vector<String16>& val) { return writeData(val); }
status_t Parcel::writeString16Vector(
- const std::optional<std::vector<std::optional<String16>>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeString16);
-}
-
+ const std::optional<std::vector<std::optional<String16>>>& val) { return writeData(val); }
status_t Parcel::writeString16Vector(
- const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeString16);
-}
-
+ const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val) { return writeData(val); }
status_t Parcel::writeUtf8VectorAsUtf16Vector(
- const std::optional<std::vector<std::optional<std::string>>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
-
+ const std::optional<std::vector<std::optional<std::string>>>& val) { return writeData(val); }
status_t Parcel::writeUtf8VectorAsUtf16Vector(
- const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
+ const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) { return writeData(val); }
+status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) { return writeData(val); }
-status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) {
- return writeTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
+status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<base::unique_fd>& val) { return writeData(val); }
+status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<base::unique_fd>>& val) { return writeData(val); }
+status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) { return writeData(val); }
+
+status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val) { return writeData(val); }
+status_t Parcel::writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val) { return writeData(val); }
+status_t Parcel::writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val) { return writeData(val); }
+
+status_t Parcel::writeParcelable(const Parcelable& parcelable) { return writeData(parcelable); }
+
+status_t Parcel::readUtf8FromUtf16(std::optional<std::string>* str) const { return readData(str); }
+status_t Parcel::readUtf8FromUtf16(std::unique_ptr<std::string>* str) const { return readData(str); }
+
+status_t Parcel::readString16(std::optional<String16>* pArg) const { return readData(pArg); }
+status_t Parcel::readString16(std::unique_ptr<String16>* pArg) const { return readData(pArg); }
+
+status_t Parcel::readByteVector(std::vector<int8_t>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::vector<uint8_t>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::optional<std::vector<int8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::optional<std::vector<uint8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::optional<std::vector<int32_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::optional<std::vector<int64_t>>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::optional<std::vector<uint64_t>>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::vector<uint64_t>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::optional<std::vector<float>>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::unique_ptr<std::vector<float>>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::vector<float>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::optional<std::vector<double>>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::unique_ptr<std::vector<double>>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::vector<double>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::optional<std::vector<bool>>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::unique_ptr<std::vector<bool>>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::vector<bool>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::optional<std::vector<char16_t>>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::vector<char16_t>* val) const { return readData(val); }
+
+status_t Parcel::readString16Vector(
+ std::optional<std::vector<std::optional<String16>>>* val) const { return readData(val); }
+status_t Parcel::readString16Vector(
+ std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const { return readData(val); }
+status_t Parcel::readString16Vector(std::vector<String16>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(
+ std::optional<std::vector<std::optional<std::string>>>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(
+ std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const { return readData(val); }
+
+status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<base::unique_fd>>* val) const { return readData(val); }
+status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const { return readData(val); }
+status_t Parcel::readUniqueFileDescriptorVector(std::vector<base::unique_fd>* val) const { return readData(val); }
+
+status_t Parcel::readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const { return readData(val); }
+status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const { return readData(val); }
+status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const { return readData(val); }
+
+status_t Parcel::readParcelable(Parcelable* parcelable) const { return readData(parcelable); }
status_t Parcel::writeInt32(int32_t val)
{
@@ -1091,24 +1007,6 @@
return err;
}
-status_t Parcel::writeString16(const std::optional<String16>& str)
-{
- if (!str) {
- return writeInt32(-1);
- }
-
- return writeString16(*str);
-}
-
-status_t Parcel::writeString16(const std::unique_ptr<String16>& str)
-{
- if (!str) {
- return writeInt32(-1);
- }
-
- return writeString16(*str);
-}
-
status_t Parcel::writeString16(const String16& str)
{
return writeString16(str.string(), str.size());
@@ -1138,32 +1036,6 @@
return flattenBinder(val);
}
-status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
-{
- return writeTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val)
-{
- return writeNullableTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const {
- return readTypedVector(val, &Parcel::readStrongBinder);
-}
status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) {
if (!parcelable) {
@@ -1173,14 +1045,6 @@
return writeParcelable(*parcelable);
}
-status_t Parcel::writeParcelable(const Parcelable& parcelable) {
- status_t status = writeInt32(1); // parcelable is not null.
- if (status != OK) {
- return status;
- }
- return parcelable.writeToParcel(this);
-}
-
status_t Parcel::writeNativeHandle(const native_handle* handle)
{
if (!handle || handle->version != sizeof(native_handle))
@@ -1251,18 +1115,6 @@
return writeDupFileDescriptor(fd.get());
}
-status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<base::unique_fd>& val) {
- return writeTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
-status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<base::unique_fd>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
-status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob)
{
if (len > INT32_MAX) {
@@ -1477,31 +1329,6 @@
goto data_sorted;
}
-status_t Parcel::readVectorSizeWithCoarseBoundCheck(int32_t *size) const {
- int32_t requestedSize;
- const status_t status = readInt32(&requestedSize);
- if (status != NO_ERROR) return status;
-
- // We permit negative sizes, which indicate presence of a nullable vector,
- // i.e. a vector embedded in std::optional, std::unique_ptr, or std::shared_ptr.
- if (requestedSize > 0) {
- // Check if there are fewer bytes than vector elements.
- // A lower bound is 1 byte per element, satisfied by some enum and int8_t and uint8_t.
- const size_t availableBytes = dataAvail();
- if (static_cast<size_t>(requestedSize) > availableBytes) {
- // We have a size that is greater than the number of bytes available.
- // On bounds failure we do not 'rewind' position by 4 bytes of the size already read.
- ALOGW("%s: rejecting out of bounds vector size (requestedSize):%d "
- "Parcel{dataAvail:%zu mDataSize:%zu mDataPos:%zu mDataCapacity:%zu}",
- __func__, requestedSize, availableBytes, mDataSize, mDataPos, mDataCapacity);
- return BAD_VALUE;
- }
- }
-
- *size = requestedSize;
- return NO_ERROR;
-}
-
status_t Parcel::read(void* outData, size_t len) const
{
if (len > INT32_MAX) {
@@ -1605,236 +1432,6 @@
return err;
}
-status_t Parcel::readByteVector(std::vector<int8_t>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- return readByteVectorInternal(val, size);
-}
-
-status_t Parcel::readByteVector(std::vector<uint8_t>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- return readByteVectorInternal(val, size);
-}
-
-status_t Parcel::readByteVector(std::optional<std::vector<int8_t>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (!*val) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null byte vector.
- return OK;
- }
- return readByteVectorInternal(&**val, size);
-}
-
-status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (val->get() == nullptr) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null byte vector.
- return OK;
- }
- return readByteVectorInternal(val->get(), size);
-}
-
-status_t Parcel::readByteVector(std::optional<std::vector<uint8_t>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (!*val) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null byte vector.
- return OK;
- }
- return readByteVectorInternal(&**val, size);
-}
-
-status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (val->get() == nullptr) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null byte vector.
- return OK;
- }
- return readByteVectorInternal(val->get(), size);
-}
-
-status_t Parcel::readInt32Vector(std::optional<std::vector<int32_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const {
- return readTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt64Vector(std::optional<std::vector<int64_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const {
- return readTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readUint64Vector(std::optional<std::vector<uint64_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readUint64Vector(std::vector<uint64_t>* val) const {
- return readTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readFloatVector(std::optional<std::vector<float>>* val) const {
- return readNullableTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readFloatVector(std::unique_ptr<std::vector<float>>* val) const {
- return readNullableTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readFloatVector(std::vector<float>* val) const {
- return readTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readDoubleVector(std::optional<std::vector<double>>* val) const {
- return readNullableTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readDoubleVector(std::unique_ptr<std::vector<double>>* val) const {
- return readNullableTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readDoubleVector(std::vector<double>* val) const {
- return readTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readBoolVector(std::optional<std::vector<bool>>* val) const {
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->emplace();
-
- status = readBoolVector(&**val);
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-status_t Parcel::readBoolVector(std::unique_ptr<std::vector<bool>>* val) const {
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->reset(new (std::nothrow) std::vector<bool>());
-
- status = readBoolVector(val->get());
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-status_t Parcel::readBoolVector(std::vector<bool>* val) const {
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-
- if (status != OK) {
- return status;
- }
-
- if (size < 0) {
- return UNEXPECTED_NULL;
- }
-
- val->resize(size);
-
- /* C++ bool handling means a vector of bools isn't necessarily addressable
- * (we might use individual bits)
- */
- bool data;
- for (int32_t i = 0; i < size; ++i) {
- status = readBool(&data);
- (*val)[i] = data;
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
-}
-
-status_t Parcel::readCharVector(std::optional<std::vector<char16_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const {
- return readNullableTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readCharVector(std::vector<char16_t>* val) const {
- return readTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readString16Vector(
- std::optional<std::vector<std::optional<String16>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readString16Vector(
- std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readString16Vector(std::vector<String16>* val) const {
- return readTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(
- std::optional<std::vector<std::optional<std::string>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(
- std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const {
- return readTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
status_t Parcel::readInt32(int32_t *pArg) const
{
return readAligned(pArg);
@@ -2007,36 +1604,6 @@
return NO_ERROR;
}
-status_t Parcel::readUtf8FromUtf16(std::optional<std::string>* str) const {
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readInt32(&size);
- str->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- str->emplace();
- return readUtf8FromUtf16(&**str);
-}
-
-status_t Parcel::readUtf8FromUtf16(std::unique_ptr<std::string>* str) const {
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readInt32(&size);
- str->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- str->reset(new (std::nothrow) std::string());
- return readUtf8FromUtf16(str->get());
-}
-
const char* Parcel::readCString() const
{
if (mDataPos < mDataSize) {
@@ -2103,51 +1670,6 @@
return String16();
}
-status_t Parcel::readString16(std::optional<String16>* pArg) const
-{
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readInt32(&size);
- pArg->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- pArg->emplace();
-
- status = readString16(&**pArg);
-
- if (status != OK) {
- pArg->reset();
- }
-
- return status;
-}
-
-status_t Parcel::readString16(std::unique_ptr<String16>* pArg) const
-{
- const int32_t start = dataPosition();
- int32_t size;
- status_t status = readInt32(&size);
- pArg->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- pArg->reset(new (std::nothrow) String16());
-
- status = readString16(pArg->get());
-
- if (status != OK) {
- pArg->reset();
- }
-
- return status;
-}
status_t Parcel::readString16(String16* pArg) const
{
@@ -2204,18 +1726,6 @@
return val;
}
-status_t Parcel::readParcelable(Parcelable* parcelable) const {
- int32_t have_parcelable = 0;
- status_t status = readInt32(&have_parcelable);
- if (status != OK) {
- return status;
- }
- if (!have_parcelable) {
- return UNEXPECTED_NULL;
- }
- return parcelable->readFromParcel(this);
-}
-
int32_t Parcel::readExceptionCode() const
{
binder::Status status;
@@ -2334,18 +1844,6 @@
return OK;
}
-status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<base::unique_fd>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
-status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const {
- return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
-status_t Parcel::readUniqueFileDescriptorVector(std::vector<base::unique_fd>* val) const {
- return readTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const
{
int32_t blobType;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index c38249e..edadcd5 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -406,12 +406,6 @@
, mThreadPoolSeq(1)
, mCallRestriction(CallRestriction::NONE)
{
-
-// TODO(b/166468760): enforce in build system
-#if defined(__ANDROID_APEX__)
- LOG_ALWAYS_FATAL("Cannot use libbinder in APEX (only system.img libbinder) since it is not stable.");
-#endif
-
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index 339c538..b56e09f 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -76,18 +76,12 @@
}
Stability::Level Stability::getLocalLevel() {
+#ifdef __ANDROID_APEX__
+#error APEX can't use libbinder (must use libbinder_ndk)
+#endif
+
#ifdef __ANDROID_VNDK__
- #ifdef __ANDROID_APEX__
- // TODO(b/142684679) avoid use_vendor on system APEXes
- #if !defined(__ANDROID_APEX_COM_ANDROID_MEDIA_SWCODEC__) \
- && !defined(__ANDROID_APEX_TEST_COM_ANDROID_MEDIA_SWCODEC__)
- #error VNDK + APEX only defined for com.android.media.swcodec
- #endif
- // TODO(b/142684679) avoid use_vendor on system APEXes
- return Level::SYSTEM;
- #else
- return Level::VENDOR;
- #endif
+ return Level::VENDOR;
#else
// TODO(b/139325195): split up stability levels for system/APEX.
return Level::SYSTEM;
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index dc8d74c..a7a6563 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -101,4 +101,17 @@
* This does nothing if this observer was not already registered.
*/
void unregisterPackageChangeObserver(in IPackageChangeObserver observer);
+
+ /**
+ * Returns true if the package has the SHA 256 version of the signing certificate.
+ * @see PackageManager#hasSigningCertificate(String, byte[], int), where type
+ * has been set to {@link PackageManager#CERT_INPUT_SHA256}.
+ */
+ boolean hasSha256SigningCertificate(in @utf8InCpp String packageName, in byte[] certificate);
+
+ /**
+ * Returns the debug flag for the given package.
+ * Unknown packages will cause the call to fail.
+ */
+ boolean isPackageDebuggable(in String packageName);
}
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 54c49e4..7b298f5 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -190,34 +190,47 @@
// Write an Enum vector with underlying type int8_t.
// Does not use padding; each byte is contiguous.
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::vector<T>& val);
+ status_t writeEnumVector(const std::vector<T>& val)
+ { return writeData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::optional<std::vector<T>>& val);
+ status_t writeEnumVector(const std::optional<std::vector<T>>& val)
+ { return writeData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
+ status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")))
+ { return writeData(val); }
// Write an Enum vector with underlying type != int8_t.
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::vector<T>& val);
+ status_t writeEnumVector(const std::vector<T>& val)
+ { return writeData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::optional<std::vector<T>>& val);
+ status_t writeEnumVector(const std::optional<std::vector<T>>& val)
+ { return writeData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
+ status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")))
+ { return writeData(val); }
template<typename T>
- status_t writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val);
+ status_t writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val)
+ { return writeData(val); }
template<typename T>
- status_t writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
+ status_t writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")))
+ { return writeData(val); }
template<typename T>
- status_t writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
+ status_t writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")))
+ { return writeData(val); }
template<typename T>
- status_t writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val);
+ status_t writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val)
+ { return writeData(val); }
template<typename T>
- status_t writeParcelableVector(const std::vector<T>& val);
+ status_t writeParcelableVector(const std::vector<T>& val)
+ { return writeData(val); }
template<typename T>
- status_t writeNullableParcelable(const std::optional<T>& parcelable);
+ status_t writeNullableParcelable(const std::optional<T>& parcelable)
+ { return writeData(parcelable); }
template<typename T>
- status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")));
+ status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")))
+ { return writeData(parcelable); }
status_t writeParcelable(const Parcelable& parcelable);
@@ -335,35 +348,48 @@
// Read an Enum vector with underlying type int8_t.
// Does not use padding; each byte is contiguous.
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::vector<T>* val) const;
+ status_t readEnumVector(std::vector<T>* val) const
+ { return readData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
+ status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")))
+ { return readData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::optional<std::vector<T>>* val) const;
+ status_t readEnumVector(std::optional<std::vector<T>>* val) const
+ { return readData(val); }
// Read an Enum vector with underlying type != int8_t.
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::vector<T>* val) const;
+ status_t readEnumVector(std::vector<T>* val) const
+ { return readData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
+ status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")))
+ { return readData(val); }
template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
- status_t readEnumVector(std::optional<std::vector<T>>* val) const;
+ status_t readEnumVector(std::optional<std::vector<T>>* val) const
+ { return readData(val); }
template<typename T>
status_t readParcelableVector(
- std::optional<std::vector<std::optional<T>>>* val) const;
+ std::optional<std::vector<std::optional<T>>>* val) const
+ { return readData(val); }
template<typename T>
status_t readParcelableVector(
- std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const __attribute__((deprecated("use std::optional version instead")));
+ std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const __attribute__((deprecated("use std::optional version instead")))
+ { return readData(val); }
template<typename T>
- status_t readParcelableVector(std::vector<T>* val) const;
+ status_t readParcelableVector(std::vector<T>* val) const
+ { return readData(val); }
status_t readParcelable(Parcelable* parcelable) const;
template<typename T>
- status_t readParcelable(std::optional<T>* parcelable) const;
+ status_t readParcelable(std::optional<T>* parcelable) const
+ { return readData(parcelable); }
template<typename T>
- status_t readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")));
+ status_t readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")))
+ { return readData(parcelable); }
+ // If strong binder would be nullptr, readStrongBinder() returns an error.
+ // TODO: T must be derived from IInterface, fix for clarity.
template<typename T>
status_t readStrongBinder(sp<T>* val) const;
@@ -418,20 +444,13 @@
template<typename T>
status_t read(LightFlattenable<T>& val) const;
+ // resizeOutVector is used to resize AIDL out vector parameters.
template<typename T>
status_t resizeOutVector(std::vector<T>* val) const;
template<typename T>
status_t resizeOutVector(std::optional<std::vector<T>>* val) const;
template<typename T>
status_t resizeOutVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
- template<typename T>
- status_t reserveOutVector(std::vector<T>* val, size_t* size) const;
- template<typename T>
- status_t reserveOutVector(std::optional<std::vector<T>>* val,
- size_t* size) const;
- template<typename T>
- status_t reserveOutVector(std::unique_ptr<std::vector<T>>* val,
- size_t* size) const __attribute__((deprecated("use std::optional version instead")));
// Like Parcel.java's readExceptionCode(). Reads the first int32
// off of a Parcel's header, returning 0 or the negative error
@@ -518,10 +537,6 @@
void scanForFds() const;
status_t validateReadData(size_t len) const;
- // Reads an int32 size and does a coarse bounds check against the number
- // of available bytes in the Parcel.
- status_t readVectorSizeWithCoarseBoundCheck(int32_t *size) const;
-
void updateWorkSourceRequestHeaderPosition() const;
status_t finishFlattenBinder(const sp<IBinder>& binder);
@@ -540,53 +555,544 @@
status_t writeRawNullableParcelable(const Parcelable*
parcelable);
- template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
- status_t writeEnum(const T& val);
- template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
- status_t writeEnum(const T& val);
+ //-----------------------------------------------------------------------------
+ // Generic type read and write methods for Parcel:
+ //
+ // readData(T *value) will read a value from the Parcel.
+ // writeData(const T& value) will write a value to the Parcel.
+ //
+ // Our approach to parceling is based on two overloaded functions
+ // readData() and writeData() that generate parceling code for an
+ // object automatically based on its type. The code from templates are generated at
+ // compile time (if constexpr), and decomposes an object through a call graph matching
+ // recursive descent of the template typename.
+ //
+ // This approach unifies handling of complex objects,
+ // resulting in fewer lines of code, greater consistency,
+ // extensibility to nested types, efficiency (decisions made at compile time),
+ // and better code maintainability and optimization.
+ //
+ // Design decision: Incorporate the read and write code into Parcel rather than
+ // as a non-intrusive serializer that emits a byte stream, as we have
+ // active objects, alignment, legacy code, and historical idiosyncrasies.
+ //
+ // --- Overview
+ //
+ // Parceling is a way of serializing objects into a sequence of bytes for communication
+ // between processes, as part of marshaling data for remote procedure calls.
+ //
+ // The Parcel instance contains objects serialized as bytes, such as the following:
+ //
+ // 1) Ordinary primitive data such as int, float.
+ // 2) Established structured data such as String16, std::string.
+ // 3) Parcelables, which are C++ objects that derive from Parcelable (and thus have a
+ // readFromParcel and writeToParcel method). (Similar for Java)
+ // 4) A std::vector<> of such data.
+ // 5) Nullable objects contained in std::optional, std::unique_ptr, or std::shared_ptr.
+ //
+ // And active objects from the Android ecosystem such as:
+ // 6) File descriptors, base::unique_fd (kernel object handles)
+ // 7) Binder objects, sp<IBinder> (active Android RPC handles)
+ //
+ // Objects from (1) through (5) serialize into the mData buffer.
+ // Active objects (6) and (7) serialize into both mData and mObjects buffers.
+ //
+ // --- Data layout details
+ //
+ // Data is read or written to the parcel by recursively decomposing the type of the parameter
+ // type T through readData() and writeData() methods.
+ //
+ // We focus on writeData() here in our explanation of the data layout.
+ //
+ // 1) Alignment
+ // Implementation detail: Regardless of the parameter type, writeData() calls are designed
+ // to finish at a multiple of 4 bytes, the default alignment of the Parcel.
+ //
+ // Writes of single uint8_t, int8_t, enums based on types of size 1, char16_t, etc
+ // will result in 4 bytes being written. The data is widened to int32 and then written;
+ // hence the position of the nonzero bytes depend on the native endianness of the CPU.
+ //
+ // Writes of primitive values with 8 byte size, double, int64_t, uint64_t,
+ // are stored with 4 byte alignment. The ARM and x86/x64 permit unaligned reads
+ // and writes (albeit with potential latency/throughput penalty) which may or may
+ // not be observable unless the process is IO bound.
+ //
+ // 2) Parcelables
+ // Parcelables are detected by the type's base class, and implemented through calling
+ // into the Parcelable type's readFromParcel() or writeToParcel() methods.
+ // Historically, due to null object detection, a (int32_t) 1 is prepended to the data written.
+ // Parcelables must have a default constructor (i.e. one that takes no arguments).
+ //
+ // 3) Arrays
+ // Arrays of uint8_t and int8_t, and enums based on size 1 are written as
+ // a contiguous packed byte stream. Hidden zero padding is applied at the end of the byte
+ // stream to make a multiple of 4 bytes (and prevent info leakage when writing).
+ //
+ // All other array writes can be conceptually thought of as recursively calling
+ // writeData on the individual elements (though may be implemented differently for speed).
+ // As discussed in (1), alignment rules are therefore applied for each element
+ // write (not as an aggregate whole), so the wire representation of data can be
+ // substantially larger.
+ //
+ // Historical Note:
+ // Because of element-wise alignment, CharVector and BoolVector are expanded
+ // element-wise into integers even though they could have been optimized to be packed
+ // just like uint8_t, int8_t (size 1 data).
+ //
+ // 3.1) Arrays accessed by the std::vector type. This is the default for AIDL.
+ //
+ // 4) Nullables
+ // std::optional, std::unique_ptr, std::shared_ptr are all parceled identically
+ // (i.e. result in identical byte layout).
+ // The target of the std::optional, std::unique_ptr, or std::shared_ptr
+ // can either be a std::vector, String16, std::string, or a Parcelable.
+ //
+ // Detection of null relies on peeking the first int32 data and checking if the
+ // the peeked value is considered invalid for the object:
+ // (-1 for vectors, String16, std::string) (0 for Parcelables). If the peeked value
+ // is invalid, then a null is returned.
+ //
+ // Application Note: When to use each nullable type:
+ //
+ // std::optional: Embeds the object T by value rather than creating a new instance
+ // by managed pointer as std::unique_ptr or std::shared_ptr. This will save a malloc
+ // when creating an optional instance.
+ //
+ // Use of std::optionals by value can result in copies of the underlying value stored in it,
+ // so a std::move may be used to move in and move out (for example) a vector value into
+ // the std::optional or for the std::optional itself.
+ //
+ // std::unique_ptr, std::shared_ptr: These are preferred when the lifetime of the object is
+ // already managed by the application. This reduces unnecessary copying of data
+ // especially when the calls are local in-proc (rather than via binder rpc).
+ //
+ // 5) StrongBinder (sp<IBinder>)
+ // StrongBinder objects are written regardless of null. When read, null StrongBinder values
+ // will be interpreted as UNKNOWN_ERROR if the type is a single argument <sp<T>>
+ // or in a vector argument <std::vector<sp<T>>. However, they will be read without an error
+ // if present in a std::optional, std::unique_ptr, or std::shared_ptr vector, e.g.
+ // <std::optional<std::vector<sp<T>>>.
+ //
+ // See AIDL annotation @Nullable, readStrongBinder(), and readNullableStrongBinder().
+ //
+ // Historical Note: writing a vector of StrongBinder objects <std::vector<sp<T>>
+ // containing a null will not cause an error. However reading such a vector will cause
+ // an error _and_ early termination of the read.
- template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
- status_t readEnum(T* pArg) const;
- template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
- status_t readEnum(T* pArg) const;
+ // --- Examples
+ //
+ // Using recursive parceling, we can parcel complex data types so long
+ // as they obey the rules described above.
+ //
+ // Example #1
+ // Parceling of a 3D vector
+ //
+ // std::vector<std::vector<std::vector<int32_t>>> v1 {
+ // { {1}, {2, 3}, {4} },
+ // {},
+ // { {10}, {20}, {30, 40} },
+ // };
+ // Parcel p1;
+ // p1.writeData(v1);
+ // decltype(v1) v2;
+ // p1.setDataPosition(0);
+ // p1.readData(&v2);
+ // ASSERT_EQ(v1, v2);
+ //
+ // Example #2
+ // Parceling of mixed shared pointers
+ //
+ // Parcel p1;
+ // auto sp1 = std::make_shared<std::vector<std::shared_ptr<std::vector<int>>>>(3);
+ // (*sp1)[2] = std::make_shared<std::vector<int>>(3);
+ // (*(*sp1)[2])[2] = 2;
+ // p1.writeData(sp1);
+ // decltype(sp1) sp2;
+ // p1.setDataPosition(0);
+ // p1.readData(&sp2);
+ // ASSERT_EQ((*sp1)[0], (*sp2)[0]); // nullptr
+ // ASSERT_EQ((*sp1)[1], (*sp2)[1]); // nullptr
+ // ASSERT_EQ(*(*sp1)[2], *(*sp2)[2]); // { 0, 0, 2}
- status_t writeByteVectorInternal(const int8_t* data, size_t size);
- template<typename T>
- status_t readByteVectorInternal(std::vector<T>* val, size_t size) const;
+ // --- Helper Methods
+ // TODO: move this to a utils header.
+ //
+ // Determine if a type is a specialization of a templated type
+ // Example: is_specialization_v<T, std::vector>
- template<typename T, typename U>
- status_t unsafeReadTypedVector(std::vector<T>* val,
- status_t(Parcel::*read_func)(U*) const) const;
- template<typename T>
- status_t readNullableTypedVector(std::optional<std::vector<T>>* val,
- status_t(Parcel::*read_func)(T*) const) const;
- template<typename T>
- status_t readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
- status_t(Parcel::*read_func)(T*) const) const __attribute__((deprecated("use std::optional version instead")));
- template<typename T>
- status_t readTypedVector(std::vector<T>* val,
- status_t(Parcel::*read_func)(T*) const) const;
- template<typename T, typename U>
- status_t unsafeWriteTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(U));
- template<typename T>
- status_t writeNullableTypedVector(const std::optional<std::vector<T>>& val,
- status_t(Parcel::*write_func)(const T&));
- template<typename T>
- status_t writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
- status_t(Parcel::*write_func)(const T&)) __attribute__((deprecated("use std::optional version instead")));
- template<typename T>
- status_t writeNullableTypedVector(const std::optional<std::vector<T>>& val,
- status_t(Parcel::*write_func)(T));
- template<typename T>
- status_t writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
- status_t(Parcel::*write_func)(T)) __attribute__((deprecated("use std::optional version instead")));
- template<typename T>
- status_t writeTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(const T&));
- template<typename T>
- status_t writeTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(T));
+ template <typename Test, template <typename...> class Ref>
+ struct is_specialization : std::false_type {};
+
+ template <template <typename...> class Ref, typename... Args>
+ struct is_specialization<Ref<Args...>, Ref>: std::true_type {};
+
+ template <typename Test, template <typename...> class Ref>
+ static inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value;
+
+ // Get the first template type from a container, the T from MyClass<T, ...>.
+ template<typename T> struct first_template_type;
+
+ template <template <typename ...> class V, typename T, typename... Args>
+ struct first_template_type<V<T, Args...>> {
+ using type_t = T;
+ };
+
+ template <typename T>
+ using first_template_type_t = typename first_template_type<T>::type_t;
+
+ // For static assert(false) we need a template version to avoid early failure.
+ template <typename T>
+ static inline constexpr bool dependent_false_v = false;
+
+ // primitive types that we consider packed and trivially copyable as an array
+ template <typename T>
+ static inline constexpr bool is_pointer_equivalent_array_v =
+ std::is_same_v<T, int8_t>
+ || std::is_same_v<T, uint8_t>
+ // We could support int16_t and uint16_t, but those aren't currently AIDL types.
+ || std::is_same_v<T, int32_t>
+ || std::is_same_v<T, uint32_t>
+ || std::is_same_v<T, float>
+ // are unaligned reads and write support is assumed.
+ || std::is_same_v<T, uint64_t>
+ || std::is_same_v<T, int64_t>
+ || std::is_same_v<T, double>
+ || (std::is_enum_v<T> && (sizeof(T) == 1 || sizeof(T) == 4)); // size check not type
+
+ // allowed "nullable" types
+ // These are nonintrusive containers std::optional, std::unique_ptr, std::shared_ptr.
+ template <typename T>
+ static inline constexpr bool is_parcel_nullable_type_v =
+ is_specialization_v<T, std::optional>
+ || is_specialization_v<T, std::unique_ptr>
+ || is_specialization_v<T, std::shared_ptr>;
+
+ // special int32 value to indicate NonNull or Null parcelables
+ // This is fixed to be only 0 or 1 by contract, do not change.
+ static constexpr int32_t kNonNullParcelableFlag = 1;
+ static constexpr int32_t kNullParcelableFlag = 0;
+
+ // special int32 size representing a null vector, when applicable in Nullable data.
+ // This fixed as -1 by contract, do not change.
+ static constexpr int32_t kNullVectorSize = -1;
+
+ // --- readData and writeData methods.
+ // We choose a mixture of function and template overloads to improve code readability.
+ // TODO: Consider C++20 concepts when they become available.
+
+ // writeData function overloads.
+ // Implementation detail: Function overloading improves code readability over
+ // template overloading, but prevents writeData<T> from being used for those types.
+
+ status_t writeData(bool t) {
+ return writeBool(t); // this writes as int32_t
+ }
+
+ status_t writeData(int8_t t) {
+ return writeByte(t); // this writes as int32_t
+ }
+
+ status_t writeData(uint8_t t) {
+ return writeByte(static_cast<int8_t>(t)); // this writes as int32_t
+ }
+
+ status_t writeData(char16_t t) {
+ return writeChar(t); // this writes as int32_t
+ }
+
+ status_t writeData(int32_t t) {
+ return writeInt32(t);
+ }
+
+ status_t writeData(uint32_t t) {
+ return writeUint32(t);
+ }
+
+ status_t writeData(int64_t t) {
+ return writeInt64(t);
+ }
+
+ status_t writeData(uint64_t t) {
+ return writeUint64(t);
+ }
+
+ status_t writeData(float t) {
+ return writeFloat(t);
+ }
+
+ status_t writeData(double t) {
+ return writeDouble(t);
+ }
+
+ status_t writeData(const String16& t) {
+ return writeString16(t);
+ }
+
+ status_t writeData(const std::string& t) {
+ return writeUtf8AsUtf16(t);
+ }
+
+ status_t writeData(const base::unique_fd& t) {
+ return writeUniqueFileDescriptor(t);
+ }
+
+ status_t writeData(const Parcelable& t) { // std::is_base_of_v<Parcelable, T>
+ // implemented here. writeParcelable() calls this.
+ status_t status = writeData(static_cast<int32_t>(kNonNullParcelableFlag));
+ if (status != OK) return status;
+ return t.writeToParcel(this);
+ }
+
+ // writeData<T> template overloads.
+ // Written such that the first template type parameter is the complete type
+ // of the first function parameter.
+ template <typename T,
+ typename std::enable_if_t<std::is_enum_v<T>, bool> = true>
+ status_t writeData(const T& t) {
+ // implemented here. writeEnum() calls this.
+ using UT = std::underlying_type_t<T>;
+ return writeData(static_cast<UT>(t)); // recurse
+ }
+
+ template <typename T,
+ typename std::enable_if_t<is_specialization_v<T, sp>, bool> = true>
+ status_t writeData(const T& t) {
+ return writeStrongBinder(t);
+ }
+
+ // std::optional, std::unique_ptr, std::shared_ptr special case.
+ template <typename CT,
+ typename std::enable_if_t<is_parcel_nullable_type_v<CT>, bool> = true>
+ status_t writeData(const CT& c) {
+ using T = first_template_type_t<CT>; // The T in CT == C<T, ...>
+ if constexpr (is_specialization_v<T, std::vector>
+ || std::is_same_v<T, String16>
+ || std::is_same_v<T, std::string>) {
+ if (!c) return writeData(static_cast<int32_t>(kNullVectorSize));
+ } else if constexpr (std::is_base_of_v<Parcelable, T>) {
+ if (!c) return writeData(static_cast<int32_t>(kNullParcelableFlag));
+ } else /* constexpr */ { // could define this, but raise as error.
+ static_assert(dependent_false_v<CT>);
+ }
+ return writeData(*c);
+ }
+
+ template <typename CT,
+ typename std::enable_if_t<is_specialization_v<CT, std::vector>, bool> = true>
+ status_t writeData(const CT& c) {
+ using T = first_template_type_t<CT>; // The T in CT == C<T, ...>
+ if (c.size() > std::numeric_limits<int32_t>::max()) return BAD_VALUE;
+ const auto size = static_cast<int32_t>(c.size());
+ writeData(size);
+ if constexpr (is_pointer_equivalent_array_v<T>) {
+ constexpr size_t limit = std::numeric_limits<size_t>::max() / sizeof(T);
+ if (c.size() > limit) return BAD_VALUE;
+ // is_pointer_equivalent types do not have gaps which could leak info,
+ // which is only a concern when writing through binder.
+
+ // TODO: Padding of the write is suboptimal when the length of the
+ // data is not a multiple of 4. Consider improving the write() method.
+ return write(c.data(), c.size() * sizeof(T));
+ } else if constexpr (std::is_same_v<T, bool>
+ || std::is_same_v<T, char16_t>) {
+ // reserve data space to write to
+ auto data = reinterpret_cast<int32_t*>(writeInplace(c.size() * sizeof(int32_t)));
+ if (data == nullptr) return BAD_VALUE;
+ for (const auto t: c) {
+ *data++ = static_cast<int32_t>(t);
+ }
+ } else /* constexpr */ {
+ for (const auto &t : c) {
+ const status_t status = writeData(t);
+ if (status != OK) return status;
+ }
+ }
+ return OK;
+ }
+
+ // readData function overloads.
+ // Implementation detail: Function overloading improves code readability over
+ // template overloading, but prevents readData<T> from being used for those types.
+
+ status_t readData(bool* t) const {
+ return readBool(t); // this reads as int32_t
+ }
+
+ status_t readData(int8_t* t) const {
+ return readByte(t); // this reads as int32_t
+ }
+
+ status_t readData(uint8_t* t) const {
+ return readByte(reinterpret_cast<int8_t*>(t)); // NOTE: this reads as int32_t
+ }
+
+ status_t readData(char16_t* t) const {
+ return readChar(t); // this reads as int32_t
+ }
+
+ status_t readData(int32_t* t) const {
+ return readInt32(t);
+ }
+
+ status_t readData(uint32_t* t) const {
+ return readUint32(t);
+ }
+
+ status_t readData(int64_t* t) const {
+ return readInt64(t);
+ }
+
+ status_t readData(uint64_t* t) const {
+ return readUint64(t);
+ }
+
+ status_t readData(float* t) const {
+ return readFloat(t);
+ }
+
+ status_t readData(double* t) const {
+ return readDouble(t);
+ }
+
+ status_t readData(String16* t) const {
+ return readString16(t);
+ }
+
+ status_t readData(std::string* t) const {
+ return readUtf8FromUtf16(t);
+ }
+
+ status_t readData(base::unique_fd* t) const {
+ return readUniqueFileDescriptor(t);
+ }
+
+ status_t readData(Parcelable* t) const { // std::is_base_of_v<Parcelable, T>
+ // implemented here. readParcelable() calls this.
+ int32_t present;
+ status_t status = readData(&present);
+ if (status != OK) return status;
+ if (present != kNonNullParcelableFlag) return UNEXPECTED_NULL;
+ return t->readFromParcel(this);
+ }
+
+ // readData<T> template overloads.
+ // Written such that the first template type parameter is the complete type
+ // of the first function parameter.
+
+ template <typename T,
+ typename std::enable_if_t<std::is_enum_v<T>, bool> = true>
+ status_t readData(T* t) const {
+ // implemented here. readEnum() calls this.
+ using UT = std::underlying_type_t<T>;
+ return readData(reinterpret_cast<UT*>(t));
+ }
+
+ template <typename T,
+ typename std::enable_if_t<is_specialization_v<T, sp>, bool> = true>
+ status_t readData(T* t) const {
+ return readStrongBinder(t); // Note: on null, returns failure
+ }
+
+
+ template <typename CT,
+ typename std::enable_if_t<is_parcel_nullable_type_v<CT>, bool> = true>
+ status_t readData(CT* c) const {
+ using T = first_template_type_t<CT>; // The T in CT == C<T, ...>
+ const size_t startPos = dataPosition();
+ int32_t peek;
+ status_t status = readData(&peek);
+ if (status != OK) return status;
+ if constexpr (is_specialization_v<T, std::vector>
+ || std::is_same_v<T, String16>
+ || std::is_same_v<T, std::string>) {
+ if (peek == kNullVectorSize) {
+ c->reset();
+ return OK;
+ }
+ } else if constexpr (std::is_base_of_v<Parcelable, T>) {
+ if (peek == kNullParcelableFlag) {
+ c->reset();
+ return OK;
+ }
+ } else /* constexpr */ { // could define this, but raise as error.
+ static_assert(dependent_false_v<CT>);
+ }
+ // create a new object.
+ if constexpr (is_specialization_v<CT, std::optional>) {
+ c->emplace();
+ } else /* constexpr */ {
+ T* const t = new (std::nothrow) T; // contents read from Parcel below.
+ if (t == nullptr) return NO_MEMORY;
+ c->reset(t);
+ }
+ // rewind data ptr to reread (this is pretty quick), otherwise we could
+ // pass an optional argument to readData to indicate a peeked value.
+ setDataPosition(startPos);
+ if constexpr (is_specialization_v<T, std::vector>) {
+ return readData(&**c, READ_FLAG_SP_NULLABLE); // nullable sp<> allowed now
+ } else {
+ return readData(&**c);
+ }
+ }
+
+ // std::vector special case, incorporating flags whether the vector
+ // accepts nullable sp<> to be read.
+ enum ReadFlags {
+ READ_FLAG_NONE = 0,
+ READ_FLAG_SP_NULLABLE = 1 << 0,
+ };
+
+ template <typename CT,
+ typename std::enable_if_t<is_specialization_v<CT, std::vector>, bool> = true>
+ status_t readData(CT* c, ReadFlags readFlags = READ_FLAG_NONE) const {
+ using T = first_template_type_t<CT>; // The T in CT == C<T, ...>
+ int32_t size;
+ status_t status = readInt32(&size);
+ if (status != OK) return status;
+ if (size < 0) return UNEXPECTED_NULL;
+ const size_t availableBytes = dataAvail(); // coarse bound on vector size.
+ if (static_cast<size_t>(size) > availableBytes) return BAD_VALUE;
+ c->clear(); // must clear before resizing/reserving otherwise move ctors may be called.
+ if constexpr (is_pointer_equivalent_array_v<T>) {
+ // could consider POD without gaps and alignment of 4.
+ auto data = reinterpret_cast<const T*>(
+ readInplace(static_cast<size_t>(size) * sizeof(T)));
+ if (data == nullptr) return BAD_VALUE;
+ c->insert(c->begin(), data, data + size); // insert should do a reserve().
+ } else if constexpr (std::is_same_v<T, bool>
+ || std::is_same_v<T, char16_t>) {
+ c->reserve(size); // avoids default initialization
+ auto data = reinterpret_cast<const int32_t*>(
+ readInplace(static_cast<size_t>(size) * sizeof(int32_t)));
+ if (data == nullptr) return BAD_VALUE;
+ for (int32_t i = 0; i < size; ++i) {
+ c->emplace_back(static_cast<T>(*data++));
+ }
+ } else if constexpr (is_specialization_v<T, sp>) {
+ c->resize(size); // calls ctor
+ if (readFlags & READ_FLAG_SP_NULLABLE) {
+ for (auto &t : *c) {
+ status = readNullableStrongBinder(&t); // allow nullable
+ if (status != OK) return status;
+ }
+ } else {
+ for (auto &t : *c) {
+ status = readStrongBinder(&t);
+ if (status != OK) return status;
+ }
+ }
+ } else /* constexpr */ {
+ c->resize(size); // calls ctor
+ for (auto &t : *c) {
+ status = readData(&t);
+ if (status != OK) return status;
+ }
+ }
+ return OK;
+ }
+
+ //-----------------------------------------------------------------------------
+ private:
status_t mError;
uint8_t* mData;
@@ -792,7 +1298,6 @@
template<typename T>
status_t Parcel::resizeOutVector(std::vector<T>* val) const {
int32_t size;
- // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
status_t err = readInt32(&size);
if (err != NO_ERROR) {
return err;
@@ -808,7 +1313,6 @@
template<typename T>
status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const {
int32_t size;
- // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
status_t err = readInt32(&size);
if (err != NO_ERROR) {
return err;
@@ -825,7 +1329,6 @@
template<typename T>
status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const {
int32_t size;
- // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
status_t err = readInt32(&size);
if (err != NO_ERROR) {
return err;
@@ -840,61 +1343,6 @@
}
template<typename T>
-status_t Parcel::reserveOutVector(std::vector<T>* val, size_t* size) const {
- int32_t read_size;
- status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
- if (err != NO_ERROR) {
- return err;
- }
-
- if (read_size < 0) {
- return UNEXPECTED_NULL;
- }
- *size = static_cast<size_t>(read_size);
- val->reserve(*size);
- return OK;
-}
-
-template<typename T>
-status_t Parcel::reserveOutVector(std::optional<std::vector<T>>* val, size_t* size) const {
- int32_t read_size;
- status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
- if (err != NO_ERROR) {
- return err;
- }
-
- if (read_size >= 0) {
- *size = static_cast<size_t>(read_size);
- val->emplace();
- (*val)->reserve(*size);
- } else {
- val->reset();
- }
-
- return OK;
-}
-
-template<typename T>
-status_t Parcel::reserveOutVector(std::unique_ptr<std::vector<T>>* val,
- size_t* size) const {
- int32_t read_size;
- status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
- if (err != NO_ERROR) {
- return err;
- }
-
- if (read_size >= 0) {
- *size = static_cast<size_t>(read_size);
- val->reset(new std::vector<T>());
- (*val)->reserve(*size);
- } else {
- val->reset();
- }
-
- return OK;
-}
-
-template<typename T>
status_t Parcel::readStrongBinder(sp<T>* val) const {
sp<IBinder> tmp;
status_t ret = readStrongBinder(&tmp);
@@ -926,422 +1374,6 @@
return ret;
}
-template<typename T, typename U>
-status_t Parcel::unsafeReadTypedVector(
- std::vector<T>* val,
- status_t(Parcel::*read_func)(U*) const) const {
- int32_t size;
- status_t status = this->readVectorSizeWithCoarseBoundCheck(&size);
-
- if (status != OK) {
- return status;
- }
-
- if (size < 0) {
- return UNEXPECTED_NULL;
- }
-
- if (val->max_size() < static_cast<size_t>(size)) {
- return NO_MEMORY;
- }
-
- val->resize(static_cast<size_t>(size));
-
- if (val->size() < static_cast<size_t>(size)) {
- return NO_MEMORY;
- }
-
- for (auto& v: *val) {
- status = (this->*read_func)(&v);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
-}
-
-template<typename T>
-status_t Parcel::readTypedVector(std::vector<T>* val,
- status_t(Parcel::*read_func)(T*) const) const {
- return unsafeReadTypedVector(val, read_func);
-}
-
-template<typename T>
-status_t Parcel::readNullableTypedVector(std::optional<std::vector<T>>* val,
- status_t(Parcel::*read_func)(T*) const) const {
- const size_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->emplace();
-
- status = unsafeReadTypedVector(&**val, read_func);
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-template<typename T>
-status_t Parcel::readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
- status_t(Parcel::*read_func)(T*) const) const {
- const size_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->reset(new std::vector<T>());
-
- status = unsafeReadTypedVector(val->get(), read_func);
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-template<typename T, typename U>
-status_t Parcel::unsafeWriteTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(U)) {
- if (val.size() > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
-
- status_t status = this->writeInt32(static_cast<int32_t>(val.size()));
-
- if (status != OK) {
- return status;
- }
-
- for (const auto& item : val) {
- status = (this->*write_func)(item);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
-}
-
-template<typename T>
-status_t Parcel::writeTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(const T&)) {
- return unsafeWriteTypedVector(val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeTypedVector(const std::vector<T>& val,
- status_t(Parcel::*write_func)(T)) {
- return unsafeWriteTypedVector(val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::optional<std::vector<T>>& val,
- status_t(Parcel::*write_func)(const T&)) {
- if (!val) {
- return this->writeInt32(-1);
- }
-
- return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
- status_t(Parcel::*write_func)(const T&)) {
- if (val.get() == nullptr) {
- return this->writeInt32(-1);
- }
-
- return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::optional<std::vector<T>>& val,
- status_t(Parcel::*write_func)(T)) {
- if (!val) {
- return this->writeInt32(-1);
- }
-
- return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
- status_t(Parcel::*write_func)(T)) {
- if (val.get() == nullptr) {
- return this->writeInt32(-1);
- }
-
- return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::vector<T>* val) const {
- return unsafeReadTypedVector<T, Parcelable>(val, &Parcel::readParcelable);
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::optional<std::vector<std::optional<T>>>* val) const {
- const size_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->emplace();
-
- using NullableT = std::optional<T>;
- status = unsafeReadTypedVector<NullableT, NullableT>(&**val, &Parcel::readParcelable);
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const {
- const size_t start = dataPosition();
- int32_t size;
- status_t status = readVectorSizeWithCoarseBoundCheck(&size);
- val->reset();
-
- if (status != OK || size < 0) {
- return status;
- }
-
- setDataPosition(start);
- val->reset(new std::vector<std::unique_ptr<T>>());
-
- using NullableT = std::unique_ptr<T>;
- status = unsafeReadTypedVector<NullableT, NullableT>(val->get(), &Parcel::readParcelable);
-
- if (status != OK) {
- val->reset();
- }
-
- return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelable(std::optional<T>* parcelable) const {
- const size_t start = dataPosition();
- int32_t present;
- status_t status = readInt32(&present);
- parcelable->reset();
-
- if (status != OK || !present) {
- return status;
- }
-
- setDataPosition(start);
- parcelable->emplace();
-
- status = readParcelable(&**parcelable);
-
- if (status != OK) {
- parcelable->reset();
- }
-
- return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelable(std::unique_ptr<T>* parcelable) const {
- const size_t start = dataPosition();
- int32_t present;
- status_t status = readInt32(&present);
- parcelable->reset();
-
- if (status != OK || !present) {
- return status;
- }
-
- setDataPosition(start);
- parcelable->reset(new T());
-
- status = readParcelable(parcelable->get());
-
- if (status != OK) {
- parcelable->reset();
- }
-
- return status;
-}
-
-template<typename T>
-status_t Parcel::writeNullableParcelable(const std::optional<T>& parcelable) {
- return writeRawNullableParcelable(parcelable ? &*parcelable : nullptr);
-}
-
-template<typename T>
-status_t Parcel::writeNullableParcelable(const std::unique_ptr<T>& parcelable) {
- return writeRawNullableParcelable(parcelable.get());
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::vector<T>& val) {
- return unsafeWriteTypedVector<T,const Parcelable&>(val, &Parcel::writeParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val) {
- if (!val) {
- return this->writeInt32(-1);
- }
-
- using NullableT = std::optional<T>;
- return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) {
- if (val.get() == nullptr) {
- return this->writeInt32(-1);
- }
-
- return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable<T>);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) {
- if (val.get() == nullptr) {
- return this->writeInt32(-1);
- }
-
- using NullableT = std::unique_ptr<T>;
- return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val) {
- if (val.get() == nullptr) {
- return this->writeInt32(-1);
- }
-
- using NullableT = std::optional<T>;
- return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
-status_t Parcel::writeEnum(const T& val) {
- return writeInt32(static_cast<int32_t>(val));
-}
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
-status_t Parcel::writeEnum(const T& val) {
- return writeInt64(static_cast<int64_t>(val));
-}
-
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::vector<T>& val) {
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::optional<std::vector<T>>& val) {
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
- if (!val) return writeInt32(-1);
- return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::vector<T>& val) {
- return writeTypedVector(val, &Parcel::writeEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::optional<std::vector<T>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
- return writeNullableTypedVector(val, &Parcel::writeEnum);
-}
-
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
-status_t Parcel::readEnum(T* pArg) const {
- return readInt32(reinterpret_cast<int32_t *>(pArg));
-}
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
-status_t Parcel::readEnum(T* pArg) const {
- return readInt64(reinterpret_cast<int64_t *>(pArg));
-}
-
-template<typename T>
-inline status_t Parcel::readByteVectorInternal(std::vector<T>* val, size_t size) const {
- // readByteVectorInternal expects a vector that has been reserved (but not
- // resized) to have the provided size.
- const T* data = reinterpret_cast<const T*>(readInplace(size));
- if (!data) return BAD_VALUE;
- val->clear();
- val->insert(val->begin(), data, data+size);
- return NO_ERROR;
-}
-
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::vector<T>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- return readByteVectorInternal(val, size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::optional<std::vector<T>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (!*val) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null Enum vector.
- return OK;
- }
- return readByteVectorInternal(&**val, size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
- size_t size;
- if (status_t status = reserveOutVector(val, &size); status != OK) return status;
- if (val->get() == nullptr) {
- // reserveOutVector does not create the out vector if size is < 0.
- // This occurs when writing a null Enum vector.
- return OK;
- }
- return readByteVectorInternal(val->get(), size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::vector<T>* val) const {
- return readTypedVector(val, &Parcel::readEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::optional<std::vector<T>>* val) const {
- return readNullableTypedVector(val, &Parcel::readEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
- return readNullableTypedVector(val, &Parcel::readEnum);
-}
-
// ---------------------------------------------------------------------------
inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 897c72a..eb103d3 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -15,6 +15,23 @@
*/
// TODO(b/31559095): bionic on host should define this
+package {
+ default_applicable_licenses: ["frameworks_native_libs_binder_ndk_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_binder_ndk_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_defaults {
name: "libbinder_ndk_host_user",
target: {
diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h
index bd51b11..5842925 100644
--- a/libs/binder/ndk/include_cpp/android/binder_to_string.h
+++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h
@@ -28,10 +28,22 @@
#include <codecvt>
#include <locale>
+#include <memory>
+#include <optional>
#include <sstream>
#include <string>
#include <type_traits>
+#if __has_include(<utils/StrongPointer.h>)
+#include <utils/StrongPointer.h>
+#define HAS_STRONG_POINTER
+#endif
+
+#if __has_include(<utils/String16.h>)
+#include <utils/String16.h>
+#define HAS_STRING16
+#endif
+
#if __has_include(<android/binder_ibinder.h>)
#include <android/binder_auto_utils.h>
#include <android/binder_interface_utils.h>
@@ -42,9 +54,6 @@
#include <binder/IInterface.h>
#include <binder/ParcelFileDescriptor.h>
#include <binder/ParcelableHolder.h>
-#include <utils/String16.h>
-#include <utils/StrongPointer.h>
-#define HAS_CPP_INTERFACE
#endif //_has_include
namespace android {
@@ -80,11 +89,28 @@
enum { value = decltype(_test<_T>(0))::value };
};
-// Truthy if _T is like a pointer
+template <typename T, template <typename...> typename U>
+struct IsInstantiationOf : std::false_type {};
+
+template <template <typename...> typename U, typename... Args>
+struct IsInstantiationOf<U<Args...>, U> : std::true_type {};
+
+// Truthy if _T is like a pointer: one of sp/optional/shared_ptr
template <typename _T>
class IsPointerLike {
template <typename _U>
- static auto _test(int) -> decltype(!std::declval<_U>(), *std::declval<_U>(), std::true_type());
+ static std::enable_if_t<
+#ifdef HAS_STRONG_POINTER
+ IsInstantiationOf<_U, sp>::value || // for IBinder and interface types in the C++
+ // backend
+#endif
+ IsInstantiationOf<_U, std::optional>::value || // for @nullable types in the
+ // C++/NDK backends
+ IsInstantiationOf<_U, std::shared_ptr>::value, // for interface types in the
+ // NDK backends
+
+ std::true_type>
+ _test(int);
template <typename _U>
static std::false_type _test(...);
@@ -142,12 +168,17 @@
return std::to_string(t);
} else if constexpr (std::is_same_v<std::string, _T>) {
return t;
-#ifdef HAS_CPP_INTERFACE
+#ifdef HAS_STRING16
} else if constexpr (std::is_same_v<String16, _T>) {
std::stringstream out;
out << t;
return out.str();
#endif
+ } else if constexpr (details::IsPointerLike<_T>::value) {
+ if (!t) return "(null)";
+ std::stringstream out;
+ out << ToString(*t);
+ return out.str();
} else if constexpr (details::HasToStringMethod<_T>::value) {
return t.toString();
} else if constexpr (details::HasToStringFunction<_T>::value) {
@@ -168,11 +199,6 @@
}
out << "]";
return out.str();
- } else if constexpr (details::IsPointerLike<_T>::value) {
- if (!t) return "(null)";
- std::stringstream out;
- out << ToString(*t);
- return out.str();
} else {
return "{no toString() implemented}";
}
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 2784aa8..4580751 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -31,7 +31,8 @@
*
* \return EX_NONE on success.
*/
-binder_exception_t AServiceManager_addService(AIBinder* binder, const char* instance);
+__attribute__((warn_unused_result)) binder_exception_t AServiceManager_addService(
+ AIBinder* binder, const char* instance);
/**
* Gets a binder object with this specific instance name. Will return nullptr immediately if the
@@ -94,4 +95,52 @@
*/
bool AServiceManager_isDeclared(const char* instance) __INTRODUCED_IN(31);
+/**
+ * Prevent lazy services without client from shutting down their process
+ *
+ * \param persist 'true' if the process should not exit.
+ */
+void AServiceManager_forceLazyServicesPersist(bool persist) __INTRODUCED_IN(31);
+
+/**
+ * Set a callback that is invoked when the active service count (i.e. services with clients)
+ * registered with this process drops to zero (or becomes nonzero).
+ * The callback takes a boolean argument, which is 'true' if there is
+ * at least one service with clients.
+ *
+ * \param callback function to call when the number of services
+ * with clients changes.
+ * \param context opaque pointer passed back as second parameter to the
+ * callback.
+ *
+ * The callback takes two arguments. The first is a boolean that represents if there are
+ * services with clients (true) or not (false).
+ * The second is the 'context' pointer passed during the registration.
+ *
+ * Callback return value:
+ * - false: Default behavior for lazy services (shut down the process if there
+ * are no clients).
+ * - true: Don't shut down the process even if there are no clients.
+ *
+ * This callback gives a chance to:
+ * 1 - Perform some additional operations before exiting;
+ * 2 - Prevent the process from exiting by returning "true" from the callback.
+ */
+void AServiceManager_setActiveServicesCallback(bool (*callback)(bool, void*), void* context)
+ __INTRODUCED_IN(31);
+
+/**
+ * Try to unregister all services previously registered with 'registerService'.
+ *
+ * \return true on success.
+ */
+bool AServiceManager_tryUnregister() __INTRODUCED_IN(31);
+
+/**
+ * Re-register services that were unregistered by 'tryUnregister'.
+ * This method should be called in the case 'tryUnregister' fails
+ * (and should be called on the same thread).
+ */
+void AServiceManager_reRegister() __INTRODUCED_IN(31);
+
__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index f5e8bf6..44ed48f 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -30,6 +30,8 @@
FLAG_PRIVATE_VENDOR = 0x10000000,
};
+// TODO(b/180646847): __ANDROID_APEX__ here is what allows product partition to
+// talk to system.
#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
enum {
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 9a93bf3..cef0bf3 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -120,6 +120,10 @@
AServiceManager_isDeclared; # apex llndk
AServiceManager_registerLazyService; # llndk
AServiceManager_waitForService; # apex llndk
+ AServiceManager_forceLazyServicesPersist; # llndk
+ AServiceManager_setActiveServicesCallback; # llndk
+ AServiceManager_tryUnregister; # llndk
+ AServiceManager_reRegister; # llndk
AIBinder_Class_getDescriptor;
AIBinder_Weak_clone;
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index c782d47..cb0987e 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -92,3 +92,22 @@
sp<IServiceManager> sm = defaultServiceManager();
return sm->isDeclared(String16(instance));
}
+void AServiceManager_forceLazyServicesPersist(bool persist) {
+ auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+ serviceRegistrar.forcePersist(persist);
+}
+void AServiceManager_setActiveServicesCallback(bool (*callback)(bool, void*), void* context) {
+ auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+ std::function<bool(bool)> fn = [=](bool hasClients) -> bool {
+ return callback(hasClients, context);
+ };
+ serviceRegistrar.setActiveServicesCallback(fn);
+}
+bool AServiceManager_tryUnregister() {
+ auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+ return serviceRegistrar.tryUnregister();
+}
+void AServiceManager_reRegister() {
+ auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+ serviceRegistrar.reRegister();
+}
\ No newline at end of file
diff --git a/libs/binder/ndk/tests/Android.bp b/libs/binder/ndk/tests/Android.bp
index 46e6270..bb51bf0 100644
--- a/libs/binder/ndk/tests/Android.bp
+++ b/libs/binder/ndk/tests/Android.bp
@@ -14,6 +14,15 @@
* limitations under the License.
*/
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_libs_binder_ndk_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_libs_binder_ndk_license"],
+}
+
cc_defaults {
name: "test_libbinder_ndk_defaults",
shared_libs: [
diff --git a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
index dc77467d..ecbd649 100644
--- a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
+++ b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
@@ -28,4 +28,7 @@
void forceFlushCommands();
boolean getsRequestedSid();
+
+ void forcePersist(boolean persist);
+ void setCustomActiveServicesCallback();
}
diff --git a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
index ad78e31..f3cd218 100644
--- a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
+++ b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
@@ -163,7 +163,8 @@
// LOCAL SERVERS
std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>();
- AServiceManager_addService(ndkServer->asBinder().get(), kLocalNdkServerName.c_str());
+ CHECK(STATUS_OK ==
+ AServiceManager_addService(ndkServer->asBinder().get(), kLocalNdkServerName.c_str()));
return RUN_ALL_TESTS();
}
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 0d1989e..de1a48d 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -46,6 +46,11 @@
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
constexpr char kLazyBinderNdkUnitTestService[] = "LazyBinderNdkUnitTest";
+constexpr char kForcePersistNdkUnitTestService[] = "ForcePersistNdkUnitTestService";
+constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService";
+
+constexpr unsigned int kShutdownWaitTime = 10;
+constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715;
class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) {
@@ -76,6 +81,46 @@
fsync(out);
return STATUS_OK;
}
+ ndk::ScopedAStatus forcePersist(bool persist) {
+ AServiceManager_forceLazyServicesPersist(persist);
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus setCustomActiveServicesCallback() {
+ AServiceManager_setActiveServicesCallback(activeServicesCallback, this);
+ return ndk::ScopedAStatus::ok();
+ }
+ static bool activeServicesCallback(bool hasClients, void* context) {
+ if (hasClients) {
+ return false;
+ }
+
+ // Unregister all services
+ if (!AServiceManager_tryUnregister()) {
+ // Prevent shutdown (test will fail)
+ return false;
+ }
+
+ // Re-register all services
+ AServiceManager_reRegister();
+
+ // Unregister again before shutdown
+ if (!AServiceManager_tryUnregister()) {
+ // Prevent shutdown (test will fail)
+ return false;
+ }
+
+ // Check if the context was passed correctly
+ MyBinderNdkUnitTest* service = static_cast<MyBinderNdkUnitTest*>(context);
+ if (service->contextTestValue != kContextTestValue) {
+ // Prevent shutdown (test will fail)
+ return false;
+ }
+
+ exit(EXIT_SUCCESS);
+ // Unreachable
+ }
+
+ uint64_t contextTestValue = kContextTestValue;
};
int generatedService() {
@@ -168,6 +213,16 @@
return 1; // should not return
}
+bool isServiceRunning(const char* serviceName) {
+ AIBinder* binder = AServiceManager_checkService(serviceName);
+ if (binder == nullptr) {
+ return false;
+ }
+ AIBinder_decStrong(binder);
+
+ return true;
+}
+
TEST(NdkBinder, GetServiceThatDoesntExist) {
sp<IFoo> foo = IFoo::getService("asdfghkl;");
EXPECT_EQ(nullptr, foo.get());
@@ -238,10 +293,51 @@
service = nullptr;
IPCThreadState::self()->flushCommands();
// Make sure the service is dead after some time of no use
- sleep(10);
+ sleep(kShutdownWaitTime);
ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService));
}
+TEST(NdkBinder, ForcedPersistenceTest) {
+ for (int i = 0; i < 2; i++) {
+ ndk::SpAIBinder binder(AServiceManager_waitForService(kForcePersistNdkUnitTestService));
+ std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+ aidl::IBinderNdkUnitTest::fromBinder(binder);
+ ASSERT_NE(service, nullptr);
+ ASSERT_TRUE(service->forcePersist(i == 0).isOk());
+
+ binder = nullptr;
+ service = nullptr;
+ IPCThreadState::self()->flushCommands();
+
+ sleep(kShutdownWaitTime);
+
+ bool isRunning = isServiceRunning(kForcePersistNdkUnitTestService);
+
+ if (i == 0) {
+ ASSERT_TRUE(isRunning) << "Service shut down when it shouldn't have.";
+ } else {
+ ASSERT_FALSE(isRunning) << "Service failed to shut down.";
+ }
+ }
+}
+
+TEST(NdkBinder, ActiveServicesCallbackTest) {
+ ndk::SpAIBinder binder(AServiceManager_waitForService(kActiveServicesNdkUnitTestService));
+ std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+ aidl::IBinderNdkUnitTest::fromBinder(binder);
+ ASSERT_NE(service, nullptr);
+ ASSERT_TRUE(service->setCustomActiveServicesCallback().isOk());
+
+ binder = nullptr;
+ service = nullptr;
+ IPCThreadState::self()->flushCommands();
+
+ sleep(kShutdownWaitTime);
+
+ ASSERT_FALSE(isServiceRunning(kActiveServicesNdkUnitTestService))
+ << "Service failed to shut down.";
+}
+
void LambdaOnDeath(void* cookie) {
auto onDeath = static_cast<std::function<void(void)>*>(cookie);
(*onDeath)();
@@ -564,10 +660,18 @@
}
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return lazyService(kForcePersistNdkUnitTestService);
+ }
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return lazyService(kActiveServicesNdkUnitTestService);
+ }
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
return generatedService();
}
- ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks
+ ABinderProcess_setThreadPoolMaxThreadCount(1); // to receive death notifications/callbacks
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
diff --git a/libs/binder/parcel_fuzzer/Android.bp b/libs/binder/parcel_fuzzer/Android.bp
index 3e6fe99..74b8eb8 100644
--- a/libs/binder/parcel_fuzzer/Android.bp
+++ b/libs/binder/parcel_fuzzer/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_fuzz {
name: "binder_parcel_fuzzer",
defaults: ["libbinder_ndk_host_user"],
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index fd5f2f5..e12a429 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
rust_library {
name: "libbinder_rs",
crate_name: "binder",
@@ -14,7 +23,11 @@
darwin: {
enabled: false,
}
- }
+ },
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
}
rust_library {
@@ -32,7 +45,11 @@
darwin: {
enabled: false,
}
- }
+ },
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
}
rust_bindgen {
@@ -78,6 +95,10 @@
enabled: false,
},
},
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
}
rust_test {
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 42c1e0a..d53a88f 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -16,12 +16,17 @@
//! Trait definitions for binder objects
-use crate::error::{status_t, Result};
+use crate::error::{status_t, Result, StatusCode};
use crate::parcel::Parcel;
-use crate::proxy::{DeathRecipient, SpIBinder};
+use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
use crate::sys;
+use std::borrow::Borrow;
+use std::cmp::Ordering;
use std::ffi::{c_void, CStr, CString};
+use std::fmt;
+use std::marker::PhantomData;
+use std::ops::Deref;
use std::os::raw::c_char;
use std::os::unix::io::AsRawFd;
use std::ptr;
@@ -44,7 +49,7 @@
/// interfaces) must implement this trait.
///
/// This is equivalent `IInterface` in C++.
-pub trait Interface {
+pub trait Interface: Send {
/// Convert this binder object into a generic [`SpIBinder`] reference.
fn as_binder(&self) -> SpIBinder {
panic!("This object was not a Binder object and cannot be converted into an SpIBinder.")
@@ -230,6 +235,132 @@
}
}
+/// Strong reference to a binder object
+pub struct Strong<I: FromIBinder + ?Sized>(Box<I>);
+
+impl<I: FromIBinder + ?Sized> Strong<I> {
+ /// Create a new strong reference to the provided binder object
+ pub fn new(binder: Box<I>) -> Self {
+ Self(binder)
+ }
+
+ /// Construct a new weak reference to this binder
+ pub fn downgrade(this: &Strong<I>) -> Weak<I> {
+ Weak::new(this)
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Clone for Strong<I> {
+ fn clone(&self) -> Self {
+ // Since we hold a strong reference, we should always be able to create
+ // a new strong reference to the same interface type, so try_from()
+ // should never fail here.
+ FromIBinder::try_from(self.0.as_binder()).unwrap()
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Borrow<I> for Strong<I> {
+ fn borrow(&self) -> &I {
+ &self.0
+ }
+}
+
+impl<I: FromIBinder + ?Sized> AsRef<I> for Strong<I> {
+ fn as_ref(&self) -> &I {
+ &self.0
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Deref for Strong<I> {
+ type Target = I;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<I: FromIBinder + fmt::Debug + ?Sized> fmt::Debug for Strong<I> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&**self, f)
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Ord for Strong<I> {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.0.as_binder().cmp(&other.0.as_binder())
+ }
+}
+
+impl<I: FromIBinder + ?Sized> PartialOrd for Strong<I> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.0.as_binder().partial_cmp(&other.0.as_binder())
+ }
+}
+
+impl<I: FromIBinder + ?Sized> PartialEq for Strong<I> {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.as_binder().eq(&other.0.as_binder())
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Eq for Strong<I> {}
+
+/// Weak reference to a binder object
+#[derive(Debug)]
+pub struct Weak<I: FromIBinder + ?Sized> {
+ weak_binder: WpIBinder,
+ interface_type: PhantomData<I>,
+}
+
+impl<I: FromIBinder + ?Sized> Weak<I> {
+ /// Construct a new weak reference from a strong reference
+ fn new(binder: &Strong<I>) -> Self {
+ let weak_binder = binder.as_binder().downgrade();
+ Weak {
+ weak_binder,
+ interface_type: PhantomData,
+ }
+ }
+
+ /// Upgrade this weak reference to a strong reference if the binder object
+ /// is still alive
+ pub fn upgrade(&self) -> Result<Strong<I>> {
+ self.weak_binder
+ .promote()
+ .ok_or(StatusCode::DEAD_OBJECT)
+ .and_then(FromIBinder::try_from)
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Clone for Weak<I> {
+ fn clone(&self) -> Self {
+ Self {
+ weak_binder: self.weak_binder.clone(),
+ interface_type: PhantomData,
+ }
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Ord for Weak<I> {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.weak_binder.cmp(&other.weak_binder)
+ }
+}
+
+impl<I: FromIBinder + ?Sized> PartialOrd for Weak<I> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.weak_binder.partial_cmp(&other.weak_binder)
+ }
+}
+
+impl<I: FromIBinder + ?Sized> PartialEq for Weak<I> {
+ fn eq(&self, other: &Self) -> bool {
+ self.weak_binder == other.weak_binder
+ }
+}
+
+impl<I: FromIBinder + ?Sized> Eq for Weak<I> {}
+
/// Create a function implementing a static getter for an interface class.
///
/// Each binder interface (i.e. local [`Remotable`] service or remote proxy
@@ -354,12 +485,12 @@
/// }
/// }
/// ```
-pub trait FromIBinder {
+pub trait FromIBinder: Interface {
/// Try to interpret a generic Binder object as this interface.
///
/// Returns a trait object for the `Self` interface if this object
/// implements that interface.
- fn try_from(ibinder: SpIBinder) -> Result<Box<Self>>;
+ fn try_from(ibinder: SpIBinder) -> Result<Strong<Self>>;
}
/// Trait for transparent Rust wrappers around android C++ native types.
@@ -534,8 +665,9 @@
impl $native {
/// Create a new binder service.
- pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> impl $interface {
- $crate::Binder::new($native(Box::new(inner)))
+ pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> $crate::Strong<dyn $interface> {
+ let binder = $crate::Binder::new($native(Box::new(inner)));
+ $crate::Strong::new(Box::new(binder))
}
}
@@ -577,7 +709,7 @@
}
impl $crate::FromIBinder for dyn $interface {
- fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<Box<dyn $interface>> {
+ fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<$crate::Strong<dyn $interface>> {
use $crate::AssociateClass;
let existing_class = ibinder.get_class();
@@ -590,7 +722,7 @@
// associated object as remote, because we can't cast it
// into a Rust service object without a matching class
// pointer.
- return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+ return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
}
}
@@ -600,10 +732,10 @@
if let Ok(service) = service {
// We were able to associate with our expected class and
// the service is local.
- return Ok(Box::new(service));
+ return Ok($crate::Strong::new(Box::new(service)));
} else {
// Service is remote
- return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+ return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
}
}
@@ -633,9 +765,9 @@
}
}
- // Convert a &dyn $interface to Box<dyn $interface>
+ /// Convert a &dyn $interface to Strong<dyn $interface>
impl std::borrow::ToOwned for dyn $interface {
- type Owned = Box<dyn $interface>;
+ type Owned = $crate::Strong<dyn $interface>;
fn to_owned(&self) -> Self::Owned {
self.as_binder().into_interface()
.expect(concat!("Error cloning interface ", stringify!($interface)))
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index edfb56a..43a237a 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -107,7 +107,8 @@
pub mod parcel;
pub use crate::binder::{
- FromIBinder, IBinder, Interface, InterfaceClass, Remotable, TransactionCode, TransactionFlags,
+ FromIBinder, IBinder, Interface, InterfaceClass, Remotable, Strong, TransactionCode,
+ TransactionFlags, Weak,
};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::add_service;
@@ -122,7 +123,8 @@
pub use super::parcel::ParcelFileDescriptor;
pub use super::{add_service, get_interface};
pub use super::{
- ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, WpIBinder,
+ ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, Strong, ThreadState,
+ Weak, WpIBinder,
};
/// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 8d18fb4..f57788b 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-use crate::binder::{AsNative, FromIBinder};
+use crate::binder::{AsNative, FromIBinder, Strong};
use crate::error::{status_result, status_t, Result, Status, StatusCode};
use crate::parcel::Parcel;
use crate::proxy::SpIBinder;
@@ -628,26 +628,26 @@
}
}
-impl<T: Serialize + ?Sized> Serialize for Box<T> {
+impl<T: Serialize + FromIBinder + ?Sized> Serialize for Strong<T> {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
Serialize::serialize(&**self, parcel)
}
}
-impl<T: SerializeOption + ?Sized> SerializeOption for Box<T> {
+impl<T: SerializeOption + FromIBinder + ?Sized> SerializeOption for Strong<T> {
fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
SerializeOption::serialize_option(this.map(|b| &**b), parcel)
}
}
-impl<T: FromIBinder + ?Sized> Deserialize for Box<T> {
+impl<T: FromIBinder + ?Sized> Deserialize for Strong<T> {
fn deserialize(parcel: &Parcel) -> Result<Self> {
let ibinder: SpIBinder = parcel.read()?;
FromIBinder::try_from(ibinder)
}
}
-impl<T: FromIBinder + ?Sized> DeserializeOption for Box<T> {
+impl<T: FromIBinder + ?Sized> DeserializeOption for Strong<T> {
fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
let ibinder: Option<SpIBinder> = parcel.read()?;
ibinder.map(FromIBinder::try_from).transpose()
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index e9e74c0..132e075 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -17,7 +17,7 @@
//! Rust API for interacting with a remote binder service.
use crate::binder::{
- AsNative, FromIBinder, IBinder, Interface, InterfaceClass, TransactionCode, TransactionFlags,
+ AsNative, FromIBinder, IBinder, Interface, InterfaceClass, Strong, TransactionCode, TransactionFlags,
};
use crate::error::{status_result, Result, StatusCode};
use crate::parcel::{
@@ -27,6 +27,7 @@
use crate::sys;
use std::convert::TryInto;
+use std::cmp::Ordering;
use std::ffi::{c_void, CString};
use std::fmt;
use std::os::unix::io::AsRawFd;
@@ -99,7 +100,7 @@
///
/// If this object does not implement the expected interface, the error
/// `StatusCode::BAD_TYPE` is returned.
- pub fn into_interface<I: FromIBinder + ?Sized>(self) -> Result<Box<I>> {
+ pub fn into_interface<I: FromIBinder + Interface + ?Sized>(self) -> Result<Strong<I>> {
FromIBinder::try_from(self)
}
@@ -148,6 +149,36 @@
}
}
+impl Ord for SpIBinder {
+ fn cmp(&self, other: &Self) -> Ordering {
+ let less_than = unsafe {
+ // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
+ // this pointer is always safe to pass to `AIBinder_lt` (null is
+ // also safe to pass to this function, but we should never do that).
+ sys::AIBinder_lt(self.0, other.0)
+ };
+ let greater_than = unsafe {
+ // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
+ // this pointer is always safe to pass to `AIBinder_lt` (null is
+ // also safe to pass to this function, but we should never do that).
+ sys::AIBinder_lt(other.0, self.0)
+ };
+ if !less_than && !greater_than {
+ Ordering::Equal
+ } else if less_than {
+ Ordering::Less
+ } else {
+ Ordering::Greater
+ }
+ }
+}
+
+impl PartialOrd for SpIBinder {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
impl PartialEq for SpIBinder {
fn eq(&self, other: &Self) -> bool {
ptr::eq(self.0, other.0)
@@ -326,7 +357,7 @@
// Safety: `SpIBinder` guarantees that `self` always contains a
// valid pointer to an `AIBinder`. `recipient` can always be
// converted into a valid pointer to an
- // `AIBinder_DeatRecipient`. Any value is safe to pass as the
+ // `AIBinder_DeathRecipient`. Any value is safe to pass as the
// cookie, although we depend on this value being set by
// `get_cookie` when the death recipient callback is called.
sys::AIBinder_linkToDeath(
@@ -342,7 +373,7 @@
// Safety: `SpIBinder` guarantees that `self` always contains a
// valid pointer to an `AIBinder`. `recipient` can always be
// converted into a valid pointer to an
- // `AIBinder_DeatRecipient`. Any value is safe to pass as the
+ // `AIBinder_DeathRecipient`. Any value is safe to pass as the
// cookie, although we depend on this value being set by
// `get_cookie` when the death recipient callback is called.
sys::AIBinder_unlinkToDeath(
@@ -430,6 +461,62 @@
}
}
+impl Clone for WpIBinder {
+ fn clone(&self) -> Self {
+ let ptr = unsafe {
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+ // so this pointer is always safe to pass to `AIBinder_Weak_clone`
+ // (although null is also a safe value to pass to this API).
+ //
+ // We get ownership of the returned pointer, so can construct a new
+ // WpIBinder object from it.
+ sys::AIBinder_Weak_clone(self.0)
+ };
+ assert!(!ptr.is_null(), "Unexpected null pointer from AIBinder_Weak_clone");
+ Self(ptr)
+ }
+}
+
+impl Ord for WpIBinder {
+ fn cmp(&self, other: &Self) -> Ordering {
+ let less_than = unsafe {
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+ // so this pointer is always safe to pass to `AIBinder_Weak_lt`
+ // (null is also safe to pass to this function, but we should never
+ // do that).
+ sys::AIBinder_Weak_lt(self.0, other.0)
+ };
+ let greater_than = unsafe {
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+ // so this pointer is always safe to pass to `AIBinder_Weak_lt`
+ // (null is also safe to pass to this function, but we should never
+ // do that).
+ sys::AIBinder_Weak_lt(other.0, self.0)
+ };
+ if !less_than && !greater_than {
+ Ordering::Equal
+ } else if less_than {
+ Ordering::Less
+ } else {
+ Ordering::Greater
+ }
+ }
+}
+
+impl PartialOrd for WpIBinder {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialEq for WpIBinder {
+ fn eq(&self, other: &Self) -> bool {
+ self.cmp(other) == Ordering::Equal
+ }
+}
+
+impl Eq for WpIBinder {}
+
impl Drop for WpIBinder {
fn drop(&mut self) {
unsafe {
@@ -564,7 +651,7 @@
/// Retrieve an existing service for a particular interface, blocking for a few
/// seconds if it doesn't yet exist.
-pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Box<T>> {
+pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
let service = get_service(name);
match service {
Some(service) => FromIBinder::try_from(service),
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index 8810b5d..0bf76c6 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
rust_test {
name: "rustBinderTest",
srcs: ["integration.rs"],
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index bb8c492..719229c 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -209,7 +209,7 @@
use std::thread;
use std::time::Duration;
- use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode};
+ use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode, Strong};
use super::{BnTest, ITest, ITestSameDescriptor, RUST_SERVICE_BINARY, TestService};
@@ -271,7 +271,7 @@
fn trivial_client() {
let service_name = "trivial_client_test";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Box<dyn ITest> =
+ let test_client: Strong<dyn ITest> =
binder::get_interface(service_name).expect("Did not get manager binder service");
assert_eq!(test_client.test().unwrap(), "trivial_client_test");
}
@@ -280,7 +280,7 @@
fn get_selinux_context() {
let service_name = "get_selinux_context";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Box<dyn ITest> =
+ let test_client: Strong<dyn ITest> =
binder::get_interface(service_name).expect("Did not get manager binder service");
let expected_context = unsafe {
let mut out_ptr = ptr::null_mut();
@@ -453,7 +453,7 @@
let extension = maybe_extension.expect("Remote binder did not have an extension");
- let extension: Box<dyn ITest> = FromIBinder::try_from(extension)
+ let extension: Strong<dyn ITest> = FromIBinder::try_from(extension)
.expect("Extension could not be converted to the expected interface");
assert_eq!(extension.test().unwrap(), extension_name);
@@ -479,7 +479,7 @@
// This should succeed although we will have to treat the service as
// remote.
- let _interface: Box<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
+ let _interface: Strong<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
.expect("Could not re-interpret service as the ITestSameDescriptor interface");
}
@@ -490,9 +490,60 @@
let service_ibinder = BnTest::new_binder(TestService { s: service_name.to_string() })
.as_binder();
- let service: Box<dyn ITest> = service_ibinder.into_interface()
+ let service: Strong<dyn ITest> = service_ibinder.into_interface()
.expect("Could not reassociate the generic ibinder");
assert_eq!(service.test().unwrap(), service_name);
}
+
+ #[test]
+ fn weak_binder_upgrade() {
+ let service_name = "testing_service";
+ let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+
+ let weak = Strong::downgrade(&service);
+
+ let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
+
+ assert_eq!(service, upgraded);
+ }
+
+ #[test]
+ fn weak_binder_upgrade_dead() {
+ let service_name = "testing_service";
+ let weak = {
+ let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+
+ Strong::downgrade(&service)
+ };
+
+ assert_eq!(weak.upgrade(), Err(StatusCode::DEAD_OBJECT));
+ }
+
+ #[test]
+ fn weak_binder_clone() {
+ let service_name = "testing_service";
+ let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+
+ let weak = Strong::downgrade(&service);
+ let cloned = weak.clone();
+ assert_eq!(weak, cloned);
+
+ let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
+ let clone_upgraded = cloned.upgrade().expect("Could not upgrade weak binder");
+
+ assert_eq!(service, upgraded);
+ assert_eq!(service, clone_upgraded);
+ }
+
+ #[test]
+ #[allow(clippy::eq_op)]
+ fn binder_ord() {
+ let service1 = BnTest::new_binder(TestService { s: "testing_service1".to_string() });
+ let service2 = BnTest::new_binder(TestService { s: "testing_service2".to_string() });
+
+ assert!(!(service1 < service1));
+ assert!(!(service1 > service1));
+ assert_eq!(service1 < service2, !(service2 < service1));
+ }
}
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
index 70a6dc0..ce75ab7 100644
--- a/libs/binder/rust/tests/ndk_rust_interop.rs
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -37,7 +37,7 @@
// The Rust class descriptor pointer will not match the NDK one, but the
// descriptor strings match so this needs to still associate.
- let service: Box<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) {
+ let service: binder::Strong<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) {
Err(e) => {
eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
return StatusCode::NAME_NOT_FOUND as c_int;
@@ -53,7 +53,7 @@
}
// Try using the binder service through the wrong interface type
- let wrong_service: Result<Box<dyn IBinderRustNdkInteropTestOther>, StatusCode> =
+ let wrong_service: Result<binder::Strong<dyn IBinderRustNdkInteropTestOther>, StatusCode> =
binder::get_interface(service_name);
match wrong_service {
Err(e) if e == StatusCode::BAD_TYPE => {}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 259417a..3bbb0b5 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "binder_test_defaults",
cflags: [
diff --git a/libs/binder/tests/binderParcelBenchmark.cpp b/libs/binder/tests/binderParcelBenchmark.cpp
index ec69c36..26c50eb 100644
--- a/libs/binder/tests/binderParcelBenchmark.cpp
+++ b/libs/binder/tests/binderParcelBenchmark.cpp
@@ -91,56 +91,56 @@
Results on Crosshatch Pixel 3XL
- #BM_BoolVector/1 40 ns 40 ns 17261011
- #BM_BoolVector/2 46 ns 46 ns 15029619
- #BM_BoolVector/4 65 ns 64 ns 10888021
- #BM_BoolVector/8 114 ns 114 ns 6130937
- #BM_BoolVector/16 179 ns 179 ns 3902462
- #BM_BoolVector/32 328 ns 327 ns 2138812
- #BM_BoolVector/64 600 ns 598 ns 1169414
- #BM_BoolVector/128 1168 ns 1165 ns 601281
- #BM_BoolVector/256 2288 ns 2281 ns 305737
- #BM_BoolVector/512 4535 ns 4521 ns 154668
- #BM_ByteVector/1 53 ns 52 ns 13212196
- #BM_ByteVector/2 53 ns 53 ns 13194050
- #BM_ByteVector/4 50 ns 50 ns 13768037
- #BM_ByteVector/8 50 ns 50 ns 13890210
- #BM_ByteVector/16 50 ns 50 ns 13897305
- #BM_ByteVector/32 51 ns 51 ns 13679862
- #BM_ByteVector/64 54 ns 53 ns 12988544
- #BM_ByteVector/128 64 ns 64 ns 10921227
- #BM_ByteVector/256 82 ns 81 ns 8542549
- #BM_ByteVector/512 118 ns 118 ns 5862931
- #BM_CharVector/1 32 ns 32 ns 21783579
- #BM_CharVector/2 38 ns 38 ns 18200971
- #BM_CharVector/4 53 ns 53 ns 13111785
- #BM_CharVector/8 80 ns 80 ns 8698331
- #BM_CharVector/16 159 ns 159 ns 4390738
- #BM_CharVector/32 263 ns 262 ns 2667310
- #BM_CharVector/64 486 ns 485 ns 1441118
- #BM_CharVector/128 937 ns 934 ns 749006
- #BM_CharVector/256 1848 ns 1843 ns 379537
- #BM_CharVector/512 3650 ns 3639 ns 191713
- #BM_Int32Vector/1 31 ns 31 ns 22104147
- #BM_Int32Vector/2 38 ns 38 ns 18075471
- #BM_Int32Vector/4 53 ns 52 ns 13249969
- #BM_Int32Vector/8 80 ns 80 ns 8719798
- #BM_Int32Vector/16 161 ns 160 ns 4350096
- #BM_Int32Vector/32 271 ns 270 ns 2591896
- #BM_Int32Vector/64 499 ns 498 ns 1406201
- #BM_Int32Vector/128 948 ns 945 ns 740052
- #BM_Int32Vector/256 1855 ns 1849 ns 379127
- #BM_Int32Vector/512 3665 ns 3653 ns 191533
- #BM_Int64Vector/1 31 ns 31 ns 22388370
- #BM_Int64Vector/2 38 ns 38 ns 18300347
- #BM_Int64Vector/4 53 ns 53 ns 13137818
- #BM_Int64Vector/8 81 ns 81 ns 8599613
- #BM_Int64Vector/16 167 ns 166 ns 4195953
- #BM_Int64Vector/32 280 ns 280 ns 2499271
- #BM_Int64Vector/64 523 ns 522 ns 1341380
- #BM_Int64Vector/128 991 ns 988 ns 707437
- #BM_Int64Vector/256 1940 ns 1934 ns 361704
- #BM_Int64Vector/512 3843 ns 3831 ns 183204
+ #BM_BoolVector/1 44 ns 44 ns 15630626
+ #BM_BoolVector/2 54 ns 54 ns 12900340
+ #BM_BoolVector/4 73 ns 72 ns 9749841
+ #BM_BoolVector/8 107 ns 107 ns 6503326
+ #BM_BoolVector/16 186 ns 185 ns 3773627
+ #BM_BoolVector/32 337 ns 336 ns 2083877
+ #BM_BoolVector/64 607 ns 605 ns 1154113
+ #BM_BoolVector/128 1155 ns 1151 ns 608128
+ #BM_BoolVector/256 2259 ns 2253 ns 310973
+ #BM_BoolVector/512 4469 ns 4455 ns 157277
+ #BM_ByteVector/1 41 ns 41 ns 16837425
+ #BM_ByteVector/2 41 ns 41 ns 16820726
+ #BM_ByteVector/4 38 ns 38 ns 18217813
+ #BM_ByteVector/8 38 ns 38 ns 18290298
+ #BM_ByteVector/16 38 ns 38 ns 18117817
+ #BM_ByteVector/32 38 ns 38 ns 18172385
+ #BM_ByteVector/64 41 ns 41 ns 16950055
+ #BM_ByteVector/128 53 ns 53 ns 13170749
+ #BM_ByteVector/256 69 ns 69 ns 10113626
+ #BM_ByteVector/512 106 ns 106 ns 6561936
+ #BM_CharVector/1 38 ns 38 ns 18074831
+ #BM_CharVector/2 40 ns 40 ns 17206266
+ #BM_CharVector/4 50 ns 50 ns 13785944
+ #BM_CharVector/8 67 ns 67 ns 10223316
+ #BM_CharVector/16 96 ns 96 ns 7297285
+ #BM_CharVector/32 156 ns 155 ns 4484845
+ #BM_CharVector/64 277 ns 276 ns 2536003
+ #BM_CharVector/128 520 ns 518 ns 1347070
+ #BM_CharVector/256 1006 ns 1003 ns 695952
+ #BM_CharVector/512 1976 ns 1970 ns 354673
+ #BM_Int32Vector/1 41 ns 41 ns 16951262
+ #BM_Int32Vector/2 41 ns 41 ns 16916883
+ #BM_Int32Vector/4 41 ns 41 ns 16761373
+ #BM_Int32Vector/8 42 ns 42 ns 16553179
+ #BM_Int32Vector/16 43 ns 43 ns 16200362
+ #BM_Int32Vector/32 55 ns 54 ns 12724454
+ #BM_Int32Vector/64 70 ns 69 ns 10049223
+ #BM_Int32Vector/128 107 ns 107 ns 6525796
+ #BM_Int32Vector/256 179 ns 178 ns 3922563
+ #BM_Int32Vector/512 324 ns 323 ns 2160653
+ #BM_Int64Vector/1 41 ns 41 ns 16909470
+ #BM_Int64Vector/2 41 ns 41 ns 16740788
+ #BM_Int64Vector/4 42 ns 42 ns 16564197
+ #BM_Int64Vector/8 43 ns 42 ns 16284082
+ #BM_Int64Vector/16 54 ns 54 ns 12839474
+ #BM_Int64Vector/32 69 ns 69 ns 10011010
+ #BM_Int64Vector/64 107 ns 106 ns 6557956
+ #BM_Int64Vector/128 177 ns 177 ns 3925618
+ #BM_Int64Vector/256 324 ns 323 ns 2163321
+ #BM_Int64Vector/512 613 ns 611 ns 1140418
*/
static void BM_BoolVector(benchmark::State& state) {
diff --git a/libs/binder/tests/fuzzers/Android.bp b/libs/binder/tests/fuzzers/Android.bp
index 5531296..b1263e8 100644
--- a/libs/binder/tests/fuzzers/Android.bp
+++ b/libs/binder/tests/fuzzers/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "binder_fuzz_defaults",
host_supported: true,
diff --git a/libs/binderdebug/Android.bp b/libs/binderdebug/Android.bp
index 343246a..3eeaf3e 100644
--- a/libs/binderdebug/Android.bp
+++ b/libs/binderdebug/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libbinderdebug",
vendor_available: true,
diff --git a/libs/binderdebug/tests/Android.bp b/libs/binderdebug/tests/Android.bp
index 4c06b1d..d141a05 100644
--- a/libs/binderdebug/tests/Android.bp
+++ b/libs/binderdebug/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "libbinderdebug_test",
test_suites: ["general-tests"],
diff --git a/libs/binderthreadstate/1.0/Android.bp b/libs/binderthreadstate/1.0/Android.bp
index ebdc932..99477d8 100644
--- a/libs/binderthreadstate/1.0/Android.bp
+++ b/libs/binderthreadstate/1.0/Android.bp
@@ -1,5 +1,14 @@
// This file is autogenerated by hidl-gen -Landroidbp.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
hidl_interface {
name: "binderthreadstateutilstest@1.0",
root: "binderthreadstateutilstest",
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index 08c62df..0a82463 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -14,6 +14,15 @@
// DO NOT ADD NEW USAGES OF THIS
// See comments in header file.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libbinderthreadstateutils",
double_loadable: true,
diff --git a/libs/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp
index bab2674..c5d3a32 100644
--- a/libs/bufferqueueconverter/Android.bp
+++ b/libs/bufferqueueconverter/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libbufferqueueconverter_headers",
vendor_available: true,
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index e3cd085..570af71 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libtimeinstate",
srcs: ["cputimeinstate.cpp"],
@@ -35,4 +44,3 @@
],
require_root: true,
}
-
diff --git a/libs/diskusage/Android.bp b/libs/diskusage/Android.bp
index a826306..8684061 100644
--- a/libs/diskusage/Android.bp
+++ b/libs/diskusage/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libdiskusage",
srcs: ["dirsize.c"],
diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp
index e403d36..acda402 100644
--- a/libs/dumputils/Android.bp
+++ b/libs/dumputils/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libdumputils",
diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp
index 76518c1..47c0657 100644
--- a/libs/fakeservicemanager/Android.bp
+++ b/libs/fakeservicemanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "fakeservicemanager_defaults",
host_supported: true,
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index dd0ae30..a0032ae 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libgralloctypes",
defaults: ["libbinder_ndk_host_user"],
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
index 8933dc3..6689771 100644
--- a/libs/gralloc/types/fuzzer/Android.bp
+++ b/libs/gralloc/types/fuzzer/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_fuzz {
name: "libgralloctypes_fuzzer",
defaults: ["libbinder_ndk_host_user"],
diff --git a/libs/gralloc/types/tests/Android.bp b/libs/gralloc/types/tests/Android.bp
index b939c1d..66eb0aa 100644
--- a/libs/gralloc/types/tests/Android.bp
+++ b/libs/gralloc/types/tests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "GrallocTypes_test",
shared_libs: [
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 642c5f2..a96a07a 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libgraphicsenv",
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index fa5044c..debd664 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -11,6 +11,15 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libgui_headers",
vendor_available: true,
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 1e6fc2b..82c9268 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -55,7 +55,7 @@
ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
void BLASTBufferItemConsumer::onDisconnect() {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
+ Mutex::Autolock lock(mMutex);
mPreviouslyConnected = mCurrentlyConnected;
mCurrentlyConnected = false;
if (mPreviouslyConnected) {
@@ -66,7 +66,7 @@
void BLASTBufferItemConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
+ Mutex::Autolock lock(mMutex);
if (newTimestamps) {
// BufferQueueProducer only adds a new timestamp on
// queueBuffer
@@ -90,7 +90,7 @@
const sp<Fence>& prevReleaseFence,
CompositorTiming compositorTiming,
nsecs_t latchTime, nsecs_t dequeueReadyTime) {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
+ Mutex::Autolock lock(mMutex);
// if the producer is not connected, don't bother updating,
// the next producer that connects won't access this frame event
@@ -108,7 +108,7 @@
void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect) {
bool disconnect = false;
- Mutex::Autolock lock(mFrameEventHistoryMutex);
+ Mutex::Autolock lock(mMutex);
while (!mDisconnectEvents.empty() && mDisconnectEvents.front() <= frameNumber) {
disconnect = true;
mDisconnectEvents.pop();
@@ -116,6 +116,19 @@
if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
}
+void BLASTBufferItemConsumer::setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) {
+ Mutex::Autolock lock(mMutex);
+ mBLASTBufferQueue = blastbufferqueue;
+}
+
+void BLASTBufferItemConsumer::onSidebandStreamChanged() {
+ Mutex::Autolock lock(mMutex);
+ if (mBLASTBufferQueue != nullptr) {
+ sp<NativeHandle> stream = getSidebandStream();
+ mBLASTBufferQueue->setSidebandStream(stream);
+ }
+}
+
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
int width, int height, int32_t format,
bool enableTripleBuffering)
@@ -145,6 +158,7 @@
mBufferItemConsumer->setBufferFreedListener(this);
mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
+ mBufferItemConsumer->setBlastBufferQueue(this);
mTransformHint = mSurfaceControl->getTransformHint();
mBufferItemConsumer->setTransformHint(mTransformHint);
@@ -160,6 +174,7 @@
}
BLASTBufferQueue::~BLASTBufferQueue() {
+ mBufferItemConsumer->setBlastBufferQueue(nullptr);
if (mPendingTransactions.empty()) {
return;
}
@@ -557,6 +572,13 @@
return OK;
}
+void BLASTBufferQueue::setSidebandStream(const sp<NativeHandle>& stream) {
+ std::unique_lock _lock{mMutex};
+ SurfaceComposerClient::Transaction t;
+
+ t.setSidebandStream(mSurfaceControl, stream).apply();
+}
+
sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
std::unique_lock _lock{mMutex};
sp<IBinder> scHandle = nullptr;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 27fb2a8..d41da9b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -194,6 +194,25 @@
}
}
+void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie,
+ sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mSurfaceStatsListeners.insert({surfaceControl->getHandle(),
+ SurfaceStatsCallbackEntry(context, cookie, listener)});
+}
+
+void TransactionCompletedListener::removeSurfaceStatsListener(void* context, void* cookie) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ for (auto it = mSurfaceStatsListeners.begin(); it != mSurfaceStatsListeners.end();) {
+ auto [itContext, itCookie, itListener] = it->second;
+ if (itContext == context && itCookie == cookie) {
+ it = mSurfaceStatsListeners.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
void TransactionCompletedListener::addSurfaceControlToCallbacks(
const sp<SurfaceControl>& surfaceControl,
const std::unordered_set<CallbackId>& callbackIds) {
@@ -210,6 +229,7 @@
void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
+ std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> surfaceListeners;
{
std::lock_guard<std::mutex> lock(mMutex);
@@ -226,6 +246,7 @@
*/
callbacksMap = mCallbacks;
jankListenersMap = mJankListeners;
+ surfaceListeners = mSurfaceStatsListeners;
for (const auto& transactionStats : listenerStats.transactionStats) {
for (auto& callbackId : transactionStats.callbackIds) {
mCallbacks.erase(callbackId);
@@ -259,9 +280,16 @@
surfaceControlStats);
}
for (const auto& surfaceStats : transactionStats.surfaceStats) {
+ auto listenerRange = surfaceListeners.equal_range(surfaceStats.surfaceControl);
+ for (auto it = listenerRange.first; it != listenerRange.second; it++) {
+ auto entry = it->second;
+ entry.callback(entry.context, transactionStats.latchTime,
+ transactionStats.presentFence, surfaceStats);
+ }
+
if (surfaceStats.jankData.empty()) continue;
- for (auto it = jankListenersMap.find(surfaceStats.surfaceControl);
- it != jankListenersMap.end(); it++) {
+ auto jankRange = jankListenersMap.equal_range(surfaceStats.surfaceControl);
+ for (auto it = jankRange.first; it != jankRange.second; it++) {
it->second->onJankDataAvailable(surfaceStats.jankData);
}
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index bccb71b..dd8e714 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -32,6 +32,7 @@
namespace android {
+class BLASTBufferQueue;
class BufferItemConsumer;
class BLASTBufferItemConsumer : public BufferItemConsumer {
@@ -40,27 +41,32 @@
int bufferCount, bool controlledByApp)
: BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
mCurrentlyConnected(false),
- mPreviouslyConnected(false) {}
+ mPreviouslyConnected(false),
+ mBLASTBufferQueue(nullptr) {}
void onDisconnect() override;
void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
- FrameEventHistoryDelta* outDelta) override
- REQUIRES(mFrameEventHistoryMutex);
+ FrameEventHistoryDelta* outDelta) override REQUIRES(mMutex);
void updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime,
const sp<Fence>& gpuCompositionDoneFence,
const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
CompositorTiming compositorTiming, nsecs_t latchTime,
- nsecs_t dequeueReadyTime) REQUIRES(mFrameEventHistoryMutex);
+ nsecs_t dequeueReadyTime) REQUIRES(mMutex);
void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect);
+ void setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) REQUIRES(mMutex);
+
+protected:
+ void onSidebandStreamChanged() override REQUIRES(mMutex);
private:
uint64_t mCurrentFrameNumber = 0;
- Mutex mFrameEventHistoryMutex;
- ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mFrameEventHistoryMutex);
- std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mFrameEventHistoryMutex);
- bool mCurrentlyConnected GUARDED_BY(mFrameEventHistoryMutex);
- bool mPreviouslyConnected GUARDED_BY(mFrameEventHistoryMutex);
+ Mutex mMutex;
+ ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mMutex);
+ std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mMutex);
+ bool mCurrentlyConnected GUARDED_BY(mMutex);
+ bool mPreviouslyConnected GUARDED_BY(mMutex);
+ BLASTBufferQueue* mBLASTBufferQueue GUARDED_BY(mMutex);
};
class BLASTBufferQueue
@@ -94,6 +100,8 @@
status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
+ void setSidebandStream(const sp<NativeHandle>& stream);
+
virtual ~BLASTBufferQueue();
private:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e89f3a7..8de7574 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -80,6 +80,10 @@
using TransactionCompletedCallback =
std::function<void(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
const std::vector<SurfaceControlStats>& /*stats*/)>;
+using SurfaceStatsCallback =
+ std::function<void(void* /*context*/, nsecs_t /*latchTime*/,
+ const sp<Fence>& /*presentFence*/,
+ const SurfaceStats& /*stats*/)>;
// ---------------------------------------------------------------------------
@@ -650,8 +654,21 @@
surfaceControls;
};
+ struct SurfaceStatsCallbackEntry {
+ SurfaceStatsCallbackEntry(void* context, void* cookie, SurfaceStatsCallback callback)
+ : context(context),
+ cookie(cookie),
+ callback(callback) {}
+
+ void* context;
+ void* cookie;
+ SurfaceStatsCallback callback;
+ };
+
std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
+ std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry>
+ mSurfaceStatsListeners GUARDED_BY(mMutex);
public:
static sp<TransactionCompletedListener> getInstance();
@@ -679,6 +696,10 @@
*/
void removeJankListener(const sp<JankDataListener>& listener);
+ void addSurfaceStatsListener(void* context, void* cookie, sp<SurfaceControl> surfaceControl,
+ SurfaceStatsCallback listener);
+ void removeSurfaceStatsListener(void* context, void* cookie);
+
// Overrides BnTransactionCompletedListener's onTransactionCompleted
void onTransactionCompleted(ListenerStats stats) override;
};
diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp
index 64b1eac..bddb0ac 100644
--- a/libs/gui/sysprop/Android.bp
+++ b/libs/gui/sysprop/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sysprop_library {
name: "LibGuiProperties",
srcs: ["*.sysprop"],
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 53c13c8..c801c62 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -2,6 +2,15 @@
// Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
// to integrate with auto-test framework.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "libgui_test",
test_suites: ["device-tests"],
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 5447b76..fb07a19 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -129,7 +129,11 @@
}
void setUpProducer(BLASTBufferQueueHelper adapter, sp<IGraphicBufferProducer>& producer) {
- auto igbProducer = adapter.getIGraphicBufferProducer();
+ producer = adapter.getIGraphicBufferProducer();
+ setUpProducer(producer);
+ }
+
+ void setUpProducer(sp<IGraphicBufferProducer>& igbProducer) {
ASSERT_NE(nullptr, igbProducer.get());
ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2));
IGraphicBufferProducer::QueueBufferOutput qbOutput;
@@ -137,7 +141,6 @@
igbProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false,
&qbOutput));
ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
- producer = igbProducer;
}
void fillBuffer(uint32_t* bufData, Rect rect, uint32_t stride, uint8_t r, uint8_t g,
@@ -555,6 +558,8 @@
ASSERT_EQ(queuesToNativeWindow, 1);
}
+// Test a slow producer doesn't hold up a faster producer from the same client. Essentially tests
+// BBQ uses separate transaction queues.
TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) {
sp<SurfaceControl> bgSurface =
mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
@@ -781,7 +786,7 @@
void setUpAndQueueBuffer(const sp<IGraphicBufferProducer>& igbProducer,
nsecs_t* requestedPresentTime, nsecs_t* postedTime,
IGraphicBufferProducer::QueueBufferOutput* qbOutput,
- bool getFrameTimestamps) {
+ bool getFrameTimestamps, nsecs_t requestedPresentTimeDelay = 0) {
int slot;
sp<Fence> fence;
sp<GraphicBuffer> buf;
@@ -791,7 +796,7 @@
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
- nsecs_t requestedTime = systemTime();
+ nsecs_t requestedTime = systemTime() + requestedPresentTimeDelay;
if (requestedPresentTime) *requestedPresentTime = requestedTime;
IGraphicBufferProducer::QueueBufferInput input(requestedTime, false, HAL_DATASPACE_UNKNOWN,
Rect(mDisplayWidth, mDisplayHeight),
@@ -801,6 +806,27 @@
if (postedTime) *postedTime = systemTime();
igbProducer->queueBuffer(slot, input, qbOutput);
}
+
+ void createBufferQueueProducer(sp<IGraphicBufferProducer>* bqIgbp) {
+ mBufferQueueSurfaceControl =
+ mClient->createSurface(String8("BqSurface"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferQueue);
+ ASSERT_NE(nullptr, mBufferQueueSurfaceControl.get());
+ Transaction()
+ .setLayerStack(mBufferQueueSurfaceControl, 0)
+ .show(mBufferQueueSurfaceControl)
+ .setDataspace(mBufferQueueSurfaceControl, ui::Dataspace::V0_SRGB)
+ .setSize(mBufferQueueSurfaceControl, mDisplayWidth, mDisplayHeight)
+ .setLayer(mBufferQueueSurfaceControl, std::numeric_limits<int32_t>::max())
+ .apply();
+
+ sp<Surface> bqSurface = mBufferQueueSurfaceControl->getSurface();
+ ASSERT_NE(nullptr, bqSurface.get());
+
+ *bqIgbp = bqSurface->getIGraphicBufferProducer();
+ setUpProducer(*bqIgbp);
+ }
+ sp<SurfaceControl> mBufferQueueSurfaceControl;
};
TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) {
@@ -853,4 +879,153 @@
// wait for any callbacks that have not been received
adapter.waitForCallbacks();
}
+
+// Runs the same Frame Event History test
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic_BufferQueue) {
+ sp<IGraphicBufferProducer> bqIgbp;
+ createBufferQueueProducer(&bqIgbp);
+
+ ProducerFrameEventHistory history;
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ nsecs_t requestedPresentTimeA = 0;
+ nsecs_t postedTimeA = 0;
+ setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+
+ FrameEvents* events = nullptr;
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ // wait for buffer to be presented
+ std::this_thread::sleep_for(200ms);
+
+ nsecs_t requestedPresentTimeB = 0;
+ nsecs_t postedTimeB = 0;
+ setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+
+ // frame number, requestedPresentTime, and postTime should not have changed
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ ASSERT_GE(events->latchTime, postedTimeA);
+ ASSERT_FALSE(events->hasDequeueReadyInfo());
+
+ ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
+ ASSERT_NE(nullptr, events->displayPresentFence);
+ ASSERT_NE(nullptr, events->releaseFence);
+
+ // we should also have gotten the initial values for the next frame
+ events = history.getFrame(2);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(2, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeB);
+}
+
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ ProducerFrameEventHistory history;
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ nsecs_t requestedPresentTimeA = 0;
+ nsecs_t postedTimeA = 0;
+ nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+ setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true,
+ presentTimeDelay);
+ history.applyDelta(qbOutput.frameTimestamps);
+
+ FrameEvents* events = nullptr;
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ // queue another buffer so the first can be dropped
+ nsecs_t requestedPresentTimeB = 0;
+ nsecs_t postedTimeB = 0;
+ setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+
+ // frame number, requestedPresentTime, and postTime should not have changed
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ // a valid latchtime should not be set
+ ASSERT_FALSE(events->hasLatchInfo());
+ ASSERT_FALSE(events->hasDequeueReadyInfo());
+
+ ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
+ ASSERT_NE(nullptr, events->displayPresentFence);
+ ASSERT_NE(nullptr, events->releaseFence);
+
+ // we should also have gotten the initial values for the next frame
+ events = history.getFrame(2);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(2, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeB);
+}
+
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame_BufferQueue) {
+ sp<IGraphicBufferProducer> bqIgbp;
+ createBufferQueueProducer(&bqIgbp);
+
+ ProducerFrameEventHistory history;
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ nsecs_t requestedPresentTimeA = 0;
+ nsecs_t postedTimeA = 0;
+ nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+ setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true,
+ presentTimeDelay);
+ history.applyDelta(qbOutput.frameTimestamps);
+
+ FrameEvents* events = nullptr;
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ // queue another buffer so the first can be dropped
+ nsecs_t requestedPresentTimeB = 0;
+ nsecs_t postedTimeB = 0;
+ setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+
+ // frame number, requestedPresentTime, and postTime should not have changed
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ // a valid latchtime should not be set
+ ASSERT_FALSE(events->hasLatchInfo());
+ ASSERT_FALSE(events->hasDequeueReadyInfo());
+
+ ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
+ ASSERT_NE(nullptr, events->displayPresentFence);
+ ASSERT_NE(nullptr, events->releaseFence);
+
+ // we should also have gotten the initial values for the next frame
+ events = history.getFrame(2);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(2, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeB);
+}
+
} // namespace android
diff --git a/libs/incidentcompanion/Android.bp b/libs/incidentcompanion/Android.bp
index 63411b9..ef7f523 100644
--- a/libs/incidentcompanion/Android.bp
+++ b/libs/incidentcompanion/Android.bp
@@ -14,6 +14,15 @@
* limitations under the License.
*/
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
filegroup {
name: "incidentcompanion_aidl",
srcs: [
@@ -49,4 +58,3 @@
"-Wunused-parameter",
],
}
-
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index fce3000..4253610 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -14,6 +14,15 @@
// libinput is partially built for the host (used by build time keymap validation tool)
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
filegroup {
name: "inputconstants_aidl",
srcs: [
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index acea473..6218fdc 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -234,6 +234,7 @@
}
case InputMessage::Type::FINISHED: {
msg->body.finished.handled = body.finished.handled;
+ msg->body.finished.consumeTime = body.finished.consumeTime;
break;
}
case InputMessage::Type::FOCUS: {
@@ -597,7 +598,8 @@
return mChannel->sendMessage(&msg);
}
-status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
+status_t InputPublisher::receiveFinishedSignal(
+ const std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)>& callback) {
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' publisher ~ receiveFinishedSignal", mChannel->getName().c_str());
}
@@ -605,8 +607,6 @@
InputMessage msg;
status_t result = mChannel->receiveMessage(&msg);
if (result) {
- *outSeq = 0;
- *outHandled = false;
return result;
}
if (msg.header.type != InputMessage::Type::FINISHED) {
@@ -614,8 +614,7 @@
mChannel->getName().c_str(), msg.header.type);
return UNKNOWN_ERROR;
}
- *outSeq = msg.header.seq;
- *outHandled = msg.body.finished.handled == 1;
+ callback(msg.header.seq, msg.body.finished.handled == 1, msg.body.finished.consumeTime);
return OK;
}
@@ -651,6 +650,9 @@
} else {
// Receive a fresh message.
status_t result = mChannel->receiveMessage(&mMsg);
+ if (result == OK) {
+ mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
+ }
if (result) {
// Consume the next batched event unless batches are being held for later.
if (consumeBatches || result != WOULD_BLOCK) {
@@ -1147,12 +1149,33 @@
return sendUnchainedFinishedSignal(seq, handled);
}
+nsecs_t InputConsumer::getConsumeTime(uint32_t seq) const {
+ auto it = mConsumeTimes.find(seq);
+ // Consume time will be missing if either 'finishInputEvent' is called twice, or if it was
+ // called for the wrong (synthetic?) input event. Either way, it is a bug that should be fixed.
+ LOG_ALWAYS_FATAL_IF(it == mConsumeTimes.end(), "Could not find consume time for seq=%" PRIu32,
+ seq);
+ return it->second;
+}
+
+void InputConsumer::popConsumeTime(uint32_t seq) {
+ mConsumeTimes.erase(seq);
+}
+
status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
InputMessage msg;
msg.header.type = InputMessage::Type::FINISHED;
msg.header.seq = seq;
msg.body.finished.handled = handled ? 1 : 0;
- return mChannel->sendMessage(&msg);
+ msg.body.finished.consumeTime = getConsumeTime(seq);
+ status_t result = mChannel->sendMessage(&msg);
+ if (result == OK) {
+ // Remove the consume time if the socket write succeeded. We will not need to ack this
+ // message anymore. If the socket write did not succeed, we will try again and will still
+ // need consume time.
+ popConsumeTime(seq);
+ }
+ return result;
}
bool InputConsumer::hasDeferredEvent() const {
@@ -1304,8 +1327,9 @@
break;
}
case InputMessage::Type::FINISHED: {
- out += android::base::StringPrintf("handled=%s",
- toString(msg.body.finished.handled));
+ out += android::base::StringPrintf("handled=%s, consumeTime=%" PRId64,
+ toString(msg.body.finished.handled),
+ msg.body.finished.consumeTime);
break;
}
case InputMessage::Type::FOCUS: {
@@ -1335,6 +1359,14 @@
if (mSeqChains.empty()) {
out += " <empty>\n";
}
+ out += "mConsumeTimes:\n";
+ for (const auto& [seq, consumeTime] : mConsumeTimes) {
+ out += android::base::StringPrintf(" seq = %" PRIu32 " consumeTime = %" PRId64, seq,
+ consumeTime);
+ }
+ if (mConsumeTimes.empty()) {
+ out += " <empty>\n";
+ }
return out;
}
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index b23aade..fe8a567 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -1,4 +1,13 @@
// Build the unit tests.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "libinput_tests",
srcs: [
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 9da7b69..e7e566d 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -82,6 +82,7 @@
constexpr int32_t repeatCount = 1;
constexpr nsecs_t downTime = 3;
constexpr nsecs_t eventTime = 4;
+ const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
status = mPublisher->publishKeyEvent(seq, eventId, deviceId, source, displayId, hmac, action,
flags, keyCode, scanCode, metaState, repeatCount, downTime,
@@ -122,13 +123,22 @@
uint32_t finishedSeq = 0;
bool handled = false;
- status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+ nsecs_t consumeTime;
+ status = mPublisher->receiveFinishedSignal(
+ [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+ nsecs_t inConsumeTime) -> void {
+ finishedSeq = inSeq;
+ handled = inHandled;
+ consumeTime = inConsumeTime;
+ });
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
ASSERT_EQ(seq, finishedSeq)
<< "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_TRUE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(consumeTime, publishTime)
+ << "finished signal's consume time should be greater than publish time";
}
void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
@@ -160,6 +170,7 @@
constexpr nsecs_t downTime = 3;
constexpr size_t pointerCount = 3;
constexpr nsecs_t eventTime = 4;
+ const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
for (size_t i = 0; i < pointerCount; i++) {
@@ -262,13 +273,22 @@
uint32_t finishedSeq = 0;
bool handled = true;
- status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+ nsecs_t consumeTime;
+ status = mPublisher->receiveFinishedSignal(
+ [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+ nsecs_t inConsumeTime) -> void {
+ finishedSeq = inSeq;
+ handled = inHandled;
+ consumeTime = inConsumeTime;
+ });
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
ASSERT_EQ(seq, finishedSeq)
<< "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_FALSE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(consumeTime, publishTime)
+ << "finished signal's consume time should be greater than publish time";
}
void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() {
@@ -278,6 +298,7 @@
int32_t eventId = InputEvent::nextId();
constexpr bool hasFocus = true;
constexpr bool inTouchMode = true;
+ const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
status = mPublisher->publishFocusEvent(seq, eventId, hasFocus, inTouchMode);
ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK";
@@ -302,12 +323,21 @@
uint32_t finishedSeq = 0;
bool handled = false;
- status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+ nsecs_t consumeTime;
+ status = mPublisher->receiveFinishedSignal(
+ [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+ nsecs_t inConsumeTime) -> void {
+ finishedSeq = inSeq;
+ handled = inHandled;
+ consumeTime = inConsumeTime;
+ });
ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK";
ASSERT_EQ(seq, finishedSeq)
<< "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_TRUE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(consumeTime, publishTime)
+ << "finished signal's consume time should be greater than publish time";
}
void InputPublisherAndConsumerTest::PublishAndConsumeCaptureEvent() {
@@ -316,6 +346,7 @@
constexpr uint32_t seq = 42;
int32_t eventId = InputEvent::nextId();
constexpr bool captureEnabled = true;
+ const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
status = mPublisher->publishCaptureEvent(seq, eventId, captureEnabled);
ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK";
@@ -339,12 +370,21 @@
uint32_t finishedSeq = 0;
bool handled = false;
- status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+ nsecs_t consumeTime;
+ status = mPublisher->receiveFinishedSignal(
+ [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+ nsecs_t inConsumeTime) -> void {
+ finishedSeq = inSeq;
+ handled = inHandled;
+ consumeTime = inConsumeTime;
+ });
ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK";
ASSERT_EQ(seq, finishedSeq)
<< "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_TRUE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(consumeTime, publishTime)
+ << "finished signal's consume time should be greater than publish time";
}
TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 4107d61..a886585 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -83,6 +83,7 @@
CHECK_OFFSET(InputMessage::Body::Capture, pointerCaptureEnabled, 4);
CHECK_OFFSET(InputMessage::Body::Finished, handled, 4);
+ CHECK_OFFSET(InputMessage::Body::Finished, consumeTime, 8);
}
void TestHeaderSize() {
@@ -100,7 +101,7 @@
static_assert(sizeof(InputMessage::Body::Motion) ==
offsetof(InputMessage::Body::Motion, pointers) +
sizeof(InputMessage::Body::Motion::Pointer) * MAX_POINTERS);
- static_assert(sizeof(InputMessage::Body::Finished) == 8);
+ static_assert(sizeof(InputMessage::Body::Finished) == 16);
static_assert(sizeof(InputMessage::Body::Focus) == 8);
static_assert(sizeof(InputMessage::Body::Capture) == 8);
}
diff --git a/libs/math/Android.bp b/libs/math/Android.bp
index 22d4712..3cf9f3f 100644
--- a/libs/math/Android.bp
+++ b/libs/math/Android.bp
@@ -12,6 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_libs_math_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_math_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_library_static {
name: "libmath",
host_supported: true,
diff --git a/libs/math/tests/Android.bp b/libs/math/tests/Android.bp
index 0184f56..4a7c4dd 100644
--- a/libs/math/tests/Android.bp
+++ b/libs/math/tests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_libs_math_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_libs_math_license"],
+}
+
cc_test {
name: "vec_test",
srcs: ["vec_test.cpp"],
diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp
index 8399e8c..1a4729c 100644
--- a/libs/nativebase/Android.bp
+++ b/libs/nativebase/Android.bp
@@ -12,6 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_libs_nativebase_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_nativebase_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_library_headers {
name: "libnativebase_headers",
vendor_available: true,
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index 6574ae6..ed728dc 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -12,6 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: [
+ "frameworks_native_libs_nativedisplay_license",
+ ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_nativedisplay_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_library_headers {
name: "libnativedisplay_headers",
export_include_dirs: ["include",],
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 3011dcc..8675439 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -12,6 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: [
+ "frameworks_native_libs_nativewindow_license",
+ ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_nativewindow_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
ndk_headers {
name: "libnativewindow_ndk_headers",
from: "include/android",
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index 2e4bd99..30737c1 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -14,6 +14,17 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_libs_nativewindow_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: [
+ "frameworks_native_libs_nativewindow_license",
+ ],
+}
+
cc_test {
name: "libnativewindow_test",
test_suites: [
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index d69c7ae..eb3b434 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "renderengine_defaults",
cflags: [
@@ -31,10 +40,6 @@
"libui",
"libutils",
],
- include_dirs: [
- "external/skia/src/gpu",
- ],
- whole_static_libs: ["libskia"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
}
@@ -106,6 +111,10 @@
":librenderengine_threaded_sources",
":librenderengine_skia_sources",
],
+ include_dirs: [
+ "external/skia/src/gpu",
+ ],
+ whole_static_libs: ["libskia"],
lto: {
thin: true,
},
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index 08cf2de..c478506 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,3 +1,5 @@
alecmouri@google.com
+djsollen@google.com
jreck@google.com
lpy@google.com
+scroggo@google.com
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 64d6c6b..7496b74 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -72,6 +72,7 @@
base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
bool cleanupPostRender(CleanupMode mode) override;
int getContextPriority() override;
+ bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
// Creates an output image for rendering to
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
index 19f18c0..3455e08 100644
--- a/libs/renderengine/gl/filters/BlurFilter.cpp
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -207,7 +207,7 @@
}
string BlurFilter::getVertexShader() const {
- return R"SHADER(#version 310 es
+ return R"SHADER(#version 300 es
precision mediump float;
in vec2 aPosition;
@@ -222,7 +222,7 @@
}
string BlurFilter::getFragmentShader() const {
- return R"SHADER(#version 310 es
+ return R"SHADER(#version 300 es
precision mediump float;
uniform sampler2D uTexture;
@@ -244,7 +244,7 @@
}
string BlurFilter::getMixFragShader() const {
- string shader = R"SHADER(#version 310 es
+ string shader = R"SHADER(#version 300 es
precision mediump float;
in highp vec2 vUV;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 506f81e..163a163 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -188,6 +188,10 @@
// number of contexts that can be created at a specific priority level in the system.
virtual int getContextPriority() = 0;
+ // Returns true if blur was requested in the RenderEngineCreationArgs and the implementation
+ // also supports background blur. If false, no blur will be applied when drawing layers.
+ virtual bool supportsBackgroundBlur() = 0;
+
protected:
friend class threaded::RenderEngineThreaded;
};
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 2c34da4..895ba3f 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -54,6 +54,7 @@
base::unique_fd*));
MOCK_METHOD0(cleanFramebufferCache, void());
MOCK_METHOD0(getContextPriority, int());
+ MOCK_METHOD0(supportsBackgroundBlur, bool());
};
} // namespace mock
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 1eb8da9..55ec6ad 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -286,6 +286,7 @@
}
if (args.supportsBackgroundBlur) {
+ ALOGD("Background Blurs Enabled");
mBlurFilter = new BlurFilter();
}
mCapture = std::make_unique<SkiaCapture>();
@@ -336,7 +337,7 @@
if (useProtectedContext == mInProtectedContext) {
return true;
}
- if (useProtectedContext && supportsProtectedContent()) {
+ if (useProtectedContext && !supportsProtectedContent()) {
return false;
}
const EGLSurface surface =
@@ -516,6 +517,45 @@
return shader;
}
+void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+ // Record display settings when capture is running.
+ std::stringstream displaySettings;
+ PrintTo(display, &displaySettings);
+ // Store the DisplaySettings in additional information.
+ canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
+ SkData::MakeWithCString(displaySettings.str().c_str()));
+ }
+
+ // Before doing any drawing, let's make sure that we'll start at the origin of the display.
+ // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
+ // displays might have different scaling when compared to the physical screen.
+
+ canvas->clipRect(getSkRect(display.physicalDisplay));
+ canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
+
+ const auto clipWidth = display.clip.width();
+ const auto clipHeight = display.clip.height();
+ auto rotatedClipWidth = clipWidth;
+ auto rotatedClipHeight = clipHeight;
+ // Scale is contingent on the rotation result.
+ if (display.orientation & ui::Transform::ROT_90) {
+ std::swap(rotatedClipWidth, rotatedClipHeight);
+ }
+ const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
+ static_cast<SkScalar>(rotatedClipWidth);
+ const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
+ static_cast<SkScalar>(rotatedClipHeight);
+ canvas->scale(scaleX, scaleY);
+
+ // Canvas rotation is done by centering the clip window at the origin, rotating, translating
+ // back so that the top left corner of the clip is at (0, 0).
+ canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
+ canvas->rotate(toDegrees(display.orientation));
+ canvas->translate(-clipWidth / 2, -clipHeight / 2);
+ canvas->translate(-display.clip.left, -display.clip.top);
+}
+
status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
const sp<GraphicBuffer>& buffer,
@@ -570,57 +610,50 @@
}
}
- sk_sp<SkSurface> surface =
+ sk_sp<SkSurface> dstSurface =
surfaceTextureRef->getTexture()->getOrCreateSurface(mUseColorManagement
? display.outputDataspace
: ui::Dataspace::UNKNOWN,
grContext.get());
- SkCanvas* canvas = mCapture->tryCapture(surface.get());
- if (canvas == nullptr) {
+ SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
+ if (dstCanvas == nullptr) {
ALOGE("Cannot acquire canvas from Skia.");
return BAD_VALUE;
}
+
+ // Find if any layers have requested blur, we'll use that info to decide when to render to an
+ // offscreen buffer and when to render to the native buffer.
+ sk_sp<SkSurface> activeSurface(dstSurface);
+ SkCanvas* canvas = dstCanvas;
+ SkiaCapture::OffscreenState offscreenCaptureState;
+ const LayerSettings* blurCompositionLayer = nullptr;
+ if (mBlurFilter) {
+ bool requiresCompositionLayer = false;
+ for (const auto& layer : layers) {
+ if (layer->backgroundBlurRadius > 0) {
+ // when skbug.com/11208 and b/176903027 are resolved we can add the additional
+ // restriction for layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius
+ requiresCompositionLayer = true;
+ }
+ for (auto region : layer->blurRegions) {
+ if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) {
+ requiresCompositionLayer = true;
+ }
+ }
+ if (requiresCompositionLayer) {
+ activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
+ canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
+ blurCompositionLayer = layer;
+ break;
+ }
+ }
+ }
+
+ canvas->save();
// Clear the entire canvas with a transparent black to prevent ghost images.
canvas->clear(SK_ColorTRANSPARENT);
- canvas->save();
-
- if (mCapture->isCaptureRunning()) {
- // Record display settings when capture is running.
- std::stringstream displaySettings;
- PrintTo(display, &displaySettings);
- // Store the DisplaySettings in additional information.
- canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
- SkData::MakeWithCString(displaySettings.str().c_str()));
- }
-
- // Before doing any drawing, let's make sure that we'll start at the origin of the display.
- // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
- // displays might have different scaling when compared to the physical screen.
-
- canvas->clipRect(getSkRect(display.physicalDisplay));
- canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
-
- const auto clipWidth = display.clip.width();
- const auto clipHeight = display.clip.height();
- auto rotatedClipWidth = clipWidth;
- auto rotatedClipHeight = clipHeight;
- // Scale is contingent on the rotation result.
- if (display.orientation & ui::Transform::ROT_90) {
- std::swap(rotatedClipWidth, rotatedClipHeight);
- }
- const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
- static_cast<SkScalar>(rotatedClipWidth);
- const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
- static_cast<SkScalar>(rotatedClipHeight);
- canvas->scale(scaleX, scaleY);
-
- // Canvas rotation is done by centering the clip window at the origin, rotating, translating
- // back so that the top left corner of the clip is at (0, 0).
- canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
- canvas->rotate(toDegrees(display.orientation));
- canvas->translate(-clipWidth / 2, -clipHeight / 2);
- canvas->translate(-display.clip.left, -display.clip.top);
+ initCanvas(canvas, display);
// TODO: clearRegion was required for SurfaceView when a buffer is not yet available but the
// view is still on-screen. The clear region could be re-specified as a black color layer,
@@ -647,9 +680,45 @@
for (const auto& layer : layers) {
ATRACE_NAME("DrawLayer");
- canvas->save();
- if (mCapture->isCaptureRunning()) {
+ sk_sp<SkImage> blurInput;
+ if (blurCompositionLayer == layer) {
+ LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
+ LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);
+
+ // save a snapshot of the activeSurface to use as input to the blur shaders
+ blurInput = activeSurface->makeImageSnapshot();
+
+ // TODO we could skip this step if we know the blur will cover the entire image
+ // blit the offscreen framebuffer into the destination AHB
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+ uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
+ dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
+ String8::format("SurfaceID|%" PRId64, id).c_str(),
+ nullptr);
+ dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
+ } else {
+ activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
+ }
+
+ // assign dstCanvas to canvas and ensure that the canvas state is up to date
+ canvas = dstCanvas;
+ canvas->save();
+ initCanvas(canvas, display);
+
+ LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() !=
+ dstSurface->getCanvas()->getSaveCount());
+ LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() !=
+ dstSurface->getCanvas()->getTotalMatrix());
+
+ // assign dstSurface to activeSurface
+ activeSurface = dstSurface;
+ }
+
+ canvas->save();
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
// Record the name of the layer if the capture is running.
std::stringstream layerSettings;
PrintTo(*layer, &layerSettings);
@@ -657,34 +726,42 @@
canvas->drawAnnotation(SkRect::MakeEmpty(), layer->name.c_str(),
SkData::MakeWithCString(layerSettings.str().c_str()));
}
-
// Layers have a local transform that should be applied to them
canvas->concat(getSkM44(layer->geometry.positionTransform).asM33());
- SkPaint paint;
- const auto& bounds = layer->geometry.boundaries;
- const auto dest = getSkRect(bounds);
- const auto layerRect = canvas->getTotalMatrix().mapRect(dest);
- std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
- if (mBlurFilter) {
+ const auto bounds = getSkRect(layer->geometry.boundaries);
+ if (mBlurFilter && layerHasBlur(layer)) {
+ std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
+
+ // if multiple layers have blur, then we need to take a snapshot now because
+ // only the lowest layer will have blurImage populated earlier
+ if (!blurInput) {
+ blurInput = activeSurface->makeImageSnapshot();
+ }
+ // rect to be blurred in the coordinate space of blurInput
+ const auto blurRect = canvas->getTotalMatrix().mapRect(bounds);
+
if (layer->backgroundBlurRadius > 0) {
ATRACE_NAME("BackgroundBlur");
- auto blurredSurface = mBlurFilter->generate(canvas, surface,
- layer->backgroundBlurRadius, layerRect);
- cachedBlurs[layer->backgroundBlurRadius] = blurredSurface;
+ auto blurredImage =
+ mBlurFilter->generate(grContext.get(), layer->backgroundBlurRadius,
+ blurInput, blurRect);
- drawBlurRegion(canvas, getBlurRegion(layer), layerRect, blurredSurface);
+ cachedBlurs[layer->backgroundBlurRadius] = blurredImage;
+
+ mBlurFilter->drawBlurRegion(canvas, getBlurRegion(layer), blurRect, blurredImage,
+ blurInput);
}
- if (layer->blurRegions.size() > 0) {
- for (auto region : layer->blurRegions) {
- if (cachedBlurs[region.blurRadius]) {
- continue;
- }
+ for (auto region : layer->blurRegions) {
+ if (cachedBlurs[region.blurRadius] != nullptr) {
ATRACE_NAME("BlurRegion");
- auto blurredSurface =
- mBlurFilter->generate(canvas, surface, region.blurRadius, layerRect);
- cachedBlurs[region.blurRadius] = blurredSurface;
+ cachedBlurs[region.blurRadius] =
+ mBlurFilter->generate(grContext.get(), region.blurRadius, blurInput,
+ blurRect);
}
+
+ mBlurFilter->drawBlurRegion(canvas, region, blurRect,
+ cachedBlurs[region.blurRadius], blurInput);
}
}
@@ -698,6 +775,7 @@
: layer->sourceDataspace)
: ui::Dataspace::UNKNOWN;
+ SkPaint paint;
if (layer->source.buffer.buffer) {
ATRACE_NAME("DrawImage");
const auto& item = layer->source.buffer;
@@ -724,7 +802,7 @@
// textureTansform was intended to be passed directly into a shader, so when
// building the total matrix with the textureTransform we need to first
// normalize it, then apply the textureTransform, then scale back up.
- texMatrix.preScale(1.0f / bounds.getWidth(), 1.0f / bounds.getHeight());
+ texMatrix.preScale(1.0f / bounds.width(), 1.0f / bounds.height());
texMatrix.postScale(image->width(), image->height());
SkMatrix matrix;
@@ -794,14 +872,10 @@
paint.setColorFilter(filter);
- for (const auto effectRegion : layer->blurRegions) {
- drawBlurRegion(canvas, effectRegion, layerRect, cachedBlurs[effectRegion.blurRadius]);
- }
-
if (layer->shadow.length > 0) {
const auto rect = layer->geometry.roundedCornersRadius > 0
? getSkRect(layer->geometry.roundedCornersCrop)
- : dest;
+ : bounds;
drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
} else {
// Shadows are assumed to live only on their own layer - it's not valid
@@ -812,7 +886,7 @@
if (layer->geometry.roundedCornersRadius > 0) {
canvas->clipRRect(getRoundedRect(layer), true);
}
- canvas->drawRect(dest, paint);
+ canvas->drawRect(bounds, paint);
}
canvas->restore();
}
@@ -820,7 +894,8 @@
mCapture->endCapture();
{
ATRACE_NAME("flush surface");
- surface->flush();
+ LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface);
+ activeSurface->flush();
}
if (drawFence != nullptr) {
@@ -877,6 +952,10 @@
.bottom = static_cast<int>(rect.fBottom)};
}
+inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer) {
+ return layer->backgroundBlurRadius > 0 || layer->blurRegions.size();
+}
+
inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) {
return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
}
@@ -916,53 +995,6 @@
flags);
}
-void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
- const SkRect& layerRect, sk_sp<SkImage> blurredImage) {
- ATRACE_CALL();
-
- SkPaint paint;
- paint.setAlpha(static_cast<int>(effectRegion.alpha * 255));
- const auto matrix = getBlurShaderTransform(canvas, layerRect);
- SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
- paint.setShader(blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling,
- &matrix));
-
- auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
- effectRegion.bottom);
-
- if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
- effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
- const SkVector radii[4] =
- {SkVector::Make(effectRegion.cornerRadiusTL, effectRegion.cornerRadiusTL),
- SkVector::Make(effectRegion.cornerRadiusTR, effectRegion.cornerRadiusTR),
- SkVector::Make(effectRegion.cornerRadiusBL, effectRegion.cornerRadiusBL),
- SkVector::Make(effectRegion.cornerRadiusBR, effectRegion.cornerRadiusBR)};
- SkRRect roundedRect;
- roundedRect.setRectRadii(rect, radii);
- canvas->drawRRect(roundedRect, paint);
- } else {
- canvas->drawRect(rect, paint);
- }
-}
-
-SkMatrix SkiaGLRenderEngine::getBlurShaderTransform(const SkCanvas* canvas,
- const SkRect& layerRect) {
- // 1. Apply the blur shader matrix, which scales up the blured surface to its real size
- auto matrix = mBlurFilter->getShaderMatrix();
- // 2. Since the blurred surface has the size of the layer, we align it with the
- // top left corner of the layer position.
- matrix.postConcat(SkMatrix::Translate(layerRect.fLeft, layerRect.fTop));
- // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the
- // original surface orientation. The inverse matrix has to be applied to align the blur
- // surface with the current orientation/position of the canvas.
- SkMatrix drawInverse;
- if (canvas->getTotalMatrix().invert(&drawInverse)) {
- matrix.postConcat(drawInverse);
- }
-
- return matrix;
-}
-
EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
EGLContext shareContext,
std::optional<ContextPriority> contextPriority,
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 810fc2a..5779ae6 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -61,6 +61,7 @@
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
bool useProtectedContext(bool useProtectedContext) override;
+ bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
protected:
void dump(std::string& result) override;
@@ -81,17 +82,16 @@
inline SkRect getSkRect(const Rect& layer);
inline SkRRect getRoundedRect(const LayerSettings* layer);
inline BlurRegion getBlurRegion(const LayerSettings* layer);
+ inline bool layerHasBlur(const LayerSettings* layer);
inline SkColor getSkColor(const vec4& color);
inline SkM44 getSkM44(const mat4& matrix);
inline SkPoint3 getSkPoint3(const vec3& vector);
base::unique_fd flush();
bool waitFence(base::unique_fd fenceFd);
+ void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
const ShadowSettings& shadowSettings);
- void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerRect,
- sk_sp<SkImage> blurredImage);
- SkMatrix getBlurShaderTransform(const SkCanvas* canvas, const SkRect& layerRect);
// If mUseColorManagement is correct and layer needsLinearEffect, it returns a linear runtime
// shader. Otherwise it returns the input shader.
sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader, const LayerSettings* layer,
diff --git a/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp
index e9cfead..40f5cf2 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.cpp
+++ b/libs/renderengine/skia/debug/SkiaCapture.cpp
@@ -41,11 +41,11 @@
mTimer.stop();
}
-SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) {
+SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
// If we are not running yet, set up.
- if (!mCaptureRunning) {
+ if (CC_LIKELY(!mCaptureRunning)) {
mTimerInterval = std::chrono::milliseconds(
base::GetIntProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS, 0));
// Set up the multi-frame capture. If we fail to set it up, then just return canvas.
@@ -56,7 +56,8 @@
// Start the new timer. When timer expires, write to file.
mTimer.setTimeout(
[this] {
- endCapture();
+ const std::scoped_lock lock(mMutex);
+ LOG_ALWAYS_FATAL_IF(mCurrentPageCanvas != nullptr);
writeToFile();
// To avoid going in circles, set the flag to 0. This way the capture can be
// restarted just by setting the flag and without restarting the process.
@@ -65,29 +66,82 @@
mTimerInterval);
}
+ mMutex.lock();
+
// Create a canvas pointer, fill it.
- SkCanvas* pictureCanvas = mMultiPic->beginPage(surface->width(), surface->height());
+ mCurrentPageCanvas = mMultiPic->beginPage(surface->width(), surface->height());
// Setting up an nway canvas is common to any kind of capture.
mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
mNwayCanvas->addCanvas(surface->getCanvas());
- mNwayCanvas->addCanvas(pictureCanvas);
+ mNwayCanvas->addCanvas(mCurrentPageCanvas);
return mNwayCanvas.get();
}
-void SkiaCapture::endCapture() {
+void SkiaCapture::endCapture() NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
// Don't end anything if we are not running.
- if (!mCaptureRunning) {
+ if (CC_LIKELY(!mCaptureRunning)) {
return;
}
// Reset the canvas pointer.
+ mCurrentPageCanvas = nullptr;
mNwayCanvas.reset();
// End page.
if (mMultiPic) {
mMultiPic->endPage();
}
+ mMutex.unlock();
+}
+
+SkCanvas* SkiaCapture::tryOffscreenCapture(SkSurface* surface, OffscreenState* state) {
+ ATRACE_CALL();
+ // Don't start anything if we are not running.
+ if (CC_LIKELY(!mCaptureRunning)) {
+ return surface->getCanvas();
+ }
+
+ // Create a canvas pointer, fill it.
+ state->offscreenRecorder = std::make_unique<SkPictureRecorder>();
+ SkCanvas* pictureCanvas =
+ state->offscreenRecorder->beginRecording(surface->width(), surface->height());
+
+ // Setting up an nway canvas is common to any kind of capture.
+ state->offscreenCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
+ state->offscreenCanvas->addCanvas(surface->getCanvas());
+ state->offscreenCanvas->addCanvas(pictureCanvas);
+
+ return state->offscreenCanvas.get();
+}
+
+uint64_t SkiaCapture::endOffscreenCapture(OffscreenState* state) {
+ ATRACE_CALL();
+ // Don't end anything if we are not running.
+ if (CC_LIKELY(!mCaptureRunning)) {
+ return 0;
+ }
+
+ // compute the uniqueID for this capture
+ static std::atomic<uint64_t> nextID{1};
+ const uint64_t uniqueID = nextID.fetch_add(1, std::memory_order_relaxed);
+
+ // Reset the canvas pointer as we are no longer drawing into it
+ state->offscreenCanvas.reset();
+
+ // Record the offscreen as a picture in the currently active page.
+ SkRect bounds =
+ SkRect::Make(state->offscreenRecorder->getRecordingCanvas()->imageInfo().dimensions());
+ mCurrentPageCanvas
+ ->drawAnnotation(bounds,
+ String8::format("OffscreenLayerDraw|%" PRId64, uniqueID).c_str(),
+ nullptr);
+ mCurrentPageCanvas->drawPicture(state->offscreenRecorder->finishRecordingAsPicture());
+
+ // Reset the offscreen picture recorder
+ state->offscreenRecorder.reset();
+
+ return uniqueID;
}
void SkiaCapture::writeToFile() {
diff --git a/libs/renderengine/skia/debug/SkiaCapture.h b/libs/renderengine/skia/debug/SkiaCapture.h
index eaaf598..5e18e60 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.h
+++ b/libs/renderengine/skia/debug/SkiaCapture.h
@@ -18,8 +18,12 @@
#include <SkDocument.h>
#include <SkNWayCanvas.h>
+#include <SkPictureRecorder.h>
#include <SkSurface.h>
+
#include <chrono>
+#include <mutex>
+
#include "CaptureTimer.h"
#include "tools/SkSharingProc.h"
@@ -48,6 +52,16 @@
// Returns whether the capture is running.
bool isCaptureRunning() { return mCaptureRunning; }
+ // Offscreen state member variables are private to SkiaCapture, but the allocation
+ // and lifetime is managed by the caller. This enables nested offscreen
+ // captures to occur.
+ struct OffscreenState {
+ std::unique_ptr<SkPictureRecorder> offscreenRecorder;
+ std::unique_ptr<SkNWayCanvas> offscreenCanvas;
+ };
+ SkCanvas* tryOffscreenCapture(SkSurface* surface, OffscreenState* state);
+ uint64_t endOffscreenCapture(OffscreenState* state);
+
private:
// Performs the first-frame work of a multi frame SKP capture. Returns true if successful.
bool setupMultiFrameCapture();
@@ -61,10 +75,16 @@
std::unique_ptr<SkSharingSerialContext> mSerialContext;
std::unique_ptr<SkNWayCanvas> mNwayCanvas;
+ SkCanvas* mCurrentPageCanvas = nullptr;
+
// Capturing and interval control.
bool mCaptureRunning = false;
CaptureTimer mTimer;
Interval mTimerInterval = 0ms;
+
+ // Mutex to ensure that a frame in progress when the timer fires is allowed to run to
+ // completion before we write the file to disk.
+ std::mutex mMutex;
};
} // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 87b1a7c..5960e48 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -20,6 +20,7 @@
#include <SkCanvas.h>
#include <SkData.h>
#include <SkPaint.h>
+#include <SkRRect.h>
#include <SkRuntimeEffect.h>
#include <SkSize.h>
#include <SkString.h>
@@ -34,17 +35,14 @@
BlurFilter::BlurFilter() {
SkString blurString(R"(
in shader input;
- uniform float in_inverseScale;
uniform float2 in_blurOffset;
half4 main(float2 xy) {
- float2 scaled_xy = float2(xy.x * in_inverseScale, xy.y * in_inverseScale);
-
- half4 c = sample(input, scaled_xy);
- c += sample(input, scaled_xy + float2( in_blurOffset.x, in_blurOffset.y));
- c += sample(input, scaled_xy + float2( in_blurOffset.x, -in_blurOffset.y));
- c += sample(input, scaled_xy + float2(-in_blurOffset.x, in_blurOffset.y));
- c += sample(input, scaled_xy + float2(-in_blurOffset.x, -in_blurOffset.y));
+ half4 c = sample(input, xy);
+ c += sample(input, xy + float2( in_blurOffset.x, in_blurOffset.y));
+ c += sample(input, xy + float2( in_blurOffset.x, -in_blurOffset.y));
+ c += sample(input, xy + float2(-in_blurOffset.x, in_blurOffset.y));
+ c += sample(input, xy + float2(-in_blurOffset.x, -in_blurOffset.y));
return half4(c.rgb * 0.2, 1.0);
}
@@ -55,10 +53,26 @@
LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str());
}
mBlurEffect = std::move(blurEffect);
+
+ SkString mixString(R"(
+ in shader blurredInput;
+ in shader originalInput;
+ uniform float mixFactor;
+
+ half4 main(float2 xy) {
+ return half4(mix(sample(originalInput), sample(blurredInput), mixFactor));
+ }
+ )");
+
+ auto [mixEffect, mixError] = SkRuntimeEffect::Make(mixString);
+ if (!mixEffect) {
+ LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str());
+ }
+ mMixEffect = std::move(mixEffect);
}
-sk_sp<SkImage> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
- const uint32_t blurRadius, SkRect rect) const {
+sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius,
+ const sk_sp<SkImage> input, const SkRect& blurRect) const {
// Kawase is an approximation of Gaussian, but it behaves differently from it.
// A radius transformation is required for approximating them, and also to introduce
// non-integer steps, necessary to smoothly interpolate large radii.
@@ -66,40 +80,110 @@
float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius));
float radiusByPasses = tmpRadius / (float)numberOfPasses;
- SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)rect.width() * kInputScale,
- (float)rect.height() * kInputScale);
+ // create blur surface with the bit depth and colorspace of the original surface
+ SkImageInfo scaledInfo = input->imageInfo().makeWH(blurRect.width() * kInputScale,
+ blurRect.height() * kInputScale);
const float stepX = radiusByPasses;
const float stepY = radiusByPasses;
- // start by drawing and downscaling and doing the first blur pass
+ // For sampling Skia's API expects the inverse of what logically seems appropriate. In this
+ // case you might expect Translate(blurRect.fLeft, blurRect.fTop) X Scale(kInverseInputScale)
+ // but instead we must do the inverse.
+ SkMatrix blurMatrix = SkMatrix::Translate(-blurRect.fLeft, -blurRect.fTop);
+ blurMatrix.postScale(kInputScale, kInputScale);
+
+ // start by downscaling and doing the first blur pass
SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
blurBuilder.child("input") =
- input->makeImageSnapshot(rect.round())
- ->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
- blurBuilder.uniform("in_inverseScale") = kInverseInputScale;
- blurBuilder.uniform("in_blurOffset") =
- SkV2{stepX * kInverseInputScale, stepY * kInverseInputScale};
+ input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix);
+ blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale};
- sk_sp<SkImage> tmpBlur(
- blurBuilder.makeImage(canvas->recordingContext(), nullptr, scaledInfo, false));
+ sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false));
// And now we'll build our chain of scaled blur stages
- blurBuilder.uniform("in_inverseScale") = 1.0f;
for (auto i = 1; i < numberOfPasses; i++) {
const float stepScale = (float)i * kInputScale;
blurBuilder.child("input") =
tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
- tmpBlur = blurBuilder.makeImage(canvas->recordingContext(), nullptr, scaledInfo, false);
+ tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false);
}
return tmpBlur;
}
-SkMatrix BlurFilter::getShaderMatrix() const {
- return SkMatrix::Scale(kInverseInputScale, kInverseInputScale);
+static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRect, float scale) {
+ // 1. Apply the blur shader matrix, which scales up the blured surface to its real size
+ auto matrix = SkMatrix::Scale(scale, scale);
+ // 2. Since the blurred surface has the size of the layer, we align it with the
+ // top left corner of the layer position.
+ matrix.postConcat(SkMatrix::Translate(blurRect.fLeft, blurRect.fTop));
+ // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the
+ // original surface orientation. The inverse matrix has to be applied to align the blur
+ // surface with the current orientation/position of the canvas.
+ SkMatrix drawInverse;
+ if (canvas != nullptr && canvas->getTotalMatrix().invert(&drawInverse)) {
+ matrix.postConcat(drawInverse);
+ }
+ return matrix;
+}
+
+void BlurFilter::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
+ const SkRect& blurRect, sk_sp<SkImage> blurredImage,
+ sk_sp<SkImage> input) {
+ ATRACE_CALL();
+
+ SkPaint paint;
+ paint.setAlphaf(effectRegion.alpha);
+ if (effectRegion.alpha == 1.0f) {
+ paint.setBlendMode(SkBlendMode::kSrc);
+ }
+
+ const auto blurMatrix = getShaderTransform(canvas, blurRect, kInverseInputScale);
+ SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
+ const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
+ linearSampling, &blurMatrix);
+
+ if (effectRegion.blurRadius < kMaxCrossFadeRadius) {
+ // For sampling Skia's API expects the inverse of what logically seems appropriate. In this
+ // case you might expect the matrix to simply be the canvas matrix.
+ SkMatrix inputMatrix;
+ if (!canvas->getTotalMatrix().invert(&inputMatrix)) {
+ ALOGE("matrix was unable to be inverted");
+ }
+
+ SkRuntimeShaderBuilder blurBuilder(mMixEffect);
+ blurBuilder.child("blurredInput") = blurShader;
+ blurBuilder.child("originalInput") =
+ input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling,
+ inputMatrix);
+ blurBuilder.uniform("mixFactor") = effectRegion.blurRadius / kMaxCrossFadeRadius;
+
+ paint.setShader(blurBuilder.makeShader(nullptr, true));
+ } else {
+ paint.setShader(blurShader);
+ }
+
+ // TODO we should AA at least the drawRoundRect which would mean no SRC blending
+ // TODO this round rect calculation doesn't match the one used to draw in RenderEngine
+ auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
+ effectRegion.bottom);
+
+ if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
+ effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
+ const SkVector radii[4] =
+ {SkVector::Make(effectRegion.cornerRadiusTL, effectRegion.cornerRadiusTL),
+ SkVector::Make(effectRegion.cornerRadiusTR, effectRegion.cornerRadiusTR),
+ SkVector::Make(effectRegion.cornerRadiusBL, effectRegion.cornerRadiusBL),
+ SkVector::Make(effectRegion.cornerRadiusBR, effectRegion.cornerRadiusBR)};
+ SkRRect roundedRect;
+ roundedRect.setRectRadii(rect, radii);
+ canvas->drawRRect(roundedRect, paint);
+ } else {
+ canvas->drawRect(rect, paint);
+ }
}
} // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 08641c9..731ba11 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -20,6 +20,7 @@
#include <SkImage.h>
#include <SkRuntimeEffect.h>
#include <SkSurface.h>
+#include <ui/BlurRegion.h>
using namespace std;
@@ -48,13 +49,15 @@
virtual ~BlurFilter(){};
// Execute blur, saving it to a texture
- sk_sp<SkImage> generate(SkCanvas* canvas, const sk_sp<SkSurface> input, const uint32_t radius,
- SkRect rect) const;
- // Returns a matrix that should be applied to the blur shader
- SkMatrix getShaderMatrix() const;
+ sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
+ const sk_sp<SkImage> blurInput, const SkRect& blurRect) const;
+
+ void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& blurRect,
+ sk_sp<SkImage> blurredImage, sk_sp<SkImage> input);
private:
sk_sp<SkRuntimeEffect> mBlurEffect;
+ sk_sp<SkRuntimeEffect> mMixEffect;
};
} // namespace skia
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index 51c7028..d0e19dd 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "librenderengine_test",
defaults: ["skia_deps", "surfaceflinger_defaults"],
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 58afe6e..500a90b 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -914,13 +914,6 @@
template <typename SourceVariant>
void RenderEngineTest::fillBufferAndBlurBackground() {
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.surface_flinger.supports_background_blur", value, "0");
- if (!atoi(value)) {
- // This device doesn't support blurs, no-op.
- return;
- }
-
auto blurRadius = 50;
auto center = DEFAULT_DISPLAY_WIDTH / 2;
@@ -950,15 +943,20 @@
blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
blurLayer.geometry.boundaries = fullscreenRect().toFloatRect();
blurLayer.backgroundBlurRadius = blurRadius;
+ SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this);
blurLayer.alpha = 0;
layers.push_back(&blurLayer);
invokeDraw(settings, layers);
- expectBufferColor(Rect(center - 1, center - 5, center, center + 5), 150, 150, 0, 255,
- 50 /* tolerance */);
- expectBufferColor(Rect(center, center - 5, center + 1, center + 5), 150, 150, 0, 255,
- 50 /* tolerance */);
+ // solid color
+ expectBufferColor(Rect(0, 0, 1, 1), 255, 0, 0, 255, 0 /* tolerance */);
+
+ if (mRE->supportsBackgroundBlur()) {
+ // blurred color (downsampling should result in the center color being close to 128)
+ expectBufferColor(Rect(center - 1, center - 5, center + 1, center + 5), 128, 128, 0, 255,
+ 10 /* tolerance */);
+ }
}
template <typename SourceVariant>
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 02ff06f..08b672a 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -144,6 +144,17 @@
ASSERT_EQ(true, result);
}
+TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsFalse) {
+ EXPECT_CALL(*mRenderEngine, supportsBackgroundBlur()).WillOnce(Return(false));
+ status_t result = mThreadedRE->supportsBackgroundBlur();
+ ASSERT_EQ(false, result);
+}
+
+TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsTrue) {
+ EXPECT_CALL(*mRenderEngine, supportsBackgroundBlur()).WillOnce(Return(true));
+ status_t result = mThreadedRE->supportsBackgroundBlur();
+ ASSERT_EQ(true, result);
+}
TEST_F(RenderEngineThreadedTest, drawLayers) {
renderengine::DisplaySettings settings;
std::vector<const renderengine::LayerSettings*> layers;
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 3b97f56..f448135 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -315,6 +315,21 @@
return resultFuture.get();
}
+bool RenderEngineThreaded::supportsBackgroundBlur() {
+ std::promise<bool> resultPromise;
+ std::future<bool> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::supportsBackgroundBlur");
+ bool returnValue = instance.supportsBackgroundBlur();
+ resultPromise.set_value(returnValue);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
} // namespace threaded
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 8b1e2de..8279cbc 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -64,6 +64,7 @@
void cleanFramebufferCache() override;
int getContextPriority() override;
+ bool supportsBackgroundBlur() override;
private:
void threadMain(CreateInstanceFactory factory);
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index e8154a6..497c33c 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libsensor",
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 9d817ae..240738d 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -468,6 +468,19 @@
mUuid.i64[1] = 0;
}
+void Sensor::capMinDelayMicros(int32_t cappedMinDelay) {
+ if (mMinDelay < cappedMinDelay) {
+ mMinDelay = cappedMinDelay;
+ }
+}
+
+void Sensor::capHighestDirectReportRateLevel(int32_t cappedRateLevel) {
+ if (cappedRateLevel < getHighestDirectReportRateLevel()) {
+ mFlags &= ~SENSOR_FLAG_MASK_DIRECT_REPORT;
+ mFlags |= cappedRateLevel << SENSOR_FLAG_SHIFT_DIRECT_REPORT;
+ }
+}
+
int32_t Sensor::getId() const {
return int32_t(mUuid.i64[0]);
}
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 324d443..374b68f 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -104,6 +104,9 @@
int32_t getId() const;
void setId(int32_t id);
+ void capMinDelayMicros(int32_t cappedMinDelay);
+ void capHighestDirectReportRateLevel(int32_t cappedRateLevel);
+
// LightFlattenable protocol
inline bool isFixedSize() const { return false; }
size_t getFlattenedSize() const;
diff --git a/libs/sensor/tests/Android.bp b/libs/sensor/tests/Android.bp
index c9a7668..8fdb003 100644
--- a/libs/sensor/tests/Android.bp
+++ b/libs/sensor/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "libsensor_test",
diff --git a/libs/sensorprivacy/Android.bp b/libs/sensorprivacy/Android.bp
index 4a606ff..00514c4 100644
--- a/libs/sensorprivacy/Android.bp
+++ b/libs/sensorprivacy/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libsensorprivacy",
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 714ee3e..3b024be 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -12,6 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_libs_ui_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_defaults {
name: "libui-defaults",
clang: true,
@@ -77,7 +94,6 @@
"libarect",
"libmath",
],
-
}
cc_library_shared {
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index d005ce8..516aad8 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_libs_ui_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+}
+
cc_test {
name: "Region_test",
shared_libs: ["libui"],
diff --git a/libs/ui/tools/Android.bp b/libs/ui/tools/Android.bp
index fb46c2b..c28c303 100644
--- a/libs/ui/tools/Android.bp
+++ b/libs/ui/tools/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_libs_ui_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+}
+
cc_defaults {
name: "libui_tools_default",
clang_cflags: [
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp
index 49bc6bf..83c250a 100644
--- a/libs/vibrator/Android.bp
+++ b/libs/vibrator/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libvibrator",
vendor_available: true,
diff --git a/libs/vibrator/fuzzer/Android.bp b/libs/vibrator/fuzzer/Android.bp
index 8020151..f2a313c 100644
--- a/libs/vibrator/fuzzer/Android.bp
+++ b/libs/vibrator/fuzzer/Android.bp
@@ -17,6 +17,15 @@
*****************************************************************************
*/
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_fuzz {
name: "vibrator_fuzzer",
diff --git a/libs/vr/Android.bp b/libs/vr/Android.bp
index e8176cf..b308895 100644
--- a/libs/vr/Android.bp
+++ b/libs/vr/Android.bp
@@ -1,3 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-BSD
+ // legacy_notice
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
subdirs = [
"*",
]
diff --git a/libs/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp
index 13af470..2eb2f9f 100644
--- a/libs/vr/libbroadcastring/Android.bp
+++ b/libs/vr/libbroadcastring/Android.bp
@@ -1,3 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libbroadcastring",
clang: true,
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 37c19d4..45bdd35 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libbufferhub_headers",
export_include_dirs: ["include"],
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 77c7911..f372bd7 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sourceFiles = [
"buffer_hub_queue_client.cpp",
"buffer_hub_queue_parcelable.cpp",
diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
index ef1eed6..fc1f376 100644
--- a/libs/vr/libbufferhubqueue/benchmarks/Android.bp
+++ b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
@@ -1,4 +1,15 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_benchmark {
srcs: ["buffer_transport_benchmark.cpp"],
shared_libs: [
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index a337921..e883916 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -1,4 +1,15 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
header_libraries = [
"libdvr_headers",
]
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index 8c354fb..365a676 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sourceFiles = [
"display_client.cpp",
"display_manager_client.cpp",
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index d5a19d3..83c30d7 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -13,6 +13,17 @@
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libdvr_headers",
export_include_dirs: ["include"],
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 3260447..4ed80a4 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
srcs: [
"dvr_display_manager-test.cpp",
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index e751768..9e1e516 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
localIncludeFiles = [
"include",
]
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 24ba830..c1f6da3 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libpdx_headers",
export_include_dirs: ["private"],
diff --git a/libs/vr/libpdx/fuzz/Android.bp b/libs/vr/libpdx/fuzz/Android.bp
index b36e0de..cc32b18 100644
--- a/libs/vr/libpdx/fuzz/Android.bp
+++ b/libs/vr/libpdx/fuzz/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_fuzz {
name: "libpdx_service_dispatcher_fuzzer",
clang: true,
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index b3534de..ea73d7a 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -1,3 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "pdx_default_transport_compiler_defaults",
clang: true,
@@ -75,4 +86,3 @@
"libpdx_default_transport",
],
}
-
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index 1d6eea2..532d1a7 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -1,3 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libpdx_uds",
clang: true,
diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp
index 35d3dea..5beee35 100644
--- a/libs/vr/libperformance/Android.bp
+++ b/libs/vr/libperformance/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sourceFiles = [
"performance_client.cpp",
"performance_rpc.cpp",
diff --git a/libs/vr/libvr_manager/Android.bp b/libs/vr/libvr_manager/Android.bp
index 2cd6a28..6f2ada4 100644
--- a/libs/vr/libvr_manager/Android.bp
+++ b/libs/vr/libvr_manager/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libvr_manager",
srcs: [
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index abc64bd..8aca9a5 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sourceFiles = [
"acquired_buffer.cpp",
"epoll_event_dispatcher.cpp",
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
index 7fafd3b..dafd354 100644
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -1,3 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
shared_libs = [
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index 8542790..8f566a0 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sourceFiles = [
"pose_client.cpp",
"latency_model.cpp",
@@ -52,4 +63,3 @@
header_libs: ["libdvr_headers"],
name: "libvrsensor",
}
-
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 8b94f61..3878cb1 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -12,6 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-BSD
+ // SPDX-license-identifier-MIT
+ // legacy_notice
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
ndk_headers {
name: "libEGL_headers",
from: "include",
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 5d17561..7861d62 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -1,4 +1,13 @@
// Build the ETC1 library
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libETC1",
srcs: ["ETC1/etc1.cpp"],
diff --git a/opengl/tests/Android.bp b/opengl/tests/Android.bp
index 639f351..da717bd 100644
--- a/opengl/tests/Android.bp
+++ b/opengl/tests/Android.bp
@@ -1,4 +1,16 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-BSD
+ // SPDX-license-identifier-MIT
+ // legacy_notice
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
subdirs = [
"angeles",
"configdump",
@@ -16,4 +28,3 @@
"hwc",
"lib",
]
-
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index e3912a8..51c9376 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -1,4 +1,13 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "EGL_test",
diff --git a/opengl/tests/angeles/Android.bp b/opengl/tests/angeles/Android.bp
index 5c398a6..5b81501 100644
--- a/opengl/tests/angeles/Android.bp
+++ b/opengl/tests/angeles/Android.bp
@@ -1,5 +1,50 @@
// Copyright 2006 The Android Open Source Project
+package {
+ default_applicable_licenses: [
+ "frameworks_native_opengl_tests_angeles_license",
+ ],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change included anything that looked like it might be a license
+// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
+//
+// Please consider removing redundant or irrelevant files from 'license_text:'.
+//
+// large-scale-change filtered out the below license kinds as false-positives:
+// SPDX-license-identifier-LGPL
+// SPDX-license-identifier-LGPL-2.1
+// SPDX-license-identifier-LGPL-3.0
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_native_opengl_tests_angeles_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-BSD",
+ "SPDX-license-identifier-MIT",
+ "legacy_notice",
+ ],
+ license_text: [
+ "license-BSD.txt",
+ "license-LGPL.txt",
+ "license.txt",
+ ],
+}
+
cc_test {
name: "angeles",
diff --git a/opengl/tests/configdump/Android.bp b/opengl/tests/configdump/Android.bp
index ee967970..ffb0c1f 100644
--- a/opengl/tests/configdump/Android.bp
+++ b/opengl/tests/configdump/Android.bp
@@ -1,3 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-configdump",
diff --git a/opengl/tests/fillrate/Android.bp b/opengl/tests/fillrate/Android.bp
index 689cee4..e4bff01 100644
--- a/opengl/tests/fillrate/Android.bp
+++ b/opengl/tests/fillrate/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-fillrate",
diff --git a/opengl/tests/filter/Android.bp b/opengl/tests/filter/Android.bp
index 23241e1..3b92b37 100644
--- a/opengl/tests/filter/Android.bp
+++ b/opengl/tests/filter/Android.bp
@@ -1,3 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-filter",
diff --git a/opengl/tests/finish/Android.bp b/opengl/tests/finish/Android.bp
index be20851..c2dfbc3 100644
--- a/opengl/tests/finish/Android.bp
+++ b/opengl/tests/finish/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-finish",
diff --git a/opengl/tests/gl2_basic/Android.bp b/opengl/tests/gl2_basic/Android.bp
index f4538ad..c54bdf3 100644
--- a/opengl/tests/gl2_basic/Android.bp
+++ b/opengl/tests/gl2_basic/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl2_basic",
diff --git a/opengl/tests/gl2_cameraeye/Android.bp b/opengl/tests/gl2_cameraeye/Android.bp
index 00e00df..6b8ee85 100644
--- a/opengl/tests/gl2_cameraeye/Android.bp
+++ b/opengl/tests/gl2_cameraeye/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
android_app {
name: "GL2CameraEye",
// Only compile source java files in this apk.
diff --git a/opengl/tests/gl2_copyTexImage/Android.bp b/opengl/tests/gl2_copyTexImage/Android.bp
index 87fa7ea..0a84d25 100644
--- a/opengl/tests/gl2_copyTexImage/Android.bp
+++ b/opengl/tests/gl2_copyTexImage/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl2_copyTexImage",
diff --git a/opengl/tests/gl2_java/Android.bp b/opengl/tests/gl2_java/Android.bp
index a8e5d7d..a33075e 100644
--- a/opengl/tests/gl2_java/Android.bp
+++ b/opengl/tests/gl2_java/Android.bp
@@ -1,6 +1,15 @@
//########################################################################
// OpenGL ES 2.0 Java sample
//########################################################################
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
android_app {
name: "GL2Java",
srcs: ["**/*.java"],
diff --git a/opengl/tests/gl2_jni/Android.bp b/opengl/tests/gl2_jni/Android.bp
index 8d4323f..79773cb 100644
--- a/opengl/tests/gl2_jni/Android.bp
+++ b/opengl/tests/gl2_jni/Android.bp
@@ -3,6 +3,15 @@
// This makefile builds both an activity and a shared library.
//########################################################################
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
android_app {
name: "GL2JNI",
srcs: ["**/*.java"],
diff --git a/opengl/tests/gl2_yuvtex/Android.bp b/opengl/tests/gl2_yuvtex/Android.bp
index b64d94d..fadf0e8 100644
--- a/opengl/tests/gl2_yuvtex/Android.bp
+++ b/opengl/tests/gl2_yuvtex/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl2_yuvtex",
diff --git a/opengl/tests/gl_basic/Android.bp b/opengl/tests/gl_basic/Android.bp
index 5eed17e..f777401 100644
--- a/opengl/tests/gl_basic/Android.bp
+++ b/opengl/tests/gl_basic/Android.bp
@@ -1,3 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl_basic",
diff --git a/opengl/tests/gl_jni/Android.bp b/opengl/tests/gl_jni/Android.bp
index 0cb129a..dc46483 100644
--- a/opengl/tests/gl_jni/Android.bp
+++ b/opengl/tests/gl_jni/Android.bp
@@ -4,6 +4,15 @@
//########################################################################
// Build activity
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
android_app {
name: "GLJNI",
srcs: ["**/*.java"],
diff --git a/opengl/tests/gl_perf/Android.bp b/opengl/tests/gl_perf/Android.bp
index 25a317c..ca0f7e8 100644
--- a/opengl/tests/gl_perf/Android.bp
+++ b/opengl/tests/gl_perf/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl2_perf",
diff --git a/opengl/tests/gl_perfapp/Android.bp b/opengl/tests/gl_perfapp/Android.bp
index 66afb6a..2f62346 100644
--- a/opengl/tests/gl_perfapp/Android.bp
+++ b/opengl/tests/gl_perfapp/Android.bp
@@ -2,6 +2,15 @@
// OpenGL ES Perf App
// This makefile builds both an activity and a shared library.
//########################################################################
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
android_app {
name: "GLPerf",
srcs: ["**/*.java"],
diff --git a/opengl/tests/gl_yuvtex/Android.bp b/opengl/tests/gl_yuvtex/Android.bp
index 9b4924a..7844186 100644
--- a/opengl/tests/gl_yuvtex/Android.bp
+++ b/opengl/tests/gl_yuvtex/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gl_yuvtex",
diff --git a/opengl/tests/gldual/Android.bp b/opengl/tests/gldual/Android.bp
index 1006d44..3d6e677 100644
--- a/opengl/tests/gldual/Android.bp
+++ b/opengl/tests/gldual/Android.bp
@@ -4,6 +4,15 @@
//########################################################################
// Build activity
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
android_app {
name: "GLDual",
srcs: ["**/*.java"],
diff --git a/opengl/tests/gralloc/Android.bp b/opengl/tests/gralloc/Android.bp
index 33c3dba..5fb4556 100644
--- a/opengl/tests/gralloc/Android.bp
+++ b/opengl/tests/gralloc/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "test-opengl-gralloc",
diff --git a/opengl/tests/hwc/Android.bp b/opengl/tests/hwc/Android.bp
index 55f058f..719eb11 100644
--- a/opengl/tests/hwc/Android.bp
+++ b/opengl/tests/hwc/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "hwc_tests_defaults",
diff --git a/opengl/tests/lib/Android.bp b/opengl/tests/lib/Android.bp
index 2f6095d..05c9397 100644
--- a/opengl/tests/lib/Android.bp
+++ b/opengl/tests/lib/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libglTest",
diff --git a/opengl/tests/lighting1709/Android.bp b/opengl/tests/lighting1709/Android.bp
index e734dd1..79daa26 100644
--- a/opengl/tests/lighting1709/Android.bp
+++ b/opengl/tests/lighting1709/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
android_test {
name: "LightingTest",
srcs: ["**/*.java"],
diff --git a/opengl/tests/linetex/Android.bp b/opengl/tests/linetex/Android.bp
index dbc2cdb..61976e5 100644
--- a/opengl/tests/linetex/Android.bp
+++ b/opengl/tests/linetex/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-opengl-linetex",
srcs: ["linetex.cpp"],
diff --git a/opengl/tests/swapinterval/Android.bp b/opengl/tests/swapinterval/Android.bp
index eed4dff..a76f4cf 100644
--- a/opengl/tests/swapinterval/Android.bp
+++ b/opengl/tests/swapinterval/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-opengl-swapinterval",
srcs: ["swapinterval.cpp"],
diff --git a/opengl/tests/testFramerate/Android.bp b/opengl/tests/testFramerate/Android.bp
index 5aa83b0..4334d88 100644
--- a/opengl/tests/testFramerate/Android.bp
+++ b/opengl/tests/testFramerate/Android.bp
@@ -2,6 +2,15 @@
// Test framerate and look for hiccups
//########################################################################
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
android_app {
name: "TestFramerate",
srcs: ["**/*.java"],
diff --git a/opengl/tests/testLatency/Android.bp b/opengl/tests/testLatency/Android.bp
index c516dc3..473cb42 100644
--- a/opengl/tests/testLatency/Android.bp
+++ b/opengl/tests/testLatency/Android.bp
@@ -1,6 +1,15 @@
//########################################################################
// Test end-to-end latency.
//########################################################################
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
android_app {
name: "TestLatency",
sdk_version: "8",
diff --git a/opengl/tests/testPauseResume/Android.bp b/opengl/tests/testPauseResume/Android.bp
index 810e895..8171e1f 100644
--- a/opengl/tests/testPauseResume/Android.bp
+++ b/opengl/tests/testPauseResume/Android.bp
@@ -1,4 +1,13 @@
// OpenGL ES JNI sample
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
android_app {
name: "TestEGL",
srcs: ["**/*.java"],
diff --git a/opengl/tests/testViewport/Android.bp b/opengl/tests/testViewport/Android.bp
index 629b573..13ce3ad 100644
--- a/opengl/tests/testViewport/Android.bp
+++ b/opengl/tests/testViewport/Android.bp
@@ -2,6 +2,15 @@
// OpenGL ES JNI sample
// This makefile builds both an activity and a shared library.
//########################################################################
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
android_app {
name: "TestViewport",
srcs: ["**/*.java"],
diff --git a/opengl/tests/textures/Android.bp b/opengl/tests/textures/Android.bp
index 84adda2..f113ff7 100644
--- a/opengl/tests/textures/Android.bp
+++ b/opengl/tests/textures/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-opengl-textures",
srcs: ["textures.cpp"],
diff --git a/opengl/tests/tritex/Android.bp b/opengl/tests/tritex/Android.bp
index 390397b..759582c 100644
--- a/opengl/tests/tritex/Android.bp
+++ b/opengl/tests/tritex/Android.bp
@@ -1,3 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-opengl-tritex",
srcs: ["tritex.cpp"],
diff --git a/services/audiomanager/Android.bp b/services/audiomanager/Android.bp
index 12ad47e..e6fb2c3 100644
--- a/services/audiomanager/Android.bp
+++ b/services/audiomanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libaudiomanager",
diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp
index c3da216..72bd292 100644
--- a/services/automotive/display/Android.bp
+++ b/services/automotive/display/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "android.frameworks.automotive.display@1.0-service",
defaults: ["hidl_defaults"],
diff --git a/services/batteryservice/Android.bp b/services/batteryservice/Android.bp
index 66ee8ff..1e37991 100644
--- a/services/batteryservice/Android.bp
+++ b/services/batteryservice/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libbatteryservice_headers",
vendor_available: true,
diff --git a/services/displayservice/Android.bp b/services/displayservice/Android.bp
index 4d2d873..8681784 100644
--- a/services/displayservice/Android.bp
+++ b/services/displayservice/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libdisplayservicehidl",
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 9a9bca1..b9b6a19 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "gpuservice_defaults",
cflags: [
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
index b875814..9842ed7 100644
--- a/services/gpuservice/bpfprogs/Android.bp
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
bpf {
name: "gpu_mem.o",
srcs: ["gpu_mem.c"],
diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp
index b2230b6..830e53d 100644
--- a/services/gpuservice/gpumem/Android.bp
+++ b/services/gpuservice/gpumem/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libgpumem",
srcs: [
diff --git a/services/gpuservice/gpustats/Android.bp b/services/gpuservice/gpustats/Android.bp
index f52602a..54291ad 100644
--- a/services/gpuservice/gpustats/Android.bp
+++ b/services/gpuservice/gpustats/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libgfxstats",
srcs: [
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 9606daa..6d87c45 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "gpuservice_unittest",
test_suites: ["device-tests"],
diff --git a/services/gpuservice/tracing/Android.bp b/services/gpuservice/tracing/Android.bp
index 919fed3..a1bc1ed 100644
--- a/services/gpuservice/tracing/Android.bp
+++ b/services/gpuservice/tracing/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libgpumemtracer",
srcs: [
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index b640e9c..9b98a17 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -13,6 +13,15 @@
// limitations under the License.
// Default flags to be used throughout all libraries in inputflinger.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "inputflinger_defaults",
cflags: [
diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp
index bd275a7..ea37f4d 100644
--- a/services/inputflinger/benchmarks/Android.bp
+++ b/services/inputflinger/benchmarks/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_benchmark {
name: "inputflinger_benchmarks",
srcs: [
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index e5b131e..393f649 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libinputdispatcher_headers",
export_include_dirs: [
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 499f42e..45a007b 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -272,6 +272,7 @@
std::string obscuringPackage;
bool enabled;
int32_t pid;
+ nsecs_t consumeTime; // time when the event was consumed by InputConsumer
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 2909939..9898e9d 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1673,9 +1673,7 @@
if (!mKeyIsWaitingForEventsTimeout.has_value()) {
// Start the timer
- ALOGD("Waiting to send key to %s because there are unprocessed events that may cause "
- "focus to change",
- focusedWindowName);
+ // Wait to send key because there are unprocessed events that may cause focus to change
mKeyIsWaitingForEventsTimeout = currentTime +
std::chrono::duration_cast<std::chrono::nanoseconds>(KEY_WAITING_FOR_EVENTS_TIMEOUT)
.count();
@@ -2834,10 +2832,6 @@
* This includes situations like the soft BACK button key. When the user releases (lifts up the
* finger) the back button, then navigation bar will inject KEYCODE_BACK with ACTION_UP.
* Both of those ACTION_UP events would not be logged
- * Monitors (both gesture and global): any gesture monitors or global monitors receiving events
- * will not be logged. This is omitted to reduce the amount of data printed.
- * If you see <none>, it's likely that one of the gesture monitors pilfered the event, and therefore
- * gesture monitor is the only connection receiving the remainder of the gesture.
*/
void InputDispatcher::updateInteractionTokensLocked(const EventEntry& entry,
const std::vector<InputTarget>& targets) {
@@ -2867,8 +2861,8 @@
sp<IBinder> token = target.inputChannel->getConnectionToken();
sp<Connection> connection = getConnectionLocked(token);
- if (connection == nullptr || connection->monitor) {
- continue; // We only need to keep track of the non-monitor connections.
+ if (connection == nullptr) {
+ continue;
}
newConnectionTokens.insert(std::move(token));
newConnections.emplace_back(connection);
@@ -2878,12 +2872,12 @@
}
mInteractionConnectionTokens = newConnectionTokens;
- std::string windowList;
+ std::string targetList;
for (const sp<Connection>& connection : newConnections) {
- windowList += connection->getWindowName() + ", ";
+ targetList += connection->getWindowName() + ", ";
}
- std::string message = "Interaction with windows: " + windowList;
- if (windowList.empty()) {
+ std::string message = "Interaction with: " + targetList;
+ if (targetList.empty()) {
message += "<none>";
}
android_log_event_list(LOGTAG_INPUT_INTERACTION) << message << LOG_ID_EVENTS;
@@ -3113,7 +3107,7 @@
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, uint32_t seq,
- bool handled) {
+ bool handled, nsecs_t consumeTime) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
connection->getInputChannelName().c_str(), seq, toString(handled));
@@ -3125,7 +3119,7 @@
}
// Notify other system components and prepare to start the next dispatch cycle.
- onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
+ onDispatchCycleFinishedLocked(currentTime, connection, seq, handled, consumeTime);
}
void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
@@ -3196,13 +3190,15 @@
bool gotOne = false;
status_t status;
for (;;) {
- uint32_t seq;
- bool handled;
- status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
+ std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)> callback =
+ std::bind(&InputDispatcher::finishDispatchCycleLocked, d, currentTime,
+ connection, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3);
+
+ status = connection->inputPublisher.receiveFinishedSignal(callback);
if (status) {
break;
}
- d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
gotOne = true;
}
if (gotOne) {
@@ -3219,8 +3215,7 @@
}
} else {
// Monitor channels are never explicitly unregistered.
- // We do it automatically when the remote endpoint is closed so don't warn
- // about them.
+ // We do it automatically when the remote endpoint is closed so don't warn about them.
const bool stillHaveWindowHandle =
d->getWindowHandleLocked(connection->inputChannel->getConnectionToken()) !=
nullptr;
@@ -4976,7 +4971,7 @@
bool notify) {
sp<Connection> connection = getConnectionLocked(connectionToken);
if (connection == nullptr) {
- ALOGW("Attempted to unregister already unregistered input channel");
+ // Connection can be removed via socket hang up or an explicit call to 'removeInputChannel'
return BAD_VALUE;
}
@@ -5040,9 +5035,11 @@
}
TouchState& state = stateIt->second;
+ std::shared_ptr<InputChannel> requestingChannel;
std::optional<int32_t> foundDeviceId;
for (const TouchedMonitor& touchedMonitor : state.gestureMonitors) {
if (touchedMonitor.monitor.inputChannel->getConnectionToken() == token) {
+ requestingChannel = touchedMonitor.monitor.inputChannel;
foundDeviceId = state.deviceId;
}
}
@@ -5058,13 +5055,19 @@
"gesture monitor stole pointer stream");
options.deviceId = deviceId;
options.displayId = displayId;
+ std::string canceledWindows = "[";
for (const TouchedWindow& window : state.windows) {
std::shared_ptr<InputChannel> channel =
getInputChannelLocked(window.windowHandle->getToken());
if (channel != nullptr) {
synthesizeCancelationEventsForInputChannelLocked(channel, options);
+ canceledWindows += channel->getName() + ", ";
}
}
+ canceledWindows += "]";
+ ALOGI("Monitor %s is stealing touch from %s", requestingChannel->getName().c_str(),
+ canceledWindows.c_str());
+
// Then clear the current touch state so we stop dispatching to them as well.
state.filterNonMonitors();
}
@@ -5154,13 +5157,14 @@
void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
const sp<Connection>& connection, uint32_t seq,
- bool handled) {
+ bool handled, nsecs_t consumeTime) {
std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
&InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
commandEntry->connection = connection;
commandEntry->eventTime = currentTime;
commandEntry->seq = seq;
commandEntry->handled = handled;
+ commandEntry->consumeTime = consumeTime;
postCommandLocked(std::move(commandEntry));
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index c93d74e..83094c2 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -528,7 +528,7 @@
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
REQUIRES(mLock);
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- uint32_t seq, bool handled) REQUIRES(mLock);
+ uint32_t seq, bool handled, nsecs_t consumeTime) REQUIRES(mLock);
void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool notify) REQUIRES(mLock);
void drainDispatchQueue(std::deque<DispatchEntry*>& queue);
@@ -578,7 +578,8 @@
// Interesting events that we might like to log or tell the framework about.
void onDispatchCycleFinishedLocked(nsecs_t currentTime, const sp<Connection>& connection,
- uint32_t seq, bool handled) REQUIRES(mLock);
+ uint32_t seq, bool handled, nsecs_t consumeTime)
+ REQUIRES(mLock);
void onDispatchCycleBrokenLocked(nsecs_t currentTime, const sp<Connection>& connection)
REQUIRES(mLock);
void onFocusChangedLocked(const FocusResolver::FocusChanges& changes) REQUIRES(mLock);
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index 9e797e4..18d0226 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libinputflingerhost",
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 7f979f2..518e295 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libinputreader_headers",
export_include_dirs: [
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 8fc6f4a..574f651 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -520,7 +520,8 @@
}
void InputDevice::notifyReset(nsecs_t when) {
- mContext->notifyDeviceReset(when, mId);
+ NotifyDeviceResetArgs args(mContext->getNextId(), when, mId);
+ mContext->getListener()->notifyDeviceReset(&args);
}
std::optional<int32_t> InputDevice::getAssociatedDisplayId() {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index c044393..14fb77b 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -339,7 +339,8 @@
updateGlobalMetaStateLocked();
// Enqueue configuration changed.
- mContext.notifyConfigurationChanged(when);
+ NotifyConfigurationChangedArgs args(mContext.getNextId(), when);
+ mQueuedListener->notifyConfigurationChanged(&args);
}
void InputReader::refreshConfigurationLocked(uint32_t changes) {
@@ -366,7 +367,9 @@
}
if (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE) {
- mContext.notifyPointerCaptureChanged(now, mConfig.pointerCapture);
+ const NotifyPointerCaptureChangedArgs args(mContext.getNextId(), now,
+ mConfig.pointerCapture);
+ mQueuedListener->notifyPointerCaptureChanged(&args);
}
}
@@ -885,69 +888,16 @@
return mReader->mPolicy.get();
}
+InputListenerInterface* InputReader::ContextImpl::getListener() {
+ return mReader->mQueuedListener.get();
+}
+
EventHubInterface* InputReader::ContextImpl::getEventHub() {
return mReader->mEventHub.get();
}
-void InputReader::ContextImpl::notifyConfigurationChanged(nsecs_t when) {
- NotifyConfigurationChangedArgs args(mIdGenerator.nextId(), when);
- mReader->mQueuedListener->notifyConfigurationChanged(&args);
-}
-
-void InputReader::ContextImpl::notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source,
- int32_t displayId, uint32_t policyFlags, int32_t action,
- int32_t flags, int32_t keyCode, int32_t scanCode,
- int32_t metaState, nsecs_t downTime) {
- NotifyKeyArgs args(mIdGenerator.nextId(), eventTime, deviceId, source, displayId, policyFlags,
- action, flags, keyCode, scanCode, metaState, downTime);
- mReader->mQueuedListener->notifyKey(&args);
-}
-void InputReader::ContextImpl::notifyMotion(
- nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
- uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags,
- int32_t metaState, int32_t buttonState, MotionClassification classification,
- int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
- float xCursorPosition, float yCursorPosition, nsecs_t downTime,
- const std::vector<TouchVideoFrame>& videoFrames) {
- NotifyMotionArgs args(mIdGenerator.nextId(), eventTime, deviceId, source, displayId,
- policyFlags, action, actionButton, flags, metaState, buttonState,
- classification, edgeFlags, pointerCount, pointerProperties, pointerCoords,
- xPrecision, yPrecision, xCursorPosition, yCursorPosition, downTime,
- videoFrames);
- mReader->mQueuedListener->notifyMotion(&args);
-}
-
-void InputReader::ContextImpl::notifySensor(nsecs_t when, int32_t deviceId,
- InputDeviceSensorType sensorType,
- InputDeviceSensorAccuracy accuracy,
- bool accuracyChanged, nsecs_t timestamp,
- std::vector<float> values) {
- NotifySensorArgs args(mIdGenerator.nextId(), when, deviceId, AINPUT_SOURCE_SENSOR, sensorType,
- accuracy, accuracyChanged, timestamp, std::move(values));
- mReader->mQueuedListener->notifySensor(&args);
-}
-
-void InputReader::ContextImpl::notifyVibratorState(nsecs_t when, int32_t deviceId, bool isOn) {
- NotifyVibratorStateArgs args(mIdGenerator.nextId(), when, deviceId, isOn);
- mReader->mQueuedListener->notifyVibratorState(&args);
-}
-
-void InputReader::ContextImpl::notifySwitch(nsecs_t eventTime, uint32_t switchValues,
- uint32_t switchMask) {
- NotifySwitchArgs args(mIdGenerator.nextId(), eventTime, 0 /*policyFlags*/, switchValues,
- switchMask);
- mReader->mQueuedListener->notifySwitch(&args);
-}
-
-void InputReader::ContextImpl::notifyDeviceReset(nsecs_t when, int32_t deviceId) {
- NotifyDeviceResetArgs args(mIdGenerator.nextId(), when, deviceId);
- mReader->mQueuedListener->notifyDeviceReset(&args);
-}
-
-void InputReader::ContextImpl::notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) {
- const NotifyPointerCaptureChangedArgs args(mIdGenerator.nextId(), when, hasCapture);
- mReader->mQueuedListener->notifyPointerCaptureChanged(&args);
+int32_t InputReader::ContextImpl::getNextId() {
+ return mIdGenerator.nextId();
}
} // namespace android
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 5f78149..81e3e9a 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -131,31 +131,11 @@
void dispatchExternalStylusState(const StylusState& outState)
NO_THREAD_SAFETY_ANALYSIS override;
InputReaderPolicyInterface* getPolicy() NO_THREAD_SAFETY_ANALYSIS override;
+ InputListenerInterface* getListener() NO_THREAD_SAFETY_ANALYSIS override;
EventHubInterface* getEventHub() NO_THREAD_SAFETY_ANALYSIS override;
+ int32_t getNextId() NO_THREAD_SAFETY_ANALYSIS override;
void updateLedMetaState(int32_t metaState) NO_THREAD_SAFETY_ANALYSIS override;
int32_t getLedMetaState() NO_THREAD_SAFETY_ANALYSIS override;
-
- // Send events to InputListener interface
- void notifyConfigurationChanged(nsecs_t when) override;
- void notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
- uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
- int32_t scanCode, int32_t metaState, nsecs_t downTime) override;
- void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
- uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags,
- int32_t metaState, int32_t buttonState,
- MotionClassification classification, int32_t edgeFlags,
- uint32_t pointerCount, const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
- float xCursorPosition, float yCursorPosition, nsecs_t downTime,
- const std::vector<TouchVideoFrame>& videoFrames) override;
- void notifySwitch(nsecs_t eventTime, uint32_t switchValues, uint32_t switchMask) override;
- void notifySensor(nsecs_t when, int32_t deviceId, InputDeviceSensorType sensorType,
- InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
- nsecs_t timestamp, std::vector<float> values) override;
- void notifyVibratorState(nsecs_t when, int32_t deviceId, bool isOn) override;
- void notifyDeviceReset(nsecs_t when, int32_t deviceId) override;
- void notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) override;
-
} mContext;
friend class ContextImpl;
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index e6ea523..dc807f7 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -55,34 +55,13 @@
virtual void dispatchExternalStylusState(const StylusState& outState) = 0;
virtual InputReaderPolicyInterface* getPolicy() = 0;
+ virtual InputListenerInterface* getListener() = 0;
virtual EventHubInterface* getEventHub() = 0;
+ virtual int32_t getNextId() = 0;
+
virtual void updateLedMetaState(int32_t metaState) = 0;
virtual int32_t getLedMetaState() = 0;
-
- // Send events to InputListener interface
-
- virtual void notifyConfigurationChanged(nsecs_t when) = 0;
- virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
- uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
- int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
- virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source,
- int32_t displayId, uint32_t policyFlags, int32_t action,
- int32_t actionButton, int32_t flags, int32_t metaState,
- int32_t buttonState, MotionClassification classification,
- int32_t edgeFlags, uint32_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords, float xPrecision,
- float yPrecision, float xCursorPosition, float yCursorPosition,
- nsecs_t downTime,
- const std::vector<TouchVideoFrame>& videoFrames) = 0;
- virtual void notifySwitch(nsecs_t eventTime, uint32_t switchValues, uint32_t switchMask) = 0;
- virtual void notifySensor(nsecs_t when, int32_t deviceId, InputDeviceSensorType sensorType,
- InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
- nsecs_t timestamp, std::vector<float> values) = 0;
- virtual void notifyVibratorState(nsecs_t when, int32_t deviceId, bool isOn) = 0;
- virtual void notifyDeviceReset(nsecs_t when, int32_t deviceId) = 0;
- virtual void notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) = 0;
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 7f7b33c..254b64b 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -175,7 +175,8 @@
}
bumpGeneration();
if (changes) {
- getContext()->notifyDeviceReset(when, getDeviceId());
+ NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
+ getListener()->notifyDeviceReset(&args);
}
}
@@ -382,35 +383,40 @@
while (!released.isEmpty()) {
int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
buttonState &= ~actionButton;
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
- metaState, buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision,
- xCursorPosition, yCursorPosition, downTime,
- /* videoFrames */ {});
+ NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, getDeviceId(),
+ mSource, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
+ metaState, buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision,
+ xCursorPosition, yCursorPosition, downTime,
+ /* videoFrames */ {});
+ getListener()->notifyMotion(&releaseArgs);
}
}
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- motionEventAction, 0, 0, metaState, currentButtonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &pointerProperties, &pointerCoords, mXPrecision, mYPrecision,
- xCursorPosition, yCursorPosition, downTime,
- /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &pointerProperties, &pointerCoords, mXPrecision, mYPrecision,
+ xCursorPosition, yCursorPosition, downTime,
+ /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
if (buttonsPressed) {
BitSet32 pressed(buttonsPressed);
while (!pressed.isEmpty()) {
int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
buttonState |= actionButton;
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+ NotifyMotionArgs pressArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
metaState, buttonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
&pointerCoords, mXPrecision, mYPrecision,
xCursorPosition, yCursorPosition, downTime,
/* videoFrames */ {});
+ getListener()->notifyMotion(&pressArgs);
}
}
@@ -418,12 +424,13 @@
// Send hover move after UP to tell the application that the mouse is hovering now.
if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
- currentButtonState, MotionClassification::NONE,
+ NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+ 0, metaState, currentButtonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
&pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
yCursorPosition, downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&hoverArgs);
}
// Send scroll events.
@@ -431,12 +438,13 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
- currentButtonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
- yCursorPosition, downTime, /* videoFrames */ {});
+ NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
+ metaState, currentButtonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
+ yCursorPosition, downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&scrollArgs);
}
}
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 44af998..1cc5979 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -19,6 +19,7 @@
#include "EventHub.h"
#include "InputDevice.h"
+#include "InputListener.h"
#include "InputReaderContext.h"
#include "StylusState.h"
#include "VibrationElement.h"
@@ -47,6 +48,7 @@
inline const std::string getDeviceName() { return mDeviceContext.getName(); }
inline InputReaderContext* getContext() { return mDeviceContext.getContext(); }
inline InputReaderPolicyInterface* getPolicy() { return getContext()->getPolicy(); }
+ inline InputListenerInterface* getListener() { return getContext()->getListener(); }
virtual uint32_t getSources() = 0;
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 28f29e0..37aa140 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -337,12 +337,13 @@
// TODO: Use the input device configuration to control this behavior more finely.
uint32_t policyFlags = 0;
- getContext()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE,
- policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &pointerProperties, &pointerCoords, 0, 0,
- AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_JOYSTICK,
+ ADISPLAY_ID_NONE, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
+ buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &pointerProperties, &pointerCoords, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis,
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 03d7405..8b9f235 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -350,9 +350,10 @@
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
}
- getContext()->notifyKey(when, getDeviceId(), mSource, getDisplayId(), policyFlags,
- down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
+ NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(),
+ policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
+ AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
+ getListener()->notifyKey(&args);
}
ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 3f8a364..594ff42 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -121,12 +121,13 @@
int32_t metaState = getContext()->getGlobalMetaState();
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
- /* buttonState */ 0, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+ NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
+ metaState, /* buttonState */ 0, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+ getListener()->notifyMotion(&scrollArgs);
}
mRotaryEncoderScrollAccumulator.finishSync();
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index 68c1e40..7ac2dec 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -405,10 +405,13 @@
// Convert to Android unit
convertFromLinuxToAndroid(values, sensorType);
// Notify dispatcher for sensor event
- getContext()->notifySensor(when, getDeviceId(), sensorType, sensor.sensorInfo.accuracy,
- sensor.accuracy !=
- sensor.sensorInfo.accuracy /* accuracyChanged */,
- timestamp /* hwTimestamp */, std::move(values));
+ NotifySensorArgs args(getContext()->getNextId(), when, getDeviceId(),
+ AINPUT_SOURCE_SENSOR, sensorType, sensor.sensorInfo.accuracy,
+ sensor.accuracy !=
+ sensor.sensorInfo.accuracy /* accuracyChanged */,
+ timestamp /* hwTimestamp */, values);
+
+ getListener()->notifySensor(&args);
sensor.lastSampleTimeNs = timestamp;
sensor.accuracy = sensor.sensorInfo.accuracy;
}
diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
index 07de244..4f73681 100644
--- a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
@@ -56,7 +56,10 @@
void SwitchInputMapper::sync(nsecs_t when) {
if (mUpdatedSwitchMask) {
uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask;
- getContext()->notifySwitch(when, updatedSwitchValues, mUpdatedSwitchMask);
+ NotifySwitchArgs args(getContext()->getNextId(), when, 0 /*policyFlags*/,
+ updatedSwitchValues, mUpdatedSwitchMask);
+ getListener()->notifySwitch(&args);
+
mUpdatedSwitchMask = 0;
}
}
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index ff6341f..a86443d 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -66,8 +66,9 @@
(currentButtonState & buttonState)) ||
(action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) &&
!(currentButtonState & buttonState))) {
- context->notifyKey(when, deviceId, source, displayId, policyFlags, action, 0 /*flags*/,
- keyCode, 0 /*scanCode*/, context->getGlobalMetaState(), when);
+ NotifyKeyArgs args(context->getNextId(), when, deviceId, source, displayId, policyFlags,
+ action, 0, keyCode, 0, context->getGlobalMetaState(), when);
+ context->getListener()->notifyKey(&args);
}
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 1a17bef..d1df37b 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -397,7 +397,8 @@
if (changes && resetNeeded) {
// Send reset, unless this is the first time the device has been configured,
// in which case the reader will call reset itself after all mappers are ready.
- getContext()->notifyDeviceReset(when, getDeviceId());
+ NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
+ getListener()->notifyDeviceReset(&args);
}
}
@@ -1845,9 +1846,10 @@
int32_t metaState = getContext()->getGlobalMetaState();
policyFlags |= POLICY_FLAG_VIRTUAL;
- getContext()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, mViewport.displayId,
- policyFlags, keyEventAction, keyEventFlags, keyCode, scanCode,
- metaState, downTime);
+ NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD,
+ mViewport.displayId, policyFlags, keyEventAction, keyEventFlags, keyCode,
+ scanCode, metaState, downTime);
+ getListener()->notifyKey(&args);
}
void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) {
@@ -2526,11 +2528,12 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
const int32_t displayId = mPointerController->getDisplayId();
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &pointerProperties, &pointerCoords, 0, 0, x, y,
- mPointerGesture.downTime, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+ buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
+ 1, &pointerProperties, &pointerCoords, 0, 0, x, y,
+ mPointerGesture.downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
// Update state.
@@ -3445,28 +3448,28 @@
mPointerSimple.down = false;
// Send up.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
- mLastRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
- &mPointerSimple.lastCoords, mOrientedXPrecision,
- mOrientedYPrecision, xCursorPosition, yCursorPosition,
- mPointerSimple.downTime,
- /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
+ mLastRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
+ &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
+ xCursorPosition, yCursorPosition, mPointerSimple.downTime,
+ /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
if (mPointerSimple.hovering && !hovering) {
mPointerSimple.hovering = false;
// Send hover exit.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
- mLastRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
- &mPointerSimple.lastCoords, mOrientedXPrecision,
- mOrientedYPrecision, xCursorPosition, yCursorPosition,
- mPointerSimple.downTime,
- /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
+ mLastRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
+ &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
+ xCursorPosition, yCursorPosition, mPointerSimple.downTime,
+ /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
if (down) {
@@ -3475,24 +3478,25 @@
mPointerSimple.downTime = when;
// Send down.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties,
- &mPointerSimple.currentCoords, mOrientedXPrecision,
- mOrientedYPrecision, xCursorPosition, yCursorPosition,
- mPointerSimple.downTime, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0,
+ metaState, mCurrentRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+ mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+ yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
// Send move.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
- mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
- yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
+ mCurrentRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+ &mPointerSimple.currentCoords, mOrientedXPrecision,
+ mOrientedYPrecision, xCursorPosition, yCursorPosition,
+ mPointerSimple.downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
if (hovering) {
@@ -3500,24 +3504,25 @@
mPointerSimple.hovering = true;
// Send hover enter.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties,
- &mPointerSimple.currentCoords, mOrientedXPrecision,
- mOrientedYPrecision, xCursorPosition, yCursorPosition,
- mPointerSimple.downTime, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0,
+ metaState, mCurrentRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+ mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+ yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
// Send hover move.
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
- mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
- yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+ mCurrentRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+ &mPointerSimple.currentCoords, mOrientedXPrecision,
+ mOrientedYPrecision, xCursorPosition, yCursorPosition,
+ mPointerSimple.downTime, /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
@@ -3532,14 +3537,14 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties, &pointerCoords,
- mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
- yCursorPosition, mPointerSimple.downTime,
- /* videoFrames */ {});
+ NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+ policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
+ mCurrentRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+ &pointerCoords, mOrientedXPrecision, mOrientedYPrecision,
+ xCursorPosition, yCursorPosition, mPointerSimple.downTime,
+ /* videoFrames */ {});
+ getListener()->notifyMotion(&args);
}
// Save state.
@@ -3610,11 +3615,12 @@
std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
std::for_each(frames.begin(), frames.end(),
[this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
- getContext()->notifyMotion(when, deviceId, source, displayId, policyFlags, action, actionButton,
- flags, metaState, buttonState, MotionClassification::NONE, edgeFlags,
- pointerCount, pointerProperties, pointerCoords, xPrecision,
- yPrecision, xCursorPosition, yCursorPosition, downTime,
- std::move(frames));
+ NotifyMotionArgs args(getContext()->getNextId(), when, deviceId, source, displayId, policyFlags,
+ action, actionButton, flags, metaState, buttonState,
+ MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
+ pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
+ downTime, std::move(frames));
+ getListener()->notifyMotion(&args);
}
bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties,
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index 2e4ab45..3df6f36 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -53,7 +53,8 @@
mIndex = -1;
// Request InputReader to notify InputManagerService for vibration started.
- getContext()->notifyVibratorState(systemTime(), getDeviceId(), true);
+ NotifyVibratorStateArgs args(getContext()->getNextId(), systemTime(), getDeviceId(), true);
+ getListener()->notifyVibratorState(&args);
nextStep();
}
@@ -131,7 +132,8 @@
getDeviceContext().cancelVibrate();
// Request InputReader to notify InputManagerService for vibration complete.
- getContext()->notifyVibratorState(systemTime(), getDeviceId(), false);
+ NotifyVibratorStateArgs args(getContext()->getNextId(), systemTime(), getDeviceId(), false);
+ getListener()->notifyVibratorState(&args);
}
void VibratorInputMapper::dump(std::string& dump) {
diff --git a/services/inputflinger/reporter/Android.bp b/services/inputflinger/reporter/Android.bp
index fbc51da..7430731 100644
--- a/services/inputflinger/reporter/Android.bp
+++ b/services/inputflinger/reporter/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "libinputreporter_headers",
export_include_dirs: ["."],
@@ -46,4 +55,3 @@
"libinputreporter_headers",
],
}
-
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 959dadc..42b54c7 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "inputflinger_tests",
defaults: [
diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp
index 68f4f28..1d3e5b5 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libpowermanager",
diff --git a/services/schedulerservice/Android.bp b/services/schedulerservice/Android.bp
index 73802db..4ef72d0 100644
--- a/services/schedulerservice/Android.bp
+++ b/services/schedulerservice/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libschedulerservicehidl",
srcs: [
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 532a2e5..ca9ff7c 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
subdirs = [
"hidl"
]
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 2810bff..23893ea 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -914,6 +914,21 @@
return mActivationCount.valueAt(activationIndex).numActiveClients() > 0;
}
+void SensorDevice::onMicSensorAccessChanged(void* ident, int handle, nsecs_t samplingPeriodNs) {
+ Mutex::Autolock _l(mLock);
+ ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+ if (activationIndex < 0) {
+ ALOGW("Handle %d cannot be found in activation record", handle);
+ return;
+ }
+ Info& info(mActivationCount.editValueAt(activationIndex));
+ if (info.hasBatchParamsForIdent(ident)) {
+ ssize_t index = info.batchParams.indexOfKey(ident);
+ BatchParams& params = info.batchParams.editValueAt(index);
+ params.mTSample = samplingPeriodNs;
+ }
+}
+
void SensorDevice::enableAllSensors() {
if (mSensors == nullptr) return;
Mutex::Autolock _l(mLock);
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 5e7d3da..75da7bb 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -125,6 +125,10 @@
bool isSensorActive(int handle) const;
+ // To update the BatchParams of a SensorEventConnection when the mic toggle changes its state
+ // while the Sensors Off toggle is on.
+ void onMicSensorAccessChanged(void* ident, int handle, nsecs_t samplingPeriodNs);
+
// Dumpable
virtual std::string dump() const override;
virtual void dump(util::ProtoOutputStream* proto) const override;
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index e4c33da..af86d09 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -32,6 +32,8 @@
: mService(service), mUid(uid), mMem(*mem),
mHalChannelHandle(halChannelHandle),
mOpPackageName(opPackageName), mDestroyed(false) {
+ mIsRateCappedBasedOnPermission = mService->isRateCappedBasedOnPermission(mOpPackageName);
+ mUserId = multiuser_get_user_id(mUid);
ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection");
}
@@ -101,6 +103,14 @@
}
}
+void SensorService::SensorDirectConnection::onMicSensorAccessChanged(bool isMicToggleOn) {
+ if (isMicToggleOn) {
+ capRates();
+ } else {
+ uncapRates();
+ }
+}
+
bool SensorService::SensorDirectConnection::hasSensorAccess() const {
return mService->hasSensorAccess(mUid, mOpPackageName);
}
@@ -134,6 +144,7 @@
if (handle == -1 && rateLevel == SENSOR_DIRECT_RATE_STOP) {
stopAll();
+ mMicRateBackup.clear();
return NO_ERROR;
}
@@ -157,6 +168,14 @@
return INVALID_OPERATION;
}
+ int requestedRateLevel = rateLevel;
+ if (mService->isSensorInCappedSet(s.getType()) && rateLevel != SENSOR_DIRECT_RATE_STOP) {
+ status_t err = mService->adjustRateLevelBasedOnMicAndPermission(&rateLevel, mOpPackageName);
+ if (err != OK) {
+ return err;
+ }
+ }
+
struct sensors_direct_cfg_t config = {
.rate_level = rateLevel
};
@@ -168,18 +187,100 @@
if (rateLevel == SENSOR_DIRECT_RATE_STOP) {
if (ret == NO_ERROR) {
mActivated.erase(handle);
+ mMicRateBackup.erase(handle);
} else if (ret > 0) {
ret = UNKNOWN_ERROR;
}
} else {
if (ret > 0) {
mActivated[handle] = rateLevel;
+ if (mService->isSensorInCappedSet(s.getType())) {
+ // Back up the rates that the app is allowed to have if the mic toggle is off
+ // This is used in the uncapRates() function.
+ if (!mIsRateCappedBasedOnPermission ||
+ requestedRateLevel <= SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
+ mMicRateBackup[handle] = requestedRateLevel;
+ } else {
+ mMicRateBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+ }
+ }
}
}
return ret;
}
+void SensorService::SensorDirectConnection::capRates() {
+ Mutex::Autolock _l(mConnectionLock);
+ const struct sensors_direct_cfg_t capConfig = {
+ .rate_level = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL
+ };
+
+ const struct sensors_direct_cfg_t stopConfig = {
+ .rate_level = SENSOR_DIRECT_RATE_STOP
+ };
+
+ // If our requests are in the backup, then we shouldn't activate sensors from here
+ bool temporarilyStopped = mActivated.empty() && !mActivatedBackup.empty();
+ std::unordered_map<int, int>& existingConnections =
+ (!temporarilyStopped) ? mActivated : mActivatedBackup;
+
+ SensorDevice& dev(SensorDevice::getInstance());
+ for (auto &i : existingConnections) {
+ int handle = i.first;
+ int rateLevel = i.second;
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si != nullptr) {
+ const Sensor& s = si->getSensor();
+ if (mService->isSensorInCappedSet(s.getType()) &&
+ rateLevel > SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
+ mMicRateBackup[handle] = rateLevel;
+ // Modify the rate kept by the existing map
+ existingConnections[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+ // Only reconfigure the channel if it's ongoing
+ if (!temporarilyStopped) {
+ // Stopping before reconfiguring is the well-tested path in CTS
+ dev.configureDirectChannel(handle, getHalChannelHandle(), &stopConfig);
+ dev.configureDirectChannel(handle, getHalChannelHandle(), &capConfig);
+ }
+ }
+ }
+ }
+}
+
+void SensorService::SensorDirectConnection::uncapRates() {
+ Mutex::Autolock _l(mConnectionLock);
+
+ // If our requests are in the backup, then we shouldn't activate sensors from here
+ bool temporarilyStopped = mActivated.empty() && !mActivatedBackup.empty();
+ std::unordered_map<int, int>& existingConnections =
+ (!temporarilyStopped) ? mActivated : mActivatedBackup;
+
+ const struct sensors_direct_cfg_t stopConfig = {
+ .rate_level = SENSOR_DIRECT_RATE_STOP
+ };
+ SensorDevice& dev(SensorDevice::getInstance());
+ for (auto &i : mMicRateBackup) {
+ int handle = i.first;
+ int rateLevel = i.second;
+
+ const struct sensors_direct_cfg_t config = {
+ .rate_level = rateLevel
+ };
+
+ // Modify the rate kept by the existing map
+ existingConnections[handle] = rateLevel;
+
+ // Only reconfigure the channel if it's ongoing
+ if (!temporarilyStopped) {
+ // Stopping before reconfiguring is the well-tested path in CTS
+ dev.configureDirectChannel(handle, getHalChannelHandle(), &stopConfig);
+ dev.configureDirectChannel(handle, getHalChannelHandle(), &config);
+ }
+ }
+ mMicRateBackup.clear();
+}
+
void SensorService::SensorDirectConnection::stopAll(bool backupRecord) {
Mutex::Autolock _l(mConnectionLock);
stopAllLocked(backupRecord);
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index 4181b65..a3f348b 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -50,6 +50,8 @@
// regained due to changes in the sensor restricted/privacy mode or the
// app changed to idle/active status.
void onSensorAccessChanged(bool hasAccess);
+ void onMicSensorAccessChanged(bool isMicToggleOn);
+ userid_t getUserId() const { return mUserId; }
protected:
virtual ~SensorDirectConnection();
@@ -82,6 +84,11 @@
// If no requests are backed up by stopAll(), this method is no-op.
void recoverAll();
+ // Limits all active sensor direct report requests when the mic toggle is flipped to on.
+ void capRates();
+ // Recover sensor requests previously capped by capRates().
+ void uncapRates();
+
const sp<SensorService> mService;
const uid_t mUid;
const sensors_direct_mem_t mMem;
@@ -91,9 +98,12 @@
mutable Mutex mConnectionLock;
std::unordered_map<int, int> mActivated;
std::unordered_map<int, int> mActivatedBackup;
+ std::unordered_map<int, int> mMicRateBackup;
+ std::atomic_bool mIsRateCappedBasedOnPermission;
mutable Mutex mDestroyLock;
bool mDestroyed;
+ userid_t mUserId;
};
} // namepsace android
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 6810c1b7..a2e7f23 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -44,6 +44,8 @@
mCacheSize(0), mMaxCacheSize(0), mTimeOfLastEventDrop(0), mEventsDropped(0),
mPackageName(packageName), mOpPackageName(opPackageName), mTargetSdk(kTargetSdkUnknown),
mDestroyed(false) {
+ mIsRateCappedBasedOnPermission = mService->isRateCappedBasedOnPermission(mOpPackageName);
+ mUserId = multiuser_get_user_id(mUid);
mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -285,6 +287,29 @@
}
}
+// TODO(b/179649922): A better algorithm to guarantee that capped connections will get a sampling
+// rate close to 200 Hz. With the current algorithm, apps might be punished unfairly: E.g.,two apps
+// make requests to the sensor service at the same time, one is not capped and uses 250 Hz, and one
+//is capped, the capped connection will only get 125 Hz.
+void SensorService::SensorEventConnection::addSensorEventsToBuffer(bool shouldResample,
+ const sensors_event_t& sensorEvent, sensors_event_t* buffer, int* index) {
+ if (!shouldResample || !mService->isSensorInCappedSet(sensorEvent.type)) {
+ buffer[(*index)++] = sensorEvent;
+ } else {
+ int64_t lastTimestamp = -1;
+ auto entry = mSensorLastTimestamp.find(sensorEvent.sensor);
+ if (entry != mSensorLastTimestamp.end()) {
+ lastTimestamp = entry->second;
+ }
+ // Allow 10% headroom here because the clocks are not perfect.
+ if (lastTimestamp == -1 || sensorEvent.timestamp - lastTimestamp
+ >= 0.9 * SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ mSensorLastTimestamp[sensorEvent.sensor] = sensorEvent.timestamp;
+ buffer[(*index)++] = sensorEvent;
+ }
+ }
+}
+
status_t SensorService::SensorEventConnection::sendEvents(
sensors_event_t const* buffer, size_t numEvents,
sensors_event_t* scratch,
@@ -293,6 +318,8 @@
std::unique_ptr<sensors_event_t[]> sanitizedBuffer;
+ bool shouldResample = mService->isMicSensorPrivacyEnabledForUid(mUid) ||
+ mIsRateCappedBasedOnPermission;
int count = 0;
Mutex::Autolock _l(mConnectionLock);
if (scratch) {
@@ -346,7 +373,7 @@
// Regular sensor event, just copy it to the scratch buffer after checking
// the AppOp.
if (hasSensorAccess() && noteOpIfRequired(buffer[i])) {
- scratch[count++] = buffer[i];
+ addSensorEventsToBuffer(shouldResample, buffer[i], scratch, &count);
}
}
i++;
@@ -356,12 +383,13 @@
buffer[i].meta_data.sensor == sensor_handle)));
}
} else {
+ sanitizedBuffer.reset(new sensors_event_t[numEvents]);
+ scratch = sanitizedBuffer.get();
if (hasSensorAccess()) {
- scratch = const_cast<sensors_event_t *>(buffer);
- count = numEvents;
+ for (size_t i = 0; i < numEvents; i++) {
+ addSensorEventsToBuffer(shouldResample, buffer[i], scratch, &count);
+ }
} else {
- sanitizedBuffer.reset(new sensors_event_t[numEvents]);
- scratch = sanitizedBuffer.get();
for (size_t i = 0; i < numEvents; i++) {
if (buffer[i].type == SENSOR_TYPE_META_DATA) {
scratch[count++] = buffer[i++];
@@ -684,24 +712,118 @@
status_t err;
if (enabled) {
+ nsecs_t requestedSamplingPeriodNs = samplingPeriodNs;
+ bool isSensorCapped = false;
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si != nullptr) {
+ const Sensor& s = si->getSensor();
+ if (mService->isSensorInCappedSet(s.getType())) {
+ isSensorCapped = true;
+ }
+ }
+ if (isSensorCapped) {
+ err = mService->adjustSamplingPeriodBasedOnMicAndPermission(&samplingPeriodNs,
+ String16(mOpPackageName));
+ if (err != OK) {
+ return err;
+ }
+ }
err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
reservedFlags, mOpPackageName);
+ if (err == OK && isSensorCapped) {
+ if (!mIsRateCappedBasedOnPermission ||
+ requestedSamplingPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ mMicSamplingPeriodBackup[handle] = requestedSamplingPeriodNs;
+ } else {
+ mMicSamplingPeriodBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+ }
+ }
} else {
err = mService->disable(this, handle);
+ mMicSamplingPeriodBackup.erase(handle);
}
return err;
}
-status_t SensorService::SensorEventConnection::setEventRate(
- int handle, nsecs_t samplingPeriodNs)
-{
+status_t SensorService::SensorEventConnection::setEventRate(int handle, nsecs_t samplingPeriodNs) {
if (mDestroyed) {
android_errorWriteLog(0x534e4554, "168211968");
return DEAD_OBJECT;
}
- return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
+ nsecs_t requestedSamplingPeriodNs = samplingPeriodNs;
+ bool isSensorCapped = false;
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si != nullptr) {
+ const Sensor& s = si->getSensor();
+ if (mService->isSensorInCappedSet(s.getType())) {
+ isSensorCapped = true;
+ }
+ }
+ if (isSensorCapped) {
+ status_t err = mService->adjustSamplingPeriodBasedOnMicAndPermission(&samplingPeriodNs,
+ String16(mOpPackageName));
+ if (err != OK) {
+ return err;
+ }
+ }
+ status_t ret = mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
+ if (ret == OK && isSensorCapped) {
+ if (!mIsRateCappedBasedOnPermission ||
+ requestedSamplingPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ mMicSamplingPeriodBackup[handle] = requestedSamplingPeriodNs;
+ } else {
+ mMicSamplingPeriodBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+ }
+ }
+ return ret;
+}
+
+void SensorService::SensorEventConnection::onMicSensorAccessChanged(bool isMicToggleOn) {
+ if (isMicToggleOn) {
+ capRates();
+ } else {
+ uncapRates();
+ }
+}
+
+void SensorService::SensorEventConnection::capRates() {
+ Mutex::Autolock _l(mConnectionLock);
+ SensorDevice& dev(SensorDevice::getInstance());
+ for (auto &i : mMicSamplingPeriodBackup) {
+ int handle = i.first;
+ nsecs_t samplingPeriodNs = i.second;
+ if (samplingPeriodNs < SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ if (hasSensorAccess()) {
+ mService->setEventRate(this, handle, SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS,
+ mOpPackageName);
+ } else {
+ // Update SensorDevice with the capped rate so that when sensor access is restored,
+ // the correct event rate is used.
+ dev.onMicSensorAccessChanged(this, handle,
+ SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS);
+ }
+ }
+ }
+}
+
+void SensorService::SensorEventConnection::uncapRates() {
+ Mutex::Autolock _l(mConnectionLock);
+ SensorDevice& dev(SensorDevice::getInstance());
+ for (auto &i : mMicSamplingPeriodBackup) {
+ int handle = i.first;
+ nsecs_t samplingPeriodNs = i.second;
+ if (samplingPeriodNs < SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ if (hasSensorAccess()) {
+ mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
+ } else {
+ // Update SensorDevice with the uncapped rate so that when sensor access is
+ // restored, the correct event rate is used.
+ dev.onMicSensorAccessChanged(this, handle, samplingPeriodNs);
+ }
+ }
+ }
}
status_t SensorService::SensorEventConnection::flush() {
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 9487a39..7bd9d47 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -68,6 +68,9 @@
String8 getPackageName() const;
uid_t getUid() const { return mUid; }
+ // cap/uncap existing connection depending on the state of the mic toggle.
+ void onMicSensorAccessChanged(bool isMicToggleOn);
+ userid_t getUserId() const { return mUserId; }
private:
virtual ~SensorEventConnection();
@@ -137,10 +140,20 @@
// Call noteOp for the sensor if the sensor requires a permission
bool noteOpIfRequired(const sensors_event_t& event);
+ // Limits all active connections when the mic toggle is flipped to on.
+ void capRates();
+ // Recover sensor connection previously capped by capRates().
+ void uncapRates();
+ // Add sensorEvent to buffer at position index if the sensorEvent satisfies throttling rules.
+ void addSensorEventsToBuffer(bool shouldResample, const sensors_event_t& sensorEvent,
+ sensors_event_t* buffer, int* index);
sp<SensorService> const mService;
sp<BitTube> mChannel;
uid_t mUid;
+ std::atomic_bool mIsRateCappedBasedOnPermission;
+ // Store a mapping of sensor to the timestamp of their last sensor event.
+ std::unordered_map<int, int64_t> mSensorLastTimestamp;
mutable Mutex mConnectionLock;
// Number of events from wake up sensors which are still pending and haven't been delivered to
// the corresponding application. It is incremented by one unit for each write to the socket.
@@ -189,6 +202,9 @@
// Store a mapping of sensor handles to required AppOp for a sensor. This map only contains a
// valid mapping for sensors that require a permission in order to reduce the lookup time.
std::unordered_map<int32_t, int32_t> mHandleToAppOp;
+ // Mapping of sensor handles to its rate before being capped by the mic toggle.
+ std::unordered_map<int, nsecs_t> mMicSamplingPeriodBackup;
+ userid_t mUserId;
};
} // namepsace android
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8f25bdb..89d1c42 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <android-base/strings.h>
#include <android/content/pm/IPackageManagerNative.h>
#include <android/util/ProtoOutputStream.h>
#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
@@ -88,6 +89,8 @@
#define SENSOR_SERVICE_SCHED_FIFO_PRIORITY 10
// Permissions.
+static const String16 sAccessHighSensorSamplingRatePermission(
+ "android.permission.HIGH_SAMPLING_RATE_SENSORS");
static const String16 sDumpPermission("android.permission.DUMP");
static const String16 sLocationHardwarePermission("android.permission.LOCATION_HARDWARE");
static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSORS");
@@ -366,6 +369,9 @@
}
mUidPolicy->unregisterSelf();
mSensorPrivacyPolicy->unregisterSelf();
+ for (auto const& [userId, policy] : mMicSensorPrivacyPolicies) {
+ policy->unregisterSelf();
+ }
}
status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -695,6 +701,35 @@
}
}
+void SensorService::capRates(userid_t userId) {
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
+ if (conn->getUserId() == userId) {
+ conn->onMicSensorAccessChanged(true);
+ }
+ }
+
+ for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
+ if (conn->getUserId() == userId) {
+ conn->onMicSensorAccessChanged(true);
+ }
+ }
+}
+
+void SensorService::uncapRates(userid_t userId) {
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
+ if (conn->getUserId() == userId) {
+ conn->onMicSensorAccessChanged(false);
+ }
+ }
+
+ for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
+ if (conn->getUserId() == userId) {
+ conn->onMicSensorAccessChanged(false);
+ }
+ }
+}
// NOTE: This is a remote API - make sure all args are validated
status_t SensorService::shellCommand(int in, int out, int err, Vector<String16>& args) {
@@ -1209,14 +1244,20 @@
}
}
-Vector<Sensor> SensorService::getSensorList(const String16& /* opPackageName */) {
+Vector<Sensor> SensorService::getSensorList(const String16& opPackageName) {
char value[PROPERTY_VALUE_MAX];
property_get("debug.sensors", value, "0");
const Vector<Sensor>& initialSensorList = (atoi(value)) ?
mSensors.getUserDebugSensors() : mSensors.getUserSensors();
Vector<Sensor> accessibleSensorList;
+
+ bool isCapped = isRateCappedBasedOnPermission(opPackageName);
for (size_t i = 0; i < initialSensorList.size(); i++) {
Sensor sensor = initialSensorList[i];
+ if (isCapped && isSensorInCappedSet(sensor.getType())) {
+ sensor.capMinDelayMicros(SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS / 1000);
+ sensor.capHighestDirectReportRateLevel(SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL);
+ }
accessibleSensorList.add(sensor);
}
makeUuidsIntoIdsForSensorList(accessibleSensorList);
@@ -2024,6 +2065,69 @@
return mUidPolicy->isUidActive(uid);
}
+bool SensorService::isRateCappedBasedOnPermission(const String16& opPackageName) {
+ int targetSdk = getTargetSdkVersion(opPackageName);
+ bool hasSamplingRatePermission = PermissionCache::checkCallingPermission(
+ sAccessHighSensorSamplingRatePermission);
+ if (targetSdk < __ANDROID_API_S__ ||
+ (targetSdk >= __ANDROID_API_S__ && hasSamplingRatePermission)) {
+ return false;
+ }
+ return true;
+}
+
+bool SensorService::isSensorInCappedSet(int sensorType) {
+ return (sensorType == SENSOR_TYPE_ACCELEROMETER
+ || sensorType == SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED
+ || sensorType == SENSOR_TYPE_GYROSCOPE
+ || sensorType == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED
+ || sensorType == SENSOR_TYPE_MAGNETIC_FIELD
+ || sensorType == SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED);
+}
+
+status_t SensorService::adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs,
+ const String16& opPackageName) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ bool shouldCapBasedOnPermission = isRateCappedBasedOnPermission(opPackageName);
+ if (*requestedPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ return OK;
+ }
+ if (shouldCapBasedOnPermission) {
+ *requestedPeriodNs = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+ if (isPackageDebuggable(opPackageName)) {
+ return PERMISSION_DENIED;
+ }
+ return OK;
+ }
+ if (isMicSensorPrivacyEnabledForUid(uid)) {
+ *requestedPeriodNs = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+ return OK;
+ }
+ return OK;
+}
+
+status_t SensorService::adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel,
+ const String16& opPackageName) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ bool shouldCapBasedOnPermission = isRateCappedBasedOnPermission(opPackageName);
+
+ if (*requestedRateLevel <= SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
+ return OK;
+ }
+ if (shouldCapBasedOnPermission) {
+ *requestedRateLevel = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+ if (isPackageDebuggable(opPackageName)) {
+ return PERMISSION_DENIED;
+ }
+ return OK;
+ }
+ if (isMicSensorPrivacyEnabledForUid(uid)) {
+ *requestedRateLevel = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+ return OK;
+ }
+ return OK;
+}
+
void SensorService::SensorPrivacyPolicy::registerSelf() {
SensorPrivacyManager spm;
mSensorPrivacyEnabled = spm.isSensorPrivacyEnabled();
@@ -2042,16 +2146,56 @@
binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(bool enabled) {
mSensorPrivacyEnabled = enabled;
sp<SensorService> service = mService.promote();
+
if (service != nullptr) {
- if (enabled) {
- service->disableAllSensors();
+ if (mIsIndividualMic) {
+ if (enabled) {
+ service->capRates(mUserId);
+ } else {
+ service->uncapRates(mUserId);
+ }
} else {
- service->enableAllSensors();
+ if (enabled) {
+ service->disableAllSensors();
+ } else {
+ service->enableAllSensors();
+ }
}
}
return binder::Status::ok();
}
+status_t SensorService::SensorPrivacyPolicy::registerSelfForIndividual(int userId) {
+ Mutex::Autolock _l(mSensorPrivacyLock);
+
+ SensorPrivacyManager spm;
+ status_t err = spm.addIndividualSensorPrivacyListener(userId,
+ SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this);
+
+ if (err != OK) {
+ ALOGE("Cannot register a mic listener.");
+ return err;
+ }
+ mSensorPrivacyEnabled = spm.isIndividualSensorPrivacyEnabled(userId,
+ SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE);
+
+ mIsIndividualMic = true;
+ mUserId = userId;
+ return OK;
+}
+
+bool SensorService::isMicSensorPrivacyEnabledForUid(uid_t uid) {
+ userid_t userId = multiuser_get_user_id(uid);
+ if (mMicSensorPrivacyPolicies.find(userId) == mMicSensorPrivacyPolicies.end()) {
+ sp<SensorPrivacyPolicy> userPolicy = new SensorPrivacyPolicy(this);
+ if (userPolicy->registerSelfForIndividual(userId) != OK) {
+ return false;
+ }
+ mMicSensorPrivacyPolicies[userId] = userPolicy;
+ }
+ return mMicSensorPrivacyPolicies[userId]->isSensorPrivacyEnabled();
+}
+
SensorService::ConnectionSafeAutolock::ConnectionSafeAutolock(
SensorService::SensorConnectionHolder& holder, Mutex& mutex)
: mConnectionHolder(holder), mAutolock(mutex) {}
@@ -2109,4 +2253,17 @@
return ConnectionSafeAutolock(*this, mutex);
}
+bool SensorService::isPackageDebuggable(const String16& opPackageName) {
+ bool debugMode = false;
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("package_native"));
+ if (binder != nullptr) {
+ sp<content::pm::IPackageManagerNative> packageManager =
+ interface_cast<content::pm::IPackageManagerNative>(binder);
+ if (packageManager != nullptr) {
+ binder::Status status = packageManager->isPackageDebuggable(
+ opPackageName, &debugMode);
+ }
+ }
+ return debugMode;
+}
} // namespace android
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 50c7c2f..5b198d8 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -61,6 +61,15 @@
#define SENSOR_REGISTRATIONS_BUF_SIZE 200
+// Apps that targets S+ and do not have HIGH_SAMPLING_RATE_SENSORS permission will be capped
+// at 200 Hz. The cap also applies to all requests when the mic toggle is flipped to on, regardless
+// of their target SDKs and permission.
+// Capped sampling periods for apps that have non-direct sensor connections.
+#define SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS (5 * 1000 * 1000)
+// Capped sampling rate level for apps that have direct sensor connections.
+// The enum SENSOR_DIRECT_RATE_NORMAL corresponds to a rate value of at most 110 Hz.
+#define SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL SENSOR_DIRECT_RATE_NORMAL
+
namespace android {
// ---------------------------------------------------------------------------
class SensorInterface;
@@ -95,6 +104,8 @@
status_t flushSensor(const sp<SensorEventConnection>& connection,
const String16& opPackageName);
+ // Returns true if a sensor should be throttled according to our rate-throttling rules.
+ static bool isSensorInCappedSet(int sensorType);
virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
@@ -212,17 +223,23 @@
// connections will be allowed again.
class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener {
public:
- explicit SensorPrivacyPolicy(wp<SensorService> service) : mService(service) {}
+ explicit SensorPrivacyPolicy(wp<SensorService> service)
+ : mService(service), mIsIndividualMic(false), mUserId(0) {}
void registerSelf();
void unregisterSelf();
+ status_t registerSelfForIndividual(int userId);
+
bool isSensorPrivacyEnabled();
binder::Status onSensorPrivacyChanged(bool enabled);
private:
wp<SensorService> mService;
+ Mutex mSensorPrivacyLock;
std::atomic_bool mSensorPrivacyEnabled;
+ bool mIsIndividualMic;
+ userid_t mUserId;
};
enum Mode {
@@ -346,6 +363,13 @@
// whitelisted). mLock must be held to invoke this method.
bool isOperationRestrictedLocked(const String16& opPackageName);
+ status_t adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs,
+ const String16& opPackageName);
+ status_t adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel,
+ const String16& opPackageName);
+ bool isRateCappedBasedOnPermission(const String16& opPackageName);
+ bool isPackageDebuggable(const String16& opPackageName);
+
// Reset the state of SensorService to NORMAL mode.
status_t resetToNormalMode();
status_t resetToNormalModeLocked();
@@ -385,6 +409,11 @@
void enableAllSensors();
void enableAllSensorsLocked(ConnectionSafeAutolock* connLock);
+ // Caps active direct connections (when the mic toggle is flipped to on)
+ void capRates(userid_t userId);
+ // Removes the capped rate on active direct connections (when the mic toggle is flipped to off)
+ void uncapRates(userid_t userId);
+
static uint8_t sHmacGlobalKey[128];
static bool sHmacGlobalKeyIsValid;
@@ -426,6 +455,11 @@
static std::map<String16, int> sPackageTargetVersion;
static Mutex sPackageTargetVersionLock;
static String16 sSensorInterfaceDescriptorPrefix;
+
+ // Map from user to SensorPrivacyPolicy
+ std::map<userid_t, sp<SensorPrivacyPolicy>> mMicSensorPrivacyPolicies;
+ // Checks if the mic sensor privacy is enabled for the uid
+ bool isMicSensorPrivacyEnabledForUid(uid_t uid);
};
} // namespace android
diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp
index 0e1af59..9bafb3c 100644
--- a/services/sensorservice/hidl/Android.bp
+++ b/services/sensorservice/hidl/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libsensorservicehidl",
srcs: [
diff --git a/services/sensorservice/tests/Android.bp b/services/sensorservice/tests/Android.bp
index d33c0ca..ddc03a1 100644
--- a/services/sensorservice/tests/Android.bp
+++ b/services/sensorservice/tests/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-sensorservice",
srcs: ["sensorservicetest.cpp"],
diff --git a/services/stats/Android.bp b/services/stats/Android.bp
index 1ce0524..58e5993 100644
--- a/services/stats/Android.bp
+++ b/services/stats/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libstatshidl",
srcs: [
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 8d1258a..c39c983 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "surfaceflinger_defaults",
cflags: [
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index ec81ff7..097f7de 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -366,8 +366,11 @@
mFrameTracker.setFrameReadyTime(desiredPresentTime);
}
+ const Fps refreshRate = mFlinger->mRefreshRateConfigs->getCurrentRefreshRate().getFps();
+ const std::optional<Fps> renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
if (presentFence->isValid()) {
- mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence);
+ mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
+ refreshRate, renderRate);
mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber,
presentFence, FrameTracer::FrameEvent::PRESENT_FENCE);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
@@ -378,7 +381,8 @@
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
const nsecs_t actualPresentTime = display->getRefreshTimestamp();
- mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime);
+ mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
+ refreshRate, renderRate);
mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
actualPresentTime,
FrameTracer::FrameEvent::PRESENT_FENCE);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index cf87f62..f30e1eb 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -35,6 +35,7 @@
#include <renderengine/Image.h>
#include "EffectLayer.h"
+#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
namespace android {
@@ -235,10 +236,6 @@
bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
mCurrentStateModified = mCurrentState.modified;
bool stateUpdateAvailable = Layer::applyPendingStates(stateToCommit);
- if (stateUpdateAvailable && mCallbackHandleAcquireTime != -1) {
- // Update the acquire fence time if we have a buffer
- mSurfaceFrame->setAcquireFenceTime(mCallbackHandleAcquireTime);
- }
mCurrentStateModified = stateUpdateAvailable && mCurrentStateModified;
mCurrentState.modified = false;
return stateUpdateAvailable;
@@ -337,7 +334,7 @@
bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp,
const client_cache_t& clientCacheId, uint64_t frameNumber,
- std::optional<nsecs_t> /* dequeueTime */,
+ std::optional<nsecs_t> dequeueTime,
const FrameTimelineInfo& info) {
ATRACE_CALL();
@@ -377,6 +374,14 @@
setFrameTimelineVsyncForBufferTransaction(info, postTime);
}
+ if (dequeueTime && *dequeueTime != 0) {
+ const uint64_t bufferId = buffer->getId();
+ mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime,
+ FrameTracer::FrameEvent::DEQUEUE);
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime,
+ FrameTracer::FrameEvent::QUEUE);
+ }
return true;
}
@@ -452,6 +457,7 @@
if (willPresent) {
// If this transaction set an acquire fence on this layer, set its acquire time
handle->acquireTime = mCallbackHandleAcquireTime;
+ handle->frameNumber = mCurrentState.frameNumber;
// Notify the transaction completed thread that there is a pending latched callback
// handle
@@ -602,11 +608,12 @@
}
std::optional<nsecs_t> BufferStateLayer::nextPredictedPresentTime() const {
- if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) {
+ const State& drawingState(getDrawingState());
+ if (!drawingState.isAutoTimestamp || !drawingState.bufferSurfaceFrameTX) {
return std::nullopt;
}
- return mSurfaceFrame->getPredictions().presentTime;
+ return drawingState.bufferSurfaceFrameTX->getPredictions().presentTime;
}
status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
@@ -623,14 +630,22 @@
}
for (auto& handle : mDrawingState.callbackHandles) {
- handle->latchTime = latchTime;
- handle->frameNumber = mDrawingState.frameNumber;
+ if (handle->frameNumber == mDrawingState.frameNumber) {
+ handle->latchTime = latchTime;
+ }
}
const int32_t layerId = getSequence();
- mFlinger->mTimeStats->setAcquireFence(layerId, mDrawingState.frameNumber,
- std::make_shared<FenceTime>(mDrawingState.acquireFence));
- mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime);
+ const uint64_t bufferId = mDrawingState.buffer->getId();
+ const uint64_t frameNumber = mDrawingState.frameNumber;
+ const auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence);
+ mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence);
+ mFlinger->mTimeStats->setLatchTime(layerId, frameNumber, latchTime);
+
+ mFlinger->mFrameTracer->traceFence(layerId, bufferId, frameNumber, acquireFence,
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH);
auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX;
if (bufferSurfaceFrame != nullptr &&
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index ea832a2..175a40b 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -124,6 +124,7 @@
private:
friend class SlotGenerationTest;
+ friend class TransactionFrameTracerTest;
friend class TransactionSurfaceFrameTest;
inline void tracePendingBufferCount();
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 57dc60b..50bc5ed 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "libcompositionengine_defaults",
defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/Fps.h b/services/surfaceflinger/Fps.h
index 38a9af0..e9f06e5 100644
--- a/services/surfaceflinger/Fps.h
+++ b/services/surfaceflinger/Fps.h
@@ -27,7 +27,7 @@
// Value which represents "frames per second". This class is a wrapper around
// float, providing some useful utilities, such as comparisons with tolerance
-// and converting between period duruation and frequency.
+// and converting between period duration and frequency.
class Fps {
public:
static constexpr Fps fromPeriodNsecs(nsecs_t period) { return Fps(1e9f / period, period); }
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 3f833f4..da04202 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -30,6 +30,7 @@
using base::StringAppendF;
using FrameTimelineEvent = perfetto::protos::pbzero::FrameTimelineEvent;
+using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource;
void dumpTable(std::string& result, TimelineItem predictions, TimelineItem actuals,
const std::string& indent, PredictionState predictionState, nsecs_t baseTime) {
@@ -305,11 +306,17 @@
std::scoped_lock lock(mMutex);
mActualQueueTime = actualQueueTime;
}
+
void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) {
std::scoped_lock lock(mMutex);
mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
}
+void SurfaceFrame::setDropTime(nsecs_t dropTime) {
+ std::scoped_lock lock(mMutex);
+ mDropTime = dropTime;
+}
+
void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) {
std::scoped_lock lock(mMutex);
LOG_ALWAYS_FATAL_IF(mPresentState != PresentState::Unknown,
@@ -320,9 +327,19 @@
mLastLatchTime = lastLatchTime;
}
+void SurfaceFrame::setRenderRate(Fps renderRate) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mRenderRate = renderRate;
+}
+
std::optional<int32_t> SurfaceFrame::getJankType() const {
std::scoped_lock lock(mMutex);
+ if (mPresentState == PresentState::Dropped) {
+ // Return no jank if it's a dropped frame since we cannot attribute a jank to a it.
+ return JankType::None;
+ }
if (mActuals.presentTime == 0) {
+ // Frame hasn't been presented yet.
return std::nullopt;
}
return mJankType;
@@ -338,6 +355,11 @@
return mActuals;
}
+PredictionState SurfaceFrame::getPredictionState() const {
+ std::scoped_lock lock(mMutex);
+ return mPredictionState;
+}
+
SurfaceFrame::PresentState SurfaceFrame::getPresentState() const {
std::scoped_lock lock(mMutex);
return mPresentState;
@@ -353,6 +375,11 @@
return mFrameReadyMetadata;
}
+nsecs_t SurfaceFrame::getDropTime() const {
+ std::scoped_lock lock(mMutex);
+ return mDropTime;
+}
+
void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) const {
std::scoped_lock lock(mMutex);
StringAppendF(&result, "%s", indent.c_str());
@@ -367,8 +394,17 @@
StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Owner Pid : %d\n", mOwnerPid);
StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "Scheduled rendering rate: %d fps\n",
+ mRenderRate ? mRenderRate->getIntValue() : 0);
+ StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Present State : %s\n", toString(mPresentState).c_str());
StringAppendF(&result, "%s", indent.c_str());
+ if (mPresentState == PresentState::Dropped) {
+ std::chrono::nanoseconds dropTime(mDropTime - baseTime);
+ StringAppendF(&result, "Drop time : %10f\n",
+ std::chrono::duration<double, std::milli>(dropTime).count());
+ StringAppendF(&result, "%s", indent.c_str());
+ }
StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Jank Type : %s\n", jankTypeBitmaskToString(mJankType).c_str());
@@ -391,9 +427,10 @@
dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
}
-void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
- nsecs_t vsyncPeriod) {
+void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate,
+ nsecs_t displayDeadlineDelta, nsecs_t displayPresentDelta) {
std::scoped_lock lock(mMutex);
+
if (mPresentState != PresentState::Presented) {
// No need to update dropped buffers
return;
@@ -412,13 +449,16 @@
mJankType = JankType::Unknown;
mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
mFrameReadyMetadata = FrameReadyMetadata::UnknownFinish;
- mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
+ const constexpr nsecs_t kAppDeadlineDelta = -1;
+ mTimeStats->incrementJankyFrames({refreshRate, mRenderRate, mOwnerUid, mLayerName,
+ mJankType, displayDeadlineDelta, displayPresentDelta,
+ kAppDeadlineDelta});
return;
}
const nsecs_t presentDelta = mActuals.presentTime - mPredictions.presentTime;
const nsecs_t deadlineDelta = mActuals.endTime - mPredictions.endTime;
- const nsecs_t deltaToVsync = std::abs(presentDelta) % vsyncPeriod;
+ const nsecs_t deltaToVsync = std::abs(presentDelta) % refreshRate.getPeriodNsecs();
if (deadlineDelta > mJankClassificationThresholds.deadlineThreshold) {
mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
@@ -440,7 +480,8 @@
if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
// Finish on time, Present early
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+ deltaToVsync >= refreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold) {
// Delta factor of vsync
mJankType = JankType::SurfaceFlingerScheduling;
} else {
@@ -463,7 +504,8 @@
mJankType |= displayFrameJankType;
} else {
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+ deltaToVsync >= refreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold) {
// Delta factor of vsync
mJankType |= JankType::SurfaceFlingerScheduling;
} else {
@@ -482,30 +524,16 @@
}
}
}
- mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
+ mTimeStats->incrementJankyFrames({refreshRate, mRenderRate, mOwnerUid, mLayerName, mJankType,
+ displayDeadlineDelta, displayPresentDelta, deadlineDelta});
}
-/**
- * TODO(b/178637512): add inputEventId to the perfetto trace.
- */
-void SurfaceFrame::trace(int64_t displayFrameToken) {
- using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource;
-
+void SurfaceFrame::tracePredictions(int64_t displayFrameToken) const {
int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
- bool missingToken = false;
+
// Expected timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
- if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
- ALOGD("Cannot trace SurfaceFrame - %s with invalid token", mLayerName.c_str());
- missingToken = true;
- return;
- } else if (displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
- ALOGD("Cannot trace SurfaceFrame - %s with invalid displayFrameToken",
- mLayerName.c_str());
- missingToken = true;
- return;
- }
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
@@ -522,12 +550,6 @@
expectedSurfaceFrameStartEvent->set_layer_name(mDebugName);
});
- if (missingToken) {
- // If one packet can't be traced because of missing token, then no packets can be traced.
- // Exit early in this case.
- return;
- }
-
// Expected timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
@@ -540,15 +562,26 @@
expectedSurfaceFrameEndEvent->set_cookie(expectedTimelineCookie);
});
+}
+void SurfaceFrame::traceActuals(int64_t displayFrameToken) const {
int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
+
// Actual timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
// Actual start time is not yet available, so use expected start instead
- packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
+ if (mPredictionState == PredictionState::Expired) {
+ // If prediction is expired, we can't use the predicted start time. Instead, just use a
+ // start time a little earlier than the end time so that we have some info about this
+ // frame in the trace.
+ packet->set_timestamp(
+ static_cast<uint64_t>(mActuals.endTime - kPredictionExpiredStartTimeDelta));
+ } else {
+ packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
+ }
auto* event = packet->set_frame_timeline_event();
auto* actualSurfaceFrameStartEvent = event->set_actual_surface_frame_start();
@@ -573,12 +606,17 @@
actualSurfaceFrameStartEvent->set_gpu_composition(mGpuComposition);
actualSurfaceFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
});
+
// Actual timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::scoped_lock lock(mMutex);
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime));
+ if (mPresentState == PresentState::Dropped) {
+ packet->set_timestamp(static_cast<uint64_t>(mDropTime));
+ } else {
+ packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime));
+ }
auto* event = packet->set_frame_timeline_event();
auto* actualSurfaceFrameEndEvent = event->set_frame_end();
@@ -587,6 +625,23 @@
});
}
+/**
+ * TODO(b/178637512): add inputEventId to the perfetto trace.
+ */
+void SurfaceFrame::trace(int64_t displayFrameToken) const {
+ if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID ||
+ displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
+ // No packets can be traced with a missing token.
+ return;
+ }
+ if (getPredictionState() != PredictionState::Expired) {
+ // Expired predictions have zeroed timestamps. This cannot be used in any meaningful way in
+ // a trace.
+ tracePredictions(displayFrameToken);
+ }
+ traceActuals(displayFrameToken);
+}
+
namespace impl {
int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
@@ -684,10 +739,10 @@
mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame);
}
-void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) {
+void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRate) {
ATRACE_CALL();
std::scoped_lock lock(mMutex);
- mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod,
+ mCurrentDisplayFrame->onSfWakeUp(token, refreshRate,
mTokenManager.getPredictionsForToken(token), wakeUpTime);
}
@@ -705,11 +760,11 @@
mSurfaceFrames.push_back(surfaceFrame);
}
-void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod,
+void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, Fps refreshRate,
std::optional<TimelineItem> predictions,
nsecs_t wakeUpTime) {
mToken = token;
- mVsyncPeriod = vsyncPeriod;
+ mRefreshRate = refreshRate;
if (!predictions) {
mPredictionState = PredictionState::Expired;
} else {
@@ -719,11 +774,6 @@
mSurfaceFlingerActuals.startTime = wakeUpTime;
}
-void FrameTimeline::DisplayFrame::setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod) {
- mToken = token;
- mVsyncPeriod = vsyncPeriod;
-}
-
void FrameTimeline::DisplayFrame::setPredictions(PredictionState predictionState,
TimelineItem predictions) {
mPredictionState = predictionState;
@@ -740,14 +790,21 @@
void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
mSurfaceFlingerActuals.presentTime = signalTime;
- int32_t totalJankReasons = JankType::None;
+ if (mPredictionState == PredictionState::Expired) {
+ // Cannot do jank classification with expired predictions
+ mJankType = JankType::Unknown;
+ return;
+ }
// Delta between the expected present and the actual present
const nsecs_t presentDelta =
mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
+ const nsecs_t deadlineDelta =
+ mSurfaceFlingerActuals.endTime - mSurfaceFlingerPredictions.endTime;
+
// How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there
// was a prediction error or not.
- nsecs_t deltaToVsync = std::abs(presentDelta) % mVsyncPeriod;
+ nsecs_t deltaToVsync = std::abs(presentDelta) % mRefreshRate.getPeriodNsecs();
if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
: FramePresentMetadata::EarlyPresent;
@@ -776,8 +833,8 @@
if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
// Finish on time, Present early
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >=
- (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
+ deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold)) {
// Delta is a factor of vsync if its within the presentTheshold on either side
// of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
// of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -797,8 +854,8 @@
if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
// Finish on time, Present late
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >=
- (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
+ deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold)) {
// Delta is a factor of vsync if its within the presentTheshold on either side
// of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
// of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -819,29 +876,17 @@
mJankType = JankType::Unknown;
}
}
- totalJankReasons |= mJankType;
-
for (auto& surfaceFrame : mSurfaceFrames) {
- surfaceFrame->onPresent(signalTime, mJankType, mVsyncPeriod);
- auto surfaceFrameJankType = surfaceFrame->getJankType();
- if (surfaceFrameJankType != std::nullopt) {
- totalJankReasons |= *surfaceFrameJankType;
- }
+ surfaceFrame->onPresent(signalTime, mJankType, mRefreshRate, deadlineDelta, deltaToVsync);
}
- mTimeStats->incrementJankyFrames(totalJankReasons);
}
-void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
+void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid) const {
int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
- bool missingToken = false;
+
// Expected timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
- if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
- ALOGD("Cannot trace DisplayFrame with invalid token");
- missingToken = true;
- return;
- }
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerPredictions.startTime));
@@ -854,12 +899,6 @@
expectedDisplayFrameStartEvent->set_pid(surfaceFlingerPid);
});
- if (missingToken) {
- // If one packet can't be traced because of missing token, then no packets can be traced.
- // Exit early in this case.
- return;
- }
-
// Expected timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
@@ -871,9 +910,12 @@
expectedDisplayFrameEndEvent->set_cookie(expectedTimelineCookie);
});
+}
+void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid) const {
int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
- // Expected timeline start
+
+ // Actual timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
@@ -893,7 +935,8 @@
actualDisplayFrameStartEvent->set_gpu_composition(mGpuComposition);
actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
});
- // Expected timeline end
+
+ // Actual timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
@@ -904,6 +947,21 @@
actualDisplayFrameEndEvent->set_cookie(actualTimelineCookie);
});
+}
+
+void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
+ if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
+ // DisplayFrame should not have an invalid token.
+ ALOGE("Cannot trace DisplayFrame with invalid token");
+ return;
+ }
+
+ if (mPredictionState == PredictionState::Valid) {
+ // Expired and unknown predictions have zeroed timestamps. This cannot be used in any
+ // meaningful way in a trace.
+ tracePredictions(surfaceFlingerPid);
+ }
+ traceActuals(surfaceFlingerPid);
for (auto& surfaceFrame : mSurfaceFrames) {
surfaceFrame->trace(mToken);
@@ -988,7 +1046,7 @@
StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str());
StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str());
StringAppendF(&result, "Start Metadata: %s\n", toString(mFrameStartMetadata).c_str());
- std::chrono::nanoseconds vsyncPeriod(mVsyncPeriod);
+ std::chrono::nanoseconds vsyncPeriod(mRefreshRate.getPeriodNsecs());
StringAppendF(&result, "Vsync Period: %10f\n",
std::chrono::duration<double, std::milli>(vsyncPeriod).count());
nsecs_t presentDelta =
@@ -996,7 +1054,7 @@
std::chrono::nanoseconds presentDeltaNs(std::abs(presentDelta));
StringAppendF(&result, "Present delta: %10f\n",
std::chrono::duration<double, std::milli>(presentDeltaNs).count());
- std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mVsyncPeriod);
+ std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mRefreshRate.getPeriodNsecs());
StringAppendF(&result, "Present delta %% refreshrate: %10f\n",
std::chrono::duration<double, std::milli>(deltaToVsync).count());
dumpTable(result, mSurfaceFlingerPredictions, mSurfaceFlingerActuals, "", mPredictionState,
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 54e8efb..8f3157d 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -16,6 +16,7 @@
#pragma once
+#include <../Fps.h>
#include <../TimeStats/TimeStats.h>
#include <gui/ISurfaceComposer.h>
#include <gui/JankInfo.h>
@@ -170,34 +171,50 @@
TimelineItem getPredictions() const { return mPredictions; };
// Actual timestamps of the app are set individually at different functions.
// Start time (if the app provides) and Queue time are accessible after queueing the frame,
- // whereas Acquire Fence time is available only during latch.
+ // whereas Acquire Fence time is available only during latch. Drop time is available at the time
+ // the buffer was dropped.
void setActualStartTime(nsecs_t actualStartTime);
void setActualQueueTime(nsecs_t actualQueueTime);
void setAcquireFenceTime(nsecs_t acquireFenceTime);
+ void setDropTime(nsecs_t dropTime);
void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0);
+ void setRenderRate(Fps renderRate);
// Functions called by FrameTimeline
// BaseTime is the smallest timestamp in this SurfaceFrame.
// Used for dumping all timestamps relative to the oldest, making it easy to read.
nsecs_t getBaseTime() const;
// Sets the actual present time, appropriate metadata and classifies the jank.
- void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, nsecs_t vsyncPeriod);
+ // displayRefreshRate, displayDeadlineDelta, and displayPresentDelta are propagated from the
+ // display frame.
+ void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate,
+ nsecs_t displayDeadlineDelta, nsecs_t displayPresentDelta);
// All the timestamps are dumped relative to the baseTime
void dump(std::string& result, const std::string& indent, nsecs_t baseTime) const;
// Emits a packet for perfetto tracing. The function body will be executed only if tracing is
// enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding
// DisplayFrame at the trace processor side.
- void trace(int64_t displayFrameToken);
+ void trace(int64_t displayFrameToken) const;
- // Getter functions used only by FrameTimelineTests
+ // Getter functions used only by FrameTimelineTests and SurfaceFrame internally
TimelineItem getActuals() const;
pid_t getOwnerPid() const { return mOwnerPid; };
- PredictionState getPredictionState() const { return mPredictionState; };
+ PredictionState getPredictionState() const;
PresentState getPresentState() const;
FrameReadyMetadata getFrameReadyMetadata() const;
FramePresentMetadata getFramePresentMetadata() const;
+ nsecs_t getDropTime() const;
+
+ // For prediction expired frames, this delta is subtracted from the actual end time to get a
+ // start time decent enough to see in traces.
+ // TODO(b/172587309): Remove this when we have actual start times.
+ static constexpr nsecs_t kPredictionExpiredStartTimeDelta =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
private:
+ void tracePredictions(int64_t displayFrameToken) const;
+ void traceActuals(int64_t displayFrameToken) const;
+
const int64_t mToken;
const int32_t mInputEventId;
const pid_t mOwnerPid;
@@ -211,11 +228,14 @@
std::shared_ptr<TimeStats> mTimeStats;
const JankClassificationThresholds mJankClassificationThresholds;
nsecs_t mActualQueueTime GUARDED_BY(mMutex) = 0;
+ nsecs_t mDropTime GUARDED_BY(mMutex) = 0;
mutable std::mutex mMutex;
// Bitmask for the type of jank
int32_t mJankType GUARDED_BY(mMutex) = JankType::None;
// Indicates if this frame was composited by the GPU or not
bool mGpuComposition GUARDED_BY(mMutex) = false;
+ // Rendering rate for this frame.
+ std::optional<Fps> mRenderRate GUARDED_BY(mMutex);
// Enum for the type of present
FramePresentMetadata mFramePresentMetadata GUARDED_BY(mMutex) =
FramePresentMetadata::UnknownPresent;
@@ -255,7 +275,7 @@
// The first function called by SF for the current DisplayFrame. Fetches SF predictions based on
// the token and sets the actualSfWakeTime for the current DisplayFrame.
- virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) = 0;
+ virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0;
// Sets the sfPresentTime and finalizes the current DisplayFrame. Tracks the given present fence
// until it's signaled, and updates the present timestamps of all presented SurfaceFrames in
@@ -325,14 +345,13 @@
// is enabled.
void trace(pid_t surfaceFlingerPid) const;
// Sets the token, vsyncPeriod, predictions and SF start time.
- void onSfWakeUp(int64_t token, nsecs_t vsyncPeriod, std::optional<TimelineItem> predictions,
+ void onSfWakeUp(int64_t token, Fps refreshRate, std::optional<TimelineItem> predictions,
nsecs_t wakeUpTime);
// Sets the appropriate metadata, classifies the jank and returns the classified jankType.
void onPresent(nsecs_t signalTime);
// Adds the provided SurfaceFrame to the current display frame.
void addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame);
- void setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod);
void setPredictions(PredictionState predictionState, TimelineItem predictions);
void setActualStartTime(nsecs_t actualStartTime);
void setActualEndTime(nsecs_t actualEndTime);
@@ -353,6 +372,8 @@
private:
void dump(std::string& result, nsecs_t baseTime) const;
+ void tracePredictions(pid_t surfaceFlingerPid) const;
+ void traceActuals(pid_t surfaceFlingerPid) const;
int64_t mToken = FrameTimelineInfo::INVALID_VSYNC_ID;
@@ -382,7 +403,7 @@
FrameStartMetadata mFrameStartMetadata = FrameStartMetadata::UnknownStart;
// The refresh rate (vsync period) in nanoseconds as seen by SF during this DisplayFrame's
// timeline
- nsecs_t mVsyncPeriod = 0;
+ Fps mRefreshRate;
// TraceCookieCounter is used to obtain the cookie for sendig trace packets to perfetto.
// Using a reference here because the counter is owned by FrameTimeline, which outlives
// DisplayFrame.
@@ -398,7 +419,7 @@
const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
std::string layerName, std::string debugName) override;
void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
- void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) override;
+ void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override;
void setSfPresent(nsecs_t sfPresentTime,
const std::shared_ptr<FenceTime>& presentFence) override;
void parseArgs(const Vector<String16>& args, std::string& result) override;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 27b2b87..d2dc206 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1560,6 +1560,7 @@
void Layer::addSurfaceFrameDroppedForBuffer(
std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) {
+ surfaceFrame->setDropTime(systemTime());
surfaceFrame->setPresentState(PresentState::Dropped);
mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
}
@@ -1581,6 +1582,10 @@
// For Transactions, the post time is considered to be both queue and acquire fence time.
surfaceFrame->setActualQueueTime(postTime);
surfaceFrame->setAcquireFenceTime(postTime);
+ const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+ if (fps) {
+ surfaceFrame->setRenderRate(*fps);
+ }
onSurfaceFrameCreated(surfaceFrame);
return surfaceFrame;
}
@@ -1592,6 +1597,10 @@
debugName);
// For buffers, acquire fence time will set during latch.
surfaceFrame->setActualQueueTime(queueTime);
+ const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+ if (fps) {
+ surfaceFrame->setRenderRate(*fps);
+ }
// TODO(b/178542907): Implement onSurfaceFrameCreated for BQLayer as well.
onSurfaceFrameCreated(surfaceFrame);
return surfaceFrame;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 273601f..687f473 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1010,6 +1010,7 @@
friend class TestableSurfaceFlinger;
friend class RefreshRateSelectionTest;
friend class SetFrameRateTest;
+ friend class TransactionFrameTracerTest;
friend class TransactionSurfaceFrameTest;
virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
@@ -1144,9 +1145,6 @@
// Window types from WindowManager.LayoutParams
const InputWindowInfo::Type mWindowType;
- // Can only be accessed with the SF state lock held.
- std::shared_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
-
// The owner of the layer. If created from a non system process, it will be the calling uid.
// If created from a system process, the value can be passed in.
uid_t mOwnerUid;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 49ffc81..b29c624 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -125,6 +125,9 @@
GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
GRALLOC_USAGE_HW_TEXTURE,
"RefreshRateOverlayBuffer");
+ const status_t bufferStatus = buffer->initCheck();
+ LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
+ bufferStatus);
uint8_t* pixels;
buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
// Clear buffer content
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 9186538..09615f9 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -447,6 +447,9 @@
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(),
PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+ const status_t bufferStatus = buffer->initCheck();
+ LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d",
+ bufferStatus);
}
const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index e7a44a7..a03f793 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -627,6 +627,8 @@
std::vector<const RefreshRate*> sortedModes;
getSortedRefreshRateListLocked([](const RefreshRate&) { return true; }, &sortedModes);
+ // Reset the policy because the old one may no longer be valid.
+ mDisplayManagerPolicy = {};
mDisplayManagerPolicy.defaultMode = currentModeId;
mMinSupportedRefreshRate = sortedModes.front();
mMaxSupportedRefreshRate = sortedModes.back();
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 5237516..0e9eba7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -174,6 +174,8 @@
// Stores the preferred refresh rate that an app should run at.
// FrameRateOverride.refreshRateHz == 0 means no preference.
void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesMutex);
+ // Retrieves the overridden refresh rate for a given uid.
+ std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex);
private:
friend class TestableScheduler;
@@ -236,7 +238,6 @@
Fps displayRefreshRate) REQUIRES(mFeatureStateLock)
EXCLUDES(mFrameRateOverridesMutex);
- std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex);
impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const;
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a36502c..cb9fae3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1899,7 +1899,7 @@
const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);
- mFrameTimeline->setSfWakeUp(vsyncId, frameStart, stats.vsyncPeriod);
+ mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod));
refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
@@ -5851,6 +5851,10 @@
getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
static_cast<android_pixel_format>(reqPixelFormat),
1 /* layerCount */, usage, "screenshot");
+
+ const status_t bufferStatus = buffer->initCheck();
+ LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d",
+ bufferStatus);
return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
false /* regionSampling */, grayscale, captureListener);
}
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index 1d1f0c5..b4d8a9a 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -71,12 +71,14 @@
}
void SurfaceTracing::notify(const char* where) {
+ std::scoped_lock lock(mTraceLock);
if (mEnabled) {
runner->notify(where);
}
}
void SurfaceTracing::notifyLocked(const char* where) {
+ std::scoped_lock lock(mTraceLock);
if (mEnabled) {
runner->notifyLocked(where);
}
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 497ebd3..15a503d 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -81,8 +81,8 @@
SurfaceFlinger& mFlinger;
mutable std::mutex mTraceLock;
- bool mEnabled = false;
- std::unique_ptr<Runner> runner;
+ bool mEnabled GUARDED_BY(mTraceLock) = false;
+ std::unique_ptr<Runner> runner GUARDED_BY(mTraceLock);
struct Config {
uint32_t flags = TRACE_CRITICAL | TRACE_INPUT | TRACE_SYNC;
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index 0a23da2..62fddb4 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libtimestats",
srcs: [
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 5d387d6..b93f30e 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -105,53 +105,63 @@
AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
std::lock_guard<std::mutex> lock(mMutex);
- if (mTimeStats.statsStart == 0) {
+ if (mTimeStats.statsStartLegacy == 0) {
return AStatsManager_PULL_SKIP;
}
flushPowerTimeLocked();
- AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
- mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount);
- std::string frameDurationBytes =
- histogramToProtoByteString(mTimeStats.frameDuration.hist, mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
- frameDurationBytes.size());
- std::string renderEngineTimingBytes =
- histogramToProtoByteString(mTimeStats.renderEngineTiming.hist,
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(),
- renderEngineTimingBytes.size());
+ for (const auto& globalSlice : mTimeStats.stats) {
+ AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
+ mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFramesLegacy);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFramesLegacy);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFramesLegacy);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTimeLegacy);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresentLegacy.totalTime());
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCountLegacy);
+ std::string frameDurationBytes =
+ histogramToProtoByteString(mTimeStats.frameDurationLegacy.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
+ frameDurationBytes.size());
+ std::string renderEngineTimingBytes =
+ histogramToProtoByteString(mTimeStats.renderEngineTimingLegacy.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event,
+ (const uint8_t*)renderEngineTimingBytes.c_str(),
+ renderEngineTimingBytes.size());
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalFrames);
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalJankyFrames);
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongCpu);
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongGpu);
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFUnattributed);
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalAppUnattributed);
+ mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalFrames);
+ mStatsDelegate->statsEventWriteInt32(event,
+ globalSlice.second.jankPayload.totalJankyFrames);
+ mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongCpu);
+ mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongGpu);
+ mStatsDelegate->statsEventWriteInt32(event,
+ globalSlice.second.jankPayload.totalSFUnattributed);
+ mStatsDelegate->statsEventWriteInt32(event,
+ globalSlice.second.jankPayload.totalAppUnattributed);
- // TODO: populate these with real values
- mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling
- mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error
- mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing
- mStatsDelegate->statsEventWriteInt32(event, 0); // display_refresh_rate_bucket
- std::string sfDeadlineMissedBytes =
- histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)sfDeadlineMissedBytes.c_str(),
- sfDeadlineMissedBytes.size()); // sf_deadline_misses
- std::string sfPredictionErrorBytes =
- histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
- mMaxPulledHistogramBuckets);
- mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)sfPredictionErrorBytes.c_str(),
- sfPredictionErrorBytes.size()); // sf_prediction_errors
- mStatsDelegate->statsEventWriteInt32(event, 0); // render_rate_bucket
- mStatsDelegate->statsEventBuild(event);
+ // TODO: populate these with real values
+ mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling
+ mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error
+ mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing
+ mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.displayRefreshRateBucket);
+ std::string sfDeadlineMissedBytes =
+ histogramToProtoByteString(globalSlice.second.displayDeadlineDeltas.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event,
+ (const uint8_t*)sfDeadlineMissedBytes.c_str(),
+ sfDeadlineMissedBytes.size());
+ std::string sfPredictionErrorBytes =
+ histogramToProtoByteString(globalSlice.second.displayPresentDeltas.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event,
+ (const uint8_t*)sfPredictionErrorBytes.c_str(),
+ sfPredictionErrorBytes.size());
+ mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.renderRateBucket);
+ mStatsDelegate->statsEventBuild(event);
+ }
+
clearGlobalLocked();
return AStatsManager_PULL_SUCCESS;
@@ -160,9 +170,18 @@
AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) {
std::lock_guard<std::mutex> lock(mMutex);
- std::vector<TimeStatsHelper::TimeStatsLayer const*> dumpStats;
- for (const auto& ele : mTimeStats.stats) {
- dumpStats.push_back(&ele.second);
+ std::vector<TimeStatsHelper::TimeStatsLayer*> dumpStats;
+ uint32_t numLayers = 0;
+ for (const auto& globalSlice : mTimeStats.stats) {
+ numLayers += globalSlice.second.stats.size();
+ }
+
+ dumpStats.reserve(numLayers);
+
+ for (auto& globalSlice : mTimeStats.stats) {
+ for (auto& layerSlice : globalSlice.second.stats) {
+ dumpStats.push_back(&layerSlice.second);
+ }
}
std::sort(dumpStats.begin(), dumpStats.end(),
@@ -175,7 +194,7 @@
dumpStats.resize(mMaxPulledLayers);
}
- for (const auto& layer : dumpStats) {
+ for (auto& layer : dumpStats) {
AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_LAYER_INFO);
mStatsDelegate->statsEventWriteString8(event, layer->layerName.c_str());
@@ -208,17 +227,18 @@
mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling
mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error
mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing
- mStatsDelegate->statsEventWriteInt32(event, 0); // display_refresh_rate_bucket
- mStatsDelegate->statsEventWriteInt32(event, 0); // render_rate_bucket
+ mStatsDelegate->statsEventWriteInt32(
+ event, layer->displayRefreshRateBucket); // display_refresh_rate_bucket
+ mStatsDelegate->statsEventWriteInt32(event, layer->renderRateBucket); // render_rate_bucket
std::string frameRateVoteBytes = frameRateVoteToProtoByteString(0.0, 0, 0);
mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameRateVoteBytes.c_str(),
frameRateVoteBytes.size()); // set_frame_rate_vote
std::string appDeadlineMissedBytes =
- histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
+ histogramToProtoByteString(layer->deltas["appDeadlineDeltas"].hist,
mMaxPulledHistogramBuckets);
- mStatsDelegate
- ->statsEventWriteByteArray(event, (const uint8_t*)appDeadlineMissedBytes.c_str(),
- appDeadlineMissedBytes.size()); // app_deadline_misses
+ mStatsDelegate->statsEventWriteByteArray(event,
+ (const uint8_t*)appDeadlineMissedBytes.c_str(),
+ appDeadlineMissedBytes.size());
mStatsDelegate->statsEventBuild(event);
}
@@ -310,7 +330,7 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.totalFrames++;
+ mTimeStats.totalFramesLegacy++;
}
void TimeStats::incrementMissedFrames() {
@@ -319,7 +339,7 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.missedFrames++;
+ mTimeStats.missedFramesLegacy++;
}
void TimeStats::incrementClientCompositionFrames() {
@@ -328,7 +348,7 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionFrames++;
+ mTimeStats.clientCompositionFramesLegacy++;
}
void TimeStats::incrementClientCompositionReusedFrames() {
@@ -337,7 +357,7 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionReusedFrames++;
+ mTimeStats.clientCompositionReusedFramesLegacy++;
}
void TimeStats::incrementRefreshRateSwitches() {
@@ -346,7 +366,7 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.refreshRateSwitches++;
+ mTimeStats.refreshRateSwitchesLegacy++;
}
void TimeStats::incrementCompositionStrategyChanges() {
@@ -355,7 +375,7 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.compositionStrategyChanges++;
+ mTimeStats.compositionStrategyChangesLegacy++;
}
void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
@@ -364,8 +384,8 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.displayEventConnectionsCount =
- std::max(mTimeStats.displayEventConnectionsCount, count);
+ mTimeStats.displayEventConnectionsCountLegacy =
+ std::max(mTimeStats.displayEventConnectionsCountLegacy, count);
}
static int32_t msBetween(nsecs_t start, nsecs_t end) {
@@ -381,7 +401,7 @@
std::lock_guard<std::mutex> lock(mMutex);
if (mPowerTime.powerMode == PowerMode::ON) {
- mTimeStats.frameDuration.insert(msBetween(startTime, endTime));
+ mTimeStats.frameDurationLegacy.insert(msBetween(startTime, endTime));
}
}
@@ -444,12 +464,22 @@
return true;
}
-void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId) {
+static int32_t clampToSmallestBucket(Fps fps, size_t bucketWidth) {
+ return (fps.getIntValue() / bucketWidth) * bucketWidth;
+}
+
+void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
+ std::optional<Fps> renderRate) {
ATRACE_CALL();
LayerRecord& layerRecord = mTimeStatsTracker[layerId];
TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
+ const int32_t refreshRateBucket =
+ clampToSmallestBucket(displayRefreshRate, REFRESH_RATE_BUCKET_WIDTH);
+ const int32_t renderRateBucket =
+ clampToSmallestBucket(renderRate ? *renderRate : displayRefreshRate,
+ RENDER_RATE_BUCKET_WIDTH);
while (!timeRecords.empty()) {
if (!recordReadyLocked(layerId, &timeRecords[0])) break;
ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerId,
@@ -458,11 +488,21 @@
if (prevTimeRecord.ready) {
uid_t uid = layerRecord.uid;
const std::string& layerName = layerRecord.layerName;
- if (!mTimeStats.stats.count({uid, layerName})) {
- mTimeStats.stats[{uid, layerName}].uid = uid;
- mTimeStats.stats[{uid, layerName}].layerName = layerName;
+ TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
+ if (!mTimeStats.stats.count(timelineKey)) {
+ mTimeStats.stats[timelineKey].key = timelineKey;
}
- TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[{uid, layerName}];
+
+ TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey];
+
+ TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName};
+ if (!displayStats.stats.count(layerKey)) {
+ displayStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
+ displayStats.stats[layerKey].renderRateBucket = renderRateBucket;
+ displayStats.stats[layerKey].uid = uid;
+ displayStats.stats[layerKey].layerName = layerName;
+ }
+ TimeStatsHelper::TimeStatsLayer& timeStatsLayer = displayStats.stats[layerKey];
timeStatsLayer.totalFrames++;
timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
timeStatsLayer.lateAcquireFrames += layerRecord.lateAcquireFrames;
@@ -524,8 +564,16 @@
}
bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName) {
- return mTimeStats.stats.count({uid, layerName}) > 0 ||
- mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
+ uint32_t layerRecords = 0;
+ for (const auto& record : mTimeStats.stats) {
+ if (record.second.stats.count({uid, layerName}) > 0) {
+ return true;
+ }
+
+ layerRecords += record.second.stats.size();
+ }
+
+ return mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
}
void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
@@ -676,7 +724,8 @@
}
}
-void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) {
+void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+ Fps displayRefreshRate, std::optional<Fps> renderRate) {
if (!mEnabled.load()) return;
ATRACE_CALL();
@@ -695,11 +744,12 @@
layerRecord.waitData++;
}
- flushAvailableRecordsToStatsLocked(layerId);
+ flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate);
}
void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& presentFence) {
+ const std::shared_ptr<FenceTime>& presentFence,
+ Fps displayRefreshRate, std::optional<Fps> renderRate) {
if (!mEnabled.load()) return;
ATRACE_CALL();
@@ -719,16 +769,17 @@
layerRecord.waitData++;
}
- flushAvailableRecordsToStatsLocked(layerId);
+ flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate);
}
+static const constexpr int32_t kValidJankyReason = JankType::SurfaceFlingerCpuDeadlineMissed |
+ JankType::SurfaceFlingerGpuDeadlineMissed | JankType::AppDeadlineMissed |
+ JankType::DisplayHAL;
+
template <class T>
static void updateJankPayload(T& t, int32_t reasons) {
t.jankPayload.totalFrames++;
- static const constexpr int32_t kValidJankyReason = JankType::SurfaceFlingerCpuDeadlineMissed |
- JankType::SurfaceFlingerGpuDeadlineMissed | JankType::AppDeadlineMissed |
- JankType::DisplayHAL;
if (reasons & kValidJankyReason) {
t.jankPayload.totalJankyFrames++;
if ((reasons & JankType::SurfaceFlingerCpuDeadlineMissed) != 0) {
@@ -746,16 +797,7 @@
}
}
-void TimeStats::incrementJankyFrames(int32_t reasons) {
- if (!mEnabled.load()) return;
-
- ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mMutex);
-
- updateJankPayload<TimeStatsHelper::TimeStatsGlobal>(mTimeStats, reasons);
-}
-
-void TimeStats::incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) {
+void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) {
if (!mEnabled.load()) return;
ATRACE_CALL();
@@ -772,17 +814,44 @@
// TimeStats will flush the first present fence for a layer *before* FrameTimeline does so that
// the first jank record is not dropped.
- bool useDefaultLayerKey = false;
static const std::string kDefaultLayerName = "none";
- if (!mTimeStats.stats.count({uid, layerName})) {
- mTimeStats.stats[{uid, kDefaultLayerName}].uid = uid;
- mTimeStats.stats[{uid, kDefaultLayerName}].layerName = kDefaultLayerName;
- useDefaultLayerKey = true;
+
+ const int32_t refreshRateBucket =
+ clampToSmallestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH);
+ const int32_t renderRateBucket =
+ clampToSmallestBucket(info.renderRate ? *info.renderRate : info.refreshRate,
+ RENDER_RATE_BUCKET_WIDTH);
+ const TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
+
+ if (!mTimeStats.stats.count(timelineKey)) {
+ mTimeStats.stats[timelineKey].key = timelineKey;
}
- TimeStatsHelper::TimeStatsLayer& timeStatsLayer =
- mTimeStats.stats[{uid, useDefaultLayerKey ? kDefaultLayerName : layerName}];
- updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, reasons);
+ TimeStatsHelper::TimelineStats& timelineStats = mTimeStats.stats[timelineKey];
+
+ updateJankPayload<TimeStatsHelper::TimelineStats>(timelineStats, info.reasons);
+
+ TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName};
+ if (!timelineStats.stats.count(layerKey)) {
+ layerKey = {info.uid, kDefaultLayerName};
+ timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
+ timelineStats.stats[layerKey].renderRateBucket = renderRateBucket;
+ timelineStats.stats[layerKey].uid = info.uid;
+ timelineStats.stats[layerKey].layerName = kDefaultLayerName;
+ }
+
+ TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey];
+ updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, info.reasons);
+
+ if (info.reasons & kValidJankyReason) {
+ // TimeStats Histograms only retain positive values, so we don't need to check if these
+ // deadlines were really missed if we know that the frame had jank, since deadlines
+ // that were met will be dropped.
+ timelineStats.displayDeadlineDeltas.insert(static_cast<int32_t>(info.displayDeadlineDelta));
+ timelineStats.displayPresentDeltas.insert(static_cast<int32_t>(info.displayPresentJitter));
+ timeStatsLayer.deltas["appDeadlineDeltas"].insert(
+ static_cast<int32_t>(info.appDeadlineDelta));
+ }
}
void TimeStats::onDestroy(int32_t layerId) {
@@ -823,7 +892,7 @@
switch (mPowerTime.powerMode) {
case PowerMode::ON:
- mTimeStats.displayOnTime += elapsedTime;
+ mTimeStats.displayOnTimeLegacy += elapsedTime;
break;
case PowerMode::OFF:
case PowerMode::DOZE:
@@ -852,10 +921,10 @@
void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) {
std::lock_guard<std::mutex> lock(mMutex);
- if (mTimeStats.refreshRateStats.count(fps)) {
- mTimeStats.refreshRateStats[fps] += duration;
+ if (mTimeStats.refreshRateStatsLegacy.count(fps)) {
+ mTimeStats.refreshRateStatsLegacy[fps] += duration;
} else {
- mTimeStats.refreshRateStats.insert({fps, duration});
+ mTimeStats.refreshRateStatsLegacy.insert({fps, duration});
}
}
@@ -881,7 +950,7 @@
msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
- mTimeStats.presentToPresent.insert(presentToPresentMs);
+ mTimeStats.presentToPresentLegacy.insert(presentToPresentMs);
}
mGlobalRecord.prevPresentTime = curPresentTime;
@@ -908,7 +977,7 @@
}
const int32_t renderEngineMs = msBetween(duration.startTime, endNs);
- mTimeStats.renderEngineTiming.insert(renderEngineMs);
+ mTimeStats.renderEngineTimingLegacy.insert(renderEngineMs);
mGlobalRecord.renderEngineDurations.pop_front();
}
@@ -951,7 +1020,7 @@
std::lock_guard<std::mutex> lock(mMutex);
mEnabled.store(true);
- mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsStartLegacy = static_cast<int64_t>(std::time(0));
mPowerTime.prevTime = systemTime();
ALOGD("Enabled");
}
@@ -964,7 +1033,7 @@
std::lock_guard<std::mutex> lock(mMutex);
flushPowerTimeLocked();
mEnabled.store(false);
- mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
ALOGD("Disabled");
}
@@ -977,21 +1046,20 @@
void TimeStats::clearGlobalLocked() {
ATRACE_CALL();
- mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
- mTimeStats.statsEnd = 0;
- mTimeStats.totalFrames = 0;
- mTimeStats.missedFrames = 0;
- mTimeStats.clientCompositionFrames = 0;
- mTimeStats.clientCompositionReusedFrames = 0;
- mTimeStats.refreshRateSwitches = 0;
- mTimeStats.compositionStrategyChanges = 0;
- mTimeStats.displayEventConnectionsCount = 0;
- mTimeStats.displayOnTime = 0;
- mTimeStats.presentToPresent.hist.clear();
- mTimeStats.frameDuration.hist.clear();
- mTimeStats.renderEngineTiming.hist.clear();
- mTimeStats.jankPayload = TimeStatsHelper::JankPayload();
- mTimeStats.refreshRateStats.clear();
+ mTimeStats.statsStartLegacy = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
+ mTimeStats.statsEndLegacy = 0;
+ mTimeStats.totalFramesLegacy = 0;
+ mTimeStats.missedFramesLegacy = 0;
+ mTimeStats.clientCompositionFramesLegacy = 0;
+ mTimeStats.clientCompositionReusedFramesLegacy = 0;
+ mTimeStats.refreshRateSwitchesLegacy = 0;
+ mTimeStats.compositionStrategyChangesLegacy = 0;
+ mTimeStats.displayEventConnectionsCountLegacy = 0;
+ mTimeStats.displayOnTimeLegacy = 0;
+ mTimeStats.presentToPresentLegacy.hist.clear();
+ mTimeStats.frameDurationLegacy.hist.clear();
+ mTimeStats.renderEngineTimingLegacy.hist.clear();
+ mTimeStats.refreshRateStatsLegacy.clear();
mPowerTime.prevTime = systemTime();
mGlobalRecord.prevPresentTime = 0;
mGlobalRecord.presentFences.clear();
@@ -1014,11 +1082,11 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- if (mTimeStats.statsStart == 0) {
+ if (mTimeStats.statsStartLegacy == 0) {
return;
}
- mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+ mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
flushPowerTimeLocked();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index df40ef6..fd112b9 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -27,12 +27,13 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
+#include <../Fps.h>
+#include <gui/JankInfo.h>
#include <stats_event.h>
#include <stats_pull_atom_callback.h>
#include <statslog.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
-#include <gui/JankInfo.h>
#include <ui/FenceTime.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -108,23 +109,60 @@
const std::shared_ptr<FenceTime>& acquireFence) = 0;
// SetPresent{Time, Fence} are not expected to be called in the critical
// rendering path, as they flush prior fences if those fences have fired.
- virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) = 0;
+ virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+ Fps displayRefreshRate, std::optional<Fps> renderRate) = 0;
virtual void setPresentFence(int32_t layerId, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& presentFence) = 0;
+ const std::shared_ptr<FenceTime>& presentFence,
+ Fps displayRefreshRate, std::optional<Fps> renderRate) = 0;
- // Increments janky frames, tracked globally. Because FrameTimeline is the infrastructure
- // responsible for computing jank in the system, this is expected to be called from
- // FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there are no
- // jank reasons, then total frames are incremented but jank is not, for accurate accounting of
- // janky frames.
- virtual void incrementJankyFrames(int32_t reasons) = 0;
- // Increments janky frames, blamed to the provided {uid, layerName} key, with JankMetadata as
- // supplementary reasons for the jank. Because FrameTimeline is the infrastructure responsible
- // for computing jank in the system, this is expected to be called from FrameTimeline, rather
- // than directly from SurfaceFlinger or individual layers.
- // If there are no jank reasons, then total frames are incremented but jank is not, for accurate
+ // Increments janky frames, blamed to the provided {refreshRate, renderRate, uid, layerName}
+ // key, with JankMetadata as supplementary reasons for the jank. Because FrameTimeline is the
+ // infrastructure responsible for computing jank in the system, this is expected to be called
+ // from FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there
+ // are no jank reasons, then total frames are incremented but jank is not, for accurate
// accounting of janky frames.
- virtual void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) = 0;
+ // displayDeadlineDelta, displayPresentJitter, and appDeadlineDelta are also provided in order
+ // to provide contextual information about a janky frame. These values may only be uploaded if
+ // there was an associated valid jank reason, and they must be positive. When these frame counts
+ // are incremented, these are also aggregated into a global reporting packet to help with data
+ // validation and assessing of overall device health.
+ struct JankyFramesInfo {
+ Fps refreshRate;
+ std::optional<Fps> renderRate;
+ uid_t uid = 0;
+ std::string layerName;
+ int32_t reasons = 0;
+ nsecs_t displayDeadlineDelta = 0;
+ nsecs_t displayPresentJitter = 0;
+ nsecs_t appDeadlineDelta = 0;
+
+ bool operator==(const JankyFramesInfo& o) const {
+ return Fps::EqualsInBuckets{}(refreshRate, o.refreshRate) &&
+ ((renderRate == std::nullopt && o.renderRate == std::nullopt) ||
+ (renderRate != std::nullopt && o.renderRate != std::nullopt &&
+ Fps::EqualsInBuckets{}(*renderRate, *o.renderRate))) &&
+ uid == o.uid && layerName == o.layerName && reasons == o.reasons &&
+ displayDeadlineDelta == o.displayDeadlineDelta &&
+ displayPresentJitter == o.displayPresentJitter &&
+ appDeadlineDelta == o.appDeadlineDelta;
+ }
+
+ friend std::ostream& operator<<(std::ostream& os, const JankyFramesInfo& info) {
+ os << "JankyFramesInfo {";
+ os << "\n .refreshRate = " << info.refreshRate;
+ os << "\n .renderRate = "
+ << (info.renderRate ? to_string(*info.renderRate) : "nullopt");
+ os << "\n .uid = " << info.uid;
+ os << "\n .layerName = " << info.layerName;
+ os << "\n .reasons = " << info.reasons;
+ os << "\n .displayDeadlineDelta = " << info.displayDeadlineDelta;
+ os << "\n .displayPresentJitter = " << info.displayPresentJitter;
+ os << "\n .appDeadlineDelta = " << info.appDeadlineDelta;
+ return os << "\n}";
+ }
+ };
+
+ virtual void incrementJankyFrames(const JankyFramesInfo& info) = 0;
// Clean up the layer record
virtual void onDestroy(int32_t layerId) = 0;
// If SF skips or rejects a buffer, remove the corresponding TimeRecord.
@@ -268,11 +306,13 @@
void setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) override;
void setAcquireFence(int32_t layerId, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& acquireFence) override;
- void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) override;
+ void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+ Fps displayRefreshRate, std::optional<Fps> renderRate) override;
void setPresentFence(int32_t layerId, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& presentFence) override;
- void incrementJankyFrames(int32_t reasons) override;
- void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) override;
+ const std::shared_ptr<FenceTime>& presentFence, Fps displayRefreshRate,
+ std::optional<Fps> renderRate) override;
+
+ void incrementJankyFrames(const JankyFramesInfo& info) override;
// Clean up the layer record
void onDestroy(int32_t layerId) override;
// If SF skips or rejects a buffer, remove the corresponding TimeRecord.
@@ -293,7 +333,8 @@
AStatsManager_PullAtomCallbackReturn populateGlobalAtom(AStatsEventList* data);
AStatsManager_PullAtomCallbackReturn populateLayerAtom(AStatsEventList* data);
bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
- void flushAvailableRecordsToStatsLocked(int32_t layerId);
+ void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
+ std::optional<Fps> renderRate);
void flushPowerTimeLocked();
void flushAvailableGlobalRecordsToStatsLocked();
bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName);
@@ -314,6 +355,9 @@
GlobalRecord mGlobalRecord;
static const size_t MAX_NUM_LAYER_RECORDS = 200;
+
+ static const size_t REFRESH_RATE_BUCKET_WIDTH = 30;
+ static const size_t RENDER_RATE_BUCKET_WIDTH = REFRESH_RATE_BUCKET_WIDTH;
static const size_t MAX_NUM_LAYER_STATS = 200;
static const size_t MAX_NUM_PULLED_LAYERS = MAX_NUM_LAYER_STATS;
std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>();
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
index 9481cac..972edaa 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "libtimestats_proto",
export_include_dirs: ["include"],
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 0fb748f..814f046 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -41,7 +41,7 @@
if (delta < 0) return;
// std::lower_bound won't work on out of range values
if (delta > histogramConfig[HISTOGRAM_SIZE - 1]) {
- hist[histogramConfig[HISTOGRAM_SIZE - 1]] += delta / histogramConfig[HISTOGRAM_SIZE - 1];
+ hist[histogramConfig[HISTOGRAM_SIZE - 1]]++;
return;
}
auto iter = std::lower_bound(histogramConfig.begin(), histogramConfig.end(), delta);
@@ -90,6 +90,8 @@
std::string TimeStatsHelper::TimeStatsLayer::toString() const {
std::string result = "\n";
+ StringAppendF(&result, "displayRefreshRate = %d fps\n", displayRefreshRateBucket);
+ StringAppendF(&result, "renderRate = %d fps\n", renderRateBucket);
StringAppendF(&result, "uid = %d\n", uid);
StringAppendF(&result, "layerName = %s\n", layerName.c_str());
StringAppendF(&result, "packageName = %s\n", packageName.c_str());
@@ -115,35 +117,49 @@
std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> maxLayers) const {
std::string result = "SurfaceFlinger TimeStats:\n";
- StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStart);
- StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEnd);
- StringAppendF(&result, "totalFrames = %d\n", totalFrames);
- StringAppendF(&result, "missedFrames = %d\n", missedFrames);
- StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
- StringAppendF(&result, "clientCompositionReusedFrames = %d\n", clientCompositionReusedFrames);
- StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitches);
- StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChanges);
- StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
- result.append("Global aggregated jank payload:\n");
- result.append(jankPayload.toString());
+ result.append("Legacy stats are as follows:\n");
+ StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStartLegacy);
+ StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEndLegacy);
+ StringAppendF(&result, "totalFrames = %d\n", totalFramesLegacy);
+ StringAppendF(&result, "missedFrames = %d\n", missedFramesLegacy);
+ StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFramesLegacy);
+ StringAppendF(&result, "clientCompositionReusedFrames = %d\n",
+ clientCompositionReusedFramesLegacy);
+ StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy);
+ StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy);
+ StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy);
StringAppendF(&result, "displayConfigStats is as below:\n");
- for (const auto& [fps, duration] : refreshRateStats) {
+ for (const auto& [fps, duration] : refreshRateStatsLegacy) {
StringAppendF(&result, "%dfps = %ldms\n", fps, ns2ms(duration));
}
result.back() = '\n';
- StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
+ StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresentLegacy.totalTime());
StringAppendF(&result, "presentToPresent histogram is as below:\n");
- result.append(presentToPresent.toString());
- const float averageFrameDuration = frameDuration.averageTime();
+ result.append(presentToPresentLegacy.toString());
+ const float averageFrameDuration = frameDurationLegacy.averageTime();
StringAppendF(&result, "averageFrameDuration = %.3f ms\n",
std::isnan(averageFrameDuration) ? 0.0f : averageFrameDuration);
StringAppendF(&result, "frameDuration histogram is as below:\n");
- result.append(frameDuration.toString());
- const float averageRenderEngineTiming = renderEngineTiming.averageTime();
+ result.append(frameDurationLegacy.toString());
+ const float averageRenderEngineTiming = renderEngineTimingLegacy.averageTime();
StringAppendF(&result, "averageRenderEngineTiming = %.3f ms\n",
std::isnan(averageRenderEngineTiming) ? 0.0f : averageRenderEngineTiming);
StringAppendF(&result, "renderEngineTiming histogram is as below:\n");
- result.append(renderEngineTiming.toString());
+ result.append(renderEngineTimingLegacy.toString());
+
+ result.append("\nGlobal aggregated jank payload (Timeline stats):");
+ for (const auto& ele : stats) {
+ result.append("\n");
+ StringAppendF(&result, "displayRefreshRate = %d fps\n",
+ ele.second.key.displayRefreshRateBucket);
+ StringAppendF(&result, "renderRate = %d fps\n", ele.second.key.renderRateBucket);
+ result.append(ele.second.jankPayload.toString());
+ StringAppendF(&result, "sfDeadlineMisses histogram is as below:\n");
+ result.append(ele.second.displayDeadlineDeltas.toString());
+ StringAppendF(&result, "sfPredictionErrors histogram is as below:\n");
+ result.append(ele.second.displayPresentDeltas.toString());
+ }
+
const auto dumpStats = generateDumpStats(maxLayers);
for (const auto& ele : dumpStats) {
result.append(ele->toString());
@@ -173,30 +189,30 @@
SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto(
std::optional<uint32_t> maxLayers) const {
SFTimeStatsGlobalProto globalProto;
- globalProto.set_stats_start(statsStart);
- globalProto.set_stats_end(statsEnd);
- globalProto.set_total_frames(totalFrames);
- globalProto.set_missed_frames(missedFrames);
- globalProto.set_client_composition_frames(clientCompositionFrames);
- globalProto.set_display_on_time(displayOnTime);
- for (const auto& ele : refreshRateStats) {
+ globalProto.set_stats_start(statsStartLegacy);
+ globalProto.set_stats_end(statsEndLegacy);
+ globalProto.set_total_frames(totalFramesLegacy);
+ globalProto.set_missed_frames(missedFramesLegacy);
+ globalProto.set_client_composition_frames(clientCompositionFramesLegacy);
+ globalProto.set_display_on_time(displayOnTimeLegacy);
+ for (const auto& ele : refreshRateStatsLegacy) {
SFTimeStatsDisplayConfigBucketProto* configBucketProto =
globalProto.add_display_config_stats();
SFTimeStatsDisplayConfigProto* configProto = configBucketProto->mutable_config();
configProto->set_fps(ele.first);
configBucketProto->set_duration_millis(ns2ms(ele.second));
}
- for (const auto& histEle : presentToPresent.hist) {
+ for (const auto& histEle : presentToPresentLegacy.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
}
- for (const auto& histEle : frameDuration.hist) {
+ for (const auto& histEle : frameDurationLegacy.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_frame_duration();
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
}
- for (const auto& histEle : renderEngineTiming.hist) {
+ for (const auto& histEle : renderEngineTimingLegacy.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_render_engine_timing();
histProto->set_time_millis(histEle.first);
histProto->set_frame_count(histEle.second);
@@ -212,8 +228,18 @@
std::vector<TimeStatsHelper::TimeStatsLayer const*>
TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const {
std::vector<TimeStatsLayer const*> dumpStats;
+
+ int numLayers = 0;
for (const auto& ele : stats) {
- dumpStats.push_back(&ele.second);
+ numLayers += ele.second.stats.size();
+ }
+
+ dumpStats.reserve(numLayers);
+
+ for (const auto& ele : stats) {
+ for (const auto& layerEle : ele.second.stats) {
+ dumpStats.push_back(&layerEle.second);
+ }
}
std::sort(dumpStats.begin(), dumpStats.end(),
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 033eb5d..38ee888 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -57,6 +57,8 @@
uid_t uid;
std::string layerName;
std::string packageName;
+ int32_t displayRefreshRateBucket = 0;
+ int32_t renderRateBucket = 0;
int32_t totalFrames = 0;
int32_t droppedFrames = 0;
int32_t lateAcquireFrames = 0;
@@ -68,32 +70,84 @@
SFTimeStatsLayerProto toProto() const;
};
- class TimeStatsGlobal {
- public:
- int64_t statsStart = 0;
- int64_t statsEnd = 0;
- int32_t totalFrames = 0;
- int32_t missedFrames = 0;
- int32_t clientCompositionFrames = 0;
- int32_t clientCompositionReusedFrames = 0;
- int32_t refreshRateSwitches = 0;
- int32_t compositionStrategyChanges = 0;
- int32_t displayEventConnectionsCount = 0;
- int64_t displayOnTime = 0;
- Histogram presentToPresent;
- Histogram frameDuration;
- Histogram renderEngineTiming;
+ // Lifted from SkiaGLRenderEngine's LinearEffect class.
+ // Which in turn was inspired by art/runtime/class_linker.cc
+ // Also this is what boost:hash_combine does so this is a pretty good hash.
+ static size_t HashCombine(size_t seed, size_t val) {
+ return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2));
+ }
- struct StatsHasher {
- size_t operator()(const std::pair<uid_t, std::string>& p) const {
- // Normally this isn't a very good hash function due to symmetry reasons,
- // but these are distinct types so this should be good enough
- return std::hash<uid_t>{}(p.first) ^ std::hash<std::string>{}(p.second);
+ struct TimelineStatsKey {
+ int32_t displayRefreshRateBucket = 0;
+ int32_t renderRateBucket = 0;
+
+ struct Hasher {
+ size_t operator()(const TimelineStatsKey& key) const {
+ size_t result = std::hash<int32_t>{}(key.displayRefreshRateBucket);
+ return HashCombine(result, std::hash<int32_t>{}(key.renderRateBucket));
}
};
- std::unordered_map<std::pair<uid_t, std::string>, TimeStatsLayer, StatsHasher> stats;
- std::unordered_map<uint32_t, nsecs_t> refreshRateStats;
+
+ bool operator==(const TimelineStatsKey& o) const {
+ return displayRefreshRateBucket == o.displayRefreshRateBucket &&
+ renderRateBucket == o.renderRateBucket;
+ }
+ };
+
+ struct LayerStatsKey {
+ uid_t uid = 0;
+ std::string layerName;
+
+ struct Hasher {
+ size_t operator()(const LayerStatsKey& key) const {
+ size_t result = std::hash<uid_t>{}(key.uid);
+ return HashCombine(result, std::hash<std::string>{}(key.layerName));
+ }
+ };
+
+ bool operator==(const LayerStatsKey& o) const {
+ return uid == o.uid && layerName == o.layerName;
+ }
+ };
+
+ struct LayerStatsHasher {
+ size_t operator()(const std::pair<uid_t, std::string>& p) const {
+ // Normally this isn't a very good hash function due to symmetry reasons,
+ // but these are distinct types so this should be good enough
+ return std::hash<uid_t>{}(p.first) ^ std::hash<std::string>{}(p.second);
+ }
+ };
+
+ struct TimelineStats {
+ TimelineStatsKey key;
JankPayload jankPayload;
+ Histogram displayDeadlineDeltas;
+ Histogram displayPresentDeltas;
+ std::unordered_map<LayerStatsKey, TimeStatsLayer, LayerStatsKey::Hasher> stats;
+ };
+
+ class TimeStatsGlobal {
+ public:
+ // Note: these are all legacy statistics, we're keeping these around because a variety of
+ // systems and form-factors find these useful when comparing with older releases. However,
+ // the current recommendation is that the new timeline-based metrics are used, and the old
+ // ones are deprecated.
+ int64_t statsStartLegacy = 0;
+ int64_t statsEndLegacy = 0;
+ int32_t totalFramesLegacy = 0;
+ int32_t missedFramesLegacy = 0;
+ int32_t clientCompositionFramesLegacy = 0;
+ int32_t clientCompositionReusedFramesLegacy = 0;
+ int32_t refreshRateSwitchesLegacy = 0;
+ int32_t compositionStrategyChangesLegacy = 0;
+ int32_t displayEventConnectionsCountLegacy = 0;
+ int64_t displayOnTimeLegacy = 0;
+ Histogram presentToPresentLegacy;
+ Histogram frameDurationLegacy;
+ Histogram renderEngineTimingLegacy;
+ std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy;
+
+ std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats;
std::string toString(std::optional<uint32_t> maxLayers) const;
SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
index e2a28a2..c8a2b5e 100644
--- a/services/surfaceflinger/layerproto/Android.bp
+++ b/services/surfaceflinger/layerproto/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library {
name: "liblayers_proto",
export_include_dirs: ["include"],
diff --git a/services/surfaceflinger/sysprop/Android.bp b/services/surfaceflinger/sysprop/Android.bp
index 7721d7d2..f579119 100644
--- a/services/surfaceflinger/sysprop/Android.bp
+++ b/services/surfaceflinger/sysprop/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sysprop_library {
name: "SurfaceFlingerProperties",
srcs: ["*.sysprop"],
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 8142aad..78187f7 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "SurfaceFlinger_test",
defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 3535fbb..2551a19 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "sffakehwc_test",
defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 17928a0..2ac6b09 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "libsurfaceflinger_unittest",
defaults: ["surfaceflinger_defaults"],
@@ -73,6 +82,7 @@
"FrameTracerTest.cpp",
"TimerTest.cpp",
"TransactionApplicationTest.cpp",
+ "TransactionFrameTracerTest.cpp",
"TransactionSurfaceFrameTest.cpp",
"StrongTypingTest.cpp",
"VSyncDispatchTimerQueueTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 6e9f09b..1c57e4c 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -27,6 +27,7 @@
#include <cinttypes>
using namespace std::chrono_literals;
+using testing::_;
using testing::AtLeast;
using testing::Contains;
using FrameTimelineEvent = perfetto::protos::FrameTimelineEvent;
@@ -40,10 +41,6 @@
using ProtoPresentType = perfetto::protos::FrameTimelineEvent_PresentType;
using ProtoJankType = perfetto::protos::FrameTimelineEvent_JankType;
-MATCHER_P(HasBit, bit, "") {
- return (arg & bit) != 0;
-}
-
namespace android::frametimeline {
class FrameTimelineTest : public testing::Test {
@@ -109,6 +106,7 @@
void addEmptyDisplayFrame() {
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ // Trigger a flushPresentFence by calling setSfPresent for the next frame
mFrameTimeline->setSfPresent(2500, presentFence1);
}
@@ -237,50 +235,42 @@
}
TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-
int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
- int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
sLayerNameOne, sLayerNameOne);
// Set up the display frame
- mFrameTimeline->setSfWakeUp(token1, 20, 11);
+ mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
+ surfaceFrame1->setDropTime(12);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(25, presentFence1);
presentFence1->signalForTest(30);
- // Trigger a flush by calling setSfPresent for the next frame
- mFrameTimeline->setSfWakeUp(token2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
+ addEmptyDisplayFrame();
auto& droppedSurfaceFrame = getSurfaceFrame(0, 0);
EXPECT_EQ(droppedSurfaceFrame.getPresentState(), SurfaceFrame::PresentState::Dropped);
+ EXPECT_EQ(0u, droppedSurfaceFrame.getActuals().endTime);
+ EXPECT_EQ(12u, droppedSurfaceFrame.getDropTime());
EXPECT_EQ(droppedSurfaceFrame.getActuals().presentTime, 0);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
- int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
- int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 60});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
auto surfaceFrame2 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameTwo, sLayerNameTwo);
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -296,16 +286,7 @@
EXPECT_EQ(presentedSurfaceFrame1.getActuals().presentTime, 0);
EXPECT_EQ(presentedSurfaceFrame2.getActuals().presentTime, 0);
- // Trigger a flush by finalizing the next DisplayFrame
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto surfaceFrame3 =
- mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
- sUidOne, sLayerNameOne, sLayerNameOne);
- mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
- surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Dropped);
- mFrameTimeline->addSurfaceFrame(surfaceFrame3);
- mFrameTimeline->setSfPresent(56, presentFence2);
- displayFrame = getDisplayFrame(0);
+ addEmptyDisplayFrame();
// Fences have flushed, so the present timestamps should be updated
EXPECT_EQ(displayFrame->getActuals().presentTime, 42);
@@ -318,11 +299,8 @@
TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
// Insert kMaxDisplayFrames' count of DisplayFrames to fill the deque
int frameTimeFactor = 0;
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
- .Times(static_cast<int32_t>(*maxDisplayFrames));
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_))
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_))
.Times(static_cast<int32_t>(*maxDisplayFrames));
for (size_t i = 0; i < *maxDisplayFrames; i++) {
auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
@@ -334,7 +312,7 @@
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId},
sPidOne, sUidOne, sLayerNameOne,
sLayerNameOne);
- mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
+ mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
@@ -355,7 +333,7 @@
auto surfaceFrame =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
- mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
+ mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
@@ -386,9 +364,6 @@
}
TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
- .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
presentFence->signalForTest(2);
@@ -398,7 +373,7 @@
mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
sLayerNameOne);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
- mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(27, presentFence);
@@ -408,16 +383,13 @@
// Increase the size to 256
mFrameTimeline->setMaxDisplayFrames(256);
EXPECT_EQ(*maxDisplayFrames, 256u);
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
- .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
auto surfaceFrame =
mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
sLayerNameOne);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
- mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(27, presentFence);
@@ -427,16 +399,13 @@
// Shrink the size to 128
mFrameTimeline->setMaxDisplayFrames(128);
EXPECT_EQ(*maxDisplayFrames, 128u);
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
- .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
auto surfaceFrame =
mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
sLayerNameOne);
int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
- mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(27, presentFence);
@@ -446,11 +415,19 @@
// Tests related to TimeStats
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
+ Fps refreshRate = Fps(11);
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(sUidOne, sLayerNameOne,
- HasBit(JankType::SurfaceFlingerCpuDeadlineMissed)));
- EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(HasBit(JankType::SurfaceFlingerCpuDeadlineMissed)));
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne,
+ JankType::SurfaceFlingerCpuDeadlineMissed,
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(3ms)
+ .count(),
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(10ms)
+ .count(),
+ 0}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
{std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
@@ -465,7 +442,9 @@
sUidOne, sLayerNameOne, sLayerNameOne);
mFrameTimeline->setSfWakeUp(sfToken1,
std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
- 11);
+ refreshRate);
+ surfaceFrame1->setAcquireFenceTime(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count());
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
presentFence1->signalForTest(
@@ -476,9 +455,11 @@
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
+ Fps refreshRate = Fps::fromPeriodNsecs(30);
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(sUidOne, sLayerNameOne, HasBit(JankType::DisplayHAL)));
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::DisplayHAL)));
+ incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne, JankType::DisplayHAL,
+ 0, 0, 0}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
@@ -494,8 +475,10 @@
sUidOne, sLayerNameOne, sLayerNameOne);
mFrameTimeline->setSfWakeUp(sfToken1,
std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
- 30);
+ refreshRate);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ surfaceFrame1->setAcquireFenceTime(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count());
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
presentFence1->signalForTest(
std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
@@ -505,10 +488,14 @@
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
+ Fps refreshRate = Fps(11.0);
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(sUidOne, sLayerNameOne,
- HasBit(JankType::AppDeadlineMissed)));
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::AppDeadlineMissed)));
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne, JankType::AppDeadlineMissed, 0, 0,
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(25ms)
+ .count()}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
{std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
@@ -525,7 +512,7 @@
std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count());
mFrameTimeline->setSfWakeUp(sfToken1,
std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
- 11);
+ refreshRate);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
@@ -537,6 +524,45 @@
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
}
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) {
+ Fps refreshRate = Fps(11.0);
+ Fps renderRate = Fps(30.0);
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
+ JankType::AppDeadlineMissed, 0, 0,
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(25ms)
+ .count()}));
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+ {std::chrono::duration_cast<std::chrono::nanoseconds>(82ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()});
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+ sUidOne, sLayerNameOne, sLayerNameOne);
+ surfaceFrame1->setAcquireFenceTime(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count());
+ mFrameTimeline->setSfWakeUp(sfToken1,
+ std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
+ refreshRate);
+
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ surfaceFrame1->setRenderRate(renderRate);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ presentFence1->signalForTest(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
+ mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(),
+ presentFence1);
+
+ EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
+}
+
/*
* Tracing Tests
*
@@ -547,28 +573,20 @@
*/
TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-
int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
- int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
sLayerNameOne, sLayerNameOne);
// Set up the display frame
- mFrameTimeline->setSfWakeUp(token1, 20, 11);
+ mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(25, presentFence1);
presentFence1->signalForTest(30);
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(token2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
+ addEmptyDisplayFrame();
auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
EXPECT_EQ(packets.size(), 0u);
@@ -576,12 +594,9 @@
TEST_F(FrameTimelineTest, tracing_sanityTest) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
@@ -591,18 +606,13 @@
sLayerNameOne, sLayerNameOne);
// Set up the display frame
- mFrameTimeline->setSfWakeUp(token2, 20, 11);
+ mFrameTimeline->setSfWakeUp(token2, 20, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(25, presentFence1);
presentFence1->signalForTest(30);
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(token2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
- presentFence2->signalForTest(55);
-
+ addEmptyDisplayFrame();
flushTrace();
tracingSession->StopBlocking();
@@ -613,25 +623,16 @@
TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
- int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
// Set up the display frame
- mFrameTimeline->setSfWakeUp(-1, 20, 11);
+ mFrameTimeline->setSfWakeUp(-1, 20, Fps::fromPeriodNsecs(11));
mFrameTimeline->setSfPresent(25, presentFence1);
presentFence1->signalForTest(30);
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(token1, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
- presentFence2->signalForTest(60);
-
+ addEmptyDisplayFrame();
flushTrace();
tracingSession->StopBlocking();
@@ -641,30 +642,21 @@
TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
- int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne,
sLayerNameOne, sLayerNameOne);
// Set up the display frame
- mFrameTimeline->setSfWakeUp(token1, 20, 11);
+ mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(25, presentFence1);
presentFence1->signalForTest(30);
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(token2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
- presentFence2->signalForTest(60);
-
+ addEmptyDisplayFrame();
flushTrace();
tracingSession->StopBlocking();
@@ -674,6 +666,65 @@
EXPECT_EQ(packets.size(), 4u);
}
+ProtoExpectedDisplayFrameStart createProtoExpectedDisplayFrameStart(int64_t cookie, int64_t token,
+ pid_t pid) {
+ ProtoExpectedDisplayFrameStart proto;
+ proto.set_cookie(cookie);
+ proto.set_token(token);
+ proto.set_pid(pid);
+ return proto;
+}
+
+ProtoActualDisplayFrameStart createProtoActualDisplayFrameStart(
+ int64_t cookie, int64_t token, pid_t pid, ProtoPresentType presentType, bool onTimeFinish,
+ bool gpuComposition, ProtoJankType jankType) {
+ ProtoActualDisplayFrameStart proto;
+ proto.set_cookie(cookie);
+ proto.set_token(token);
+ proto.set_pid(pid);
+ proto.set_present_type(presentType);
+ proto.set_on_time_finish(onTimeFinish);
+ proto.set_gpu_composition(gpuComposition);
+ proto.set_jank_type(jankType);
+ return proto;
+}
+
+ProtoExpectedSurfaceFrameStart createProtoExpectedSurfaceFrameStart(int64_t cookie, int64_t token,
+ int64_t displayFrameToken,
+ pid_t pid,
+ std::string layerName) {
+ ProtoExpectedSurfaceFrameStart proto;
+ proto.set_cookie(cookie);
+ proto.set_token(token);
+ proto.set_display_frame_token(displayFrameToken);
+ proto.set_pid(pid);
+ proto.set_layer_name(layerName);
+ return proto;
+}
+
+ProtoActualSurfaceFrameStart createProtoActualSurfaceFrameStart(
+ int64_t cookie, int64_t token, int64_t displayFrameToken, pid_t pid, std::string layerName,
+ ProtoPresentType presentType, bool onTimeFinish, bool gpuComposition,
+ ProtoJankType jankType) {
+ ProtoActualSurfaceFrameStart proto;
+ proto.set_cookie(cookie);
+ proto.set_token(token);
+ proto.set_display_frame_token(displayFrameToken);
+ proto.set_pid(pid);
+ proto.set_layer_name(layerName);
+ proto.set_present_type(presentType);
+ proto.set_on_time_finish(onTimeFinish);
+ proto.set_gpu_composition(gpuComposition);
+ proto.set_jank_type(jankType);
+ return proto;
+}
+
+ProtoFrameEnd createProtoFrameEnd(int64_t cookie) {
+ ProtoFrameEnd proto;
+ proto.set_cookie(cookie);
+ return proto;
+}
+
void validateTraceEvent(const ProtoExpectedDisplayFrameStart& received,
const ProtoExpectedDisplayFrameStart& source) {
ASSERT_TRUE(received.has_cookie());
@@ -759,48 +810,29 @@
TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30});
- int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
// Set up the display frame
- mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11);
+ mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
mFrameTimeline->setSfPresent(26, presentFence1);
presentFence1->signalForTest(31);
int64_t traceCookie = snoopCurrentTraceCookie();
- ProtoExpectedDisplayFrameStart protoExpectedDisplayFrameStart;
- protoExpectedDisplayFrameStart.set_cookie(traceCookie + 1);
- protoExpectedDisplayFrameStart.set_token(displayFrameToken1);
- protoExpectedDisplayFrameStart.set_pid(kSurfaceFlingerPid);
+ auto protoExpectedDisplayFrameStart =
+ createProtoExpectedDisplayFrameStart(traceCookie + 1, displayFrameToken1,
+ kSurfaceFlingerPid);
+ auto protoExpectedDisplayFrameEnd = createProtoFrameEnd(traceCookie + 1);
+ auto protoActualDisplayFrameStart =
+ createProtoActualDisplayFrameStart(traceCookie + 2, displayFrameToken1,
+ kSurfaceFlingerPid,
+ FrameTimelineEvent::PRESENT_ON_TIME, true, false,
+ FrameTimelineEvent::JANK_NONE);
+ auto protoActualDisplayFrameEnd = createProtoFrameEnd(traceCookie + 2);
- ProtoFrameEnd protoExpectedDisplayFrameEnd;
- protoExpectedDisplayFrameEnd.set_cookie(traceCookie + 1);
-
- ProtoActualDisplayFrameStart protoActualDisplayFrameStart;
- protoActualDisplayFrameStart.set_cookie(traceCookie + 2);
- protoActualDisplayFrameStart.set_token(displayFrameToken1);
- protoActualDisplayFrameStart.set_pid(kSurfaceFlingerPid);
- protoActualDisplayFrameStart.set_present_type(
- ProtoPresentType(FrameTimelineEvent::PRESENT_ON_TIME));
- protoActualDisplayFrameStart.set_on_time_finish(true);
- protoActualDisplayFrameStart.set_gpu_composition(false);
- protoActualDisplayFrameStart.set_jank_type(ProtoJankType(FrameTimelineEvent::JANK_NONE));
-
- ProtoFrameEnd protoActualDisplayFrameEnd;
- protoActualDisplayFrameEnd.set_cookie(traceCookie + 2);
-
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
- presentFence2->signalForTest(55);
-
+ addEmptyDisplayFrame();
flushTrace();
tracingSession->StopBlocking();
@@ -852,75 +884,126 @@
validateTraceEvent(actualDisplayFrameEnd, protoActualDisplayFrameEnd);
}
+TEST_F(FrameTimelineTest, traceDisplayFrame_predictionExpiredDoesNotTraceExpectedTimeline) {
+ auto tracingSession = getTracingSessionForTest();
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+ tracingSession->StartBlocking();
+ int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30});
+ // Flush the token so that it would expire
+ flushTokens(systemTime() + maxTokenRetentionTime);
+
+ // Set up the display frame
+ mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
+ mFrameTimeline->setSfPresent(26, presentFence1);
+ presentFence1->signalForTest(31);
+
+ int64_t traceCookie = snoopCurrentTraceCookie();
+
+ auto protoActualDisplayFrameStart =
+ createProtoActualDisplayFrameStart(traceCookie + 1, displayFrameToken1,
+ kSurfaceFlingerPid,
+ FrameTimelineEvent::PRESENT_UNSPECIFIED, false,
+ false, FrameTimelineEvent::JANK_UNKNOWN);
+ auto protoActualDisplayFrameEnd = createProtoFrameEnd(traceCookie + 1);
+
+ addEmptyDisplayFrame();
+ flushTrace();
+ tracingSession->StopBlocking();
+
+ auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
+ // Only actual timeline packets should be in the trace
+ EXPECT_EQ(packets.size(), 2u);
+
+ // Packet - 0 : ActualDisplayFrameStart
+ const auto& packet0 = packets[0];
+ ASSERT_TRUE(packet0.has_timestamp());
+ EXPECT_EQ(packet0.timestamp(), 20u);
+ ASSERT_TRUE(packet0.has_frame_timeline_event());
+
+ const auto& event0 = packet0.frame_timeline_event();
+ ASSERT_TRUE(event0.has_actual_display_frame_start());
+ const auto& actualDisplayFrameStart = event0.actual_display_frame_start();
+ validateTraceEvent(actualDisplayFrameStart, protoActualDisplayFrameStart);
+
+ // Packet - 1 : FrameEnd (ActualDisplayFrame)
+ const auto& packet1 = packets[1];
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), 26u);
+ ASSERT_TRUE(packet1.has_frame_timeline_event());
+
+ const auto& event1 = packet1.frame_timeline_event();
+ ASSERT_TRUE(event1.has_frame_end());
+ const auto& actualDisplayFrameEnd = event1.frame_end();
+ validateTraceEvent(actualDisplayFrameEnd, protoActualDisplayFrameEnd);
+}
+
TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) {
auto tracingSession = getTracingSessionForTest();
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 25, 40});
int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({30, 35, 40});
- int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
- surfaceFrame1->setActualStartTime(0);
- surfaceFrame1->setActualQueueTime(15);
- surfaceFrame1->setAcquireFenceTime(20);
+ auto surfaceFrame2 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
+ sUidOne, sLayerNameOne, sLayerNameOne);
+ surfaceFrame1->setActualQueueTime(10);
+ surfaceFrame1->setDropTime(15);
+
+ surfaceFrame2->setActualQueueTime(15);
+ surfaceFrame2->setAcquireFenceTime(20);
// First 2 cookies will be used by the DisplayFrame
int64_t traceCookie = snoopCurrentTraceCookie() + 2;
- ProtoExpectedSurfaceFrameStart protoExpectedSurfaceFrameStart;
- protoExpectedSurfaceFrameStart.set_cookie(traceCookie + 1);
- protoExpectedSurfaceFrameStart.set_token(surfaceFrameToken);
- protoExpectedSurfaceFrameStart.set_display_frame_token(displayFrameToken1);
- protoExpectedSurfaceFrameStart.set_pid(sPidOne);
- protoExpectedSurfaceFrameStart.set_layer_name(sLayerNameOne);
+ auto protoDroppedSurfaceFrameExpectedStart =
+ createProtoExpectedSurfaceFrameStart(traceCookie + 1, surfaceFrameToken,
+ displayFrameToken1, sPidOne, sLayerNameOne);
+ auto protoDroppedSurfaceFrameExpectedEnd = createProtoFrameEnd(traceCookie + 1);
+ auto protoDroppedSurfaceFrameActualStart =
+ createProtoActualSurfaceFrameStart(traceCookie + 2, surfaceFrameToken,
+ displayFrameToken1, sPidOne, sLayerNameOne,
+ FrameTimelineEvent::PRESENT_DROPPED, false, false,
+ FrameTimelineEvent::JANK_NONE);
+ auto protoDroppedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 2);
- ProtoFrameEnd protoExpectedSurfaceFrameEnd;
- protoExpectedSurfaceFrameEnd.set_cookie(traceCookie + 1);
-
- ProtoActualSurfaceFrameStart protoActualSurfaceFrameStart;
- protoActualSurfaceFrameStart.set_cookie(traceCookie + 2);
- protoActualSurfaceFrameStart.set_token(surfaceFrameToken);
- protoActualSurfaceFrameStart.set_display_frame_token(displayFrameToken1);
- protoActualSurfaceFrameStart.set_pid(sPidOne);
- protoActualSurfaceFrameStart.set_layer_name(sLayerNameOne);
- protoActualSurfaceFrameStart.set_present_type(
- ProtoPresentType(FrameTimelineEvent::PRESENT_ON_TIME));
- protoActualSurfaceFrameStart.set_on_time_finish(true);
- protoActualSurfaceFrameStart.set_gpu_composition(false);
- protoActualSurfaceFrameStart.set_jank_type(ProtoJankType(FrameTimelineEvent::JANK_NONE));
-
- ProtoFrameEnd protoActualSurfaceFrameEnd;
- protoActualSurfaceFrameEnd.set_cookie(traceCookie + 2);
+ auto protoPresentedSurfaceFrameExpectedStart =
+ createProtoExpectedSurfaceFrameStart(traceCookie + 3, surfaceFrameToken,
+ displayFrameToken1, sPidOne, sLayerNameOne);
+ auto protoPresentedSurfaceFrameExpectedEnd = createProtoFrameEnd(traceCookie + 3);
+ auto protoPresentedSurfaceFrameActualStart =
+ createProtoActualSurfaceFrameStart(traceCookie + 4, surfaceFrameToken,
+ displayFrameToken1, sPidOne, sLayerNameOne,
+ FrameTimelineEvent::PRESENT_ON_TIME, true, false,
+ FrameTimelineEvent::JANK_NONE);
+ auto protoPresentedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 4);
// Set up the display frame
- mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11);
- surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
+ surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame2);
mFrameTimeline->setSfPresent(26, presentFence1);
presentFence1->signalForTest(40);
- // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
- // next frame
- mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11);
- mFrameTimeline->setSfPresent(55, presentFence2);
- presentFence2->signalForTest(55);
-
+ addEmptyDisplayFrame();
flushTrace();
tracingSession->StopBlocking();
auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
- EXPECT_EQ(packets.size(), 8u);
+ // 4 DisplayFrame + 4 DroppedSurfaceFrame + 4 PresentedSurfaceFrame
+ EXPECT_EQ(packets.size(), 12u);
- // Packet - 4 : ExpectedSurfaceFrameStart
+ // Packet - 4 : ExpectedSurfaceFrameStart1
const auto& packet4 = packets[4];
ASSERT_TRUE(packet4.has_timestamp());
EXPECT_EQ(packet4.timestamp(), 10u);
@@ -928,10 +1011,10 @@
const auto& event4 = packet4.frame_timeline_event();
ASSERT_TRUE(event4.has_expected_surface_frame_start());
- const auto& expectedSurfaceFrameStart = event4.expected_surface_frame_start();
- validateTraceEvent(expectedSurfaceFrameStart, protoExpectedSurfaceFrameStart);
+ const auto& expectedSurfaceFrameStart1 = event4.expected_surface_frame_start();
+ validateTraceEvent(expectedSurfaceFrameStart1, protoDroppedSurfaceFrameExpectedStart);
- // Packet - 5 : FrameEnd (ExpectedSurfaceFrame)
+ // Packet - 5 : FrameEnd (ExpectedSurfaceFrame1)
const auto& packet5 = packets[5];
ASSERT_TRUE(packet5.has_timestamp());
EXPECT_EQ(packet5.timestamp(), 25u);
@@ -939,10 +1022,10 @@
const auto& event5 = packet5.frame_timeline_event();
ASSERT_TRUE(event5.has_frame_end());
- const auto& expectedSurfaceFrameEnd = event5.frame_end();
- validateTraceEvent(expectedSurfaceFrameEnd, protoExpectedSurfaceFrameEnd);
+ const auto& expectedSurfaceFrameEnd1 = event5.frame_end();
+ validateTraceEvent(expectedSurfaceFrameEnd1, protoDroppedSurfaceFrameExpectedEnd);
- // Packet - 6 : ActualSurfaceFrameStart
+ // Packet - 6 : ActualSurfaceFrameStart1
const auto& packet6 = packets[6];
ASSERT_TRUE(packet6.has_timestamp());
EXPECT_EQ(packet6.timestamp(), 10u);
@@ -950,34 +1033,157 @@
const auto& event6 = packet6.frame_timeline_event();
ASSERT_TRUE(event6.has_actual_surface_frame_start());
- const auto& actualSurfaceFrameStart = event6.actual_surface_frame_start();
- validateTraceEvent(actualSurfaceFrameStart, protoActualSurfaceFrameStart);
+ const auto& actualSurfaceFrameStart1 = event6.actual_surface_frame_start();
+ validateTraceEvent(actualSurfaceFrameStart1, protoDroppedSurfaceFrameActualStart);
- // Packet - 7 : FrameEnd (ActualSurfaceFrame)
+ // Packet - 7 : FrameEnd (ActualSurfaceFrame1)
const auto& packet7 = packets[7];
ASSERT_TRUE(packet7.has_timestamp());
- EXPECT_EQ(packet7.timestamp(), 20u);
+ EXPECT_EQ(packet7.timestamp(), 15u);
ASSERT_TRUE(packet7.has_frame_timeline_event());
const auto& event7 = packet7.frame_timeline_event();
ASSERT_TRUE(event7.has_frame_end());
- const auto& actualSurfaceFrameEnd = event7.frame_end();
+ const auto& actualSurfaceFrameEnd1 = event7.frame_end();
+ validateTraceEvent(actualSurfaceFrameEnd1, protoDroppedSurfaceFrameActualEnd);
+
+ // Packet - 8 : ExpectedSurfaceFrameStart2
+ const auto& packet8 = packets[8];
+ ASSERT_TRUE(packet8.has_timestamp());
+ EXPECT_EQ(packet8.timestamp(), 10u);
+ ASSERT_TRUE(packet8.has_frame_timeline_event());
+
+ const auto& event8 = packet8.frame_timeline_event();
+ ASSERT_TRUE(event8.has_expected_surface_frame_start());
+ const auto& expectedSurfaceFrameStart2 = event8.expected_surface_frame_start();
+ validateTraceEvent(expectedSurfaceFrameStart2, protoPresentedSurfaceFrameExpectedStart);
+
+ // Packet - 9 : FrameEnd (ExpectedSurfaceFrame2)
+ const auto& packet9 = packets[9];
+ ASSERT_TRUE(packet9.has_timestamp());
+ EXPECT_EQ(packet9.timestamp(), 25u);
+ ASSERT_TRUE(packet9.has_frame_timeline_event());
+
+ const auto& event9 = packet9.frame_timeline_event();
+ ASSERT_TRUE(event9.has_frame_end());
+ const auto& expectedSurfaceFrameEnd2 = event9.frame_end();
+ validateTraceEvent(expectedSurfaceFrameEnd2, protoPresentedSurfaceFrameExpectedEnd);
+
+ // Packet - 10 : ActualSurfaceFrameStart2
+ const auto& packet10 = packets[10];
+ ASSERT_TRUE(packet10.has_timestamp());
+ EXPECT_EQ(packet10.timestamp(), 10u);
+ ASSERT_TRUE(packet10.has_frame_timeline_event());
+
+ const auto& event10 = packet10.frame_timeline_event();
+ ASSERT_TRUE(event10.has_actual_surface_frame_start());
+ const auto& actualSurfaceFrameStart2 = event10.actual_surface_frame_start();
+ validateTraceEvent(actualSurfaceFrameStart2, protoPresentedSurfaceFrameActualStart);
+
+ // Packet - 11 : FrameEnd (ActualSurfaceFrame2)
+ const auto& packet11 = packets[11];
+ ASSERT_TRUE(packet11.has_timestamp());
+ EXPECT_EQ(packet11.timestamp(), 20u);
+ ASSERT_TRUE(packet11.has_frame_timeline_event());
+
+ const auto& event11 = packet11.frame_timeline_event();
+ ASSERT_TRUE(event11.has_frame_end());
+ const auto& actualSurfaceFrameEnd2 = event11.frame_end();
+ validateTraceEvent(actualSurfaceFrameEnd2, protoPresentedSurfaceFrameActualEnd);
+}
+
+TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpectedTimeline) {
+ auto tracingSession = getTracingSessionForTest();
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+ tracingSession->StartBlocking();
+ constexpr nsecs_t appStartTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count();
+ constexpr nsecs_t appEndTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count();
+ constexpr nsecs_t appPresentTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+ int64_t surfaceFrameToken =
+ mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime});
+
+ // Flush the token so that it would expire
+ flushTokens(systemTime() + maxTokenRetentionTime);
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0},
+ sPidOne, sUidOne, sLayerNameOne,
+ sLayerNameOne);
+ surfaceFrame1->setActualQueueTime(appEndTime);
+ surfaceFrame1->setAcquireFenceTime(appEndTime);
+
+ constexpr nsecs_t sfStartTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count();
+ constexpr nsecs_t sfEndTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+ constexpr nsecs_t sfPresentTime =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+ int64_t displayFrameToken =
+ mTokenManager->generateTokenForPredictions({sfStartTime, sfEndTime, sfPresentTime});
+
+ // First 2 cookies will be used by the DisplayFrame
+ int64_t traceCookie = snoopCurrentTraceCookie() + 2;
+
+ auto protoActualSurfaceFrameStart =
+ createProtoActualSurfaceFrameStart(traceCookie + 1, surfaceFrameToken,
+ displayFrameToken, sPidOne, sLayerNameOne,
+ FrameTimelineEvent::PRESENT_UNSPECIFIED, false,
+ false, FrameTimelineEvent::JANK_UNKNOWN);
+ auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1);
+
+ // Set up the display frame
+ mFrameTimeline->setSfWakeUp(displayFrameToken, sfStartTime, Fps::fromPeriodNsecs(11));
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ mFrameTimeline->setSfPresent(sfEndTime, presentFence1);
+ presentFence1->signalForTest(sfPresentTime);
+
+ addEmptyDisplayFrame();
+ flushTrace();
+ tracingSession->StopBlocking();
+
+ auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
+ // Display Frame 4 packets + SurfaceFrame 2 packets
+ ASSERT_EQ(packets.size(), 6u);
+
+ // Packet - 4 : ActualSurfaceFrameStart
+ const auto& packet4 = packets[4];
+ ASSERT_TRUE(packet4.has_timestamp());
+ EXPECT_EQ(packet4.timestamp(),
+ static_cast<uint64_t>(appEndTime - SurfaceFrame::kPredictionExpiredStartTimeDelta));
+ ASSERT_TRUE(packet4.has_frame_timeline_event());
+
+ const auto& event4 = packet4.frame_timeline_event();
+ ASSERT_TRUE(event4.has_actual_surface_frame_start());
+ const auto& actualSurfaceFrameStart = event4.actual_surface_frame_start();
+ validateTraceEvent(actualSurfaceFrameStart, protoActualSurfaceFrameStart);
+
+ // Packet - 5 : FrameEnd (ActualSurfaceFrame)
+ const auto& packet5 = packets[5];
+ ASSERT_TRUE(packet5.has_timestamp());
+ EXPECT_EQ(packet5.timestamp(), static_cast<uint64_t>(appEndTime));
+ ASSERT_TRUE(packet5.has_frame_timeline_event());
+
+ const auto& event5 = packet5.frame_timeline_event();
+ ASSERT_TRUE(event5.has_frame_end());
+ const auto& actualSurfaceFrameEnd = event5.frame_end();
validateTraceEvent(actualSurfaceFrameEnd, protoActualSurfaceFrameEnd);
}
// Tests for Jank classification
TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30});
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
auto surfaceFrame =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame);
mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1001,12 +1207,11 @@
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
+ Fps vsyncRate = Fps::fromPeriodNsecs(11);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate);
mFrameTimeline->setSfPresent(26, presentFence1);
auto displayFrame = getDisplayFrame(0);
presentFence1->signalForTest(30);
@@ -1016,7 +1221,7 @@
// Trigger a flush by finalizing the next DisplayFrame
auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, vsyncRate);
mFrameTimeline->setSfPresent(56, presentFence2);
displayFrame = getDisplayFrame(0);
@@ -1030,7 +1235,6 @@
auto displayFrame2 = getDisplayFrame(1);
presentFence2->signalForTest(65);
EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
-
addEmptyDisplayFrame();
displayFrame2 = getDisplayFrame(1);
@@ -1042,12 +1246,11 @@
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
+ Fps vsyncRate = Fps::fromPeriodNsecs(11);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate);
mFrameTimeline->setSfPresent(26, presentFence1);
auto displayFrame = getDisplayFrame(0);
presentFence1->signalForTest(50);
@@ -1057,7 +1260,7 @@
// Trigger a flush by finalizing the next DisplayFrame
auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, vsyncRate);
mFrameTimeline->setSfPresent(56, presentFence2);
displayFrame = getDisplayFrame(0);
@@ -1083,11 +1286,9 @@
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({12, 18, 40});
- mFrameTimeline->setSfWakeUp(sfToken1, 12, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
mFrameTimeline->setSfPresent(22, presentFence1);
auto displayFrame = getDisplayFrame(0);
@@ -1107,11 +1308,9 @@
}
TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
- mFrameTimeline->setSfWakeUp(sfToken1, 12, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
mFrameTimeline->setSfPresent(36, presentFence1);
auto displayFrame = getDisplayFrame(0);
presentFence1->signalForTest(52);
@@ -1130,10 +1329,7 @@
}
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
- // Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
@@ -1143,7 +1339,7 @@
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame1->setAcquireFenceTime(16);
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1162,7 +1358,7 @@
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame2->setAcquireFenceTime(36);
- mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame2);
mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1187,6 +1383,14 @@
auto actuals2 = presentedSurfaceFrame2.getActuals();
EXPECT_EQ(actuals2.presentTime, 0);
+ ::testing::Mock::VerifyAndClearExpectations(mTimeStats.get());
+
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
+ sLayerNameOne, JankType::PredictionError, 0, 5,
+ 0}));
+
addEmptyDisplayFrame();
// Fences for the second frame have flushed, so the present timestamps should be updated
@@ -1203,10 +1407,7 @@
}
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
- // Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
@@ -1216,7 +1417,7 @@
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame1->setAcquireFenceTime(16);
- mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1235,7 +1436,7 @@
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame2->setAcquireFenceTime(36);
- mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame2);
mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1260,6 +1461,14 @@
auto actuals2 = presentedSurfaceFrame2.getActuals();
EXPECT_EQ(actuals2.presentTime, 0);
+ ::testing::Mock::VerifyAndClearExpectations(mTimeStats.get());
+
+ EXPECT_CALL(*mTimeStats,
+ incrementJankyFrames(
+ TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
+ sLayerNameOne, JankType::PredictionError, 0, 5,
+ 0}));
+
addEmptyDisplayFrame();
// Fences for the second frame have flushed, so the present timestamps should be updated
@@ -1276,10 +1485,8 @@
}
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
- // Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
+
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 46, 50});
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60});
@@ -1287,7 +1494,7 @@
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame1->setAcquireFenceTime(40);
- mFrameTimeline->setSfWakeUp(sfToken1, 42, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 42, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(46, presentFence1);
@@ -1320,10 +1527,7 @@
// AppDeadlineMissed. Second frame - DisplayFrame is janky. This should propagate DisplayFrame's
// jank to the SurfaceFrame.
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
- // Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({32, 36, 40});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 46, 50});
@@ -1333,7 +1537,7 @@
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame1->setAcquireFenceTime(26);
- mFrameTimeline->setSfWakeUp(sfToken1, 32, 11);
+ mFrameTimeline->setSfWakeUp(sfToken1, 32, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(36, presentFence1);
@@ -1352,7 +1556,7 @@
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame2->setAcquireFenceTime(40);
- mFrameTimeline->setSfWakeUp(sfToken2, 43, 11);
+ mFrameTimeline->setSfWakeUp(sfToken2, 43, Fps::fromPeriodNsecs(11));
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame2);
mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1393,10 +1597,8 @@
}
TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadlineMissed) {
- // Global increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
// Layer specific increment
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
@@ -1407,7 +1609,7 @@
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame1->setAcquireFenceTime(50);
- mFrameTimeline->setSfWakeUp(sfToken1, 52, 30);
+ mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
mFrameTimeline->setSfPresent(56, presentFence1);
@@ -1426,7 +1628,7 @@
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
sUidOne, sLayerNameOne, sLayerNameOne);
surfaceFrame2->setAcquireFenceTime(84);
- mFrameTimeline->setSfWakeUp(sfToken2, 112, 30);
+ mFrameTimeline->setSfWakeUp(sfToken2, 112, Fps::fromPeriodNsecs(30));
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54);
mFrameTimeline->addSurfaceFrame(surfaceFrame2);
mFrameTimeline->setSfPresent(116, presentFence2);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 376995f..06f2036 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -1792,6 +1792,26 @@
ASSERT_TRUE(frameRateOverrides.empty());
}
+TEST_F(RefreshRateConfigsTest, updateDisplayModes) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_30);
+ refreshRateConfigs->setDisplayManagerPolicy({DisplayModeId(HWC_CONFIG_ID_30),
+ /* allowGroupSwitching */ false,
+ /* range */ {Fps(30.0f), Fps(30.0f)}});
+
+ refreshRateConfigs->updateDisplayModes(m60_90Device, HWC_CONFIG_ID_60);
+
+ const auto currentRefreshRate = refreshRateConfigs->getCurrentRefreshRate();
+ EXPECT_TRUE(currentRefreshRate.getFps().equalsWithMargin(Fps(60.0)));
+ EXPECT_EQ(currentRefreshRate.getModeId(), HWC_CONFIG_ID_60);
+
+ EXPECT_TRUE(
+ getMaxSupportedRefreshRate(*refreshRateConfigs).getFps().equalsWithMargin(Fps(90.0)));
+ EXPECT_TRUE(
+ getMinSupportedRefreshRate(*refreshRateConfigs).getFps().equalsWithMargin(Fps(60.0)));
+}
+
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index ce2bfef..dee13d6 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -410,6 +410,10 @@
const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; }
+ mock::FrameTracer* getFrameTracer() const {
+ return static_cast<mock::FrameTracer*>(mFlinger->mFrameTracer.get());
+ }
+
/* ------------------------------------------------------------------------
* Read-write access to private data to set up preconditions and assert
* post-conditions.
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index df4464e..35c32ec 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -55,14 +55,21 @@
using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode;
// clang-format off
-#define FMT_PROTO true
-#define FMT_STRING false
-#define LAYER_ID_0 0
-#define LAYER_ID_1 1
-#define UID_0 123
-#define LAYER_ID_INVALID -1
-#define NUM_LAYERS 1
-#define NUM_LAYERS_INVALID "INVALID"
+#define FMT_PROTO true
+#define FMT_STRING false
+#define LAYER_ID_0 0
+#define LAYER_ID_1 1
+#define UID_0 123
+#define REFRESH_RATE_0 61
+#define RENDER_RATE_0 31
+#define REFRESH_RATE_BUCKET_0 60
+#define RENDER_RATE_BUCKET_0 30
+#define LAYER_ID_INVALID -1
+#define NUM_LAYERS 1
+#define NUM_LAYERS_INVALID "INVALID"
+
+const constexpr Fps kRefreshRate0 = Fps(static_cast<float>(REFRESH_RATE_0));
+const constexpr Fps kRenderRate0 = Fps(static_cast<float>(RENDER_RATE_0));
enum InputCommand : int32_t {
ENABLE = 0,
@@ -246,11 +253,13 @@
ASSERT_NO_FATAL_FAILURE(mTimeStats->setDesiredTime(id, frameNumber, ts));
break;
case TimeStamp::PRESENT:
- ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts));
+ ASSERT_NO_FATAL_FAILURE(
+ mTimeStats->setPresentTime(id, frameNumber, ts, kRefreshRate0, kRenderRate0));
break;
case TimeStamp::PRESENT_FENCE:
- ASSERT_NO_FATAL_FAILURE(
- mTimeStats->setPresentFence(id, frameNumber, std::make_shared<FenceTime>(ts)));
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentFence(id, frameNumber,
+ std::make_shared<FenceTime>(ts),
+ kRefreshRate0, kRenderRate0));
break;
default:
ALOGD("Invalid timestamp type");
@@ -352,48 +361,29 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
-TEST_F(TimeStatsTest, canIncreaseJankyFrames) {
- // this stat is not in the proto so verify by checking the string dump
- EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
-
- insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
- mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::DisplayHAL);
- mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::None);
-
- const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
- std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
- EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "jankyFrames = " + std::to_string(4);
- EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
- EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
- EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "sfUnattributedJankyFrame = " + std::to_string(1);
- EXPECT_THAT(result, HasSubstr(expectedResult));
- expectedResult = "appUnattributedJankyFrame = " + std::to_string(1);
- EXPECT_THAT(result, HasSubstr(expectedResult));
-}
-
TEST_F(TimeStatsTest, canIncreaseJankyFramesForLayer) {
// this stat is not in the proto so verify by checking the string dump
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerCpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::DisplayHAL, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::None, 1, 2, 3});
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
- std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
+ std::string expectedResult =
+ "displayRefreshRate = " + std::to_string(REFRESH_RATE_BUCKET_0) + " fps";
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "renderRate = " + std::to_string(RENDER_RATE_BUCKET_0) + " fps";
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "totalTimelineFrames = " + std::to_string(5);
EXPECT_THAT(result, HasSubstr(expectedResult));
expectedResult = "jankyFrames = " + std::to_string(4);
EXPECT_THAT(result, HasSubstr(expectedResult));
@@ -848,14 +838,16 @@
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerCpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::DisplayHAL, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::None, 1, 2, 3});
EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
@@ -865,11 +857,6 @@
EXPECT_THAT(result, HasSubstr("compositionStrategyChanges = 0"));
EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
- EXPECT_THAT(result, HasSubstr("jankyFrames = 0"));
- EXPECT_THAT(result, HasSubstr("sfLongCpuJankyFrames = 0"));
- EXPECT_THAT(result, HasSubstr("sfLongGpuJankyFrames = 0"));
- EXPECT_THAT(result, HasSubstr("sfUnattributedJankyFrame = 0"));
- EXPECT_THAT(result, HasSubstr("appUnattributedJankyFrame = 0"));
}
TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
@@ -1000,11 +987,16 @@
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
- mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::DisplayHAL);
- mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(JankType::None);
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::DisplayHAL, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::None, 1, 2, 3});
EXPECT_THAT(mDelegate->mAtomTags,
UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
@@ -1015,6 +1007,8 @@
std::string expectedFrameDuration = buildExpectedHistogramBytestring({2}, {1});
std::string expectedRenderEngineTiming = buildExpectedHistogramBytestring({1, 2}, {1, 1});
std::string expectedEmptyHistogram = buildExpectedHistogramBytestring({}, {});
+ std::string expectedSfDeadlineMissed = buildExpectedHistogramBytestring({1}, {4});
+ std::string expectedSfPredictionErrors = buildExpectedHistogramBytestring({2}, {4});
{
InSequence seq;
@@ -1047,18 +1041,20 @@
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0));
EXPECT_CALL(*mDelegate,
statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(),
- expectedEmptyHistogram.size()),
- expectedEmptyHistogram.size()));
+ BytesEq((const uint8_t*)
+ expectedSfDeadlineMissed.c_str(),
+ expectedSfDeadlineMissed.size()),
+ expectedSfDeadlineMissed.size()));
EXPECT_CALL(*mDelegate,
statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(),
- expectedEmptyHistogram.size()),
- expectedEmptyHistogram.size()));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+ BytesEq((const uint8_t*)
+ expectedSfPredictionErrors.c_str(),
+ expectedSfPredictionErrors.size()),
+ expectedSfPredictionErrors.size()));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0));
EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
}
@@ -1091,14 +1087,16 @@
}
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerCpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::DisplayHAL, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::AppDeadlineMissed, 1, 2, 3});
+ mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+ JankType::None, 1, 2, 3});
EXPECT_THAT(mDelegate->mAtomTags,
UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
@@ -1113,7 +1111,7 @@
std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1});
std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1});
std::string expectedFrameRateOverride = frameRateVoteToProtoByteString(0.0, 0, 0);
- std::string expectedEmptyHistogram = buildExpectedHistogramBytestring({}, {});
+ std::string expectedAppDeadlineMissed = buildExpectedHistogramBytestring({3}, {4});
{
InSequence seq;
EXPECT_CALL(*mDelegate,
@@ -1170,8 +1168,8 @@
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0));
EXPECT_CALL(*mDelegate,
statsEventWriteByteArray(mDelegate->mEvent,
BytesEq((const uint8_t*)
@@ -1180,9 +1178,10 @@
expectedFrameRateOverride.size()));
EXPECT_CALL(*mDelegate,
statsEventWriteByteArray(mDelegate->mEvent,
- BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(),
- expectedEmptyHistogram.size()),
- expectedEmptyHistogram.size()));
+ BytesEq((const uint8_t*)
+ expectedAppDeadlineMissed.c_str(),
+ expectedAppDeadlineMissed.size()),
+ expectedAppDeadlineMissed.size()));
EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
}
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
new file mode 100644
index 0000000..dbadf75
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <log/log.h>
+#include <utils/String8.h>
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockVsyncController.h"
+
+namespace android {
+
+using testing::_;
+using testing::Mock;
+using testing::Return;
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using PresentState = frametimeline::SurfaceFrame::PresentState;
+
+class TransactionFrameTracerTest : public testing::Test {
+public:
+ TransactionFrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ setupScheduler();
+ setupComposer(0);
+ }
+
+ ~TransactionFrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ sp<BufferStateLayer> createBufferStateLayer() {
+ sp<Client> client;
+ LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0,
+ LayerMetadata());
+ return new BufferStateLayer(args);
+ }
+
+ void commitTransaction(Layer* layer) {
+ layer->pushPendingState();
+ auto c = layer->getCurrentState();
+ if (layer->applyPendingStates(&c)) {
+ layer->commitTransaction(c);
+ }
+ }
+
+ void setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ auto vsyncController = std::make_unique<mock::VsyncController>();
+ auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
+
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*vsyncTracker, currentPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
+ std::move(eventThread), std::move(sfEventThread));
+ }
+
+ void setupComposer(uint32_t virtualDisplayCount) {
+ mComposer = new Hwc2::mock::Composer();
+ EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+ Mock::VerifyAndClear(mComposer);
+ }
+
+ TestableSurfaceFlinger mFlinger;
+ Hwc2::mock::Composer* mComposer = nullptr;
+ FenceToFenceTimeMap fenceFactory;
+ client_cache_t mClientCache;
+
+ void BLASTTransactionSendsFrameTracerEvents() {
+ sp<BufferStateLayer> layer = createBufferStateLayer();
+
+ sp<Fence> fence(new Fence());
+ sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ int32_t layerId = layer->getSequence();
+ uint64_t bufferId = buffer->getId();
+ uint64_t frameNumber = 5;
+ nsecs_t dequeueTime = 10;
+ nsecs_t postTime = 20;
+ EXPECT_CALL(*mFlinger.getFrameTracer(), traceNewLayer(layerId, "buffer-state-layer"));
+ EXPECT_CALL(*mFlinger.getFrameTracer(),
+ traceTimestamp(layerId, bufferId, frameNumber, dequeueTime,
+ FrameTracer::FrameEvent::DEQUEUE, /*duration*/ 0));
+ EXPECT_CALL(*mFlinger.getFrameTracer(),
+ traceTimestamp(layerId, bufferId, frameNumber, postTime,
+ FrameTracer::FrameEvent::QUEUE, /*duration*/ 0));
+ layer->setBuffer(buffer, fence, postTime, /*desiredPresentTime*/ 30, false, mClientCache,
+ frameNumber, dequeueTime, FrameTimelineInfo{});
+
+ commitTransaction(layer.get());
+ bool computeVisisbleRegions;
+ nsecs_t latchTime = 25;
+ EXPECT_CALL(*mFlinger.getFrameTracer(),
+ traceFence(layerId, bufferId, frameNumber, _,
+ FrameTracer::FrameEvent::ACQUIRE_FENCE, /*startTime*/ 0));
+ EXPECT_CALL(*mFlinger.getFrameTracer(),
+ traceTimestamp(layerId, bufferId, frameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH, /*duration*/ 0));
+ layer->updateTexImage(computeVisisbleRegions, latchTime, /*expectedPresentTime*/ 0);
+
+ auto glDoneFence = fenceFactory.createFenceTimeForTest(fence);
+ auto presentFence = fenceFactory.createFenceTimeForTest(fence);
+ CompositorTiming compositorTiming;
+ EXPECT_CALL(*mFlinger.getFrameTracer(),
+ traceFence(layerId, bufferId, frameNumber, presentFence,
+ FrameTracer::FrameEvent::PRESENT_FENCE, /*startTime*/ 0));
+ layer->onPostComposition(nullptr, glDoneFence, presentFence, compositorTiming);
+ }
+};
+
+TEST_F(TransactionFrameTracerTest, BLASTTransactionSendsFrameTracerEvents) {
+ BLASTTransactionSendsFrameTracerEvents();
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index aa6798d..bf9ec39 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -157,8 +157,10 @@
sp<Fence> fence2(new Fence());
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ nsecs_t start = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0});
+ nsecs_t end = systemTime();
acquireFence2->signalForTest(12);
EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
@@ -171,6 +173,9 @@
EXPECT_EQ(1, droppedSurfaceFrame->getToken());
EXPECT_EQ(PresentState::Dropped, droppedSurfaceFrame->getPresentState());
+ EXPECT_EQ(0u, droppedSurfaceFrame->getActuals().endTime);
+ auto dropTime = droppedSurfaceFrame->getDropTime();
+ EXPECT_TRUE(dropTime > start && dropTime < end);
EXPECT_EQ(1, presentedSurfaceFrame->getToken());
EXPECT_EQ(PresentState::Presented, presentedSurfaceFrame->getPresentState());
@@ -328,6 +333,41 @@
EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime);
}
+
+ void PendingSurfaceFramesRemovedAfterClassification() {
+ sp<BufferStateLayer> layer = createBufferStateLayer();
+
+ sp<Fence> fence1(new Fence());
+ auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
+ sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
+ {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+ const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+ sp<Fence> fence2(new Fence());
+ auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
+ sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
+ {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ acquireFence2->signalForTest(12);
+
+ ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+ auto& presentedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+ commitTransaction(layer.get());
+ bool computeVisisbleRegions;
+ layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+ // Both the droppedSurfaceFrame and presentedSurfaceFrame should be in
+ // pendingJankClassifications.
+ EXPECT_EQ(2u, layer->mPendingJankClassifications.size());
+ presentedSurfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11),
+ /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0);
+ layer->releasePendingBuffer(25);
+
+ EXPECT_EQ(0u, layer->mPendingJankClassifications.size());
+ }
};
TEST_F(TransactionSurfaceFrameTest, PresentedBufferlessSurfaceFrame) {
@@ -364,4 +404,7 @@
MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken();
}
+TEST_F(TransactionSurfaceFrameTest, PendingSurfaceFramesRemovedAfterClassification) {
+ PendingSurfaceFramesRemovedAfterClassification();
+}
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
index 0a6a9f4..44b9b73 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
@@ -31,7 +31,7 @@
MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr<frametimeline::SurfaceFrame>));
- MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, nsecs_t));
+ MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps));
MOCK_METHOD2(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&));
};
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 99ec353..3e4a0b8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -48,10 +48,11 @@
MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t));
MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t));
MOCK_METHOD3(setAcquireFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
- MOCK_METHOD3(setPresentTime, void(int32_t, uint64_t, nsecs_t));
- MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
- MOCK_METHOD1(incrementJankyFrames, void(int32_t));
- MOCK_METHOD3(incrementJankyFrames, void(uid_t, const std::string&, int32_t));
+ MOCK_METHOD5(setPresentTime, void(int32_t, uint64_t, nsecs_t, Fps, std::optional<Fps>));
+ MOCK_METHOD5(setPresentFence,
+ void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&, Fps,
+ std::optional<Fps>));
+ MOCK_METHOD1(incrementJankyFrames, void(const JankyFramesInfo&));
MOCK_METHOD1(onDestroy, void(int32_t));
MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t));
MOCK_METHOD1(setPowerMode,
diff --git a/services/surfaceflinger/tests/vsync/Android.bp b/services/surfaceflinger/tests/vsync/Android.bp
index 6a89945..bae9796 100644
--- a/services/surfaceflinger/tests/vsync/Android.bp
+++ b/services/surfaceflinger/tests/vsync/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-vsync-events",
defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/tests/waitforvsync/Android.bp b/services/surfaceflinger/tests/waitforvsync/Android.bp
index cb6d0fd..ffed4d7 100644
--- a/services/surfaceflinger/tests/waitforvsync/Android.bp
+++ b/services/surfaceflinger/tests/waitforvsync/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_binary {
name: "test-waitforvsync",
cflags: [
diff --git a/services/utils/Android.bp b/services/utils/Android.bp
index f3d2bc9..81e1232 100644
--- a/services/utils/Android.bp
+++ b/services/utils/Android.bp
@@ -15,6 +15,15 @@
//
// Static library used in testing and executables
//
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libserviceutils",
diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp
index f21254c..54cf5b7 100644
--- a/services/utils/tests/Android.bp
+++ b/services/utils/tests/Android.bp
@@ -14,6 +14,15 @@
// Build unit tests.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_test {
name: "prioritydumper_test",
test_suites: ["device-tests"],
diff --git a/services/vr/Android.bp b/services/vr/Android.bp
index 80df479..980dcf4 100644
--- a/services/vr/Android.bp
+++ b/services/vr/Android.bp
@@ -1,3 +1,13 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
subdirs = [
"*",
]
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 7097e7a..8523bb2 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
sharedLibraries = [
"libbase",
"libcutils",
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 3728731..866007e 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libvr_hwc-hal",
diff --git a/services/vr/hardware_composer/aidl/Android.bp b/services/vr/hardware_composer/aidl/Android.bp
index a1d5392..98afdec 100644
--- a/services/vr/hardware_composer/aidl/Android.bp
+++ b/services/vr/hardware_composer/aidl/Android.bp
@@ -1,3 +1,14 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_static {
name: "libvr_hwc-binder",
srcs: [
diff --git a/services/vr/performanced/Android.bp b/services/vr/performanced/Android.bp
index 0ef8cc4..5eca88b 100644
--- a/services/vr/performanced/Android.bp
+++ b/services/vr/performanced/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-MIT
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_defaults {
name: "performanced_defaults",
static_libs: [
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index 9cf4905..f2ec5a4 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -2,6 +2,15 @@
// Touchpad implementation.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
src = [
"EvdevInjector.cpp",
"VirtualTouchpadEvdev.cpp",
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index 4934970..33599ea 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -14,6 +14,16 @@
// This module makes the Vulkan libhardware HAL headers available, for
// the loader and for HAL/driver implementations.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ // SPDX-license-identifier-MIT
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_headers {
name: "hwvulkan_headers",
vendor_available: true,
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 1d29bab..67cd875 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -13,6 +13,15 @@
// limitations under the License.
// Headers module is in external/vulkan-headers/Android.bp.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
ndk_library {
name: "libvulkan",
symbol_file: "libvulkan.map.txt",
diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp
index ba02504..0daad9c 100644
--- a/vulkan/nulldrv/Android.bp
+++ b/vulkan/nulldrv/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
// Real drivers would set this to vulkan.$(TARGET_BOARD_PLATFORM)
name: "vulkan.default",
diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp
index 8528898..fa0258b 100644
--- a/vulkan/vkjson/Android.bp
+++ b/vulkan/vkjson/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
cc_library_shared {
name: "libvkjson",
srcs: [