Snap for 6188643 from 415974ebae005add7f781f468c8ae8a02f1b1e2c to rvc-release
Change-Id: Ib1a6b5b48e09bc46df3785c3629de2a26a16340a
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 4a84884..0473bb8 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -8,6 +8,7 @@
include/input/
libs/binder/fuzzer/
libs/binder/ndk/
+ libs/binderthreadstate/
libs/graphicsenv/
libs/gui/
libs/input/
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index cfd6a3e..08d4657 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1102,7 +1102,7 @@
binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
const std::string& dataAppName, int32_t appId, const std::string& seInfo,
- int32_t targetSdkVersion) {
+ int32_t targetSdkVersion, const std::string& fromCodePath) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(fromUuid);
CHECK_ARGUMENT_UUID(toUuid);
@@ -1119,13 +1119,12 @@
// Copy app
{
- auto from = create_data_app_package_path(from_uuid, data_app_name);
auto to = create_data_app_package_path(to_uuid, data_app_name);
auto to_parent = create_data_app_path(to_uuid);
- int rc = copy_directory_recursive(from.c_str(), to_parent.c_str());
+ int rc = copy_directory_recursive(fromCodePath.c_str(), to_parent.c_str());
if (rc != 0) {
- res = error(rc, "Failed copying " + from + " to " + to);
+ res = error(rc, "Failed copying " + fromCodePath + " to " + to);
goto fail;
}
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index dd56de6..eb35fd3 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -97,7 +97,7 @@
binder::Status moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
const std::string& dataAppName, int32_t appId, const std::string& seInfo,
- int32_t targetSdkVersion);
+ int32_t targetSdkVersion, const std::string& fromCodePath);
binder::Status dexopt(const std::string& apkPath, int32_t uid,
const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 07ced0d..80d9703 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -52,7 +52,7 @@
void moveCompleteApp(@nullable @utf8InCpp String fromUuid, @nullable @utf8InCpp String toUuid,
@utf8InCpp String packageName, @utf8InCpp String dataAppName, int appId,
- @utf8InCpp String seInfo, int targetSdkVersion);
+ @utf8InCpp String seInfo, int targetSdkVersion, @utf8InCpp String fromCodePath);
void dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName,
@utf8InCpp String instructionSet, int dexoptNeeded,
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 571a5ca..412fc6b 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -97,15 +97,21 @@
uint32_t stride;
/** The bitmap pixel format. See {@link AndroidBitmapFormat} */
int32_t format;
- /** Two bits are used to encode alpha. Use ANDROID_BITMAP_FLAGS_ALPHA_MASK
- * and ANDROID_BITMAP_FLAGS_ALPHA_SHIFT to retrieve them. One bit is used
- * to encode whether the Bitmap uses the HARDWARE Config. Use
- * ANDROID_BITMAP_FLAGS_IS_HARDWARE to know.*/
+ /** Bitfield containing information about the bitmap.
+ *
+ * <p>Two bits are used to encode alpha. Use {@link ANDROID_BITMAP_FLAGS_ALPHA_MASK}
+ * and {@link ANDROID_BITMAP_FLAGS_ALPHA_SHIFT} to retrieve them.</p>
+ *
+ * <p>One bit is used to encode whether the Bitmap uses the HARDWARE Config. Use
+ * {@link ANDROID_BITMAP_FLAGS_IS_HARDWARE} to know.</p>
+ *
+ * <p>These flags were introduced in API level 30.</p>
+ */
uint32_t flags;
} AndroidBitmapInfo;
/**
- * Given a java bitmap object, fill out the AndroidBitmapInfo struct for it.
+ * Given a java bitmap object, fill out the {@link AndroidBitmapInfo} struct for it.
* If the call fails, the info parameter will be ignored.
*/
int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 1ee3853..5f9d400 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -138,7 +138,6 @@
"liblog",
"libcutils",
"libutils",
- "libbinderthreadstate",
],
header_libs: [
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 4981d7a..4dcd07a 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "IPCThreadState"
#include <binder/IPCThreadState.h>
-#include <binderthreadstate/IPCThreadStateBase.h>
#include <binder/Binder.h>
#include <binder/BpBinder.h>
@@ -803,6 +802,7 @@
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
+ mServingStackPointer(nullptr),
mWorkSource(kUnsetWorkSource),
mPropagateWorkSource(false),
mStrictModePolicy(0),
@@ -813,7 +813,6 @@
clearCaller();
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
- mIPCThreadStateBase = IPCThreadStateBase::self();
}
IPCThreadState::~IPCThreadState()
@@ -1163,9 +1162,6 @@
"Not enough command data for brTRANSACTION");
if (result != NO_ERROR) break;
- //Record the fact that we're in a binder call.
- mIPCThreadStateBase->pushCurrentState(
- IPCThreadStateBase::CallState::BINDER);
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
@@ -1173,6 +1169,9 @@
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
+ const void* origServingStackPointer = mServingStackPointer;
+ mServingStackPointer = &origServingStackPointer; // anything on the stack
+
const pid_t origPid = mCallingPid;
const char* origSid = mCallingSid;
const uid_t origUid = mCallingUid;
@@ -1223,7 +1222,6 @@
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
- mIPCThreadStateBase->popCurrentState();
//ALOGI("<<<< TRANSACT from pid %d restore pid %d sid %s uid %d\n",
// mCallingPid, origPid, (origSid ? origSid : "<N/A>"), origUid);
@@ -1235,6 +1233,7 @@
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
}
+ mServingStackPointer = origServingStackPointer;
mCallingPid = origPid;
mCallingSid = origSid;
mCallingUid = origUid;
@@ -1290,8 +1289,8 @@
return result;
}
-bool IPCThreadState::isServingCall() const {
- return mIPCThreadStateBase->getCurrentBinderCallState() == IPCThreadStateBase::CallState::BINDER;
+const void* IPCThreadState::getServingStackPointer() const {
+ return mServingStackPointer;
}
void IPCThreadState::threadDestructor(void *st)
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 7489afa..9aa7651 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -26,6 +26,9 @@
},
{
"name": "aidl_lazy_test"
+ },
+ {
+ "name": "libbinderthreadstateutils_test"
}
]
}
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index a7a7292..618f88c 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -87,4 +87,7 @@
* package.
*/
@utf8InCpp String getModuleMetadataPackageName();
+
+ /* Returns the names of all packages. */
+ @utf8InCpp String[] getAllPackages();
}
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index ff9244e..4818889 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -29,8 +29,6 @@
// ---------------------------------------------------------------------------
namespace android {
-class IPCThreadStateBase;
-
class IPCThreadState
{
public:
@@ -113,31 +111,12 @@
// Service manager registration
void setTheContextObject(sp<BBinder> obj);
- // Is this thread currently serving a binder call. This method
- // returns true if while traversing backwards from the function call
- // stack for this thread, we encounter a function serving a binder
- // call before encountering a hwbinder call / hitting the end of the
- // call stack.
- // Eg: If thread T1 went through the following call pattern
- // 1) T1 receives and executes hwbinder call H1.
- // 2) While handling H1, T1 makes binder call B1.
- // 3) The handler of B1, calls into T1 with a callback B2.
- // If isServingCall() is called during H1 before 3), this method
- // will return false, else true.
+ // WARNING: DO NOT USE THIS API
//
- // ----
- // | B2 | ---> While callback B2 is being handled, during 3).
- // ----
- // | H1 | ---> While H1 is being handled.
- // ----
- // Fig: Thread Call stack while handling B2
- //
- // This is since after 3), while traversing the thread call stack,
- // we hit a binder call before a hwbinder call / end of stack. This
- // method may be typically used to determine whether to use
- // hardware::IPCThreadState methods or IPCThreadState methods to
- // infer information about thread state.
- bool isServingCall() const;
+ // Returns a pointer to the stack from the last time a transaction
+ // was initiated by the kernel. Used to compare when making nested
+ // calls between multiple different transports.
+ const void* getServingStackPointer() const;
// The work source represents the UID of the process we should attribute the transaction
// to. We use -1 to specify that the work source was not set using #setWorkSource.
@@ -181,6 +160,7 @@
Parcel mIn;
Parcel mOut;
status_t mLastError;
+ const void* mServingStackPointer;
pid_t mCallingPid;
const char* mCallingSid;
uid_t mCallingUid;
@@ -191,7 +171,6 @@
bool mPropagateWorkSource;
int32_t mStrictModePolicy;
int32_t mLastTransactionBinderFlags;
- IPCThreadStateBase *mIPCThreadStateBase;
ProcessState::CallRestriction mCallRestriction;
};
diff --git a/libs/binderthreadstate/1.0/Android.bp b/libs/binderthreadstate/1.0/Android.bp
new file mode 100644
index 0000000..ebdc932
--- /dev/null
+++ b/libs/binderthreadstate/1.0/Android.bp
@@ -0,0 +1,14 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "binderthreadstateutilstest@1.0",
+ root: "binderthreadstateutilstest",
+ system_ext_specific: true,
+ srcs: [
+ "IHidlStuff.hal",
+ ],
+ interfaces: [
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/libs/binderthreadstate/1.0/IHidlStuff.hal b/libs/binderthreadstate/1.0/IHidlStuff.hal
new file mode 100644
index 0000000..ffb6499
--- /dev/null
+++ b/libs/binderthreadstate/1.0/IHidlStuff.hal
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package binderthreadstateutilstest@1.0;
+
+interface IHidlStuff {
+ callLocal();
+ call(int32_t idx);
+};
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index ee1a6a4..4655e1d 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -12,6 +12,59 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// DO NOT ADD NEW USAGES OF THIS
+// See comments in header file.
+cc_library_static {
+ name: "libbinderthreadstateutils",
+ double_loadable: true,
+ vendor_available: true,
+ host_supported: true,
+
+ shared_libs: [
+ "libbinder",
+ "libhidlbase", // libhwbinder is in here
+ ],
+
+ export_include_dirs: ["include"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+hidl_package_root {
+ name: "binderthreadstateutilstest",
+}
+
+aidl_interface {
+ name: "binderthreadstateutilstest.aidl",
+ srcs: ["IAidlStuff.aidl"],
+}
+
+cc_test {
+ name: "libbinderthreadstateutils_test",
+ srcs: ["test.cpp"],
+ static_libs: [
+ "binderthreadstateutilstest@1.0",
+ "binderthreadstateutilstest.aidl-cpp",
+ "libbinderthreadstateutils",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libhidlbase",
+ "libutils",
+ "liblog",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+ require_root: true,
+}
+
+// TODO(b/148692216): remove empty lib
cc_library {
name: "libbinderthreadstate",
recovery_available: true,
@@ -21,28 +74,4 @@
support_system_process: true,
},
host_supported: true,
-
- srcs: [
- "IPCThreadStateBase.cpp",
- ],
-
- header_libs: [
- "libbase_headers",
- "libutils_headers",
- ],
-
- shared_libs: [
- "liblog",
- ],
-
- export_include_dirs: ["include"],
-
- sanitize: {
- misc_undefined: ["integer"],
- },
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
}
diff --git a/libs/binderthreadstate/IAidlStuff.aidl b/libs/binderthreadstate/IAidlStuff.aidl
new file mode 100644
index 0000000..0c81c42
--- /dev/null
+++ b/libs/binderthreadstate/IAidlStuff.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+interface IAidlStuff {
+ void callLocal();
+ void call(int idx);
+}
diff --git a/libs/binderthreadstate/IPCThreadStateBase.cpp b/libs/binderthreadstate/IPCThreadStateBase.cpp
deleted file mode 100644
index fede151..0000000
--- a/libs/binderthreadstate/IPCThreadStateBase.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#define LOG_TAG "IPCThreadStateBase"
-
-#include <binderthreadstate/IPCThreadStateBase.h>
-#include <android-base/macros.h>
-
-#include <utils/Log.h>
-
-#include <errno.h>
-#include <inttypes.h>
-#include <pthread.h>
-
-namespace android {
-
-static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
-static bool gHaveTLS = false;
-static pthread_key_t gTLS = 0;
-
-IPCThreadStateBase::IPCThreadStateBase() {
- pthread_setspecific(gTLS, this);
-}
-
-IPCThreadStateBase* IPCThreadStateBase::self()
-{
- if (gHaveTLS) {
-restart:
- const pthread_key_t k = gTLS;
- IPCThreadStateBase* st = (IPCThreadStateBase*)pthread_getspecific(k);
- if (st) return st;
- return new IPCThreadStateBase;
- }
-
- pthread_mutex_lock(&gTLSMutex);
- if (!gHaveTLS) {
- int key_create_value = pthread_key_create(&gTLS, threadDestructor);
- if (key_create_value != 0) {
- pthread_mutex_unlock(&gTLSMutex);
- ALOGW("IPCThreadStateBase::self() unable to create TLS key, expect a crash: %s\n",
- strerror(key_create_value));
- return nullptr;
- }
- gHaveTLS = true;
- }
- pthread_mutex_unlock(&gTLSMutex);
- goto restart;
-}
-
-void IPCThreadStateBase::pushCurrentState(CallState callState) {
- mCallStateStack.emplace(callState);
-}
-
-IPCThreadStateBase::CallState IPCThreadStateBase::popCurrentState() {
- ALOG_ASSERT(mCallStateStack.size > 0);
- CallState val = mCallStateStack.top();
- mCallStateStack.pop();
- return val;
-}
-
-IPCThreadStateBase::CallState IPCThreadStateBase::getCurrentBinderCallState() {
- if (mCallStateStack.size() > 0) {
- return mCallStateStack.top();
- }
- return CallState::NONE;
-}
-
-void IPCThreadStateBase::threadDestructor(void *st)
-{
- IPCThreadStateBase* const self = static_cast<IPCThreadStateBase*>(st);
- if (self) {
- delete self;
- }
-}
-
-}; // namespace android
diff --git a/libs/binderthreadstate/TEST_MAPPING b/libs/binderthreadstate/TEST_MAPPING
new file mode 100644
index 0000000..2bd0463
--- /dev/null
+++ b/libs/binderthreadstate/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libbinderthreadstateutils_test"
+ }
+ ]
+}
diff --git a/libs/binderthreadstate/include/binderthreadstate/CallerUtils.h b/libs/binderthreadstate/include/binderthreadstate/CallerUtils.h
new file mode 100644
index 0000000..a3e5026
--- /dev/null
+++ b/libs/binderthreadstate/include/binderthreadstate/CallerUtils.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// WARNING: DO NOT USE THIS
+// You should:
+// - have code know how it is handling things. Pass in caller information rather
+// than assuming that code is running in a specific global context
+// - use AIDL exclusively in your stack (HIDL is no longer required anywhere)
+
+#include <binder/IPCThreadState.h>
+#include <hwbinder/IPCThreadState.h>
+
+namespace android {
+
+enum class BinderCallType {
+ NONE,
+ BINDER,
+ HWBINDER,
+};
+
+// Based on where we are in recursion of nested binder/hwbinder calls, determine
+// which one we are closer to.
+inline static BinderCallType getCurrentServingCall() {
+ const void* hwbinderSp = android::hardware::IPCThreadState::self()->getServingStackPointer();
+ const void* binderSp = android::IPCThreadState::self()->getServingStackPointer();
+
+ if (hwbinderSp == nullptr && binderSp == nullptr) return BinderCallType::NONE;
+ if (hwbinderSp == nullptr) return BinderCallType::BINDER;
+ if (binderSp == nullptr) return BinderCallType::HWBINDER;
+
+ if (hwbinderSp < binderSp) return BinderCallType::HWBINDER;
+ return BinderCallType::BINDER;
+}
+
+} // namespace android
diff --git a/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h b/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
deleted file mode 100644
index 6fdcc84..0000000
--- a/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2018 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 BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
-#define BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
-
-#include <stack>
-namespace android {
-
-class IPCThreadStateBase {
-public:
- enum CallState {
- HWBINDER,
- BINDER,
- NONE,
- };
- static IPCThreadStateBase* self();
- void pushCurrentState(CallState callState);
- CallState popCurrentState();
- CallState getCurrentBinderCallState();
-
-private:
- IPCThreadStateBase();
- static void threadDestructor(void *st);
-
- std::stack<CallState> mCallStateStack;
-};
-
-}; // namespace android
-
-#endif // BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
diff --git a/libs/binderthreadstate/test.cpp b/libs/binderthreadstate/test.cpp
new file mode 100644
index 0000000..68cc225
--- /dev/null
+++ b/libs/binderthreadstate/test.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <BnAidlStuff.h>
+#include <android-base/logging.h>
+#include <binder/IServiceManager.h>
+#include <binderthreadstate/CallerUtils.h>
+#include <binderthreadstateutilstest/1.0/IHidlStuff.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlTransportSupport.h>
+#include <linux/prctl.h>
+#include <sys/prctl.h>
+
+using android::BinderCallType;
+using android::defaultServiceManager;
+using android::getCurrentServingCall;
+using android::getService;
+using android::OK;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+using android::hardware::Return;
+using binderthreadstateutilstest::V1_0::IHidlStuff;
+
+constexpr size_t kP1Id = 1;
+constexpr size_t kP2Id = 2;
+
+// AIDL and HIDL are in separate namespaces so using same service names
+std::string id2name(size_t id) {
+ return "libbinderthreadstateutils-" + std::to_string(id);
+}
+
+// There are two servers calling each other recursively like this.
+//
+// P1 P2
+// | --HIDL--> |
+// | <--HIDL-- |
+// | --AIDL--> |
+// | <--AIDL-- |
+// | --HIDL--> |
+// | <--HIDL-- |
+// | --AIDL--> |
+// | <--AIDL-- |
+// ..........
+//
+// Calls always come in pairs (AIDL returns AIDL, HIDL returns HIDL) because
+// this means that P1 always has a 'waitForResponse' call which can service the
+// returning call and continue the recursion. Of course, with more threads, more
+// complicated calls are possible, but this should do here.
+
+static void callHidl(size_t id, int32_t idx) {
+ auto stuff = IHidlStuff::getService(id2name(id));
+ CHECK(stuff->call(idx).isOk());
+}
+
+static void callAidl(size_t id, int32_t idx) {
+ sp<IAidlStuff> stuff;
+ CHECK(OK == android::getService<IAidlStuff>(String16(id2name(id).c_str()), &stuff));
+ CHECK(stuff->call(idx).isOk());
+}
+
+class HidlServer : public IHidlStuff {
+public:
+ HidlServer(size_t thisId, size_t otherId) : thisId(thisId), otherId(otherId) {}
+ size_t thisId;
+ size_t otherId;
+
+ Return<void> callLocal() {
+ CHECK(BinderCallType::NONE == getCurrentServingCall());
+ return android::hardware::Status::ok();
+ }
+ Return<void> call(int32_t idx) {
+ LOG(INFO) << "HidlServer CALL " << thisId << " to " << otherId << " at idx: " << idx
+ << " with tid: " << gettid();
+ CHECK(BinderCallType::HWBINDER == getCurrentServingCall());
+ if (idx > 0) {
+ if (thisId == kP1Id && idx % 4 < 2) {
+ callHidl(otherId, idx - 1);
+ } else {
+ callAidl(otherId, idx - 1);
+ }
+ }
+ CHECK(BinderCallType::HWBINDER == getCurrentServingCall());
+ return android::hardware::Status::ok();
+ }
+};
+class AidlServer : public BnAidlStuff {
+public:
+ AidlServer(size_t thisId, size_t otherId) : thisId(thisId), otherId(otherId) {}
+ size_t thisId;
+ size_t otherId;
+
+ Status callLocal() {
+ CHECK(BinderCallType::NONE == getCurrentServingCall());
+ return Status::ok();
+ }
+ Status call(int32_t idx) {
+ LOG(INFO) << "AidlServer CALL " << thisId << " to " << otherId << " at idx: " << idx
+ << " with tid: " << gettid();
+ CHECK(BinderCallType::BINDER == getCurrentServingCall());
+ if (idx > 0) {
+ if (thisId == kP2Id && idx % 4 < 2) {
+ callHidl(otherId, idx - 1);
+ } else {
+ callAidl(otherId, idx - 1);
+ }
+ }
+ CHECK(BinderCallType::BINDER == getCurrentServingCall());
+ return Status::ok();
+ }
+};
+
+TEST(BinderThreadState, LocalHidlCall) {
+ sp<IHidlStuff> server = new HidlServer(0, 0);
+ EXPECT_TRUE(server->callLocal().isOk());
+}
+
+TEST(BinderThreadState, LocalAidlCall) {
+ sp<IAidlStuff> server = new AidlServer(0, 0);
+ EXPECT_TRUE(server->callLocal().isOk());
+}
+
+TEST(BindThreadState, RemoteHidlCall) {
+ auto stuff = IHidlStuff::getService(id2name(kP1Id));
+ ASSERT_NE(nullptr, stuff);
+ ASSERT_TRUE(stuff->call(0).isOk());
+}
+TEST(BindThreadState, RemoteAidlCall) {
+ sp<IAidlStuff> stuff;
+ ASSERT_EQ(OK, android::getService<IAidlStuff>(String16(id2name(kP1Id).c_str()), &stuff));
+ ASSERT_NE(nullptr, stuff);
+ ASSERT_TRUE(stuff->call(0).isOk());
+}
+
+TEST(BindThreadState, RemoteNestedStartHidlCall) {
+ auto stuff = IHidlStuff::getService(id2name(kP1Id));
+ ASSERT_NE(nullptr, stuff);
+ ASSERT_TRUE(stuff->call(100).isOk());
+}
+TEST(BindThreadState, RemoteNestedStartAidlCall) {
+ sp<IAidlStuff> stuff;
+ ASSERT_EQ(OK, android::getService<IAidlStuff>(String16(id2name(kP1Id).c_str()), &stuff));
+ ASSERT_NE(nullptr, stuff);
+ EXPECT_TRUE(stuff->call(100).isOk());
+}
+
+int server(size_t thisId, size_t otherId) {
+ // AIDL
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ sp<AidlServer> aidlServer = new AidlServer(thisId, otherId);
+ CHECK(OK == defaultServiceManager()->addService(String16(id2name(thisId).c_str()), aidlServer));
+ android::ProcessState::self()->startThreadPool();
+
+ // HIDL
+ setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+ android::hardware::configureRpcThreadpool(1, true /*callerWillJoin*/);
+ sp<IHidlStuff> hidlServer = new HidlServer(thisId, otherId);
+ CHECK(OK == hidlServer->registerAsService(id2name(thisId).c_str()));
+ android::hardware::joinRpcThreadpool();
+
+ return EXIT_FAILURE;
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return server(kP1Id, kP2Id);
+ }
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return server(kP2Id, kP1Id);
+ }
+
+ android::waitForService<IAidlStuff>(String16(id2name(kP1Id).c_str()));
+ android::hardware::details::waitForHwService(IHidlStuff::descriptor, id2name(kP1Id).c_str());
+ android::waitForService<IAidlStuff>(String16(id2name(kP2Id).c_str()));
+ android::hardware::details::waitForHwService(IHidlStuff::descriptor, id2name(kP2Id).c_str());
+
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
index 9f5b0ff..de3503b 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -48,50 +48,6 @@
remote()->transact(BnGpuService::SET_GPU_STATS, data, &reply, IBinder::FLAG_ONEWAY);
}
- virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
- if (!outStats) return UNEXPECTED_NULL;
-
- Parcel data, reply;
- status_t status;
-
- if ((status = data.writeInterfaceToken(IGpuService::getInterfaceDescriptor())) != OK)
- return status;
-
- if ((status = remote()->transact(BnGpuService::GET_GPU_STATS_GLOBAL_INFO, data, &reply)) !=
- OK)
- return status;
-
- int32_t result = 0;
- if ((status = reply.readInt32(&result)) != OK) return status;
- if (result != OK) return result;
-
- outStats->clear();
- return reply.readParcelableVector(outStats);
- }
-
- virtual status_t getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const {
- if (!outStats) return UNEXPECTED_NULL;
-
- Parcel data, reply;
- status_t status;
-
- if ((status = data.writeInterfaceToken(IGpuService::getInterfaceDescriptor())) != OK) {
- return status;
- }
-
- if ((status = remote()->transact(BnGpuService::GET_GPU_STATS_APP_INFO, data, &reply)) !=
- OK) {
- return status;
- }
-
- int32_t result = 0;
- if ((status = reply.readInt32(&result)) != OK) return status;
- if (result != OK) return result;
-
- outStats->clear();
- return reply.readParcelableVector(outStats);
- }
-
virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
const GpuStatsInfo::Stats stats, const uint64_t value) {
Parcel data, reply;
@@ -150,32 +106,6 @@
return OK;
}
- case GET_GPU_STATS_GLOBAL_INFO: {
- CHECK_INTERFACE(IGpuService, data, reply);
-
- std::vector<GpuStatsGlobalInfo> stats;
- const status_t result = getGpuStatsGlobalInfo(&stats);
-
- if ((status = reply->writeInt32(result)) != OK) return status;
- if (result != OK) return result;
-
- if ((status = reply->writeParcelableVector(stats)) != OK) return status;
-
- return OK;
- }
- case GET_GPU_STATS_APP_INFO: {
- CHECK_INTERFACE(IGpuService, data, reply);
-
- std::vector<GpuStatsAppInfo> stats;
- const status_t result = getGpuStatsAppInfo(&stats);
-
- if ((status = reply->writeInt32(result)) != OK) return status;
- if (result != OK) return result;
-
- if ((status = reply->writeParcelableVector(stats)) != OK) return status;
-
- return OK;
- }
case SET_TARGET_STATS: {
CHECK_INTERFACE(IGpuService, data, reply);
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index f523d58..c7c6d1e 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -16,12 +16,11 @@
#pragma once
-#include <vector>
-
#include <binder/IInterface.h>
#include <cutils/compiler.h>
#include <graphicsenv/GpuStatsInfo.h>
-#include <graphicsenv/GraphicsEnv.h>
+
+#include <vector>
namespace android {
@@ -43,20 +42,12 @@
// set target stats.
virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
const GpuStatsInfo::Stats stats, const uint64_t value = 0) = 0;
-
- // get GPU global stats from GpuStats module.
- virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const = 0;
-
- // get GPU app stats from GpuStats module.
- virtual status_t getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const = 0;
};
class BnGpuService : public BnInterface<IGpuService> {
public:
enum IGpuServiceTag {
SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION,
- GET_GPU_STATS_GLOBAL_INFO,
- GET_GPU_STATS_APP_INFO,
SET_TARGET_STATS,
// Always append new enum to the end.
};
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 55a892e..40c044d 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -202,6 +202,10 @@
"libvndksupport",
],
+ static_libs: [
+ "libbinderthreadstateutils",
+ ],
+
header_libs: [
"libgui_headers",
"libnativebase_headers",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 4e62da7..e2f5d31 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -31,6 +31,68 @@
namespace android {
+void BLASTBufferItemConsumer::onDisconnect() {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mPreviouslyConnected = mCurrentlyConnected;
+ mCurrentlyConnected = false;
+ if (mPreviouslyConnected) {
+ mDisconnectEvents.push(mCurrentFrameNumber);
+ }
+ mFrameEventHistory.onDisconnect();
+}
+
+void BLASTBufferItemConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+ FrameEventHistoryDelta* outDelta) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ if (newTimestamps) {
+ // BufferQueueProducer only adds a new timestamp on
+ // queueBuffer
+ mCurrentFrameNumber = newTimestamps->frameNumber;
+ mFrameEventHistory.addQueue(*newTimestamps);
+ }
+ if (outDelta) {
+ // frame event histories will be processed
+ // only after the producer connects and requests
+ // deltas for the first time. Forward this intent
+ // to SF-side to turn event processing back on
+ mPreviouslyConnected = mCurrentlyConnected;
+ mCurrentlyConnected = true;
+ mFrameEventHistory.getAndResetDelta(outDelta);
+ }
+}
+
+void BLASTBufferItemConsumer::updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime,
+ const sp<Fence>& glDoneFence,
+ const sp<Fence>& presentFence,
+ const sp<Fence>& prevReleaseFence,
+ CompositorTiming compositorTiming,
+ nsecs_t latchTime, nsecs_t dequeueReadyTime) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+
+ // if the producer is not connected, don't bother updating,
+ // the next producer that connects won't access this frame event
+ if (!mCurrentlyConnected) return;
+ std::shared_ptr<FenceTime> glDoneFenceTime = std::make_shared<FenceTime>(glDoneFence);
+ std::shared_ptr<FenceTime> presentFenceTime = std::make_shared<FenceTime>(presentFence);
+ std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(prevReleaseFence);
+
+ mFrameEventHistory.addLatch(frameNumber, latchTime);
+ mFrameEventHistory.addRelease(frameNumber, dequeueReadyTime, std::move(releaseFenceTime));
+ mFrameEventHistory.addPreComposition(frameNumber, refreshStartTime);
+ mFrameEventHistory.addPostComposition(frameNumber, glDoneFenceTime, presentFenceTime,
+ compositorTiming);
+}
+
+void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect) {
+ bool disconnect = false;
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ while (!mDisconnectEvents.empty() && mDisconnectEvents.front() <= frameNumber) {
+ disconnect = true;
+ mDisconnectEvents.pop();
+ }
+ if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
+}
+
BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height)
: mSurfaceControl(surface),
mWidth(width),
@@ -39,7 +101,7 @@
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
mConsumer->setMaxAcquiredBufferCount(MAX_ACQUIRED_BUFFERS);
mBufferItemConsumer =
- new BufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
+ new BLASTBufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
static int32_t id = 0;
auto name = std::string("BLAST Consumer") + std::to_string(id);
id++;
@@ -79,11 +141,21 @@
std::unique_lock _lock{mMutex};
ATRACE_CALL();
+ if (!stats.empty()) {
+ mTransformHint = stats[0].transformHint;
+ mBufferItemConsumer->setTransformHint(mTransformHint);
+ mBufferItemConsumer->updateFrameTimestamps(stats[0].frameEventStats.frameNumber,
+ stats[0].frameEventStats.refreshStartTime,
+ stats[0].frameEventStats.gpuCompositionDoneFence,
+ stats[0].presentFence,
+ stats[0].previousReleaseFence,
+ stats[0].frameEventStats.compositorTiming,
+ stats[0].latchTime,
+ stats[0].frameEventStats.dequeueReadyTime);
+ }
if (mPendingReleaseItem.item.mGraphicBuffer != nullptr) {
- if (stats.size() > 0) {
+ if (!stats.empty()) {
mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence;
- mTransformHint = stats[0].transformHint;
- mBufferItemConsumer->setTransformHint(mTransformHint);
} else {
ALOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback");
mPendingReleaseItem.releaseFence = nullptr;
@@ -144,6 +216,14 @@
mNumAcquired++;
mSubmitted.push(bufferItem);
+ bool needsDisconnect = false;
+ mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect);
+
+ // if producer disconnected before, notify SurfaceFlinger
+ if (needsDisconnect) {
+ t->notifyProducerDisconnect(mSurfaceControl);
+ }
+
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
diff --git a/libs/gui/BufferQueueThreadState.cpp b/libs/gui/BufferQueueThreadState.cpp
index 3b531ec..c13030b 100644
--- a/libs/gui/BufferQueueThreadState.cpp
+++ b/libs/gui/BufferQueueThreadState.cpp
@@ -15,6 +15,7 @@
*/
#include <binder/IPCThreadState.h>
+#include <binderthreadstate/CallerUtils.h>
#include <hwbinder/IPCThreadState.h>
#include <private/gui/BufferQueueThreadState.h>
#include <unistd.h>
@@ -22,14 +23,14 @@
namespace android {
uid_t BufferQueueThreadState::getCallingUid() {
- if (hardware::IPCThreadState::self()->isServingCall()) {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingUid();
}
return IPCThreadState::self()->getCallingUid();
}
pid_t BufferQueueThreadState::getCallingPid() {
- if (hardware::IPCThreadState::self()->isServingCall()) {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingPid();
}
return IPCThreadState::self()->getCallingPid();
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 8af1a1c..15f966d 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -104,7 +104,7 @@
mConfigChangeFlag = configChangeFlag;
}
-int DisplayEventDispatcher::getFd() {
+int DisplayEventDispatcher::getFd() const {
return mReceiver.getFd();
}
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index e5e25aa..69f7894 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -30,6 +30,66 @@
} // Anonymous namespace
+status_t FrameEventHistoryStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeUint64(frameNumber);
+ if (err != NO_ERROR) return err;
+
+ if (gpuCompositionDoneFence) {
+ err = output->writeBool(true);
+ if (err != NO_ERROR) return err;
+
+ err = output->write(*gpuCompositionDoneFence);
+ } else {
+ err = output->writeBool(false);
+ }
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(compositorTiming.deadline);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(compositorTiming.interval);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(compositorTiming.presentLatency);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(refreshStartTime);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(dequeueReadyTime);
+ return err;
+}
+
+status_t FrameEventHistoryStats::readFromParcel(const Parcel* input) {
+ status_t err = input->readUint64(&frameNumber);
+ if (err != NO_ERROR) return err;
+
+ bool hasFence = false;
+ err = input->readBool(&hasFence);
+ if (err != NO_ERROR) return err;
+
+ if (hasFence) {
+ gpuCompositionDoneFence = new Fence();
+ err = input->read(*gpuCompositionDoneFence);
+ if (err != NO_ERROR) return err;
+ }
+
+ err = input->readInt64(&(compositorTiming.deadline));
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&(compositorTiming.interval));
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&(compositorTiming.presentLatency));
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&refreshStartTime);
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&dequeueReadyTime);
+ return err;
+}
+
status_t SurfaceStats::writeToParcel(Parcel* output) const {
status_t err = output->writeStrongBinder(surfaceControl);
if (err != NO_ERROR) {
@@ -49,6 +109,11 @@
err = output->writeBool(false);
}
err = output->writeUint32(transformHint);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ err = output->writeParcelable(eventStats);
return err;
}
@@ -74,6 +139,11 @@
}
}
err = input->readUint32(&transformHint);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ err = input->readParcelable(&eventStats);
return err;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 43bccf6..7017b7c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -222,8 +222,10 @@
surfaceControlStats
.emplace_back(callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl],
- surfaceStats.acquireTime, surfaceStats.previousReleaseFence,
- surfaceStats.transformHint);
+ transactionStats.latchTime, surfaceStats.acquireTime,
+ transactionStats.presentFence,
+ surfaceStats.previousReleaseFence, surfaceStats.transformHint,
+ surfaceStats.eventStats);
if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) {
callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl]
@@ -1235,6 +1237,18 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyProducerDisconnect(
+ const sp<SurfaceControl>& sc) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eProducerDisconnect;
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren(
const sp<SurfaceControl>& sc) {
layer_state_t* s = getLayerState(sc);
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index be429fe..d72eb5a 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -33,6 +33,35 @@
class BufferItemConsumer;
+class BLASTBufferItemConsumer : public BufferItemConsumer {
+public:
+ BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
+ int bufferCount, bool controlledByApp)
+ : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
+ mCurrentlyConnected(false),
+ mPreviouslyConnected(false) {}
+
+ void onDisconnect() override;
+ void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+ FrameEventHistoryDelta* outDelta) override
+ REQUIRES(mFrameEventHistoryMutex);
+ 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);
+ void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect);
+
+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);
+};
+
class BLASTBufferQueue
: public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
{
@@ -89,7 +118,7 @@
sp<IGraphicBufferConsumer> mConsumer;
sp<IGraphicBufferProducer> mProducer;
- sp<BufferItemConsumer> mBufferItemConsumer;
+ sp<BLASTBufferItemConsumer> mBufferItemConsumer;
SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex);
};
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 679d572..fcdf6bf 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -32,7 +32,7 @@
void dispose();
status_t scheduleVsync();
void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag);
- int getFd();
+ int getFd() const;
virtual int handleEvent(int receiveFd, int events, void* data);
protected:
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index 816dd2b..4af8659 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -174,7 +174,6 @@
std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE};
};
-
// Used by the consumer to keep track of which fields it already sent to
// the producer.
class FrameEventDirtyFields {
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 9c15225..c58634b 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -21,6 +21,7 @@
#include <binder/Parcelable.h>
#include <binder/SafeInterface.h>
+#include <gui/FrameTimestamps.h>
#include <ui/Fence.h>
#include <utils/Timers.h>
@@ -35,6 +36,27 @@
using CallbackId = int64_t;
+class FrameEventHistoryStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ FrameEventHistoryStats() = default;
+ FrameEventHistoryStats(uint64_t fn, const sp<Fence>& gpuCompFence, CompositorTiming compTiming,
+ nsecs_t refreshTime, nsecs_t dequeueReadyTime)
+ : frameNumber(fn),
+ gpuCompositionDoneFence(gpuCompFence),
+ compositorTiming(compTiming),
+ refreshStartTime(refreshTime),
+ dequeueReadyTime(dequeueReadyTime) {}
+
+ uint64_t frameNumber;
+ sp<Fence> gpuCompositionDoneFence;
+ CompositorTiming compositorTiming;
+ nsecs_t refreshStartTime;
+ nsecs_t dequeueReadyTime;
+};
+
class SurfaceStats : public Parcelable {
public:
status_t writeToParcel(Parcel* output) const override;
@@ -42,16 +64,18 @@
SurfaceStats() = default;
SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
- uint32_t hint)
+ uint32_t hint, FrameEventHistoryStats frameEventStats)
: surfaceControl(sc),
acquireTime(time),
previousReleaseFence(prevReleaseFence),
- transformHint(hint) {}
+ transformHint(hint),
+ eventStats(frameEventStats) {}
sp<IBinder> surfaceControl;
nsecs_t acquireTime = -1;
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
+ FrameEventHistoryStats eventStats;
};
class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index c256a09..2d53b48 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -102,6 +102,7 @@
eFrameRateSelectionPriority = 0x20'00000000,
eFrameRateChanged = 0x40'00000000,
eBackgroundBlurRadiusChanged = 0x80'00000000,
+ eProducerDisconnect = 0x100'00000000,
};
layer_state_t()
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 6eec2b7..d0bb6a3 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -52,17 +52,24 @@
class Region;
struct SurfaceControlStats {
- SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t time,
- const sp<Fence>& prevReleaseFence, uint32_t hint)
+ SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime, nsecs_t acquireTime,
+ const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
+ uint32_t hint, FrameEventHistoryStats eventStats)
: surfaceControl(sc),
- acquireTime(time),
+ latchTime(latchTime),
+ acquireTime(acquireTime),
+ presentFence(presentFence),
previousReleaseFence(prevReleaseFence),
- transformHint(hint) {}
+ transformHint(hint),
+ frameEventStats(eventStats) {}
sp<SurfaceControl> surfaceControl;
+ nsecs_t latchTime = -1;
nsecs_t acquireTime = -1;
+ sp<Fence> presentFence;
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
+ FrameEventHistoryStats frameEventStats;
};
using TransactionCompletedCallbackTakesContext =
@@ -484,6 +491,9 @@
Transaction& addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext);
+ // ONLY FOR BLAST ADAPTER
+ Transaction& notifyProducerDisconnect(const sp<SurfaceControl>& sc);
+
// Detaches all child surfaces (and their children recursively)
// from their SurfaceControl.
// The child SurfaceControls will not throw exceptions or return errors,
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index a273914..b40eb14 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -21,6 +21,7 @@
#include <android/hardware/graphics/common/1.2/types.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
+#include <gui/FrameTimestamps.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
#include <gui/SurfaceComposerClient.h>
@@ -647,4 +648,79 @@
TEST_F(BLASTBufferQueueTransformTest, setTransform_ROT_270) {
test(ui::Transform::ROT_270);
}
+
+class BLASTFrameEventHistoryTest : public BLASTBufferQueueTest {
+public:
+ void setUpAndQueueBuffer(const sp<IGraphicBufferProducer>& igbProducer,
+ nsecs_t* requestedPresentTime, nsecs_t* postedTime,
+ IGraphicBufferProducer::QueueBufferOutput* qbOutput,
+ bool getFrameTimestamps) {
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
+ PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr);
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+ ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
+
+ nsecs_t requestedTime = systemTime();
+ if (requestedPresentTime) *requestedPresentTime = requestedTime;
+ IGraphicBufferProducer::QueueBufferInput input(requestedTime, false, HAL_DATASPACE_UNKNOWN,
+ Rect(mDisplayWidth, mDisplayHeight),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
+ Fence::NO_FENCE, /*sticky*/ 0,
+ getFrameTimestamps);
+ if (postedTime) *postedTime = systemTime();
+ igbProducer->queueBuffer(slot, input, qbOutput);
+ }
+};
+
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> igbProducer;
+ ProducerFrameEventHistory history;
+ setUpProducer(adapter, igbProducer);
+
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ nsecs_t requestedPresentTimeA = 0;
+ nsecs_t postedTimeA = 0;
+ setUpAndQueueBuffer(igbProducer, &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);
+
+ adapter.waitForCallbacks();
+
+ // queue another buffer so we query for frame event deltas
+ 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);
+
+ ASSERT_GE(events->latchTime, postedTimeA);
+ ASSERT_GE(events->dequeueReadyTime, events->latchTime);
+ 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/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 58fff8f..0f7e2fb 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -264,6 +264,11 @@
return reinterpret_cast<Choreographer*>(choreographer);
}
+static inline const Choreographer* AChoreographer_to_Choreographer(
+ const AChoreographer* choreographer) {
+ return reinterpret_cast<const Choreographer*>(choreographer);
+}
+
static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
return reinterpret_cast<AChoreographer*>(choreographer);
}
@@ -321,7 +326,7 @@
delete AChoreographer_to_Choreographer(choreographer);
}
-int AChoreographer_getFd(AChoreographer* choreographer) {
+int AChoreographer_getFd(const AChoreographer* choreographer) {
return AChoreographer_to_Choreographer(choreographer)->getFd();
}
diff --git a/libs/nativedisplay/include/apex/choreographer.h b/libs/nativedisplay/include/apex/choreographer.h
index b17b497..683abc4 100644
--- a/libs/nativedisplay/include/apex/choreographer.h
+++ b/libs/nativedisplay/include/apex/choreographer.h
@@ -43,7 +43,7 @@
* events. One such way is registering the file descriptor to a Looper instance,
* although this is not a requirement.
*/
-int AChoreographer_getFd(AChoreographer* choreographer);
+int AChoreographer_getFd(const AChoreographer* choreographer);
/**
* Provides a callback to handle all pending events emitted by this
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 4c7b629..3d77059 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -59,7 +59,7 @@
"gl/Program.cpp",
"gl/ProgramCache.cpp",
"gl/filters/BlurFilter.cpp",
- "gl/filters/LensBlurFilter.cpp",
+ "gl/filters/KawaseBlurFilter.cpp",
"gl/filters/GaussianBlurFilter.cpp",
"gl/filters/GenericProgram.cpp",
],
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 69003fb8..e523836 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -51,7 +51,7 @@
#include "ProgramCache.h"
#include "filters/BlurFilter.h"
#include "filters/GaussianBlurFilter.h"
-#include "filters/LensBlurFilter.h"
+#include "filters/KawaseBlurFilter.h"
extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
@@ -285,6 +285,9 @@
// now figure out what version of GL did we actually get
GlesVersion version = parseGlesVersion(extensions.getVersion());
+ LOG_ALWAYS_FATAL_IF(args.supportsBackgroundBlur && version < GLES_VERSION_3_0,
+ "Blurs require OpenGL ES 3.0. Please unset ro.surface_flinger.supports_background_blur");
+
// initialize the renderer while GL is current
std::unique_ptr<GLESRenderEngine> engine;
switch (version) {
@@ -428,11 +431,11 @@
if (args.supportsBackgroundBlur) {
char isGaussian[PROPERTY_VALUE_MAX];
- property_get("debug.sf.gaussianBlur", isGaussian, "1");
+ property_get("debug.sf.gaussianBlur", isGaussian, "0");
if (atoi(isGaussian)) {
mBlurFilter = new GaussianBlurFilter(*this);
} else {
- mBlurFilter = new LensBlurFilter(*this);
+ mBlurFilter = new KawaseBlurFilter(*this);
}
checkErrors("BlurFilter creation");
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 4fc457f..ebf78fe 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -262,7 +262,7 @@
friend class GLFramebuffer;
friend class BlurFilter;
friend class GaussianBlurFilter;
- friend class LensBlurFilter;
+ friend class KawaseBlurFilter;
friend class GenericProgram;
std::unique_ptr<FlushTracer> mFlushTracer;
std::unique_ptr<ImageManager> mImageManager = std::make_unique<ImageManager>(this);
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
index 48c2560..f8b0a7a 100644
--- a/libs/renderengine/gl/filters/BlurFilter.cpp
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -71,8 +71,18 @@
}
void BlurFilter::drawMesh(GLuint uv, GLuint position) {
- GLfloat positions[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f};
- GLfloat texCoords[] = {0.0, 0.0, 0.0, 1.0f, 1.0f, 1.0f, 1.0f, 0};
+ static constexpr auto size = 2.0f;
+ static constexpr auto translation = 1.0f;
+ GLfloat positions[] = {
+ translation-size, -translation-size,
+ translation-size, -translation+size,
+ translation+size, -translation+size
+ };
+ GLfloat texCoords[] = {
+ 0.0f, 0.0f-translation,
+ 0.0f, size-translation,
+ size, size-translation
+ };
// set attributes
glEnableVertexAttribArray(uv);
@@ -82,7 +92,7 @@
positions);
// draw mesh
- glDrawArrays(GL_TRIANGLE_FAN, 0 /* first */, 4 /* count */);
+ glDrawArrays(GL_TRIANGLES, 0 /* first */, 3 /* count */);
mEngine.checkErrors("Drawing blur mesh");
}
diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h
index 6889939..67b3895 100644
--- a/libs/renderengine/gl/filters/BlurFilter.h
+++ b/libs/renderengine/gl/filters/BlurFilter.h
@@ -33,7 +33,7 @@
static constexpr float kFboScale = 0.25f;
// To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited
// image, up to this radius.
- static constexpr float kMaxCrossFadeRadius = 15.0f;
+ static constexpr float kMaxCrossFadeRadius = 30.0f;
explicit BlurFilter(GLESRenderEngine& engine);
virtual ~BlurFilter(){};
diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp
new file mode 100644
index 0000000..fc26bcc
--- /dev/null
+++ b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "KawaseBlurFilter.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#include <ui/GraphicTypes.h>
+
+#include <utils/Trace.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+KawaseBlurFilter::KawaseBlurFilter(GLESRenderEngine& engine)
+ : BlurFilter(engine), mFbo(engine), mProgram(engine) {
+ mProgram.compile(getVertexShader(), getFragmentShader());
+ mPosLoc = mProgram.getAttributeLocation("aPosition");
+ mUvLoc = mProgram.getAttributeLocation("aUV");
+ mTextureLoc = mProgram.getUniformLocation("uTexture");
+ mOffsetLoc = mProgram.getUniformLocation("uOffset");
+}
+
+void KawaseBlurFilter::allocateTextures() {
+ mFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight());
+}
+
+status_t KawaseBlurFilter::prepare() {
+ ATRACE_NAME("KawaseBlurFilter::prepare");
+
+ if (mFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
+ ALOGE("Invalid FBO");
+ return mFbo.getStatus();
+ }
+ if (!mProgram.isValid()) {
+ ALOGE("Invalid shader");
+ return GL_INVALID_OPERATION;
+ }
+
+ blit(mCompositionFbo, mBlurredFbo);
+
+ // 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.
+ auto radius = mRadius / 6.0f;
+
+ // Calculate how many passes we'll do, based on the radius.
+ // Too many passes will make the operation expensive.
+ auto passes = min(kMaxPasses, (uint32_t)ceil(radius));
+
+ // We'll ping pong between our textures, to accumulate the result of various offsets.
+ mProgram.useProgram();
+ GLFramebuffer* draw = &mFbo;
+ GLFramebuffer* read = &mBlurredFbo;
+ float stepX = radius / (float)mCompositionFbo.getBufferWidth() / (float)passes;
+ float stepY = radius / (float)mCompositionFbo.getBufferHeight() / (float)passes;
+ glActiveTexture(GL_TEXTURE0);
+ glUniform1i(mTextureLoc, 0);
+ for (auto i = 0; i < passes; i++) {
+ ATRACE_NAME("KawaseBlurFilter::renderPass");
+ draw->bind();
+
+ glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight());
+ glBindTexture(GL_TEXTURE_2D, read->getTextureName());
+ glUniform2f(mOffsetLoc, stepX * i, stepY * i);
+ mEngine.checkErrors("Setting uniforms");
+
+ drawMesh(mUvLoc, mPosLoc);
+
+ // Swap buffers for next iteration
+ auto tmp = draw;
+ draw = read;
+ read = tmp;
+ }
+
+ // Copy texture, given that we're expected to end on mBlurredFbo.
+ if (draw == &mBlurredFbo) {
+ blit(mFbo, mBlurredFbo);
+ }
+
+ // Cleanup
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return NO_ERROR;
+}
+
+string KawaseBlurFilter::getFragmentShader() const {
+ return R"SHADER(#version 310 es
+ precision mediump float;
+
+ uniform sampler2D uTexture;
+ highp uniform vec2 uOffset;
+
+ highp in vec2 vUV;
+ out vec4 fragColor;
+
+ vec4 kawaseBlur() {
+ return (texture(uTexture, vec2(-1.0, 1.0) * uOffset + vUV, 0.0)
+ + texture(uTexture, uOffset + vUV, 0.0)
+ + texture(uTexture, vec2(1.0, -1.0) * uOffset + vUV, 0.0)
+ + texture(uTexture, vec2(-1.0) * uOffset + vUV, 0.0))
+ * 0.25;
+ }
+
+ void main() {
+ fragColor = kawaseBlur();
+ }
+ )SHADER";
+}
+
+void KawaseBlurFilter::blit(GLFramebuffer& read, GLFramebuffer& draw) const {
+ read.bindAsReadBuffer();
+ draw.bindAsDrawBuffer();
+ glBlitFramebuffer(0, 0, read.getBufferWidth(), read.getBufferHeight(), 0, 0,
+ draw.getBufferWidth(), draw.getBufferHeight(), GL_COLOR_BUFFER_BIT,
+ GL_LINEAR);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.h b/libs/renderengine/gl/filters/KawaseBlurFilter.h
new file mode 100644
index 0000000..ec81f81
--- /dev/null
+++ b/libs/renderengine/gl/filters/KawaseBlurFilter.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/GraphicTypes.h>
+#include "../GLESRenderEngine.h"
+#include "../GLFramebuffer.h"
+#include "BlurFilter.h"
+#include "GenericProgram.h"
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class KawaseBlurFilter : public BlurFilter {
+public:
+ static constexpr uint32_t kMaxPasses = 8;
+
+ explicit KawaseBlurFilter(GLESRenderEngine& engine);
+ status_t prepare() override;
+ void allocateTextures() override;
+
+private:
+ string getFragmentShader() const;
+ void blit(GLFramebuffer& read, GLFramebuffer& draw) const;
+
+ GLFramebuffer mFbo;
+
+ GenericProgram mProgram;
+ GLuint mPosLoc;
+ GLuint mUvLoc;
+ GLuint mTextureLoc;
+ GLuint mOffsetLoc;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/LensBlurFilter.cpp b/libs/renderengine/gl/filters/LensBlurFilter.cpp
deleted file mode 100644
index fb29fbb..0000000
--- a/libs/renderengine/gl/filters/LensBlurFilter.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright 2019 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.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "LensBlurFilter.h"
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES3/gl3.h>
-#include <GLES3/gl3ext.h>
-#include <ui/GraphicTypes.h>
-#include <cstdint>
-
-#include <utils/Trace.h>
-
-namespace android {
-namespace renderengine {
-namespace gl {
-
-// Number of blur samples in shader (for loop)
-static constexpr auto kNumSamples = 12;
-
-LensBlurFilter::LensBlurFilter(GLESRenderEngine& engine)
- : BlurFilter(engine),
- mVerticalDiagonalPassFbo(engine, true /* multiTarget */),
- mVerticalDiagonalProgram(engine),
- mCombinedProgram(engine) {
- mVerticalDiagonalProgram.compile(getVertexShader(), getFragmentShader(false));
- mCombinedProgram.compile(getVertexShader(), getFragmentShader(true));
-
- mVDPosLoc = mVerticalDiagonalProgram.getAttributeLocation("aPosition");
- mVDUvLoc = mVerticalDiagonalProgram.getAttributeLocation("aUV");
- mVDTexture0Loc = mVerticalDiagonalProgram.getUniformLocation("uTexture0");
- mVDSizeLoc = mVerticalDiagonalProgram.getUniformLocation("uSize");
- mVDRadiusLoc = mVerticalDiagonalProgram.getUniformLocation("uRadius");
- mVDNumSamplesLoc = mVerticalDiagonalProgram.getUniformLocation("uNumSamples");
-
- mCPosLoc = mCombinedProgram.getAttributeLocation("aPosition");
- mCUvLoc = mCombinedProgram.getAttributeLocation("aUV");
- mCTexture0Loc = mCombinedProgram.getUniformLocation("uTexture0");
- mCTexture1Loc = mCombinedProgram.getUniformLocation("uTexture1");
- mCSizeLoc = mCombinedProgram.getUniformLocation("uSize");
- mCRadiusLoc = mCombinedProgram.getUniformLocation("uRadius");
- mCNumSamplesLoc = mCombinedProgram.getUniformLocation("uNumSamples");
-}
-
-void LensBlurFilter::allocateTextures() {
- mVerticalDiagonalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(),
- mBlurredFbo.getBufferHeight());
-}
-
-status_t LensBlurFilter::prepare() {
- ATRACE_NAME("LensBlurFilter::prepare");
-
- if (mVerticalDiagonalPassFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
- ALOGE("Invalid vertical-diagonal FBO");
- return mVerticalDiagonalPassFbo.getStatus();
- }
- if (!mVerticalDiagonalProgram.isValid()) {
- ALOGE("Invalid vertical-diagonal shader");
- return GL_INVALID_OPERATION;
- }
- if (!mCombinedProgram.isValid()) {
- ALOGE("Invalid blur shader");
- return GL_INVALID_OPERATION;
- }
-
- // First, we'll apply the vertical/diagonal pass, that receives the flattened background layers,
- // and writes the output to two textures (vertical and diagonal.)
- mVerticalDiagonalPassFbo.bind();
- mVerticalDiagonalProgram.useProgram();
-
- // set uniforms
- auto width = mVerticalDiagonalPassFbo.getBufferWidth();
- auto height = mVerticalDiagonalPassFbo.getBufferHeight();
- auto radiusF = fmax(1.0f, mRadius * kFboScale);
- glViewport(0, 0, width, height);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName());
- glUniform1i(mVDTexture0Loc, 0);
- glUniform2f(mVDSizeLoc, mDisplayWidth, mDisplayHeight);
- glUniform1f(mVDRadiusLoc, radiusF);
- glUniform1i(mVDNumSamplesLoc, kNumSamples);
- mEngine.checkErrors("Setting vertical-diagonal pass uniforms");
-
- drawMesh(mVDUvLoc, mVDPosLoc);
-
- // Now we'll combine the multi render pass into a blurred image
- mBlurredFbo.bind();
- mCombinedProgram.useProgram();
-
- // set uniforms
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, mVerticalDiagonalPassFbo.getTextureName());
- glUniform1i(mCTexture0Loc, 0);
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, mVerticalDiagonalPassFbo.getSecondaryTextureName());
- glUniform1i(mCTexture1Loc, 1);
- glUniform2f(mCSizeLoc, mDisplayWidth, mDisplayHeight);
- glUniform1f(mCRadiusLoc, radiusF);
- glUniform1i(mCNumSamplesLoc, kNumSamples);
- mEngine.checkErrors("Setting vertical pass uniforms");
-
- drawMesh(mCUvLoc, mCPosLoc);
-
- // reset active texture
- mBlurredFbo.unbind();
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, 0);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, 0);
-
- // unbind program
- glUseProgram(0);
-
- return NO_ERROR;
-}
-
-string LensBlurFilter::getFragmentShader(bool forComposition) const {
- string shader = "#version 310 es\n#define DIRECTION ";
- shader += (forComposition ? "1" : "0");
- shader += R"SHADER(
- precision mediump float;
- #define PI 3.14159265359
-
- uniform sampler2D uTexture0;
- uniform vec2 uSize;
- uniform float uRadius;
- uniform int uNumSamples;
-
- highp in vec2 vUV;
-
- #if DIRECTION == 0
- layout(location = 0) out vec4 fragColor0;
- layout(location = 1) out vec4 fragColor1;
- #else
- uniform sampler2D uTexture1;
- out vec4 fragColor;
- #endif
-
- const vec2 verticalMult = vec2(cos(PI / 2.0), sin(PI / 2.0));
- const vec2 diagonalMult = vec2(cos(-PI / 6.0), sin(-PI / 6.0));
- const vec2 diagonal2Mult = vec2(cos(-5.0 * PI / 6.0), sin(-5.0 * PI / 6.0));
-
- vec3 blur(const sampler2D tex, vec2 uv, const vec2 direction, float radius,
- int samples, float intensity) {
- vec3 finalColor = vec3(0.0);
- uv += direction * 0.5;
-
- for (int i = 0; i < samples; i++){
- float delta = radius * float(i) / float(samples);
- vec3 color = texture(tex, uv + direction * delta).rgb;
- color.rgb *= intensity;
- finalColor += color;
- }
-
- return finalColor / float(samples);
- }
-
- vec3 blur(const sampler2D tex, vec2 uv, const vec2 direction, float radius,
- int samples) {
- return blur(tex, uv, direction, radius, samples, 1.0);
- }
-
- vec4[2] verticalDiagonalLensBlur (vec2 uv, sampler2D texture, vec2 resolution,
- float radius, int samples) {
- // Vertical Blur
- vec2 blurDirV = 1.0 / resolution.xy * verticalMult;
- vec3 colorV = blur(texture, uv, blurDirV, radius, samples);
-
- // Diagonal Blur
- vec2 blurDirD = 1.0 / resolution.xy * diagonalMult;
- vec3 colorD = blur(texture, uv, blurDirD, radius, samples);
-
- vec4 composed[2];
- composed[0] = vec4(colorV, 1.0);
- // added * 0.5, to remap
- composed[1] = vec4((colorD + colorV) * 0.5, 1.0);
-
- return composed;
- }
-
- vec4 rhombiLensBlur (vec2 uv, sampler2D texture0, sampler2D texture1, vec2 resolution,
- float radius, int samples) {
- vec2 blurDirection1 = 1.0 / resolution.xy * diagonalMult;
- vec3 color1 = blur(texture0, uv, blurDirection1, radius, samples);
-
- vec2 blurDirection2 = 1.0 / resolution.xy * diagonal2Mult;
- vec3 color2 = blur(texture1, uv, blurDirection2, radius, samples, 2.0);
-
- return vec4((color1 + color2) * 0.33, 1.0);
- }
-
- void main() {
- #if DIRECTION == 0
- // First pass: outputs two textures
- vec4 colorOut[] = verticalDiagonalLensBlur(vUV, uTexture0, uSize, uRadius, uNumSamples);
- fragColor0 = colorOut[0];
- fragColor1 = colorOut[1];
- #else
- // Second pass: combines both textures into a blurred one.
- fragColor = rhombiLensBlur(vUV, uTexture0, uTexture1, uSize, uRadius, uNumSamples);
- #endif
- }
-
- )SHADER";
- return shader;
-}
-
-} // namespace gl
-} // namespace renderengine
-} // namespace android
diff --git a/libs/renderengine/gl/filters/LensBlurFilter.h b/libs/renderengine/gl/filters/LensBlurFilter.h
deleted file mode 100644
index 1620c5a..0000000
--- a/libs/renderengine/gl/filters/LensBlurFilter.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2019 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.
- */
-
-#pragma once
-
-#include <ui/GraphicTypes.h>
-#include "../GLESRenderEngine.h"
-#include "../GLFramebuffer.h"
-#include "BlurFilter.h"
-#include "GenericProgram.h"
-
-using namespace std;
-
-namespace android {
-namespace renderengine {
-namespace gl {
-
-class LensBlurFilter : public BlurFilter {
-public:
- explicit LensBlurFilter(GLESRenderEngine& engine);
- status_t prepare() override;
- void allocateTextures() override;
-
-private:
- string getFragmentShader(bool forComposition) const;
-
- // Intermediate render pass
- GLFramebuffer mVerticalDiagonalPassFbo;
-
- // Vertical/diagonal pass and its uniforms
- GenericProgram mVerticalDiagonalProgram;
- GLuint mVDPosLoc;
- GLuint mVDUvLoc;
- GLuint mVDTexture0Loc;
- GLuint mVDSizeLoc;
- GLuint mVDRadiusLoc;
- GLuint mVDNumSamplesLoc;
-
- // Blur composition pass and its uniforms
- GenericProgram mCombinedProgram;
- GLuint mCPosLoc;
- GLuint mCUvLoc;
- GLuint mCTexture0Loc;
- GLuint mCTexture1Loc;
- GLuint mCSizeLoc;
- GLuint mCRadiusLoc;
- GLuint mCNumSamplesLoc;
-};
-
-} // namespace gl
-} // namespace renderengine
-} // namespace android
\ No newline at end of file
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 91a76f1..7bb0e4a 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -57,16 +57,6 @@
isDriverLoaded, driverLoadingTime);
}
-status_t GpuService::getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
- mGpuStats->pullGlobalStats(outStats);
- return OK;
-}
-
-status_t GpuService::getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const {
- mGpuStats->pullAppStats(outStats);
- return OK;
-}
-
void GpuService::setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
const GpuStatsInfo::Stats stats, const uint64_t value) {
mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value);
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index b3dc2e2..b3e34d5 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -25,22 +25,11 @@
#include <mutex>
#include <vector>
-#include <unordered_map>
namespace android {
class GpuStats;
-struct MemoryStruct {
- int64_t gpuMemory;
- int64_t mappedMemory;
- int64_t ionMemory;
-};
-
-// A map that keeps track of how much memory of each type is allocated by every process.
-// Format: map[pid][memoryType] = MemoryStruct()'
-using GpuMemoryMap = std::unordered_map<int32_t, std::unordered_map<std::string, MemoryStruct>>;
-
class GpuService : public BnGpuService, public PriorityDumper {
public:
static const char* const SERVICE_NAME ANDROID_API;
@@ -59,8 +48,6 @@
const std::string& appPackageName, const int32_t vulkanVersion,
GpuStatsInfo::Driver driver, bool isDriverLoaded,
int64_t driverLoadingTime) override;
- status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const override;
- status_t getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const override;
void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
const GpuStatsInfo::Stats stats, const uint64_t value) override;
@@ -82,8 +69,6 @@
status_t doDump(int fd, const Vector<String16>& args, bool asProto);
- status_t getQCommGpuMemoryInfo(GpuMemoryMap* memories, std::string* result, int32_t dumpPid) const;
-
/*
* Attributes
*/
diff --git a/services/gpuservice/gpustats/Android.bp b/services/gpuservice/gpustats/Android.bp
index 49a98cc..f52602a 100644
--- a/services/gpuservice/gpustats/Android.bp
+++ b/services/gpuservice/gpustats/Android.bp
@@ -7,9 +7,17 @@
"libcutils",
"libgraphicsenv",
"liblog",
+ "libprotoutil",
+ "libstatslog",
+ "libstatspull",
+ "libstatssocket",
"libutils",
],
export_include_dirs: ["include"],
+ export_shared_lib_headers: [
+ "libstatspull",
+ "libstatssocket",
+ ],
cppflags: [
"-Wall",
"-Werror",
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index 71e6b97..d094532 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -17,16 +17,31 @@
#define LOG_TAG "GpuStats"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <gpustats/GpuStats.h>
+#include "gpustats/GpuStats.h"
+#include <android/util/ProtoOutputStream.h>
#include <cutils/properties.h>
#include <log/log.h>
+#include <stats_event.h>
+#include <statslog.h>
#include <utils/Trace.h>
#include <unordered_set>
namespace android {
+GpuStats::GpuStats() {
+ AStatsManager_registerPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO,
+ GpuStats::pullAtomCallback, nullptr, this);
+ AStatsManager_registerPullAtomCallback(android::util::GPU_STATS_APP_INFO,
+ GpuStats::pullAtomCallback, nullptr, this);
+}
+
+GpuStats::~GpuStats() {
+ AStatsManager_unregisterPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO);
+ AStatsManager_unregisterPullAtomCallback(android::util::GPU_STATS_APP_INFO);
+}
+
static void addLoadingCount(GpuStatsInfo::Driver driver, bool isDriverLoaded,
GpuStatsGlobalInfo* const outGlobalInfo) {
switch (driver) {
@@ -233,34 +248,114 @@
}
}
-void GpuStats::pullGlobalStats(std::vector<GpuStatsGlobalInfo>* outStats) {
- ATRACE_CALL();
+static std::string protoOutputStreamToByteString(android::util::ProtoOutputStream& proto) {
+ if (!proto.size()) return "";
- std::lock_guard<std::mutex> lock(mLock);
- outStats->clear();
- outStats->reserve(mGlobalStats.size());
-
- interceptSystemDriverStatsLocked();
-
- for (const auto& ele : mGlobalStats) {
- outStats->emplace_back(ele.second);
+ std::string byteString;
+ sp<android::util::ProtoReader> reader = proto.data();
+ while (reader->readBuffer() != nullptr) {
+ const size_t toRead = reader->currentToRead();
+ byteString.append((char*)reader->readBuffer(), toRead);
+ reader->move(toRead);
}
- mGlobalStats.clear();
+ if (byteString.size() != proto.size()) return "";
+
+ return byteString;
}
-void GpuStats::pullAppStats(std::vector<GpuStatsAppInfo>* outStats) {
+static std::string int64VectorToProtoByteString(const std::vector<int64_t>& value) {
+ if (value.empty()) return "";
+
+ android::util::ProtoOutputStream proto;
+ for (const auto& ele : value) {
+ proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+ 1 /* field id */,
+ (long long)ele);
+ }
+
+ return protoOutputStreamToByteString(proto);
+}
+
+AStatsManager_PullAtomCallbackReturn GpuStats::pullAppInfoAtom(AStatsEventList* data) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mLock);
- outStats->clear();
- outStats->reserve(mAppStats.size());
- for (const auto& ele : mAppStats) {
- outStats->emplace_back(ele.second);
+ if (data) {
+ for (const auto& ele : mAppStats) {
+ AStatsEvent* event = AStatsEventList_addStatsEvent(data);
+ AStatsEvent_setAtomId(event, android::util::GPU_STATS_APP_INFO);
+ AStatsEvent_writeString(event, ele.second.appPackageName.c_str());
+ AStatsEvent_writeInt64(event, ele.second.driverVersionCode);
+
+ std::string bytes = int64VectorToProtoByteString(ele.second.glDriverLoadingTime);
+ AStatsEvent_writeByteArray(event, (const uint8_t*)bytes.c_str(), bytes.length());
+
+ bytes = int64VectorToProtoByteString(ele.second.vkDriverLoadingTime);
+ AStatsEvent_writeByteArray(event, (const uint8_t*)bytes.c_str(), bytes.length());
+
+ bytes = int64VectorToProtoByteString(ele.second.angleDriverLoadingTime);
+ AStatsEvent_writeByteArray(event, (const uint8_t*)bytes.c_str(), bytes.length());
+
+ AStatsEvent_writeBool(event, ele.second.cpuVulkanInUse);
+ AStatsEvent_writeBool(event, ele.second.falsePrerotation);
+ AStatsEvent_writeBool(event, ele.second.gles1InUse);
+ AStatsEvent_build(event);
+ }
}
mAppStats.clear();
+
+ return AStatsManager_PULL_SUCCESS;
+}
+
+AStatsManager_PullAtomCallbackReturn GpuStats::pullGlobalInfoAtom(AStatsEventList* data) {
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mLock);
+ // flush cpuVulkanVersion and glesVersion to builtin driver stats
+ interceptSystemDriverStatsLocked();
+
+ if (data) {
+ for (const auto& ele : mGlobalStats) {
+ AStatsEvent* event = AStatsEventList_addStatsEvent(data);
+ AStatsEvent_setAtomId(event, android::util::GPU_STATS_GLOBAL_INFO);
+ AStatsEvent_writeString(event, ele.second.driverPackageName.c_str());
+ AStatsEvent_writeString(event, ele.second.driverVersionName.c_str());
+ AStatsEvent_writeInt64(event, ele.second.driverVersionCode);
+ AStatsEvent_writeInt64(event, ele.second.driverBuildTime);
+ AStatsEvent_writeInt64(event, ele.second.glLoadingCount);
+ AStatsEvent_writeInt64(event, ele.second.glLoadingFailureCount);
+ AStatsEvent_writeInt64(event, ele.second.vkLoadingCount);
+ AStatsEvent_writeInt64(event, ele.second.vkLoadingFailureCount);
+ AStatsEvent_writeInt32(event, ele.second.vulkanVersion);
+ AStatsEvent_writeInt32(event, ele.second.cpuVulkanVersion);
+ AStatsEvent_writeInt32(event, ele.second.glesVersion);
+ AStatsEvent_writeInt64(event, ele.second.angleLoadingCount);
+ AStatsEvent_writeInt64(event, ele.second.angleLoadingFailureCount);
+ AStatsEvent_build(event);
+ }
+ }
+
+ mGlobalStats.clear();
+
+ return AStatsManager_PULL_SUCCESS;
+}
+
+AStatsManager_PullAtomCallbackReturn GpuStats::pullAtomCallback(int32_t atomTag,
+ AStatsEventList* data,
+ void* cookie) {
+ ATRACE_CALL();
+
+ GpuStats* pGpuStats = reinterpret_cast<GpuStats*>(cookie);
+ if (atomTag == android::util::GPU_STATS_GLOBAL_INFO) {
+ return pGpuStats->pullGlobalInfoAtom(data);
+ } else if (atomTag == android::util::GPU_STATS_APP_INFO) {
+ return pGpuStats->pullAppInfoAtom(data);
+ }
+
+ return AStatsManager_PULL_SKIP;
}
} // namespace android
diff --git a/services/gpuservice/gpustats/include/gpustats/GpuStats.h b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
index bcb9e0d..8ca4e4e 100644
--- a/services/gpuservice/gpustats/include/gpustats/GpuStats.h
+++ b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
@@ -18,6 +18,7 @@
#include <graphicsenv/GpuStatsInfo.h>
#include <graphicsenv/GraphicsEnv.h>
+#include <stats_pull_atom_callback.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -29,8 +30,8 @@
class GpuStats {
public:
- GpuStats() = default;
- ~GpuStats() = default;
+ GpuStats();
+ ~GpuStats();
// Insert new gpu driver stats into global stats and app stats.
void insertDriverStats(const std::string& driverPackageName,
@@ -43,15 +44,22 @@
const GpuStatsInfo::Stats stats, const uint64_t value);
// dumpsys interface
void dump(const Vector<String16>& args, std::string* result);
- // Pull gpu global stats
- void pullGlobalStats(std::vector<GpuStatsGlobalInfo>* outStats);
- // Pull gpu app stats
- void pullAppStats(std::vector<GpuStatsAppInfo>* outStats);
// This limits the worst case number of loading times tracked.
static const size_t MAX_NUM_LOADING_TIMES = 50;
private:
+ // Friend class for testing.
+ friend class TestableGpuStats;
+
+ // Native atom puller callback registered in statsd.
+ static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atomTag,
+ AStatsEventList* data,
+ void* cookie);
+ // Pull global into into global atom.
+ AStatsManager_PullAtomCallbackReturn pullGlobalInfoAtom(AStatsEventList* data);
+ // Pull app into into app atom.
+ AStatsManager_PullAtomCallbackReturn pullAppInfoAtom(AStatsEventList* data);
// Dump global stats
void dumpGlobalLocked(std::string* result);
// Dump app stats
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index fee5bd4..538506d 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -26,6 +26,8 @@
"libgfxstats",
"libgraphicsenv",
"liblog",
+ "libstatslog",
+ "libstatspull",
"libutils",
],
static_libs: [
diff --git a/services/gpuservice/tests/unittests/GpuStatsTest.cpp b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
index f038c8a..37ebeae 100644
--- a/services/gpuservice/tests/unittests/GpuStatsTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
@@ -21,9 +21,13 @@
#include <gmock/gmock.h>
#include <gpustats/GpuStats.h>
#include <gtest/gtest.h>
+#include <stats_pull_atom_callback.h>
+#include <statslog.h>
#include <utils/String16.h>
#include <utils/Vector.h>
+#include "TestableGpuStats.h"
+
namespace android {
namespace {
@@ -249,5 +253,55 @@
EXPECT_FALSE(inputCommand(InputCommand::DUMP_GLOBAL).empty());
}
+TEST_F(GpuStatsTest, skipPullInvalidAtom) {
+ TestableGpuStats testableGpuStats(mGpuStats.get());
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_GLOBAL).empty());
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_APP).empty());
+
+ EXPECT_TRUE(testableGpuStats.makePullAtomCallback(-1) == AStatsManager_PULL_SKIP);
+
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_GLOBAL).empty());
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_APP).empty());
+}
+
+TEST_F(GpuStatsTest, canPullGlobalAtom) {
+ TestableGpuStats testableGpuStats(mGpuStats.get());
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_GLOBAL).empty());
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_APP).empty());
+
+ EXPECT_TRUE(testableGpuStats.makePullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO) ==
+ AStatsManager_PULL_SUCCESS);
+
+ EXPECT_TRUE(inputCommand(InputCommand::DUMP_GLOBAL).empty());
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_APP).empty());
+}
+
+TEST_F(GpuStatsTest, canPullAppAtom) {
+ TestableGpuStats testableGpuStats(mGpuStats.get());
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_GLOBAL).empty());
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_APP).empty());
+
+ EXPECT_TRUE(testableGpuStats.makePullAtomCallback(android::util::GPU_STATS_APP_INFO) ==
+ AStatsManager_PULL_SUCCESS);
+
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_GLOBAL).empty());
+ EXPECT_TRUE(inputCommand(InputCommand::DUMP_APP).empty());
+}
+
} // namespace
} // namespace android
diff --git a/services/gpuservice/tests/unittests/TestableGpuStats.h b/services/gpuservice/tests/unittests/TestableGpuStats.h
new file mode 100644
index 0000000..4ea564c
--- /dev/null
+++ b/services/gpuservice/tests/unittests/TestableGpuStats.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gpustats/GpuStats.h>
+#include <stdint.h>
+
+namespace android {
+
+class TestableGpuStats {
+public:
+ explicit TestableGpuStats(GpuStats *gpuStats) : mGpuStats(gpuStats) {}
+
+ AStatsManager_PullAtomCallbackReturn makePullAtomCallback(int32_t atomTag) {
+ return mGpuStats->pullAtomCallback(atomTag, nullptr, mGpuStats);
+ }
+
+private:
+ GpuStats *mGpuStats;
+};
+
+} // namespace android
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 1c9a4af..5246c78 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -42,6 +42,7 @@
"libbinder",
"libsensor",
"libsensorprivacy",
+ "libprotoutil",
"libcrypto",
"libbase",
"libhidlbase",
@@ -52,6 +53,8 @@
static_libs: ["android.hardware.sensors@1.0-convert"],
+ generated_headers: ["framework-cppstream-protos"],
+
// our public headers depend on libsensor and libsensorprivacy
export_shared_lib_headers: ["libsensor", "libsensorprivacy"],
}
diff --git a/services/sensorservice/RecentEventLogger.cpp b/services/sensorservice/RecentEventLogger.cpp
index 207b097..d7ca6e1 100644
--- a/services/sensorservice/RecentEventLogger.cpp
+++ b/services/sensorservice/RecentEventLogger.cpp
@@ -17,6 +17,8 @@
#include "RecentEventLogger.h"
#include "SensorServiceUtils.h"
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <utils/Timers.h>
#include <inttypes.h>
@@ -84,6 +86,40 @@
return std::string(buffer.string());
}
+/**
+ * Dump debugging information as android.service.SensorEventsProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void RecentEventLogger::dump(util::ProtoOutputStream* proto) const {
+ using namespace service::SensorEventsProto;
+ std::lock_guard<std::mutex> lk(mLock);
+
+ proto->write(RecentEventsLog::RECENT_EVENTS_COUNT, int(mRecentEvents.size()));
+ for (int i = mRecentEvents.size() - 1; i >= 0; --i) {
+ const auto& ev = mRecentEvents[i];
+ const uint64_t token = proto->start(RecentEventsLog::EVENTS);
+ proto->write(Event::TIMESTAMP_SEC, float(ev.mEvent.timestamp) / 1e9f);
+ proto->write(Event::WALL_TIMESTAMP_MS, ev.mWallTime.tv_sec * 1000LL
+ + ns2ms(ev.mWallTime.tv_nsec));
+
+ if (mMaskData) {
+ proto->write(Event::MASKED, true);
+ } else {
+ if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+ proto->write(Event::INT64_DATA, int64_t(ev.mEvent.u64.step_counter));
+ } else {
+ for (size_t k = 0; k < mEventSize; ++k) {
+ proto->write(Event::FLOAT_ARRAY, ev.mEvent.data[k]);
+ }
+ }
+ }
+ proto->end(token);
+ }
+}
+
void RecentEventLogger::setFormat(std::string format) {
if (format == "mask_data" ) {
mMaskData = true;
diff --git a/services/sensorservice/RecentEventLogger.h b/services/sensorservice/RecentEventLogger.h
index 67378b7..3a2ae77 100644
--- a/services/sensorservice/RecentEventLogger.h
+++ b/services/sensorservice/RecentEventLogger.h
@@ -48,6 +48,7 @@
// Dumpable interface
virtual std::string dump() const override;
+ virtual void dump(util::ProtoOutputStream* proto) const override;
virtual void setFormat(std::string format) override;
protected:
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index c7a8f5b..33f940f 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -21,6 +21,8 @@
#include "SensorService.h"
#include <android-base/logging.h>
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <sensors/convert.h>
#include <cutils/atomic.h>
#include <utils/Errors.h>
@@ -39,6 +41,7 @@
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
+using android::util::ProtoOutputStream;
namespace android {
// ---------------------------------------------------------------------------
@@ -396,6 +399,43 @@
return result.string();
}
+/**
+ * Dump debugging information as android.service.SensorDeviceProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorDevice::dump(ProtoOutputStream* proto) const {
+ using namespace service::SensorDeviceProto;
+ if (mSensors == nullptr) {
+ proto->write(INITIALIZED , false);
+ return;
+ }
+ proto->write(INITIALIZED , true);
+ proto->write(TOTAL_SENSORS , int(mSensorList.size()));
+ proto->write(ACTIVE_SENSORS , int(mActivationCount.size()));
+
+ Mutex::Autolock _l(mLock);
+ for (const auto & s : mSensorList) {
+ int32_t handle = s.handle;
+ const Info& info = mActivationCount.valueFor(handle);
+ if (info.numActiveClients() == 0) continue;
+
+ uint64_t token = proto->start(SENSORS);
+ proto->write(SensorProto::HANDLE , handle);
+ proto->write(SensorProto::ACTIVE_COUNT , int(info.batchParams.size()));
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ const BatchParams& params = info.batchParams[j];
+ proto->write(SensorProto::SAMPLING_PERIOD_MS , params.mTSample / 1e6f);
+ proto->write(SensorProto::BATCHING_PERIOD_MS , params.mTBatch / 1e6f);
+ }
+ proto->write(SensorProto::SAMPLING_PERIOD_SELECTED , info.bestBatchParams.mTSample / 1e6f);
+ proto->write(SensorProto::BATCHING_PERIOD_SELECTED , info.bestBatchParams.mTBatch / 1e6f);
+ proto->end(token);
+ }
+}
+
ssize_t SensorDevice::getSensorList(sensor_t const** list) {
*list = &mSensorList[0];
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index d2c6994..33aa7d6 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -123,7 +123,8 @@
bool isSensorActive(int handle) const;
// Dumpable
- virtual std::string dump() const;
+ virtual std::string dump() const override;
+ virtual void dump(util::ProtoOutputStream* proto) const override;
private:
friend class Singleton<SensorDevice>;
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index cd0ea5d..106efd6 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -16,12 +16,16 @@
#include "SensorDevice.h"
#include "SensorDirectConnection.h"
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <hardware/sensors.h>
#define UNUSED(x) (void)(x)
namespace android {
+using util::ProtoOutputStream;
+
SensorService::SensorDirectConnection::SensorDirectConnection(const sp<SensorService>& service,
uid_t uid, const sensors_direct_mem_t *mem, int32_t halChannelHandle,
const String16& opPackageName)
@@ -64,6 +68,27 @@
}
}
+/**
+ * Dump debugging information as android.service.SensorDirectConnectionProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorService::SensorDirectConnection::dump(ProtoOutputStream* proto) const {
+ using namespace service::SensorDirectConnectionProto;
+ Mutex::Autolock _l(mConnectionLock);
+ proto->write(PACKAGE_NAME, std::string(String8(mOpPackageName).string()));
+ proto->write(HAL_CHANNEL_HANDLE, getHalChannelHandle());
+ proto->write(NUM_SENSOR_ACTIVATED, int(mActivated.size()));
+ for (auto &i : mActivated) {
+ uint64_t token = proto->start(SENSORS);
+ proto->write(SensorProto::SENSOR, i.first);
+ proto->write(SensorProto::RATE, i.second);
+ proto->end(token);
+ }
+}
+
sp<BitTube> SensorService::SensorDirectConnection::getSensorChannel() const {
return nullptr;
}
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index 5c398a8..ead08d3 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -40,6 +40,7 @@
const sensors_direct_mem_t *mem, int32_t halChannelHandle,
const String16& opPackageName);
void dump(String8& result) const;
+ void dump(util::ProtoOutputStream* proto) const;
uid_t getUid() const { return mUid; }
int32_t getHalChannelHandle() const;
bool isEquivalent(const sensors_direct_mem_t *mem) const;
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 0e40940..9a13c00 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -17,6 +17,8 @@
#include <sys/socket.h>
#include <utils/threads.h>
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <sensor/SensorEventQueue.h>
#include "vec.h"
@@ -110,6 +112,51 @@
#endif
}
+/**
+ * Dump debugging information as android.service.SensorEventConnectionProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorService::SensorEventConnection::dump(util::ProtoOutputStream* proto) const {
+ using namespace service::SensorEventConnectionProto;
+ Mutex::Autolock _l(mConnectionLock);
+
+ if (!mService->isWhiteListedPackage(getPackageName())) {
+ proto->write(OPERATING_MODE, OP_MODE_RESTRICTED);
+ } else if (mDataInjectionMode) {
+ proto->write(OPERATING_MODE, OP_MODE_DATA_INJECTION);
+ } else {
+ proto->write(OPERATING_MODE, OP_MODE_NORMAL);
+ }
+ proto->write(PACKAGE_NAME, std::string(mPackageName.string()));
+ proto->write(WAKE_LOCK_REF_COUNT, int32_t(mWakeLockRefCount));
+ proto->write(UID, int32_t(mUid));
+ proto->write(CACHE_SIZE, int32_t(mCacheSize));
+ proto->write(MAX_CACHE_SIZE, int32_t(mMaxCacheSize));
+ for (size_t i = 0; i < mSensorInfo.size(); ++i) {
+ const FlushInfo& flushInfo = mSensorInfo.valueAt(i);
+ const uint64_t token = proto->start(FLUSH_INFOS);
+ proto->write(FlushInfoProto::SENSOR_NAME,
+ std::string(mService->getSensorName(mSensorInfo.keyAt(i))));
+ proto->write(FlushInfoProto::SENSOR_HANDLE, mSensorInfo.keyAt(i));
+ proto->write(FlushInfoProto::FIRST_FLUSH_PENDING, flushInfo.mFirstFlushPending);
+ proto->write(FlushInfoProto::PENDING_FLUSH_EVENTS_TO_SEND,
+ flushInfo.mPendingFlushEventsToSend);
+ proto->end(token);
+ }
+#if DEBUG_CONNECTIONS
+ proto->write(EVENTS_RECEIVED, mEventsReceived);
+ proto->write(EVENTS_SENT, mEventsSent);
+ proto->write(EVENTS_CACHE, mEventsSentFromCache);
+ proto->write(EVENTS_DROPPED, mEventsReceived - (mEventsSentFromCache + mEventsSent +
+ mCacheSize));
+ proto->write(TOTAL_ACKS_NEEDED, mTotalAcksNeeded);
+ proto->write(TOTAL_ACKS_RECEIVED, mTotalAcksReceived);
+#endif
+}
+
bool SensorService::SensorEventConnection::addSensor(int32_t handle) {
Mutex::Autolock _l(mConnectionLock);
sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index fd881cb..caf5d7c 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -62,6 +62,7 @@
bool removeSensor(int32_t handle);
void setFirstFlushPending(int32_t handle, bool value);
void dump(String8& result);
+ void dump(util::ProtoOutputStream* proto) const;
bool needsWakeLock();
void resetWakeLockRefCount();
String8 getPackageName() const;
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
index 414f673..e27b52b 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -18,6 +18,9 @@
#include "SensorFusion.h"
#include "SensorService.h"
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
+
namespace android {
// ---------------------------------------------------------------------------
@@ -183,7 +186,7 @@
return mAcc.getMinDelay();
}
-void SensorFusion::dump(String8& result) {
+void SensorFusion::dump(String8& result) const {
const Fusion& fusion_9axis(mFusions[FUSION_9AXIS]);
result.appendFormat("9-axis fusion %s (%zd clients), gyro-rate=%7.2fHz, "
"q=< %g, %g, %g, %g > (%g), "
@@ -235,5 +238,42 @@
fusion_nogyro.getBias().z);
}
+void SensorFusion::dumpFusion(FUSION_MODE mode, util::ProtoOutputStream* proto) const {
+ using namespace service::SensorFusionProto::FusionProto;
+ const Fusion& fusion(mFusions[mode]);
+ proto->write(ENABLED, mEnabled[mode]);
+ proto->write(NUM_CLIENTS, (int)mClients[mode].size());
+ proto->write(ESTIMATED_GYRO_RATE, mEstimatedGyroRate);
+ proto->write(ATTITUDE_X, fusion.getAttitude().x);
+ proto->write(ATTITUDE_Y, fusion.getAttitude().y);
+ proto->write(ATTITUDE_Z, fusion.getAttitude().z);
+ proto->write(ATTITUDE_W, fusion.getAttitude().w);
+ proto->write(ATTITUDE_LENGTH, length(fusion.getAttitude()));
+ proto->write(BIAS_X, fusion.getBias().x);
+ proto->write(BIAS_Y, fusion.getBias().y);
+ proto->write(BIAS_Z, fusion.getBias().z);
+}
+
+/**
+ * Dump debugging information as android.service.SensorFusionProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorFusion::dump(util::ProtoOutputStream* proto) const {
+ uint64_t token = proto->start(service::SensorFusionProto::FUSION_9AXIS);
+ dumpFusion(FUSION_9AXIS, proto);
+ proto->end(token);
+
+ token = proto->start(service::SensorFusionProto::FUSION_NOMAG);
+ dumpFusion(FUSION_NOMAG, proto);
+ proto->end(token);
+
+ token = proto->start(service::SensorFusionProto::FUSION_NOGYRO);
+ dumpFusion(FUSION_NOGYRO, proto);
+ proto->end(token);
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h
index 8c0fbf9..66a7290 100644
--- a/services/sensorservice/SensorFusion.h
+++ b/services/sensorservice/SensorFusion.h
@@ -90,7 +90,9 @@
float getPowerUsage(int mode=FUSION_9AXIS) const;
int32_t getMinDelay() const;
- void dump(String8& result);
+ void dump(String8& result) const;
+ void dump(util::ProtoOutputStream* proto) const;
+ void dumpFusion(FUSION_MODE mode, util::ProtoOutputStream* proto) const;
};
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
index aa306d8..0ce32cc 100644
--- a/services/sensorservice/SensorList.cpp
+++ b/services/sensorservice/SensorList.cpp
@@ -16,6 +16,8 @@
#include "SensorList.h"
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <hardware/sensors.h>
#include <utils/String8.h>
@@ -203,6 +205,64 @@
return std::string(result.string());
}
+/**
+ * Dump debugging information as android.service.SensorListProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorList::dump(util::ProtoOutputStream* proto) const {
+ using namespace service::SensorListProto;
+ using namespace service::SensorListProto::SensorProto;
+
+ forEachSensor([&proto] (const Sensor& s) -> bool {
+ const uint64_t token = proto->start(SENSORS);
+ proto->write(HANDLE, s.getHandle());
+ proto->write(NAME, std::string(s.getName().string()));
+ proto->write(VENDOR, std::string(s.getVendor().string()));
+ proto->write(VERSION, s.getVersion());
+ proto->write(STRING_TYPE, std::string(s.getStringType().string()));
+ proto->write(TYPE, s.getType());
+ proto->write(REQUIRED_PERMISSION, std::string(s.getRequiredPermission().size() ?
+ s.getRequiredPermission().string() : ""));
+ proto->write(FLAGS, int(s.getFlags()));
+ switch (s.getReportingMode()) {
+ case AREPORTING_MODE_CONTINUOUS:
+ proto->write(REPORTING_MODE, RM_CONTINUOUS);
+ break;
+ case AREPORTING_MODE_ON_CHANGE:
+ proto->write(REPORTING_MODE, RM_ON_CHANGE);
+ break;
+ case AREPORTING_MODE_ONE_SHOT:
+ proto->write(REPORTING_MODE, RM_ONE_SHOT);
+ break;
+ case AREPORTING_MODE_SPECIAL_TRIGGER:
+ proto->write(REPORTING_MODE, RM_SPECIAL_TRIGGER);
+ break;
+ default:
+ proto->write(REPORTING_MODE, RM_UNKNOWN);
+ }
+ proto->write(MAX_DELAY_US, s.getMaxDelay());
+ proto->write(MIN_DELAY_US, s.getMinDelay());
+ proto->write(FIFO_MAX_EVENT_COUNT, int(s.getFifoMaxEventCount()));
+ proto->write(FIFO_RESERVED_EVENT_COUNT, int(s.getFifoReservedEventCount()));
+ proto->write(IS_WAKEUP, s.isWakeUpSensor());
+ proto->write(DATA_INJECTION_SUPPORTED, s.isDataInjectionSupported());
+ proto->write(IS_DYNAMIC, s.isDynamicSensor());
+ proto->write(HAS_ADDITIONAL_INFO, s.hasAdditionalInfo());
+ proto->write(HIGHEST_RATE_LEVEL, s.getHighestDirectReportRateLevel());
+ proto->write(ASHMEM, s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_ASHMEM));
+ proto->write(GRALLOC, s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_GRALLOC));
+ proto->write(MIN_VALUE, s.getMinValue());
+ proto->write(MAX_VALUE, s.getMaxValue());
+ proto->write(RESOLUTION, s.getResolution());
+ proto->write(POWER_USAGE, s.getPowerUsage());
+ proto->end(token);
+ return true;
+ });
+}
+
SensorList::~SensorList() {
}
diff --git a/services/sensorservice/SensorList.h b/services/sensorservice/SensorList.h
index 6b90ad9..8424b22 100644
--- a/services/sensorservice/SensorList.h
+++ b/services/sensorservice/SensorList.h
@@ -71,6 +71,7 @@
// Dumpable interface
virtual std::string dump() const override;
+ virtual void dump(util::ProtoOutputStream* proto) const override;
virtual ~SensorList();
private:
diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index 5411515..a34a65b 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -17,10 +17,14 @@
#ifndef ANDROID_SENSOR_REGISTRATION_INFO_H
#define ANDROID_SENSOR_REGISTRATION_INFO_H
-#include "SensorServiceUtils.h"
-#include <utils/Thread.h>
+#include <ctime>
#include <iomanip>
#include <sstream>
+#include <utils/Thread.h>
+
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
+#include "SensorServiceUtils.h"
namespace android {
@@ -30,7 +34,7 @@
public:
SensorRegistrationInfo() : mPackageName() {
mSensorHandle = mSamplingRateUs = mMaxReportLatencyUs = INT32_MIN;
- mHour = mMin = mSec = INT8_MIN;
+ mRealtimeSec = 0;
mActivated = false;
}
@@ -47,25 +51,26 @@
mPid = (thread != nullptr) ? thread->getCallingPid() : -1;
mUid = (thread != nullptr) ? thread->getCallingUid() : -1;
- time_t rawtime = time(nullptr);
- struct tm * timeinfo = localtime(&rawtime);
- mHour = static_cast<int8_t>(timeinfo->tm_hour);
- mMin = static_cast<int8_t>(timeinfo->tm_min);
- mSec = static_cast<int8_t>(timeinfo->tm_sec);
+ timespec curTime;
+ clock_gettime(CLOCK_REALTIME_COARSE, &curTime);
+ mRealtimeSec = curTime.tv_sec;
}
static bool isSentinel(const SensorRegistrationInfo& info) {
- return (info.mHour == INT8_MIN &&
- info.mMin == INT8_MIN &&
- info.mSec == INT8_MIN);
+ return (info.mSensorHandle == INT32_MIN && info.mRealtimeSec == 0);
}
// Dumpable interface
virtual std::string dump() const override {
+ struct tm* timeinfo = localtime(&mRealtimeSec);
+ const int8_t hour = static_cast<int8_t>(timeinfo->tm_hour);
+ const int8_t min = static_cast<int8_t>(timeinfo->tm_min);
+ const int8_t sec = static_cast<int8_t>(timeinfo->tm_sec);
+
std::ostringstream ss;
- ss << std::setfill('0') << std::setw(2) << static_cast<int>(mHour) << ":"
- << std::setw(2) << static_cast<int>(mMin) << ":"
- << std::setw(2) << static_cast<int>(mSec)
+ ss << std::setfill('0') << std::setw(2) << static_cast<int>(hour) << ":"
+ << std::setw(2) << static_cast<int>(min) << ":"
+ << std::setw(2) << static_cast<int>(sec)
<< (mActivated ? " +" : " -")
<< " 0x" << std::hex << std::setw(8) << mSensorHandle << std::dec
<< std::setfill(' ') << " pid=" << std::setw(5) << mPid
@@ -77,6 +82,25 @@
return ss.str();
}
+ /**
+ * Dump debugging information as android.service.SensorRegistrationInfoProto protobuf message
+ * using ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+ virtual void dump(util::ProtoOutputStream* proto) const override {
+ using namespace service::SensorRegistrationInfoProto;
+ proto->write(TIMESTAMP_SEC, int64_t(mRealtimeSec));
+ proto->write(SENSOR_HANDLE, mSensorHandle);
+ proto->write(PACKAGE_NAME, std::string(mPackageName.string()));
+ proto->write(PID, int32_t(mPid));
+ proto->write(UID, int32_t(mUid));
+ proto->write(SAMPLING_RATE_US, mSamplingRateUs);
+ proto->write(MAX_REPORT_LATENCY_US, mMaxReportLatencyUs);
+ proto->write(ACTIVATED, mActivated);
+ }
+
private:
int32_t mSensorHandle;
String8 mPackageName;
@@ -85,8 +109,7 @@
int64_t mSamplingRateUs;
int64_t mMaxReportLatencyUs;
bool mActivated;
- int8_t mHour, mMin, mSec;
-
+ time_t mRealtimeSec;
};
} // namespace android;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index c2e1204..e803c9a 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
#include <android/content/pm/IPackageManagerNative.h>
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <binder/ActivityManager.h>
#include <binder/BinderService.h>
#include <binder/IServiceManager.h>
@@ -404,6 +406,8 @@
// Transition to data injection mode supported only from NORMAL mode.
return INVALID_OPERATION;
}
+ } else if (args.size() == 1 && args[0] == String16("--proto")) {
+ return dumpProtoLocked(fd, &connLock);
} else if (!mSensors.hasAnySensor()) {
result.append("No Sensors on the device\n");
result.appendFormat("devInitCheck : %d\n", SensorDevice::getInstance().initCheck());
@@ -506,6 +510,124 @@
return NO_ERROR;
}
+/**
+ * Dump debugging information as android.service.SensorServiceProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+status_t SensorService::dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock) const {
+ using namespace service::SensorServiceProto;
+ util::ProtoOutputStream proto;
+ const bool privileged = IPCThreadState::self()->getCallingUid() == 0;
+
+ timespec curTime;
+ clock_gettime(CLOCK_REALTIME, &curTime);
+ proto.write(CURRENT_TIME_MS, curTime.tv_sec * 1000 + ns2ms(curTime.tv_nsec));
+
+ // Write SensorDeviceProto
+ uint64_t token = proto.start(SENSOR_DEVICE);
+ SensorDevice::getInstance().dump(&proto);
+ proto.end(token);
+
+ // Write SensorListProto
+ token = proto.start(SENSORS);
+ mSensors.dump(&proto);
+ proto.end(token);
+
+ // Write SensorFusionProto
+ token = proto.start(FUSION_STATE);
+ SensorFusion::getInstance().dump(&proto);
+ proto.end(token);
+
+ // Write SensorEventsProto
+ token = proto.start(SENSOR_EVENTS);
+ for (auto&& i : mRecentEvent) {
+ sp<SensorInterface> s = mSensors.getInterface(i.first);
+ if (!i.second->isEmpty()) {
+ i.second->setFormat(privileged || s->getSensor().getRequiredPermission().isEmpty() ?
+ "normal" : "mask_data");
+ const uint64_t mToken = proto.start(service::SensorEventsProto::RECENT_EVENTS_LOGS);
+ proto.write(service::SensorEventsProto::RecentEventsLog::NAME,
+ std::string(s->getSensor().getName().string()));
+ i.second->dump(&proto);
+ proto.end(mToken);
+ }
+ }
+ proto.end(token);
+
+ // Write ActiveSensorProto
+ SensorDevice& dev = SensorDevice::getInstance();
+ for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
+ int handle = mActiveSensors.keyAt(i);
+ if (dev.isSensorActive(handle)) {
+ token = proto.start(ACTIVE_SENSORS);
+ proto.write(service::ActiveSensorProto::NAME,
+ std::string(getSensorName(handle).string()));
+ proto.write(service::ActiveSensorProto::HANDLE, handle);
+ proto.write(service::ActiveSensorProto::NUM_CONNECTIONS,
+ int(mActiveSensors.valueAt(i)->getNumConnections()));
+ proto.end(token);
+ }
+ }
+
+ proto.write(SOCKET_BUFFER_SIZE, int(mSocketBufferSize));
+ proto.write(SOCKET_BUFFER_SIZE_IN_EVENTS, int(mSocketBufferSize / sizeof(sensors_event_t)));
+ proto.write(WAKE_LOCK_ACQUIRED, mWakeLockAcquired);
+
+ switch(mCurrentOperatingMode) {
+ case NORMAL:
+ proto.write(OPERATING_MODE, OP_MODE_NORMAL);
+ break;
+ case RESTRICTED:
+ proto.write(OPERATING_MODE, OP_MODE_RESTRICTED);
+ proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.string()));
+ break;
+ case DATA_INJECTION:
+ proto.write(OPERATING_MODE, OP_MODE_DATA_INJECTION);
+ proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.string()));
+ break;
+ default:
+ proto.write(OPERATING_MODE, OP_MODE_UNKNOWN);
+ }
+ proto.write(SENSOR_PRIVACY, mSensorPrivacyPolicy->isSensorPrivacyEnabled());
+
+ // Write repeated SensorEventConnectionProto
+ const auto& activeConnections = connLock->getActiveConnections();
+ for (size_t i = 0; i < activeConnections.size(); i++) {
+ token = proto.start(ACTIVE_CONNECTIONS);
+ activeConnections[i]->dump(&proto);
+ proto.end(token);
+ }
+
+ // Write repeated SensorDirectConnectionProto
+ const auto& directConnections = connLock->getDirectConnections();
+ for (size_t i = 0 ; i < directConnections.size() ; i++) {
+ token = proto.start(DIRECT_CONNECTIONS);
+ directConnections[i]->dump(&proto);
+ proto.end(token);
+ }
+
+ // Write repeated SensorRegistrationInfoProto
+ const int startIndex = mNextSensorRegIndex;
+ int curr = startIndex;
+ do {
+ const SensorRegistrationInfo& reg_info = mLastNSensorRegistrations[curr];
+ if (SensorRegistrationInfo::isSentinel(reg_info)) {
+ // Ignore sentinel, proceed to next item.
+ curr = (curr + 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % SENSOR_REGISTRATIONS_BUF_SIZE;
+ continue;
+ }
+ token = proto.start(PREVIOUS_REGISTRATIONS);
+ reg_info.dump(&proto);
+ proto.end(token);
+ curr = (curr + 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % SENSOR_REGISTRATIONS_BUF_SIZE;
+ } while (startIndex != curr);
+
+ return proto.flush(fd) ? OK : UNKNOWN_ERROR;
+}
+
void SensorService::disableAllSensors() {
ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
disableAllSensorsLocked(&connLock);
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index fa23da0..7d17dda 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -286,6 +286,7 @@
virtual int setOperationParameter(
int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
virtual status_t dump(int fd, const Vector<String16>& args);
+ status_t dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock) const;
String8 getSensorName(int handle) const;
bool isVirtualSensor(int handle) const;
sp<SensorInterface> getSensorInterfaceFromHandle(int handle) const;
diff --git a/services/sensorservice/SensorServiceUtils.h b/services/sensorservice/SensorServiceUtils.h
index 1558feb..49457cf 100644
--- a/services/sensorservice/SensorServiceUtils.h
+++ b/services/sensorservice/SensorServiceUtils.h
@@ -21,11 +21,17 @@
#include <string>
namespace android {
+
+namespace util {
+class ProtoOutputStream;
+}
+
namespace SensorServiceUtil {
class Dumpable {
public:
virtual std::string dump() const = 0;
+ virtual void dump(util::ProtoOutputStream*) const {}
virtual void setFormat(std::string ) {}
virtual ~Dumpable() {}
};
diff --git a/services/stats/Android.bp b/services/stats/Android.bp
new file mode 100644
index 0000000..1ce0524
--- /dev/null
+++ b/services/stats/Android.bp
@@ -0,0 +1,22 @@
+cc_library_shared {
+ name: "libstatshidl",
+ srcs: [
+ "StatsHal.cpp",
+ ],
+ cflags: ["-Wall", "-Werror"],
+ shared_libs: [
+ "android.frameworks.stats@1.0",
+ "libhidlbase",
+ "liblog",
+ "libstatslog",
+ "libstatssocket",
+ "libutils",
+ ],
+ export_include_dirs: [
+ "include/",
+ ],
+ local_include_dirs: [
+ "include/stats",
+ ],
+ vintf_fragments: ["android.frameworks.stats@1.0-service.xml"]
+}
diff --git a/services/stats/OWNERS b/services/stats/OWNERS
new file mode 100644
index 0000000..a61babf
--- /dev/null
+++ b/services/stats/OWNERS
@@ -0,0 +1,9 @@
+jeffreyhuang@google.com
+joeo@google.com
+jtnguyen@google.com
+muhammadq@google.com
+ruchirr@google.com
+singhtejinder@google.com
+tsaichristine@google.com
+yaochen@google.com
+yro@google.com
diff --git a/services/stats/StatsHal.cpp b/services/stats/StatsHal.cpp
new file mode 100644
index 0000000..80c3b65
--- /dev/null
+++ b/services/stats/StatsHal.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#define LOG_TAG "StatsHal"
+
+#include <log/log.h>
+#include <statslog.h>
+
+#include "StatsHal.h"
+
+namespace android {
+namespace frameworks {
+namespace stats {
+namespace V1_0 {
+namespace implementation {
+
+StatsHal::StatsHal() {}
+
+hardware::Return<void> StatsHal::reportSpeakerImpedance(
+ const SpeakerImpedance& speakerImpedance) {
+ android::util::stats_write(android::util::SPEAKER_IMPEDANCE_REPORTED,
+ speakerImpedance.speakerLocation, speakerImpedance.milliOhms);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportHardwareFailed(const HardwareFailed& hardwareFailed) {
+ android::util::stats_write(android::util::HARDWARE_FAILED, int32_t(hardwareFailed.hardwareType),
+ hardwareFailed.hardwareLocation, int32_t(hardwareFailed.errorCode));
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportPhysicalDropDetected(
+ const PhysicalDropDetected& physicalDropDetected) {
+ android::util::stats_write(android::util::PHYSICAL_DROP_DETECTED,
+ int32_t(physicalDropDetected.confidencePctg), physicalDropDetected.accelPeak,
+ physicalDropDetected.freefallDuration);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportChargeCycles(const ChargeCycles& chargeCycles) {
+ std::vector<int32_t> buckets = chargeCycles.cycleBucket;
+ int initialSize = buckets.size();
+ for (int i = 0; i < 10 - initialSize; i++) {
+ buckets.push_back(-1); // Push -1 for buckets that do not exist.
+ }
+ android::util::stats_write(android::util::CHARGE_CYCLES_REPORTED, buckets[0], buckets[1],
+ buckets[2], buckets[3], buckets[4], buckets[5], buckets[6], buckets[7], buckets[8],
+ buckets[9]);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportBatteryHealthSnapshot(
+ const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) {
+ android::util::stats_write(android::util::BATTERY_HEALTH_SNAPSHOT,
+ int32_t(batteryHealthSnapshotArgs.type), batteryHealthSnapshotArgs.temperatureDeciC,
+ batteryHealthSnapshotArgs.voltageMicroV, batteryHealthSnapshotArgs.currentMicroA,
+ batteryHealthSnapshotArgs.openCircuitVoltageMicroV,
+ batteryHealthSnapshotArgs.resistanceMicroOhm, batteryHealthSnapshotArgs.levelPercent);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportSlowIo(const SlowIo& slowIo) {
+ android::util::stats_write(android::util::SLOW_IO, int32_t(slowIo.operation), slowIo.count);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportBatteryCausedShutdown(
+ const BatteryCausedShutdown& batteryCausedShutdown) {
+ android::util::stats_write(android::util::BATTERY_CAUSED_SHUTDOWN,
+ batteryCausedShutdown.voltageMicroV);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportUsbPortOverheatEvent(
+ const UsbPortOverheatEvent& usbPortOverheatEvent) {
+ android::util::stats_write(android::util::USB_PORT_OVERHEAT_EVENT_REPORTED,
+ usbPortOverheatEvent.plugTemperatureDeciC, usbPortOverheatEvent.maxTemperatureDeciC,
+ usbPortOverheatEvent.timeToOverheat, usbPortOverheatEvent.timeToHysteresis,
+ usbPortOverheatEvent.timeToInactive);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportSpeechDspStat(
+ const SpeechDspStat& speechDspStat) {
+ android::util::stats_write(android::util::SPEECH_DSP_STAT_REPORTED,
+ speechDspStat.totalUptimeMillis, speechDspStat.totalDowntimeMillis,
+ speechDspStat.totalCrashCount, speechDspStat.totalRecoverCount);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
+ std::string reverseDomainName = (std::string) vendorAtom.reverseDomainName;
+ if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
+ ALOGE("Atom ID %ld is not a valid vendor atom ID", (long) vendorAtom.atomId);
+ return hardware::Void();
+ }
+ if (reverseDomainName.length() > 50) {
+ ALOGE("Vendor atom reverse domain name %s is too long.", reverseDomainName.c_str());
+ return hardware::Void();
+ }
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, vendorAtom.atomId);
+ AStatsEvent_writeString(event, vendorAtom.reverseDomainName.c_str());
+ for (int i = 0; i < (int)vendorAtom.values.size(); i++) {
+ switch (vendorAtom.values[i].getDiscriminator()) {
+ case VendorAtom::Value::hidl_discriminator::intValue:
+ AStatsEvent_writeInt32(event, vendorAtom.values[i].intValue());
+ break;
+ case VendorAtom::Value::hidl_discriminator::longValue:
+ AStatsEvent_writeInt64(event, vendorAtom.values[i].longValue());
+ break;
+ case VendorAtom::Value::hidl_discriminator::floatValue:
+ AStatsEvent_writeFloat(event, vendorAtom.values[i].floatValue());
+ break;
+ case VendorAtom::Value::hidl_discriminator::stringValue:
+ AStatsEvent_writeString(event, vendorAtom.values[i].stringValue().c_str());
+ break;
+ }
+ }
+ AStatsEvent_build(event);
+ AStatsEvent_write(event);
+ AStatsEvent_release(event);
+
+ return hardware::Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace stats
+} // namespace frameworks
+} // namespace android
diff --git a/services/stats/android.frameworks.stats@1.0-service.xml b/services/stats/android.frameworks.stats@1.0-service.xml
new file mode 100644
index 0000000..bb02f66
--- /dev/null
+++ b/services/stats/android.frameworks.stats@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+ <hal>
+ <name>android.frameworks.stats</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IStats</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/services/stats/include/stats/StatsHal.h b/services/stats/include/stats/StatsHal.h
new file mode 100644
index 0000000..071e54f
--- /dev/null
+++ b/services/stats/include/stats/StatsHal.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/frameworks/stats/1.0/IStats.h>
+#include <android/frameworks/stats/1.0/types.h>
+
+#include <stats_event.h>
+
+using namespace android::frameworks::stats::V1_0;
+
+namespace android {
+namespace frameworks {
+namespace stats {
+namespace V1_0 {
+namespace implementation {
+
+using android::hardware::Return;
+
+/**
+* Implements the Stats HAL
+*/
+class StatsHal : public IStats {
+public:
+ StatsHal();
+
+ /**
+ * Binder call to get SpeakerImpedance atom.
+ */
+ virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override;
+
+ /**
+ * Binder call to get HardwareFailed atom.
+ */
+ virtual Return<void> reportHardwareFailed(const HardwareFailed& hardwareFailed) override;
+
+ /**
+ * Binder call to get PhysicalDropDetected atom.
+ */
+ virtual Return<void> reportPhysicalDropDetected(
+ const PhysicalDropDetected& physicalDropDetected) override;
+
+ /**
+ * Binder call to get ChargeCyclesReported atom.
+ */
+ virtual Return<void> reportChargeCycles(const ChargeCycles& chargeCycles) override;
+
+ /**
+ * Binder call to get BatteryHealthSnapshot atom.
+ */
+ virtual Return<void> reportBatteryHealthSnapshot(
+ const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) override;
+
+ /**
+ * Binder call to get SlowIo atom.
+ */
+ virtual Return<void> reportSlowIo(const SlowIo& slowIo) override;
+
+ /**
+ * Binder call to get BatteryCausedShutdown atom.
+ */
+ virtual Return<void> reportBatteryCausedShutdown(
+ const BatteryCausedShutdown& batteryCausedShutdown) override;
+
+ /**
+ * Binder call to get UsbPortOverheatEvent atom.
+ */
+ virtual Return<void> reportUsbPortOverheatEvent(
+ const UsbPortOverheatEvent& usbPortOverheatEvent) override;
+
+ /**
+ * Binder call to get Speech DSP state atom.
+ */
+ virtual Return<void> reportSpeechDspStat(
+ const SpeechDspStat& speechDspStat) override;
+
+ /**
+ * Binder call to get vendor atom.
+ */
+ virtual Return<void> reportVendorAtom(const VendorAtom& vendorAtom) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace stats
+} // namespace frameworks
+} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index b193e30..923a81c 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -115,6 +115,7 @@
void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
for (const auto& handle : mDrawingState.callbackHandles) {
handle->transformHint = mTransformHint;
+ handle->dequeueReadyTime = dequeueReadyTime;
}
mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
@@ -133,6 +134,14 @@
}
}
+void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
+ const CompositorTiming& compositorTiming) {
+ for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->gpuCompositionDoneFence = glDoneFence;
+ handle->compositorTiming = compositorTiming;
+ }
+}
+
bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
if (getSidebandStreamChanged() || getAutoRefresh()) {
return true;
@@ -245,14 +254,15 @@
return true;
}
-bool BufferStateLayer::updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
- nsecs_t desiredPresentTime) {
+bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
+ nsecs_t desiredPresentTime) {
Mutex::Autolock lock(mFrameEventHistoryMutex);
mAcquireTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> acquireFenceTime =
std::make_shared<FenceTime>((acquireFence ? acquireFence : Fence::NO_FENCE));
NewFrameEventsEntry newTimestamps = {mCurrentState.frameNumber, postedTime, desiredPresentTime,
acquireFenceTime};
+ mFrameEventHistory.setProducerWantsEvents();
mFrameEventHistory.addQueue(newTimestamps);
return true;
}
@@ -277,12 +287,12 @@
mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
mFlinger->mFrameTracer->traceTimestamp(layerId, buffer->getId(), mCurrentState.frameNumber,
postTime, FrameTracer::FrameEvent::POST);
+ desiredPresentTime = desiredPresentTime <= 0 ? 0 : desiredPresentTime;
mCurrentState.desiredPresentTime = desiredPresentTime;
- mFlinger->mScheduler->recordLayerHistory(this,
- desiredPresentTime <= 0 ? 0 : desiredPresentTime);
+ mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime);
- updateFrameEventHistory(acquireFence, postTime, desiredPresentTime);
+ addFrameEvent(acquireFence, postTime, desiredPresentTime);
return true;
}
@@ -447,6 +457,13 @@
return mCurrentState.desiredPresentTime <= expectedPresentTime;
}
+bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) {
+ for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->refreshStartTime = refreshStartTime;
+ }
+ return BufferLayer::onPreComposition(refreshStartTime);
+}
+
uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const {
return mDrawingState.frameNumber;
}
@@ -530,6 +547,7 @@
for (auto& handle : mDrawingState.callbackHandles) {
handle->latchTime = latchTime;
+ handle->frameNumber = mDrawingState.frameNumber;
}
if (!SyncFeatures::getInstance().useNativeFenceSync()) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 679d1ba..6ee5802 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -45,6 +45,9 @@
void setTransformHint(uint32_t orientation) const override;
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
+ void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
+ const CompositorTiming& compositorTiming) override;
+
bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override {
@@ -80,6 +83,8 @@
bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
void forceSendCallbacks() override;
+ bool addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
+ nsecs_t requestedPresentTime) override;
// Override to ignore legacy layer state properties that are not used by BufferStateLayer
bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; }
@@ -106,6 +111,7 @@
// -----------------------------------------------------------------------
bool fenceHasSignaled() const override;
bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
+ bool onPreComposition(nsecs_t refreshStartTime) override;
protected:
void gatherBufferInfo() override;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 810e0af..de4a080 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -372,6 +372,10 @@
return false;
};
virtual void forceSendCallbacks() {}
+ virtual bool addFrameEvent(const sp<Fence>& /*acquireFence*/, nsecs_t /*postedTime*/,
+ nsecs_t /*requestedPresentTime*/) {
+ return false;
+ }
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
virtual bool setColorSpaceAgnostic(const bool agnostic);
bool setShadowRadius(float shadowRadius);
@@ -596,6 +600,8 @@
// If a buffer was replaced this frame, release the former buffer
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
+ virtual void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+ const CompositorTiming& /*compositorTiming*/) {}
/*
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 0f55615..c73e825 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -216,20 +216,12 @@
const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- if (!mRefreshRateSwitching) {
- return *mCurrentRefreshRate;
- } else {
- return *mAvailableRefreshRates.front();
- }
+ return *mAvailableRefreshRates.front();
}
const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- if (!mRefreshRateSwitching) {
- return *mCurrentRefreshRate;
- } else {
return *mAvailableRefreshRates.back();
- }
}
const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
@@ -242,18 +234,14 @@
mCurrentRefreshRate = &mRefreshRates.at(configId);
}
-RefreshRateConfigs::RefreshRateConfigs(bool refreshRateSwitching,
- const std::vector<InputConfig>& configs,
- HwcConfigIndexType currentHwcConfig)
- : mRefreshRateSwitching(refreshRateSwitching) {
+RefreshRateConfigs::RefreshRateConfigs(const std::vector<InputConfig>& configs,
+ HwcConfigIndexType currentHwcConfig) {
init(configs, currentHwcConfig);
}
RefreshRateConfigs::RefreshRateConfigs(
- bool refreshRateSwitching,
const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
- HwcConfigIndexType currentConfigId)
- : mRefreshRateSwitching(refreshRateSwitching) {
+ HwcConfigIndexType currentConfigId) {
std::vector<InputConfig> inputConfigs;
for (size_t configId = 0; configId < configs.size(); ++configId) {
auto configGroup = HwcConfigGroupType(configs[configId]->getConfigGroup());
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index c4dea0d..fc95959 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -94,9 +94,6 @@
// Returns true if config is allowed by the current policy.
bool isConfigAllowed(HwcConfigIndexType config) const EXCLUDES(mLock);
- // Returns true if this device is doing refresh rate switching. This won't change at runtime.
- bool refreshRateSwitchingSupported() const { return mRefreshRateSwitching; }
-
// Describes the different options the layer voted for refresh rate
enum class LayerVoteType {
NoVote, // Doesn't care about the refresh rate
@@ -167,10 +164,9 @@
nsecs_t vsyncPeriod = 0;
};
- RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
+ RefreshRateConfigs(const std::vector<InputConfig>& configs,
HwcConfigIndexType currentHwcConfig);
- RefreshRateConfigs(bool refreshRateSwitching,
- const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
+ RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
HwcConfigIndexType currentConfigId);
private:
@@ -208,8 +204,6 @@
const RefreshRate* mMinSupportedRefreshRate;
const RefreshRate* mMaxSupportedRefreshRate;
- const bool mRefreshRateSwitching;
-
mutable std::mutex mLock;
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index bc4f805..49a269f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -530,8 +530,6 @@
using base::StringAppendF;
const char* const states[] = {"off", "on"};
- const bool supported = mRefreshRateConfigs.refreshRateSwitchingSupported();
- StringAppendF(&result, "+ Refresh rate switching: %s\n", states[supported]);
StringAppendF(&result, "+ Content detection: %s\n", states[mLayerHistory != nullptr]);
StringAppendF(&result, "+ Idle timer: %s\n",
@@ -575,35 +573,44 @@
}
HwcConfigIndexType Scheduler::calculateRefreshRateType() {
- if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) {
- return mRefreshRateConfigs.getCurrentRefreshRate().configId;
+ // This block of the code checks whether any layers used the SetFrameRate API. If they have,
+ // their request should be honored regardless of whether the device has refresh rate switching
+ // turned off.
+ if (layerHistoryHasClientSpecifiedFrameRate()) {
+ if (!mUseContentDetectionV2) {
+ return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements)
+ .configId;
+ } else {
+ return mRefreshRateConfigs.getRefreshRateForContentV2(mFeatures.contentRequirements)
+ .configId;
+ }
}
// If the layer history doesn't have the frame rate specified, use the old path. NOTE:
// if we remove the kernel idle timer, and use our internal idle timer, this code will have to
// be refactored.
- if (!layerHistoryHasClientSpecifiedFrameRate()) {
- // If Display Power is not in normal operation we want to be in performance mode.
- // When coming back to normal mode, a grace period is given with DisplayPowerTimer
- if (!mFeatures.isDisplayPowerStateNormal ||
- mFeatures.displayPowerTimer == TimerState::Reset) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
- }
+ // If Display Power is not in normal operation we want to be in performance mode.
+ // When coming back to normal mode, a grace period is given with DisplayPowerTimer
+ if (mDisplayPowerTimer &&
+ (!mFeatures.isDisplayPowerStateNormal ||
+ mFeatures.displayPowerTimer == TimerState::Reset)) {
+ return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ }
- // As long as touch is active we want to be in performance mode
- if (mFeatures.touch == TouchState::Active) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
- }
+ // As long as touch is active we want to be in performance mode
+ if (mTouchTimer && mFeatures.touch == TouchState::Active) {
+ return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ }
- // If timer has expired as it means there is no new content on the screen
- if (mFeatures.idleTimer == TimerState::Expired) {
- return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
- }
+ // If timer has expired as it means there is no new content on the screen
+ if (mIdleTimer && mFeatures.idleTimer == TimerState::Expired) {
+ return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
}
if (!mUseContentDetectionV2) {
- // If content detection is off we choose performance as we don't know the content fps
+ // If content detection is off we choose performance as we don't know the content fps.
if (mFeatures.contentDetection == ContentDetectionState::Off) {
+ // TODO(b/148428554): Be careful to not always call this.
return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
}
@@ -623,6 +630,10 @@
std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ // Make sure that the default config ID is first updated, before returned.
+ if (mFeatures.configId.has_value()) {
+ mFeatures.configId = calculateRefreshRateType();
+ }
return mFeatures.configId;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 33d85cb..e8c7a55 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -556,12 +556,6 @@
readPersistentProperties();
mBootStage = BootStage::FINISHED;
- if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
- // set the refresh rate according to the policy
- const auto& performanceRefreshRate = mRefreshRateConfigs->getMaxRefreshRateByPolicy();
- changeRefreshRateLocked(performanceRefreshRate, Scheduler::ConfigEvent::None);
- }
-
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
mRefreshRateOverlay->changeRefreshRate(mRefreshRateConfigs->getCurrentRefreshRate());
@@ -2037,12 +2031,10 @@
ATRACE_CALL();
ALOGV("postComposition");
- // Release any buffers which were replaced this frame
nsecs_t dequeueReadyTime = systemTime();
for (auto& layer : mLayersWithQueuedFrames) {
layer->releasePendingBuffer(dequeueReadyTime);
}
-
// |mStateLock| not needed as we are on the main thread
const auto displayDevice = getDefaultDisplayDeviceLocked();
@@ -2720,8 +2712,7 @@
auto currentConfig = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(primaryDisplayId));
mRefreshRateConfigs =
- std::make_unique<scheduler::RefreshRateConfigs>(refresh_rate_switching(false),
- getHwComposer().getConfigs(
+ std::make_unique<scheduler::RefreshRateConfigs>(getHwComposer().getConfigs(
primaryDisplayId),
currentConfig);
mRefreshRateStats =
@@ -3349,6 +3340,11 @@
layer->pushPendingState();
}
+ // Only set by BLAST adapter layers
+ if (what & layer_state_t::eProducerDisconnect) {
+ layer->onDisconnect();
+ }
+
if (what & layer_state_t::ePositionChanged) {
if (layer->setPosition(s.x, s.y)) {
flags |= eTraversalNeeded;
@@ -5706,26 +5702,19 @@
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
display->getActiveConfig(), vsyncPeriod);
- if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
- auto configId = mScheduler->getPreferredConfigId();
- auto preferredRefreshRate = configId
- ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
- : mRefreshRateConfigs->getMinRefreshRateByPolicy();
- ALOGV("trying to switch to Scheduler preferred config %d (%s)",
- preferredRefreshRate.configId.value(), preferredRefreshRate.name.c_str());
- if (isDisplayConfigAllowed(preferredRefreshRate.configId)) {
- ALOGV("switching to Scheduler preferred config %d",
- preferredRefreshRate.configId.value());
- setDesiredActiveConfig(
- {preferredRefreshRate.configId, Scheduler::ConfigEvent::Changed});
- } else {
- // Set the highest allowed config
- setDesiredActiveConfig({mRefreshRateConfigs->getMaxRefreshRateByPolicy().configId,
- Scheduler::ConfigEvent::Changed});
- }
+ auto configId = mScheduler->getPreferredConfigId();
+ auto preferredRefreshRate = configId
+ ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
+ // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind.
+ : mRefreshRateConfigs->getRefreshRateFromConfigId(defaultConfig);
+ ALOGV("trying to switch to Scheduler preferred config %d (%s)",
+ preferredRefreshRate.configId.value(), preferredRefreshRate.name.c_str());
+
+ if (isDisplayConfigAllowed(preferredRefreshRate.configId)) {
+ ALOGV("switching to Scheduler preferred config %d", preferredRefreshRate.configId.value());
+ setDesiredActiveConfig({preferredRefreshRate.configId, Scheduler::ConfigEvent::Changed});
} else {
- ALOGV("switching to config %d", defaultConfig.value());
- setDesiredActiveConfig({defaultConfig, Scheduler::ConfigEvent::Changed});
+ LOG_ALWAYS_FATAL("Desired config not allowed: %d", preferredRefreshRate.configId.value());
}
return NO_ERROR;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index b4716eb..e199b53 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -19,6 +19,7 @@
#include <android/hardware/configstore/1.1/types.h>
#include <configstore/Utils.h>
+#include <log/log.h>
#include <cstdlib>
#include <tuple>
@@ -227,8 +228,12 @@
}
bool refresh_rate_switching(bool defaultValue) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
auto temp = SurfaceFlingerProperties::refresh_rate_switching();
+#pragma clang diagnostic pop
if (temp.has_value()) {
+ ALOGW("Using deprecated refresh_rate_switching sysprop. Value: %d", *temp);
return *temp;
}
return defaultValue;
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index daa67ae..0cdff8f 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -237,9 +237,13 @@
// destroyed the client side is dead and there won't be anyone to send the callback to.
sp<IBinder> surfaceControl = handle->surfaceControl.promote();
if (surfaceControl) {
+ FrameEventHistoryStats eventStats(handle->frameNumber,
+ handle->gpuCompositionDoneFence->getSnapshot().fence,
+ handle->compositorTiming, handle->refreshStartTime,
+ handle->dequeueReadyTime);
transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
handle->previousReleaseFence,
- handle->transformHint);
+ handle->transformHint, eventStats);
}
return NO_ERROR;
}
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index 12ea8fe..f50147a 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -45,6 +45,11 @@
nsecs_t acquireTime = -1;
nsecs_t latchTime = -1;
uint32_t transformHint = 0;
+ std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE};
+ CompositorTiming compositorTiming;
+ nsecs_t refreshStartTime = 0;
+ nsecs_t dequeueReadyTime = 0;
+ uint64_t frameNumber = 0;
};
class TransactionCompletedThread {
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index ed2b220..764181a 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -311,6 +311,7 @@
scope: System
access: Readonly
prop_name: "ro.surface_flinger.refresh_rate_switching"
+ deprecated: true
}
prop {
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index d24ad18..bee99f4 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -75,6 +75,7 @@
prop {
api_name: "refresh_rate_switching"
prop_name: "ro.surface_flinger.refresh_rate_switching"
+ deprecated: true
}
prop {
api_name: "running_without_sync_framework"
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index d9481be..18e9941 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -63,8 +63,7 @@
auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
- RefreshRateConfigs mConfigs{true,
- {
+ RefreshRateConfigs mConfigs{{
RefreshRateConfigs::InputConfig{HwcConfigIndexType(0),
HwcConfigGroupType(0),
LO_FPS_PERIOD},
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index bb3bbad..959c256 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -71,8 +71,7 @@
auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
- RefreshRateConfigs mConfigs{true,
- {
+ RefreshRateConfigs mConfigs{{
RefreshRateConfigs::InputConfig{HwcConfigIndexType(0),
HwcConfigGroupType(0),
LO_FPS_PERIOD},
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 7c1ecea..841c624 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -74,26 +74,14 @@
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
-}
-
-TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingNotSupported) {
- std::vector<RefreshRateConfigs::InputConfig> configs{
- {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}};
- auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
}
TEST_F(RefreshRateConfigsTest, invalidPolicy) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
ASSERT_LT(refreshRateConfigs->setPolicy(HwcConfigIndexType(10), 60, 60, nullptr), 0);
ASSERT_LT(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 20, 40, nullptr), 0);
}
@@ -103,10 +91,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
const auto minRate = refreshRateConfigs->getMinRefreshRate();
const auto performanceRate = refreshRateConfigs->getMaxRefreshRate();
@@ -128,10 +113,8 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_1, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
const auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
const auto performanceRate = refreshRateConfigs->getMaxRefreshRate();
const auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -145,7 +128,6 @@
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90, nullptr), 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
const auto minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
const auto performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -161,9 +143,8 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
auto performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -174,7 +155,6 @@
ASSERT_EQ(expectedPerformanceConfig, performanceRate);
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -187,8 +167,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
{
auto current = refreshRateConfigs->getCurrentRefreshRate();
EXPECT_EQ(current.configId, HWC_CONFIG_ID_60);
@@ -212,10 +191,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
@@ -276,10 +252,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
@@ -387,10 +360,7 @@
{HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected72Config = {HWC_CONFIG_ID_72, VSYNC_72, HWC_GROUP_ID_0, "72fps", 70};
@@ -430,10 +400,7 @@
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90},
{HWC_CONFIG_ID_120, HWC_GROUP_ID_0, VSYNC_120}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
@@ -474,8 +441,7 @@
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90},
{HWC_CONFIG_ID_120, HWC_GROUP_ID_0, VSYNC_120}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
@@ -542,10 +508,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
@@ -583,10 +546,7 @@
{HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
@@ -625,10 +585,7 @@
{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
@@ -681,10 +638,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
@@ -707,10 +661,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
@@ -738,10 +689,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
@@ -779,10 +727,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 8e07c79..18d6bd2 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -47,8 +47,8 @@
~RefreshRateStatsTest();
void init(const std::vector<RefreshRateConfigs::InputConfig>& configs) {
- mRefreshRateConfigs = std::make_unique<RefreshRateConfigs>(
- /*refreshRateSwitching=*/true, configs, /*currentConfig=*/CONFIG_ID_0);
+ mRefreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfig=*/CONFIG_ID_0);
mRefreshRateStats =
std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
/*currentConfigId=*/CONFIG_ID_0,
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 82a00ee..89002a8 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -73,8 +73,7 @@
std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{
{{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}};
mRefreshRateConfigs = std::make_unique<
- scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
- /*currentConfig=*/HwcConfigIndexType(0));
+ scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0));
mScheduler = std::make_unique<TestableScheduler>(*mRefreshRateConfigs, false);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 64838ca..798ba76 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -202,8 +202,7 @@
std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{
{{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}};
mFlinger->mRefreshRateConfigs = std::make_unique<
- scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
- /*currentConfig=*/HwcConfigIndexType(0));
+ scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0));
mFlinger->mRefreshRateStats = std::make_unique<
scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats,
/*currentConfig=*/HwcConfigIndexType(0),
diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/services/surfaceflinger/tests/utils/CallbackUtils.h
index 4e2b7c3..1318deb 100644
--- a/services/surfaceflinger/tests/utils/CallbackUtils.h
+++ b/services/surfaceflinger/tests/utils/CallbackUtils.h
@@ -121,8 +121,10 @@
void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
nsecs_t latchTime) const {
- const auto& [surfaceControl, acquireTime, previousReleaseFence, transformHint] =
- surfaceControlStats;
+ const auto&
+ [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence,
+ transformHint,
+ frameEvents] = surfaceControlStats;
ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
<< "bad acquire time";