Merge "SF: Move/refactor presentation loop to CompositionEngine"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index a8e6738..b781da3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2328,9 +2328,6 @@
// clang-format off
case 'd': do_add_date = true; break;
case 'z': do_zip_file = true; break;
- // o=use_outfile not supported anymore.
- // TODO(b/111441001): Remove when all callers have migrated.
- case 'o': break;
case 's': use_socket = true; break;
case 'S': use_control_socket = true; break;
case 'v': show_header_only = true; break;
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index 14937b8..e491a4b 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -11,8 +11,7 @@
# dumpstatez generates a zipped bugreport but also uses a socket to print the file location once
# it is finished.
-service dumpstatez /system/bin/dumpstate -S -d -z \
- -o /data/user_de/0/com.android.shell/files/bugreports/bugreport
+service dumpstatez /system/bin/dumpstate -S -d -z
socket dumpstate stream 0660 shell log
class main
disabled
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 181046a..dbbcdff 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -201,9 +201,7 @@
(char*)"dumpstate",
(char*)"-d",
(char*)"-z",
- (char*)"-B",
- (char*)"-o",
- (char*)dirname(android::base::GetExecutablePath().c_str())
+ (char*)"-B"
};
// clang-format on
sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 3ada153..cbac839 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -53,7 +53,7 @@
MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&));
MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int));
MOCK_METHOD1(listServices, Vector<String16>(int));
-
+ MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 119e4c3..b3aa342 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -28,6 +28,13 @@
ServiceManager::~ServiceManager() {
// this should only happen in tests
+ for (const auto& [name, callbacks] : mNameToCallback) {
+ CHECK(!callbacks.empty()) << name;
+ for (const auto& callback : callbacks) {
+ CHECK(callback != nullptr) << name;
+ }
+ }
+
for (const auto& [name, service] : mNameToService) {
CHECK(service.binder != nullptr) << name;
}
@@ -117,6 +124,14 @@
.dumpPriority = dumpPriority,
};
+ auto it = mNameToCallback.find(name);
+ if (it != mNameToCallback.end()) {
+ for (const sp<IServiceCallback>& cb : it->second) {
+ // permission checked in registerForNotifications
+ cb->onRegistration(name, binder);
+ }
+ }
+
return Status::ok();
}
@@ -146,6 +161,84 @@
return Status::ok();
}
+Status ServiceManager::registerForNotifications(
+ const std::string& name, const sp<IServiceCallback>& callback) {
+ auto ctx = mAccess->getCallingContext();
+
+ if (!mAccess->canFind(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ if (!isValidServiceName(name)) {
+ LOG(ERROR) << "Invalid service name: " << name;
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (callback == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+
+ if (OK != IInterface::asBinder(callback)->linkToDeath(this)) {
+ LOG(ERROR) << "Could not linkToDeath when adding " << name;
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+
+ mNameToCallback[name].push_back(callback);
+
+ if (auto it = mNameToService.find(name); it != mNameToService.end()) {
+ const sp<IBinder>& binder = it->second.binder;
+
+ // never null if an entry exists
+ CHECK(binder != nullptr) << name;
+ callback->onRegistration(name, binder);
+ }
+
+ return Status::ok();
+}
+Status ServiceManager::unregisterForNotifications(
+ const std::string& name, const sp<IServiceCallback>& callback) {
+ auto ctx = mAccess->getCallingContext();
+
+ if (!mAccess->canFind(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ bool found = false;
+
+ auto it = mNameToCallback.find(name);
+ if (it != mNameToCallback.end()) {
+ removeCallback(IInterface::asBinder(callback), &it, &found);
+ }
+
+ if (!found) {
+ LOG(ERROR) << "Trying to unregister callback, but none exists " << name;
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+
+ return Status::ok();
+}
+
+void ServiceManager::removeCallback(const wp<IBinder>& who,
+ CallbackMap::iterator* it,
+ bool* found) {
+ std::vector<sp<IServiceCallback>>& listeners = (*it)->second;
+
+ for (auto lit = listeners.begin(); lit != listeners.end();) {
+ if (IInterface::asBinder(*lit) == who) {
+ if(found) *found = true;
+ lit = listeners.erase(lit);
+ } else {
+ ++lit;
+ }
+ }
+
+ if (listeners.empty()) {
+ *it = mNameToCallback.erase(*it);
+ } else {
+ it++;
+ }
+}
+
void ServiceManager::binderDied(const wp<IBinder>& who) {
for (auto it = mNameToService.begin(); it != mNameToService.end();) {
if (who == it->second.binder) {
@@ -154,6 +247,10 @@
++it;
}
}
+
+ for (auto it = mNameToCallback.begin(); it != mNameToCallback.end();) {
+ removeCallback(who, &it, nullptr /*found*/);
+ }
}
} // namespace android
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 43723c5..fcc5124 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -17,11 +17,14 @@
#pragma once
#include <android/os/BnServiceManager.h>
+#include <android/os/IServiceCallback.h>
#include "Access.h"
namespace android {
+using os::IServiceCallback;
+
class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
public:
ServiceManager(std::unique_ptr<Access>&& access);
@@ -29,19 +32,35 @@
binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override;
binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override;
- binder::Status addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) override;
+ binder::Status addService(const std::string& name, const sp<IBinder>& binder,
+ bool allowIsolated, int32_t dumpPriority) override;
binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override;
+ binder::Status registerForNotifications(const std::string& name,
+ const sp<IServiceCallback>& callback) override;
+ binder::Status unregisterForNotifications(const std::string& name,
+ const sp<IServiceCallback>& callback) override;
void binderDied(const wp<IBinder>& who) override;
private:
struct Service {
- sp<IBinder> binder;
+ sp<IBinder> binder; // not null
bool allowIsolated;
int32_t dumpPriority;
};
- std::map<std::string, Service> mNameToService;
+ using CallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>;
+ using ServiceMap = std::map<std::string, Service>;
+
+ // removes a callback from mNameToCallback, removing it if the vector is empty
+ // this updates iterator to the next location
+ void removeCallback(const wp<IBinder>& who,
+ CallbackMap::iterator* it,
+ bool* found);
+
+ CallbackMap mNameToCallback;
+ ServiceMap mNameToService;
+
std::unique_ptr<Access> mAccess;
};
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index 91485e4..3c211d2 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+#include <android/os/BnServiceCallback.h>
+#include <binder/Binder.h>
#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <cutils/android_filesystem_config.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
@@ -24,8 +27,11 @@
using android::sp;
using android::Access;
+using android::BBinder;
using android::IBinder;
using android::ServiceManager;
+using android::binder::Status;
+using android::os::BnServiceCallback;
using android::os::IServiceManager;
using testing::_;
using testing::ElementsAre;
@@ -33,9 +39,14 @@
using testing::Return;
static sp<IBinder> getBinder() {
- // It doesn't matter what remote binder it is, we just need one so that linkToDeath will work.
- // The context manager (servicemanager) is easy to get and is in another process.
- return android::ProcessState::self()->getContextObject(nullptr);
+ class LinkableBinder : public BBinder {
+ android::status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override {
+ // let SM linkToDeath
+ return android::OK;
+ }
+ };
+
+ return new LinkableBinder;
}
class MockAccess : public Access {
@@ -132,12 +143,14 @@
TEST(GetService, HappyHappy) {
auto sm = getPermissiveServiceManager();
- EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
+ sp<IBinder> service = getBinder();
+
+ EXPECT_TRUE(sm->addService("foo", service, false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
sp<IBinder> out;
EXPECT_TRUE(sm->getService("foo", &out).isOk());
- EXPECT_EQ(getBinder(), out);
+ EXPECT_EQ(service, out);
}
TEST(GetService, NonExistant) {
@@ -181,12 +194,13 @@
sp<ServiceManager> sm = new ServiceManager(std::move(access));
- EXPECT_TRUE(sm->addService("foo", getBinder(), true /*allowIsolated*/,
+ sp<IBinder> service = getBinder();
+ EXPECT_TRUE(sm->addService("foo", service, true /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
sp<IBinder> out;
EXPECT_TRUE(sm->getService("foo", &out).isOk());
- EXPECT_EQ(getBinder(), out.get());
+ EXPECT_EQ(service, out.get());
}
TEST(GetService, NotAllowedFromIsolated) {
@@ -265,3 +279,145 @@
// all there and in the right order
EXPECT_THAT(out, ElementsAre("sa"));
}
+
+class CallbackHistorian : public BnServiceCallback {
+ Status onRegistration(const std::string& name, const sp<IBinder>& binder) override {
+ registrations.push_back(name);
+ binders.push_back(binder);
+ return Status::ok();
+ }
+
+ android::status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override {
+ // let SM linkToDeath
+ return android::OK;
+ }
+
+public:
+ std::vector<std::string> registrations;
+ std::vector<sp<IBinder>> binders;
+};
+
+TEST(ServiceNotifications, NoPermissionsRegister) {
+ std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
+
+ EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{}));
+ EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false));
+
+ sp<ServiceManager> sm = new ServiceManager(std::move(access));
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ EXPECT_EQ(sm->registerForNotifications("foofoo", cb).exceptionCode(),
+ Status::EX_SECURITY);
+}
+
+TEST(ServiceNotifications, NoPermissionsUnregister) {
+ std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
+
+ EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{}));
+ EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false));
+
+ sp<ServiceManager> sm = new ServiceManager(std::move(access));
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ // should always hit security error first
+ EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(),
+ Status::EX_SECURITY);
+}
+
+TEST(ServiceNotifications, InvalidName) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ EXPECT_EQ(sm->registerForNotifications("foo@foo", cb).exceptionCode(),
+ Status::EX_ILLEGAL_ARGUMENT);
+}
+
+TEST(ServiceNotifications, NullCallback) {
+ auto sm = getPermissiveServiceManager();
+
+ EXPECT_EQ(sm->registerForNotifications("foofoo", nullptr).exceptionCode(),
+ Status::EX_NULL_POINTER);
+}
+
+TEST(ServiceNotifications, Unregister) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk());
+ EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), 0);
+}
+
+TEST(ServiceNotifications, UnregisterWhenNoRegistrationExists) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(),
+ Status::EX_ILLEGAL_STATE);
+}
+
+TEST(ServiceNotifications, NoNotification) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk());
+ EXPECT_TRUE(sm->addService("otherservice", getBinder(),
+ false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ EXPECT_THAT(cb->registrations, ElementsAre());
+ EXPECT_THAT(cb->binders, ElementsAre());
+}
+
+TEST(ServiceNotifications, GetNotification) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ sp<IBinder> service = getBinder();
+
+ EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk());
+ EXPECT_TRUE(sm->addService("asdfasdf", service,
+ false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf"));
+ EXPECT_THAT(cb->binders, ElementsAre(service));
+}
+
+TEST(ServiceNotifications, GetNotificationForAlreadyRegisteredService) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ sp<IBinder> service = getBinder();
+
+ EXPECT_TRUE(sm->addService("asdfasdf", service,
+ false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk());
+
+ EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf"));
+ EXPECT_THAT(cb->binders, ElementsAre(service));
+}
+
+TEST(ServiceNotifications, GetMultipleNotification) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<CallbackHistorian> cb = new CallbackHistorian;
+
+ sp<IBinder> binder1 = getBinder();
+ sp<IBinder> binder2 = getBinder();
+
+ EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk());
+ EXPECT_TRUE(sm->addService("asdfasdf", binder1,
+ false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+ EXPECT_TRUE(sm->addService("asdfasdf", binder2,
+ false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf", "asdfasdf"));
+ EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf", "asdfasdf"));
+}
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 027418a..6ece4a2 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -86,10 +86,8 @@
vendor: {
exclude_srcs: [
"ActivityManager.cpp",
- "AppOpsManager.cpp",
"IActivityManager.cpp",
"IAppOpsCallback.cpp",
- "IAppOpsService.cpp",
"IBatteryStats.cpp",
"IMediaResourceMonitor.cpp",
"IPermissionController.cpp",
@@ -145,6 +143,7 @@
name: "libbinder_aidl",
srcs: [
"aidl/android/content/pm/IPackageManagerNative.aidl",
+ "aidl/android/os/IServiceCallback.aidl",
"aidl/android/os/IServiceManager.aidl",
],
path: "aidl",
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 525685c..e2af01c 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -21,10 +21,18 @@
#include <utils/SystemClock.h>
+#include <sys/types.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AppOpsManager"
+
namespace android {
namespace {
+#ifndef __ANDROID_VNDK__
#if defined(__BRILLO__)
// Because Brillo has no application model, security policy is managed
// statically (at build time) with SELinux controls.
@@ -33,13 +41,17 @@
#else
const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED;
#endif // defined(__BRILLO__)
+#endif // __ANDROID_VNDK__
} // namespace
static String16 _appops("appops");
+#ifndef __ANDROID_VNDK__
static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER;
+#endif // __ANDROID_VNDK__
static sp<IBinder> gToken;
+#ifndef __ANDROID_VNDK__
static const sp<IBinder>& getToken(const sp<IAppOpsService>& service) {
pthread_mutex_lock(&gTokenMutex);
if (gToken == nullptr || gToken->pingBinder() != NO_ERROR) {
@@ -48,6 +60,17 @@
pthread_mutex_unlock(&gTokenMutex);
return gToken;
}
+#endif // __ANDROID_VNDK__
+
+thread_local uint64_t notedAppOpsInThisBinderTransaction[2];
+thread_local int32_t uidOfThisBinderTransaction = -1;
+
+// Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note
+#ifndef __ANDROID_VNDK__
+uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0};
+#else
+uint8_t appOpsToNote[128] = {0};
+#endif // __ANDROID_VNDK__
AppOpsManager::AppOpsManager()
{
@@ -85,6 +108,7 @@
}
#endif // defined(__BRILLO__)
+#ifndef __ANDROID_VNDK__
int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage)
{
sp<IAppOpsService> service = getService();
@@ -102,18 +126,41 @@
}
int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) {
+ return noteOp(op, uid, callingPackage, String16("noteOp from native code"));
+}
+
+int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage,
+ const String16& message) {
sp<IAppOpsService> service = getService();
- return service != nullptr
+ int32_t mode = service != nullptr
? service->noteOperation(op, uid, callingPackage)
: APP_OPS_MANAGER_UNAVAILABLE_MODE;
+
+ if (mode == AppOpsManager::MODE_ALLOWED) {
+ markAppOpNoted(uid, callingPackage, op, message);
+ }
+
+ return mode;
}
int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
bool startIfModeDefault) {
+ return startOpNoThrow(op, uid, callingPackage, startIfModeDefault,
+ String16("startOpNoThrow from native code"));
+}
+
+int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+ bool startIfModeDefault, const String16& message) {
sp<IAppOpsService> service = getService();
- return service != nullptr
+ int32_t mode = service != nullptr
? service->startOperation(getToken(service), op, uid, callingPackage,
startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+
+ if (mode == AppOpsManager::MODE_ALLOWED) {
+ markAppOpNoted(uid, callingPackage, op, message);
+ }
+
+ return mode;
}
void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
@@ -146,5 +193,47 @@
return -1;
}
+void AppOpsManager::setCameraAudioRestriction(int32_t mode) {
+ sp<IAppOpsService> service = getService();
+ if (service != nullptr) {
+ service->setCameraAudioRestriction(mode);
+ }
+}
+
+#endif // __ANDROID_VNDK__
+
+bool AppOpsManager::shouldCollectNotes(int32_t opcode) {
+ sp<IAppOpsService> service = getService();
+ if (service != nullptr) {
+ return service->shouldCollectNotes(opcode);
+ }
+ return false;
+}
+
+void AppOpsManager::markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
+ const String16& message) {
+ // check it the appops needs to be collected and cache result
+ if (appOpsToNote[opCode] == 0) {
+ if (shouldCollectNotes(opCode)) {
+ appOpsToNote[opCode] = 2;
+ } else {
+ appOpsToNote[opCode] = 1;
+ }
+ }
+
+ if (appOpsToNote[opCode] != 2) {
+ return;
+ }
+
+ noteAsyncOp(String16(), uid, packageName, opCode, message);
+}
+
+void AppOpsManager::noteAsyncOp(const String16& callingPackageName, int32_t uid,
+ const String16& packageName, int32_t opCode, const String16& message) {
+ sp<IAppOpsService> service = getService();
+ if (service != nullptr) {
+ return service->noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+ }
+}
}; // namespace android
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index c426f3a..b6360cb 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -34,6 +34,7 @@
{
}
+#ifndef __ANDROID_VNDK__
virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -111,7 +112,6 @@
return reply.readStrongBinder();
}
-
virtual int32_t permissionToOpCode(const String16& permission) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -137,6 +137,52 @@
}
return reply.readInt32();
}
+
+ virtual void setCameraAudioRestriction(int32_t mode) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION, data, &reply);
+ }
+
+#endif
+ virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
+ const String16& packageName, int32_t opCode, const String16& message) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+
+ // Convert empty callingPackage into null string
+ if (callingPackageName.size() != 0) {
+ data.writeString16(callingPackageName);
+ } else {
+ data.writeString16(nullptr, 0);
+ }
+
+ data.writeInt32(uid);
+
+ // Convert empty packageName into null string
+ if (packageName.size() != 0) {
+ data.writeString16(packageName);
+ } else {
+ data.writeString16(nullptr, 0);
+ }
+
+ data.writeInt32(opCode);
+ data.writeString16(message);
+ remote()->transact(NOTE_ASYNC_OP_TRANSACTION, data, &reply);
+ }
+
+ virtual bool shouldCollectNotes(int32_t opCode) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+ data.writeInt32(opCode);
+ remote()->transact(SHOULD_COLLECT_NOTES_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readExceptionCode() != 0) {
+ return false;
+ }
+ return reply.readBool();
+ }
};
IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService");
@@ -149,6 +195,7 @@
{
//printf("AppOpsService received: "); data.print();
switch(code) {
+#ifndef __ANDROID_VNDK__
case CHECK_OPERATION_TRANSACTION: {
CHECK_INTERFACE(IAppOpsService, data, reply);
int32_t code = data.readInt32();
@@ -234,6 +281,33 @@
reply->writeInt32(res);
return NO_ERROR;
} break;
+ case SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION: {
+ CHECK_INTERFACE(IAppOpsService, data, reply);
+ const int32_t mode = data.readInt32();
+ setCameraAudioRestriction(mode);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+#endif // __ANDROID_VNDK__
+ case NOTE_ASYNC_OP_TRANSACTION: {
+ CHECK_INTERFACE(IAppOpsService, data, reply);
+ String16 callingPackageName = data.readString16();
+ int32_t uid = data.readInt32();
+ String16 packageName = data.readString16();
+ int32_t opCode = data.readInt32();
+ String16 message = data.readString16();
+ noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case SHOULD_COLLECT_NOTES_TRANSACTION: {
+ CHECK_INTERFACE(IAppOpsService, data, reply);
+ int32_t opCode = data.readInt32();
+ bool shouldCollect = shouldCollectNotes(opCode);
+ reply->writeNoException();
+ reply->writeBool(shouldCollect);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 74f1f47..715a460 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -18,6 +18,7 @@
#include <binder/IServiceManager.h>
+#include <android/os/BnServiceCallback.h>
#include <android/os/IServiceManager.h>
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
@@ -212,6 +213,64 @@
return res;
}
+ sp<IBinder> waitForService(const String16& name16) override {
+ class Waiter : public android::os::BnServiceCallback {
+ Status onRegistration(const std::string& /*name*/,
+ const sp<IBinder>& binder) override {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mBinder = binder;
+ lock.unlock();
+ mCv.notify_one();
+ return Status::ok();
+ }
+ public:
+ sp<IBinder> mBinder;
+ std::mutex mMutex;
+ std::condition_variable mCv;
+ };
+
+ const std::string name = String8(name16).c_str();
+
+ sp<IBinder> out;
+ if(!mTheRealServiceManager->checkService(name, &out).isOk()) {
+ return nullptr;
+ }
+ if(out != nullptr) return out;
+
+ sp<Waiter> waiter = new Waiter;
+ if (!mTheRealServiceManager->registerForNotifications(
+ name, waiter).isOk()) {
+ return nullptr;
+ }
+
+ while(true) {
+ {
+ std::unique_lock<std::mutex> lock(waiter->mMutex);
+ using std::literals::chrono_literals::operator""s;
+ waiter->mCv.wait_for(lock, 1s, [&] {
+ return waiter->mBinder != nullptr;
+ });
+ if (waiter->mBinder != nullptr) return waiter->mBinder;
+ }
+
+ // Handle race condition for lazy services. Here is what can happen:
+ // - the service dies (not processed by init yet).
+ // - sm processes death notification.
+ // - sm gets checkService and calls init to start service.
+ // - init gets the start signal, but the service already appears
+ // started, so it does nothing.
+ // - init gets death signal, but doesn't know it needs to restart
+ // the service
+ // - we need to request service again to get it to start
+ if(!mTheRealServiceManager->checkService(name, &out).isOk()) {
+ return nullptr;
+ }
+ if(out != nullptr) return out;
+
+ ALOGW("Waited one second for %s", name.c_str());
+ }
+ }
+
private:
sp<AidlServiceManager> mTheRealServiceManager;
};
diff --git a/libs/binder/aidl/android/os/IServiceCallback.aidl b/libs/binder/aidl/android/os/IServiceCallback.aidl
new file mode 100644
index 0000000..b29dfed
--- /dev/null
+++ b/libs/binder/aidl/android/os/IServiceCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.os;
+
+/**
+ * @hide
+ */
+oneway interface IServiceCallback {
+ /**
+ * Called when a service is registered.
+ *
+ * @param name the service name that has been registered with
+ * @param binder the binder that is registered
+ */
+ void onRegistration(@utf8InCpp String name, IBinder binder);
+}
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 50a72aa..60c2cce 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -16,6 +16,8 @@
package android.os;
+import android.os.IServiceCallback;
+
/**
* Basic interface for finding and publishing system services.
*
@@ -77,4 +79,14 @@
* Return a list of all currently running services.
*/
@utf8InCpp String[] listServices(int dumpPriority);
+
+ /**
+ * Request a callback when a service is registered.
+ */
+ void registerForNotifications(@utf8InCpp String name, IServiceCallback callback);
+
+ /**
+ * Unregisters all requests for notifications for a specific callback.
+ */
+ void unregisterForNotifications(@utf8InCpp String name, IServiceCallback callback);
}
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 17493b4..dff4d49 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -17,8 +17,6 @@
#ifndef ANDROID_APP_OPS_MANAGER_H
#define ANDROID_APP_OPS_MANAGER_H
-#ifndef __ANDROID_VNDK__
-
#include <binder/IAppOpsService.h>
#include <utils/threads.h>
@@ -35,6 +33,7 @@
MODE_ERRORED = IAppOpsService::MODE_ERRORED
};
+#ifndef __ANDROID_VNDK__
enum {
OP_NONE = -1,
OP_COARSE_LOCATION = 0,
@@ -109,34 +108,60 @@
OP_START_FOREGROUND = 76,
OP_BLUETOOTH_SCAN = 77,
OP_USE_BIOMETRIC = 78,
+ OP_ACTIVITY_RECOGNITION = 79,
+ OP_SMS_FINANCIAL_TRANSACTIONS = 80,
+ OP_READ_MEDIA_AUDIO = 81,
+ OP_WRITE_MEDIA_AUDIO = 82,
+ OP_READ_MEDIA_VIDEO = 83,
+ OP_WRITE_MEDIA_VIDEO = 84,
+ OP_READ_MEDIA_IMAGES = 85,
+ OP_WRITE_MEDIA_IMAGES = 86,
+ OP_LEGACY_STORAGE = 87,
+ OP_ACCESS_ACCESSIBILITY = 88,
+ OP_READ_DEVICE_IDENTIFIERS = 89,
+ _NUM_OP = 90
};
+#endif // __ANDROID_VNDK__
AppOpsManager();
+#ifndef __ANDROID_VNDK__
int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid,
const String16& callingPackage);
+ // @Deprecated, use noteOp(int32_t, int32_t uid, const String16&, const String16&) instead
int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
+ int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage,
+ const String16& message);
+ // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&)
+ // instead
int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
bool startIfModeDefault);
+ int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+ bool startIfModeDefault, const String16& message);
void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
void startWatchingMode(int32_t op, const String16& packageName,
const sp<IAppOpsCallback>& callback);
void stopWatchingMode(const sp<IAppOpsCallback>& callback);
int32_t permissionToOpCode(const String16& permission);
+ void setCameraAudioRestriction(int32_t mode);
+#endif // __ANDROID_VNDK__
+ void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName,
+ int32_t opCode, const String16& message);
private:
Mutex mLock;
sp<IAppOpsService> mService;
sp<IAppOpsService> getService();
+ void markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
+ const String16& message);
+ bool shouldCollectNotes(int32_t opCode);
};
}; // namespace android
+
// ---------------------------------------------------------------------------
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
#endif // ANDROID_APP_OPS_MANAGER_H
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index 3dbd0d9..009ef6c 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -19,8 +19,8 @@
#define ANDROID_IAPP_OPS_SERVICE_H
#ifndef __ANDROID_VNDK__
-
#include <binder/IAppOpsCallback.h>
+#endif
#include <binder/IInterface.h>
namespace android {
@@ -32,6 +32,7 @@
public:
DECLARE_META_INTERFACE(AppOpsService)
+#ifndef __ANDROID_VNDK__
virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
@@ -45,8 +46,14 @@
virtual int32_t permissionToOpCode(const String16& permission) = 0;
virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid,
const String16& packageName) = 0;
+ virtual void setCameraAudioRestriction(int32_t mode) = 0;
+#endif // __ANDROID_VNDK__
+ virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
+ const String16& packageName, int32_t opCode, const String16& message) = 0;
+ virtual bool shouldCollectNotes(int32_t opCode) = 0;
enum {
+#ifndef __ANDROID_VNDK__
CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1,
START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2,
@@ -56,6 +63,13 @@
GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7,
CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8,
+#endif // __ANDROID_VNDK__
+ NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9,
+ SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10,
+#ifndef __ANDROID_VNDK__
+ SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+11,
+#endif // __ANDROID_VNDK__
+
};
enum {
@@ -81,8 +95,4 @@
}; // namespace android
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
-
#endif // ANDROID_IAPP_OPS_SERVICE_H
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 30786fa..8ae860d 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -71,11 +71,24 @@
*/
// NOLINTNEXTLINE(google-default-arguments)
virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
+
+ /**
+ * Efficiently wait for a service.
+ *
+ * Returns nullptr only for permission problem or fatal error.
+ */
+ virtual sp<IBinder> waitForService(const String16& name) = 0;
};
sp<IServiceManager> defaultServiceManager();
template<typename INTERFACE>
+sp<INTERFACE> waitForService(const String16& name) {
+ const sp<IServiceManager> sm = defaultServiceManager();
+ return interface_cast<INTERFACE>(sm->waitForService(name));
+}
+
+template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
const sp<IServiceManager> sm = defaultServiceManager();
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 438f8f3..51bf78a 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -139,6 +139,7 @@
"DisplayHardware/VirtualDisplaySurface.cpp",
"Effects/Daltonizer.cpp",
"EventLog/EventLog.cpp",
+ "FrameTracer/FrameTracer.cpp",
"FrameTracker.cpp",
"Layer.cpp",
"LayerProtoHelper.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index a8bdb79..90a02b3 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -51,6 +51,7 @@
#include "Colorizer.h"
#include "DisplayDevice.h"
+#include "FrameTracer/FrameTracer.h"
#include "LayerRejecter.h"
#include "TimeStats/TimeStats.h"
@@ -71,7 +72,9 @@
BufferLayer::~BufferLayer() {
mFlinger->deleteTextureAsync(mTextureName);
- mFlinger->mTimeStats->onDestroy(getSequence());
+ const int32_t layerID = getSequence();
+ mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
void BufferLayer::useSurfaceDamage() {
@@ -314,17 +317,17 @@
if (presentFence->isValid()) {
mFlinger->mTimeStats->setPresentFence(layerID, mCurrentFrameNumber, presentFence);
- mFlinger->mTimeStats->traceFence(layerID, getCurrentBufferId(), mCurrentFrameNumber,
- presentFence, TimeStats::FrameEvent::PRESENT_FENCE);
+ mFlinger->mFrameTracer->traceFence(layerID, getCurrentBufferId(), mCurrentFrameNumber,
+ presentFence, FrameTracer::FrameEvent::PRESENT_FENCE);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
} else if (displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId);
mFlinger->mTimeStats->setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime);
- mFlinger->mTimeStats->traceTimestamp(layerID, getCurrentBufferId(), mCurrentFrameNumber,
- actualPresentTime,
- TimeStats::FrameEvent::PRESENT_FENCE);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, getCurrentBufferId(), mCurrentFrameNumber,
+ actualPresentTime,
+ FrameTracer::FrameEvent::PRESENT_FENCE);
mFrameTracker.setActualPresentTime(actualPresentTime);
}
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 6cad3c7..4da39e4 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -29,6 +29,7 @@
#include "LayerRejecter.h"
#include "SurfaceInterceptor.h"
+#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
namespace android {
@@ -48,9 +49,9 @@
// Prevent tracing the same release multiple times.
if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
- mFlinger->mTimeStats->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
- std::make_shared<FenceTime>(releaseFence),
- TimeStats::FrameEvent::RELEASE_FENCE);
+ mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
+ std::make_shared<FenceTime>(releaseFence),
+ FrameTracer::FrameEvent::RELEASE_FENCE);
mPreviousReleasedFrameNumber = mPreviousFrameNumber;
}
}
@@ -337,6 +338,7 @@
mQueueItems.clear();
mQueuedFrames = 0;
mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
// Once we have hit this state, the shadow queue may no longer
@@ -366,12 +368,12 @@
uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId();
mFlinger->mTimeStats->setAcquireFence(layerID, currentFrameNumber,
mQueueItems[0].mFenceTime);
- mFlinger->mTimeStats->traceFence(layerID, bufferID, currentFrameNumber,
- mQueueItems[0].mFenceTime,
- TimeStats::FrameEvent::ACQUIRE_FENCE);
+ mFlinger->mFrameTracer->traceFence(layerID, bufferID, currentFrameNumber,
+ mQueueItems[0].mFenceTime,
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
mFlinger->mTimeStats->setLatchTime(layerID, currentFrameNumber, latchTime);
- mFlinger->mTimeStats->traceTimestamp(layerID, bufferID, currentFrameNumber, latchTime,
- TimeStats::FrameEvent::LATCH);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, bufferID, currentFrameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH);
mQueueItems.removeAt(0);
}
@@ -429,9 +431,9 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
const int32_t layerID = getSequence();
- mFlinger->mTimeStats->traceNewLayer(layerID, getName().c_str());
- mFlinger->mTimeStats->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber,
- systemTime(), TimeStats::FrameEvent::POST);
+ mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
+ mFlinger->mFrameTracer->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber,
+ systemTime(), FrameTracer::FrameEvent::POST);
ATRACE_CALL();
// Add this buffer from our internal queue tracker
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 4a8261d..e7d1b63 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -32,6 +32,7 @@
#include "BufferStateLayer.h"
#include "ColorLayer.h"
+#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
namespace android {
@@ -90,9 +91,9 @@
// Prevent tracing the same release multiple times.
if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
- mFlinger->mTimeStats->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
- std::make_shared<FenceTime>(releaseFence),
- TimeStats::FrameEvent::RELEASE_FENCE);
+ mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
+ std::make_shared<FenceTime>(releaseFence),
+ FrameTracer::FrameEvent::RELEASE_FENCE);
mPreviousReleasedFrameNumber = mPreviousFrameNumber;
}
}
@@ -236,9 +237,9 @@
const int32_t layerID = getSequence();
mFlinger->mTimeStats->setPostTime(layerID, mFrameNumber, getName().c_str(), postTime);
- mFlinger->mTimeStats->traceNewLayer(layerID, getName().c_str());
- mFlinger->mTimeStats->traceTimestamp(layerID, buffer->getId(), mFrameNumber, postTime,
- TimeStats::FrameEvent::POST);
+ mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
+ mFlinger->mFrameTracer->traceTimestamp(layerID, buffer->getId(), mFrameNumber, postTime,
+ FrameTracer::FrameEvent::POST);
mCurrentState.desiredPresentTime = desiredPresentTime;
if (mFlinger->mUseSmart90ForVideo) {
@@ -569,17 +570,18 @@
status_t err = bindTextureImage();
if (err != NO_ERROR) {
mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
return BAD_VALUE;
}
}
const uint64_t bufferID = getCurrentBufferId();
mFlinger->mTimeStats->setAcquireFence(layerID, mFrameNumber, getCurrentFenceTime());
- mFlinger->mTimeStats->traceFence(layerID, bufferID, mFrameNumber, getCurrentFenceTime(),
- TimeStats::FrameEvent::ACQUIRE_FENCE);
+ mFlinger->mFrameTracer->traceFence(layerID, bufferID, mFrameNumber, getCurrentFenceTime(),
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
mFlinger->mTimeStats->setLatchTime(layerID, mFrameNumber, latchTime);
- mFlinger->mTimeStats->traceTimestamp(layerID, bufferID, mFrameNumber, latchTime,
- TimeStats::FrameEvent::LATCH);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, bufferID, mFrameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH);
mCurrentStateModified = false;
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.cpp b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
new file mode 100644
index 0000000..7cbb8d8
--- /dev/null
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "FrameTracer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "FrameTracer.h"
+
+#include <android-base/stringprintf.h>
+
+#include <algorithm>
+
+PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::FrameTracer::FrameTracerDataSource);
+
+namespace android {
+
+void FrameTracer::initialize() {
+ perfetto::TracingInitArgs args;
+ args.backends = perfetto::kSystemBackend;
+ perfetto::Tracing::Initialize(args);
+ registerDataSource();
+}
+
+void FrameTracer::registerDataSource() {
+ perfetto::DataSourceDescriptor dsd;
+ dsd.set_name(kFrameTracerDataSource);
+ FrameTracerDataSource::Register(dsd);
+}
+
+void FrameTracer::traceNewLayer(int32_t layerID, const std::string& layerName) {
+ FrameTracerDataSource::Trace([this, layerID, &layerName](FrameTracerDataSource::TraceContext) {
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ mTraceTracker[layerID].layerName = layerName;
+ }
+ });
+}
+
+void FrameTracer::traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ nsecs_t timestamp, FrameEvent::BufferEventType type,
+ nsecs_t duration) {
+ FrameTracerDataSource::Trace([this, layerID, bufferID, frameNumber, timestamp, type,
+ duration](FrameTracerDataSource::TraceContext ctx) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ return;
+ }
+
+ // Handle any pending fences for this buffer.
+ tracePendingFencesLocked(ctx, layerID, bufferID);
+
+ // Complete current trace.
+ traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
+ });
+}
+
+void FrameTracer::traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& fence,
+ FrameEvent::BufferEventType type, nsecs_t startTime) {
+ FrameTracerDataSource::Trace([this, layerID, bufferID, frameNumber, &fence, type,
+ startTime](FrameTracerDataSource::TraceContext ctx) {
+ const nsecs_t signalTime = fence->getSignalTime();
+ if (signalTime != Fence::SIGNAL_TIME_INVALID) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ return;
+ }
+
+ // Handle any pending fences for this buffer.
+ tracePendingFencesLocked(ctx, layerID, bufferID);
+
+ if (signalTime != Fence::SIGNAL_TIME_PENDING) {
+ traceSpanLocked(ctx, layerID, bufferID, frameNumber, type, startTime, signalTime);
+ } else {
+ mTraceTracker[layerID].pendingFences[bufferID].push_back(
+ {.frameNumber = frameNumber,
+ .type = type,
+ .fence = fence,
+ .startTime = startTime});
+ }
+ }
+ });
+}
+
+void FrameTracer::tracePendingFencesLocked(FrameTracerDataSource::TraceContext& ctx,
+ int32_t layerID, uint64_t bufferID) {
+ if (mTraceTracker[layerID].pendingFences.count(bufferID)) {
+ auto& pendingFences = mTraceTracker[layerID].pendingFences[bufferID];
+ for (size_t i = 0; i < pendingFences.size(); ++i) {
+ auto& pendingFence = pendingFences[i];
+
+ nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
+ if (pendingFence.fence && pendingFence.fence->isValid()) {
+ signalTime = pendingFence.fence->getSignalTime();
+ if (signalTime == Fence::SIGNAL_TIME_PENDING) {
+ continue;
+ }
+ }
+
+ if (signalTime != Fence::SIGNAL_TIME_INVALID &&
+ systemTime() - signalTime < kFenceSignallingDeadline) {
+ traceSpanLocked(ctx, layerID, bufferID, pendingFence.frameNumber, pendingFence.type,
+ pendingFence.startTime, signalTime);
+ }
+
+ pendingFences.erase(pendingFences.begin() + i);
+ --i;
+ }
+ }
+}
+
+void FrameTracer::traceLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
+ FrameEvent::BufferEventType type, nsecs_t duration) {
+ auto packet = ctx.NewTracePacket();
+ packet->set_timestamp(timestamp);
+ auto* event = packet->set_graphics_frame_event()->set_buffer_event();
+ event->set_buffer_id(static_cast<uint32_t>(bufferID));
+ event->set_frame_number(frameNumber);
+ event->set_type(type);
+
+ if (mTraceTracker.find(layerID) != mTraceTracker.end() &&
+ !mTraceTracker[layerID].layerName.empty()) {
+ const std::string& layerName = mTraceTracker[layerID].layerName;
+ event->set_layer_name(layerName.c_str(), layerName.size());
+ }
+
+ if (duration > 0) {
+ event->set_duration_ns(duration);
+ }
+}
+
+void FrameTracer::traceSpanLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber,
+ FrameEvent::BufferEventType type, nsecs_t startTime,
+ nsecs_t endTime) {
+ nsecs_t timestamp = endTime;
+ nsecs_t duration = 0;
+ if (startTime > 0 && startTime < endTime) {
+ timestamp = startTime;
+ duration = endTime - startTime;
+ }
+ traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
+}
+
+void FrameTracer::onDestroy(int32_t layerID) {
+ std::lock_guard<std::mutex> traceLock(mTraceMutex);
+ mTraceTracker.erase(layerID);
+}
+
+std::string FrameTracer::miniDump() {
+ std::string result = "FrameTracer miniDump:\n";
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ android::base::StringAppendF(&result, "Number of layers currently being traced is %zu\n",
+ mTraceTracker.size());
+ return result;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.h b/services/surfaceflinger/FrameTracer/FrameTracer.h
new file mode 100644
index 0000000..d34ad81
--- /dev/null
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.h
@@ -0,0 +1,105 @@
+/*
+ * 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 <perfetto/trace/android/graphics_frame_event.pbzero.h>
+#include <perfetto/tracing.h>
+#include <ui/FenceTime.h>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace android {
+
+class FrameTracer {
+public:
+ class FrameTracerDataSource : public perfetto::DataSource<FrameTracerDataSource> {
+ virtual void OnSetup(const SetupArgs&) override{};
+ virtual void OnStart(const StartArgs&) override{};
+ virtual void OnStop(const StopArgs&) override{};
+ };
+
+ using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent;
+
+ ~FrameTracer() = default;
+
+ // Sets up the perfetto tracing backend and data source.
+ void initialize();
+ // Registers the data source with the perfetto backend. Called as part of initialize()
+ // and should not be called manually outside of tests. Public to allow for substituting a
+ // perfetto::kInProcessBackend in tests.
+ void registerDataSource();
+ // Starts tracking a new layer for tracing. Needs to be called once before traceTimestamp() or
+ // traceFence() for each layer.
+ void traceNewLayer(int32_t layerID, const std::string& layerName);
+ // Creates a trace point at the timestamp provided.
+ void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
+ FrameEvent::BufferEventType type, nsecs_t duration = 0);
+ // Creates a trace point after the provided fence has been signalled. If a startTime is provided
+ // the trace will have be timestamped from startTime until fence signalling time. If no
+ // startTime is provided, a durationless trace point will be created timestamped at fence
+ // signalling time. If the fence hasn't signalled yet, the trace point will be created the next
+ // time after signalling a trace call for this buffer occurs.
+ void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& fence, FrameEvent::BufferEventType type,
+ nsecs_t startTime = 0);
+
+ // Takes care of cleanup when a layer is destroyed.
+ void onDestroy(int32_t layerID);
+
+ std::string miniDump();
+
+ static constexpr char kFrameTracerDataSource[] = "android.surfaceflinger.frame";
+
+ // The maximum amount of time a fence has to signal before it is discarded.
+ // Used to avoid fences from previous traces generating new trace points in later ones.
+ // Public for testing.
+ static constexpr nsecs_t kFenceSignallingDeadline = 60'000'000'000; // 60 seconds
+
+private:
+ struct PendingFence {
+ uint64_t frameNumber;
+ FrameEvent::BufferEventType type;
+ std::shared_ptr<FenceTime> fence;
+ nsecs_t startTime;
+ };
+
+ struct TraceRecord {
+ std::string layerName;
+ using BufferID = uint64_t;
+ std::unordered_map<BufferID, std::vector<PendingFence>> pendingFences;
+ };
+
+ // Checks if any pending fences for a layer and buffer have signalled and, if they have, creates
+ // trace points for them.
+ void tracePendingFencesLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID);
+ // Creates a trace point by translating a start time and an end time to a timestamp and
+ // duration. If startTime is later than end time it sets end time as the timestamp and the
+ // duration to 0. Used by traceFence().
+ void traceSpanLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber, FrameEvent::BufferEventType type,
+ nsecs_t startTime, nsecs_t endTime);
+ void traceLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID,
+ uint64_t frameNumber, nsecs_t timestamp, FrameEvent::BufferEventType type,
+ nsecs_t duration = 0);
+
+ std::mutex mTraceMutex;
+ std::unordered_map<int32_t, TraceRecord> mTraceTracker;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 557d0bb..79ee827 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -22,6 +22,7 @@
#include "Layer.h"
#include <android-base/stringprintf.h>
+#include <binder/IPCThreadState.h>
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFECompositionState.h>
@@ -57,6 +58,7 @@
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
+#include "FrameTracer/FrameTracer.h"
#include "LayerProtoHelper.h"
#include "LayerRejecter.h"
#include "MonitoredProducer.h"
@@ -121,7 +123,8 @@
mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
mSchedulerLayerHandle = mFlinger->mScheduler->registerLayer(mName.c_str(), mWindowType);
-
+ mCallingPid = args.callingPid;
+ mCallingUid = args.callingUid;
mFlinger->onLayerCreated();
}
@@ -135,6 +138,21 @@
mFlinger->onLayerDestroyed(this);
}
+LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags,
+ LayerMetadata metadata)
+ : flinger(flinger),
+ client(client),
+ name(name),
+ w(w),
+ h(h),
+ flags(flags),
+ metadata(std::move(metadata)) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ callingPid = ipc->getCallingPid();
+ callingUid = ipc->getCallingUid();
+}
+
// ---------------------------------------------------------------------------
// callbacks
// ---------------------------------------------------------------------------
@@ -1323,10 +1341,17 @@
mFrameEventHistory.dump(result);
}
+void Layer::dumpCallingUidPid(std::string& result) const {
+ StringAppendF(&result, "Layer %s (%s) pid:%d uid:%d\n", getName().string(), getType(),
+ mCallingPid, mCallingUid);
+}
+
void Layer::onDisconnect() {
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.onDisconnect();
- mFlinger->mTimeStats->onDestroy(getSequence());
+ const int32_t layerID = getSequence();
+ mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 23763d2..32be980 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -80,9 +80,7 @@
struct LayerCreationArgs {
LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
- uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata)
- : flinger(flinger), client(client), name(name), w(w), h(h), flags(flags),
- metadata(std::move(metadata)) {}
+ uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata);
SurfaceFlinger* flinger;
const sp<Client>& client;
@@ -91,6 +89,8 @@
uint32_t h;
uint32_t flags;
LayerMetadata metadata;
+ pid_t callingPid;
+ uid_t callingUid;
};
class Layer : public virtual compositionengine::LayerFE {
@@ -608,6 +608,7 @@
void miniDump(std::string& result, const sp<DisplayDevice>& display) const;
void dumpFrameStats(std::string& result) const;
void dumpFrameEvents(std::string& result);
+ void dumpCallingUidPid(std::string& result) const;
void clearFrameStats();
void logFrameStats();
void getFrameStats(FrameStats* outStats) const;
@@ -932,6 +933,11 @@
bool mGetHandleCalled = false;
void removeRemoteSyncPoints();
+
+ // Tracks the process and user id of the caller when creating this layer
+ // to help debugging.
+ pid_t mCallingPid;
+ uid_t mCallingUid;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e0d1609..55835f3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -98,6 +98,7 @@
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "Effects/Daltonizer.h"
+#include "FrameTracer/FrameTracer.h"
#include "RegionSamplingThread.h"
#include "Scheduler/DispSync.h"
#include "Scheduler/DispSyncSource.h"
@@ -257,6 +258,7 @@
: mFactory(factory),
mInterceptor(mFactory.createSurfaceInterceptor(this)),
mTimeStats(mFactory.createTimeStats()),
+ mFrameTracer(std::make_unique<FrameTracer>()),
mEventQueue(mFactory.createMessageQueue()),
mCompositionEngine(mFactory.createCompositionEngine()),
mPhaseOffsets(mFactory.createPhaseOffsets()) {}
@@ -513,7 +515,7 @@
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
- mTimeStats->initializeTracing();
+ mFrameTracer->initialize();
// wait patiently for the window manager death
const String16 name("window");
@@ -2720,32 +2722,31 @@
void SurfaceFlinger::commitTransaction()
{
- if (!mLayersPendingRemoval.isEmpty()) {
- // Notify removed layers now that they can't be drawn from
- for (const auto& l : mLayersPendingRemoval) {
- recordBufferingStats(l->getName().string(),
- l->getOccupancyHistory(true));
-
- // Ensure any buffers set to display on any children are released.
- if (l->isRemovedFromCurrentState()) {
- l->latchAndReleaseBuffer();
- }
-
- // If the layer has been removed and has no parent, then it will not be reachable
- // when traversing layers on screen. Add the layer to the offscreenLayers set to
- // ensure we can copy its current to drawing state.
- if (!l->getParent()) {
- mOffscreenLayers.emplace(l.get());
- }
- }
- mLayersPendingRemoval.clear();
- }
-
- // If this transaction is part of a window animation then the next frame
- // we composite should be considered an animation as well.
- mAnimCompositionPending = mAnimTransactionPending;
-
withTracingLock([&]() {
+ if (!mLayersPendingRemoval.isEmpty()) {
+ // Notify removed layers now that they can't be drawn from
+ for (const auto& l : mLayersPendingRemoval) {
+ recordBufferingStats(l->getName().string(), l->getOccupancyHistory(true));
+
+ // Ensure any buffers set to display on any children are released.
+ if (l->isRemovedFromCurrentState()) {
+ l->latchAndReleaseBuffer();
+ }
+
+ // If the layer has been removed and has no parent, then it will not be reachable
+ // when traversing layers on screen. Add the layer to the offscreenLayers set to
+ // ensure we can copy its current to drawing state.
+ if (!l->getParent()) {
+ mOffscreenLayers.emplace(l.get());
+ }
+ }
+ mLayersPendingRemoval.clear();
+ }
+
+ // If this transaction is part of a window animation then the next frame
+ // we composite should be considered an animation as well.
+ mAnimCompositionPending = mAnimTransactionPending;
+
mDrawingState = mCurrentState;
// clear the "changed" flags in current state
mCurrentState.colorMatrixChanged = false;
@@ -4114,9 +4115,11 @@
if (asProto) {
result.append(layersProto.SerializeAsString());
} else {
+ // Dump info that we need to access from the main thread
const auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
result.append(LayerProtoParser::layerTreeToString(layerTree));
result.append("\n");
+ dumpOffscreenLayers(result);
}
}
}
@@ -4374,12 +4377,54 @@
return layersProto;
}
+void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags) const {
+ // Add a fake invisible root layer to the proto output and parent all the offscreen layers to
+ // it.
+ LayerProto* rootProto = layersProto.add_layers();
+ const int32_t offscreenRootLayerId = INT32_MAX - 2;
+ rootProto->set_id(offscreenRootLayerId);
+ rootProto->set_name("Offscreen Root");
+
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ // Add layer as child of the fake root
+ rootProto->add_children(offscreenLayer->sequence);
+
+ // Add layer
+ LayerProto* layerProto = layersProto.add_layers();
+ offscreenLayer->writeToProtoDrawingState(layerProto, traceFlags);
+ offscreenLayer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing,
+ traceFlags);
+ layerProto->set_parent(offscreenRootLayerId);
+
+ // Add children
+ offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ if (layer == offscreenLayer) {
+ return;
+ }
+ LayerProto* childProto = layersProto.add_layers();
+ layer->writeToProtoDrawingState(childProto, traceFlags);
+ layer->writeToProtoCommonState(childProto, LayerVector::StateSet::Drawing, traceFlags);
+ });
+ }
+}
+
LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
LayersProto layersProto;
postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); }));
return layersProto;
}
+void SurfaceFlinger::dumpOffscreenLayers(std::string& result) {
+ result.append("Offscreen Layers:\n");
+ postMessageSync(new LambdaMessage([&]() {
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ layer->dumpCallingUidPid(result);
+ });
+ }
+ }));
+}
+
void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
const bool colorize = !args.empty() && args[0] == String16("--color");
Colorizer colorizer(colorize);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1aa99fc..f6df33a 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -95,6 +95,7 @@
class RefreshRateOverlay;
class RegionSamplingThread;
class TimeStats;
+class FrameTracer;
namespace compositionengine {
class DisplaySurface;
@@ -863,8 +864,11 @@
void dumpDisplayIdentificationData(std::string& result) const;
void dumpWideColorInfo(std::string& result) const;
LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ void dumpOffscreenLayersProto(LayersProto& layersProto,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL)
EXCLUDES(mStateLock);
+ void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock);
void withTracingLock(std::function<void()> operation) REQUIRES(mStateLock);
bool isLayerTripleBufferingDisabled() const {
@@ -983,6 +987,7 @@
bool mTracingEnabled = false;
bool mTracingEnabledChanged GUARDED_BY(mStateLock) = false;
const std::shared_ptr<TimeStats> mTimeStats;
+ const std::unique_ptr<FrameTracer> mFrameTracer;
bool mUseHwcVirtualDisplays = false;
std::atomic<uint32_t> mFrameMissedCount = 0;
std::atomic<uint32_t> mHwcFrameMissedCount = 0;
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index 9053f2c..eb26cd0 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -163,6 +163,7 @@
entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
entry.set_where(where);
LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
+ mFlinger.dumpOffscreenLayersProto(layers);
entry.mutable_layers()->Swap(&layers);
return entry;
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index 9e1d503..2080a38 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -2,12 +2,9 @@
name: "libtimestats",
defaults: ["surfaceflinger_defaults"],
srcs: [
- "TimeStats.cpp"
+ "TimeStats.cpp",
],
export_include_dirs: ["."],
- static_libs: [
- "libperfetto_client_experimental",
- ],
shared_libs: [
"libtimestats_proto",
"libui",
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index b66e4cf..b01fa81 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -30,141 +30,10 @@
#include <algorithm>
#include <regex>
-PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::impl::TimeStats::TimeStatsDataSource);
-
namespace android {
namespace impl {
-void TimeStats::initializeTracing() {
- perfetto::TracingInitArgs args;
- args.backends = perfetto::kSystemBackend;
- perfetto::Tracing::Initialize(args);
- registerTracingDataSource();
-}
-
-void TimeStats::registerTracingDataSource() {
- perfetto::DataSourceDescriptor dsd;
- dsd.set_name(kTimeStatsDataSource);
- TimeStatsDataSource::Register(dsd);
-}
-
-void TimeStats::traceNewLayer(int32_t layerID, const std::string& layerName) {
- TimeStatsDataSource::Trace([this, layerID, &layerName](TimeStatsDataSource::TraceContext) {
- if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
- std::lock_guard<std::mutex> lock(mTraceMutex);
- mTraceTracker[layerID].layerName = layerName;
- }
- });
-}
-
-void TimeStats::traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- nsecs_t timestamp, FrameEvent::BufferEventType type,
- nsecs_t duration) {
- TimeStatsDataSource::Trace([this, layerID, bufferID, frameNumber, timestamp, type,
- duration](TimeStatsDataSource::TraceContext ctx) {
- std::lock_guard<std::mutex> lock(mTraceMutex);
- if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
- return;
- }
-
- // Handle any pending fences for this buffer.
- tracePendingFencesLocked(ctx, layerID, bufferID);
-
- // Complete current trace.
- traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
- });
-}
-
-void TimeStats::traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& fence,
- FrameEvent::BufferEventType type, nsecs_t startTime) {
- TimeStatsDataSource::Trace([this, layerID, bufferID, frameNumber, &fence, type,
- startTime](TimeStatsDataSource::TraceContext ctx) {
- const nsecs_t signalTime = fence->getSignalTime();
- if (signalTime != Fence::SIGNAL_TIME_INVALID) {
- std::lock_guard<std::mutex> lock(mTraceMutex);
- if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
- return;
- }
-
- // Handle any pending fences for this buffer.
- tracePendingFencesLocked(ctx, layerID, bufferID);
-
- if (signalTime != Fence::SIGNAL_TIME_PENDING) {
- traceSpanLocked(ctx, layerID, bufferID, frameNumber, type, startTime, signalTime);
- } else {
- mTraceTracker[layerID].pendingFences[bufferID].push_back(
- {.frameNumber = frameNumber,
- .type = type,
- .fence = fence,
- .startTime = startTime});
- }
- }
- });
-}
-
-void TimeStats::tracePendingFencesLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID) {
- if (mTraceTracker[layerID].pendingFences.count(bufferID)) {
- auto& pendingFences = mTraceTracker[layerID].pendingFences[bufferID];
- for (size_t i = 0; i < pendingFences.size(); ++i) {
- auto& pendingFence = pendingFences[i];
-
- nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
- if (pendingFence.fence && pendingFence.fence->isValid()) {
- signalTime = pendingFence.fence->getSignalTime();
- if (signalTime == Fence::SIGNAL_TIME_PENDING) {
- continue;
- }
- }
-
- if (signalTime != Fence::SIGNAL_TIME_INVALID &&
- systemTime() - signalTime < kFenceSignallingDeadline) {
- traceSpanLocked(ctx, layerID, bufferID, pendingFence.frameNumber, pendingFence.type,
- pendingFence.startTime, signalTime);
- }
-
- pendingFences.erase(pendingFences.begin() + i);
- --i;
- }
- }
-}
-
-void TimeStats::traceLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
- FrameEvent::BufferEventType type, nsecs_t duration) {
- auto packet = ctx.NewTracePacket();
- packet->set_timestamp(timestamp);
- auto* event = packet->set_graphics_frame_event()->set_buffer_event();
- event->set_buffer_id(static_cast<uint32_t>(bufferID));
- event->set_frame_number(frameNumber);
- event->set_type(type);
-
- if (mTraceTracker.find(layerID) != mTraceTracker.end() &&
- !mTraceTracker[layerID].layerName.empty()) {
- const std::string& layerName = mTraceTracker[layerID].layerName;
- event->set_layer_name(layerName.c_str(), layerName.size());
- }
-
- if (duration > 0) {
- event->set_duration_ns(duration);
- }
-}
-
-void TimeStats::traceSpanLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID, uint64_t frameNumber,
- FrameEvent::BufferEventType type, nsecs_t startTime,
- nsecs_t endTime) {
- nsecs_t timestamp = endTime;
- nsecs_t duration = 0;
- if (startTime > 0 && startTime < endTime) {
- timestamp = startTime;
- duration = endTime - startTime;
- }
- traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
-}
-
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
ATRACE_CALL();
@@ -207,8 +76,6 @@
mTimeStatsTracker.size());
android::base::StringAppendF(&result, "Number of layers in the stats pool is %zu\n",
mTimeStats.stats.size());
- android::base::StringAppendF(&result, "Number of layers currently being traced is %zu\n",
- mTraceTracker.size());
return result;
}
@@ -542,15 +409,8 @@
void TimeStats::onDestroy(int32_t layerID) {
ATRACE_CALL();
ALOGV("[%d]-onDestroy", layerID);
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mTimeStatsTracker.erase(layerID);
- }
-
- {
- std::lock_guard<std::mutex> traceLock(mTraceMutex);
- mTraceTracker.erase(layerID);
- }
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTimeStatsTracker.erase(layerID);
}
void TimeStats::removeTimeRecord(int32_t layerID, uint64_t frameNumber) {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 470137a..9ebc1ad 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -17,8 +17,6 @@
#pragma once
#include <hardware/hwcomposer_defs.h>
-#include <perfetto/trace/android/graphics_frame_event.pbzero.h>
-#include <perfetto/tracing.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
#include <ui/FenceTime.h>
@@ -36,32 +34,8 @@
class TimeStats {
public:
- using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent;
-
virtual ~TimeStats() = default;
- // Sets up the perfetto tracing backend and data source.
- virtual void initializeTracing() = 0;
- // Registers the data source with the perfetto backend. Called as part of initializeTracing()
- // and should not be called manually outside of tests. Public to allow for substituting a
- // perfetto::kInProcessBackend in tests.
- virtual void registerTracingDataSource() = 0;
- // Starts tracking a new layer for tracing. Needs to be called once before traceTimestamp() or
- // traceFence() for each layer.
- virtual void traceNewLayer(int32_t layerID, const std::string& layerName) = 0;
- // Creates a trace point at the timestamp provided.
- virtual void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- nsecs_t timestamp, FrameEvent::BufferEventType type,
- nsecs_t duration = 0) = 0;
- // Creates a trace point after the provided fence has been signalled. If a startTime is provided
- // the trace will have be timestamped from startTime until fence signalling time. If no
- // startTime is provided, a durationless trace point will be created timestamped at fence
- // signalling time. If the fence hasn't signalled yet, the trace point will be created the next
- // time after signalling a trace call for this buffer occurs.
- virtual void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& fence,
- FrameEvent::BufferEventType type, nsecs_t startTime = 0) = 0;
-
virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
virtual bool isEnabled() = 0;
virtual std::string miniDump() = 0;
@@ -89,13 +63,6 @@
// Source of truth is RefrehRateStats.
virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
-
- static constexpr char kTimeStatsDataSource[] = "android.surfaceflinger.timestats";
-
- // The maximum amount of time a fence has to signal before it is discarded.
- // Used to avoid fence's from previous traces generating new trace points in later ones.
- // Public for testing.
- static constexpr nsecs_t kFenceSignallingDeadline = 60'000'000'000; // 60 seconds
};
namespace impl {
@@ -117,13 +84,6 @@
std::shared_ptr<FenceTime> presentFence;
};
- struct PendingFence {
- uint64_t frameNumber;
- FrameEvent::BufferEventType type;
- std::shared_ptr<FenceTime> fence;
- nsecs_t startTime;
- };
-
struct LayerRecord {
std::string layerName;
// This is the index in timeRecords, at which the timestamps for that
@@ -135,12 +95,6 @@
std::deque<TimeRecord> timeRecords;
};
- struct TraceRecord {
- std::string layerName;
- using BufferID = uint64_t;
- std::unordered_map<BufferID, std::vector<PendingFence>> pendingFences;
- };
-
struct PowerTime {
int32_t powerMode = HWC_POWER_MODE_OFF;
nsecs_t prevTime = 0;
@@ -152,23 +106,8 @@
};
public:
- class TimeStatsDataSource : public perfetto::DataSource<TimeStatsDataSource> {
- virtual void OnSetup(const SetupArgs&) override{};
- virtual void OnStart(const StartArgs&) override { ALOGV("TimeStats trace started"); };
- virtual void OnStop(const StopArgs&) override { ALOGV("TimeStats trace stopped"); };
- };
-
TimeStats() = default;
- void initializeTracing() override;
- void registerTracingDataSource() override;
- void traceNewLayer(int32_t layerID, const std::string& layerName) override;
- void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
- FrameEvent::BufferEventType type, nsecs_t duration = 0) override;
- void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& fence, FrameEvent::BufferEventType type,
- nsecs_t startTime = 0) override;
-
void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
bool isEnabled() override;
std::string miniDump() override;
@@ -200,20 +139,6 @@
static const size_t MAX_NUM_TIME_RECORDS = 64;
private:
- // Checks if any pending fences for a layer and buffer have signalled and, if they have, creates
- // trace points for them.
- void tracePendingFencesLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID,
- uint64_t bufferID);
- // Creates a trace point by translating a start time and an end time to a timestamp and
- // duration. If startTime is later than end time it sets end time as the timestamp and the
- // duration to 0. Used by traceFence().
- void traceSpanLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID,
- uint64_t frameNumber, FrameEvent::BufferEventType type, nsecs_t startTime,
- nsecs_t endTime);
- void traceLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID,
- uint64_t frameNumber, nsecs_t timestamp, FrameEvent::BufferEventType type,
- nsecs_t duration = 0);
-
bool recordReadyLocked(int32_t layerID, TimeRecord* timeRecord);
void flushAvailableRecordsToStatsLocked(int32_t layerID);
void flushPowerTimeLocked();
@@ -232,9 +157,6 @@
PowerTime mPowerTime;
GlobalRecord mGlobalRecord;
- std::mutex mTraceMutex;
- std::unordered_map<int32_t, TraceRecord> mTraceTracker;
-
static const size_t MAX_NUM_LAYER_RECORDS = 200;
static const size_t MAX_NUM_LAYER_STATS = 200;
};
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 0eedf9b..8d98af6 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -51,6 +51,7 @@
"RefreshRateStatsTest.cpp",
"RegionSamplingTest.cpp",
"TimeStatsTest.cpp",
+ "FrameTracerTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockDisplay.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
@@ -63,6 +64,7 @@
"mock/MockNativeWindowSurface.cpp",
"mock/MockSurfaceInterceptor.cpp",
"mock/MockTimeStats.cpp",
+ "mock/MockFrameTracer.cpp",
"mock/system/window/MockNativeWindow.cpp",
],
static_libs: [
diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
new file mode 100644
index 0000000..b5af591
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
@@ -0,0 +1,396 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <FrameTracer/FrameTracer.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <perfetto/trace/trace.pb.h>
+
+#include "libsurfaceflinger_unittest_main.h"
+
+using namespace google::protobuf;
+
+namespace android {
+namespace {
+
+class FrameTracerTest : public testing::Test {
+public:
+ FrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ // Need to initialize tracing in process for testing, and only once per test suite.
+ static bool wasInitialized = false;
+ if (!wasInitialized) {
+ perfetto::TracingInitArgs args;
+ args.backends = perfetto::kInProcessBackend;
+ perfetto::Tracing::Initialize(args);
+ wasInitialized = true;
+ }
+ }
+
+ ~FrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ void SetUp() override {
+ mFrameTracer = std::make_unique<FrameTracer>();
+ mFrameTracer->registerDataSource();
+ }
+
+ void TearDown() override { mFrameTracer.reset(); }
+
+ // Each tracing session can be used for a single block of Start -> Stop.
+ static std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest() {
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name(FrameTracer::kFrameTracerDataSource);
+
+ auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+ tracingSession->Setup(cfg);
+ return tracingSession;
+ }
+
+ std::unique_ptr<FrameTracer> mFrameTracer;
+ FenceToFenceTimeMap fenceFactory;
+};
+
+TEST_F(FrameTracerTest, traceNewLayerStartsTrackingLayerWhenTracing) {
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ tracingSession->StopBlocking();
+}
+
+TEST_F(FrameTracerTest, onDestroyRemovesTheTrackedLayer) {
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const int32_t secondLayerID = 6;
+
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceNewLayer(secondLayerID, layerName);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 2\n");
+ tracingSession->StopBlocking();
+
+ mFrameTracer->onDestroy(layerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ mFrameTracer->onDestroy(layerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ mFrameTracer->onDestroy(secondLayerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+}
+
+TEST_F(FrameTracerTest, canTraceAfterAddingLayer) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 1;
+ const uint32_t bufferID = 2;
+ const uint64_t frameNumber = 3;
+ const nsecs_t timestamp = 4;
+ const nsecs_t duration = 5;
+ const auto type = FrameTracer::FrameEvent::POST;
+
+ {
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+
+ mFrameTracer->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
+ // Create second trace packet to finalize the previous one.
+ mFrameTracer->traceTimestamp(layerID, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+ }
+
+ {
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
+ // Create second trace packet to finalize the previous one.
+ mFrameTracer->traceTimestamp(layerID, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 1);
+
+ const auto& packet = trace.packet().Get(0);
+ ASSERT_TRUE(packet.has_timestamp());
+ EXPECT_EQ(packet.timestamp(), timestamp);
+ ASSERT_TRUE(packet.has_graphics_frame_event());
+ const auto& frame_event = packet.graphics_frame_event();
+ ASSERT_TRUE(frame_event.has_buffer_event());
+ const auto& buffer_event = frame_event.buffer_event();
+ ASSERT_TRUE(buffer_event.has_buffer_id());
+ EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+ ASSERT_TRUE(buffer_event.has_frame_number());
+ EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+ ASSERT_TRUE(buffer_event.has_type());
+ EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+ ASSERT_TRUE(buffer_event.has_duration_ns());
+ EXPECT_EQ(buffer_event.duration_ns(), duration);
+ }
+}
+
+TEST_F(FrameTracerTest, traceFenceTriggersOnNextTraceAfterFenceFired) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+ {
+ auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING);
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ // Trace.
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
+ // Create extra trace packet to (hopefully not) trigger and finalize the fence packet.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+ }
+
+ {
+ auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
+ const nsecs_t timestamp = systemTime();
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp);
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above.
+
+ const auto& packet = trace.packet().Get(1);
+ ASSERT_TRUE(packet.has_timestamp());
+ EXPECT_EQ(packet.timestamp(), timestamp);
+ ASSERT_TRUE(packet.has_graphics_frame_event());
+ const auto& frame_event = packet.graphics_frame_event();
+ ASSERT_TRUE(frame_event.has_buffer_event());
+ const auto& buffer_event = frame_event.buffer_event();
+ ASSERT_TRUE(buffer_event.has_buffer_id());
+ EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+ ASSERT_TRUE(buffer_event.has_frame_number());
+ EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+ ASSERT_TRUE(buffer_event.has_type());
+ EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+ EXPECT_FALSE(buffer_event.has_duration_ns());
+ }
+}
+
+TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ // traceFence called after fence signalled.
+ const nsecs_t signalTime1 = systemTime();
+ const nsecs_t startTime1 = signalTime1 + 100000;
+ auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
+
+ // traceFence called before fence signalled.
+ const nsecs_t signalTime2 = systemTime();
+ const nsecs_t startTime2 = signalTime2 + 100000;
+ auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2);
+
+ const auto& packet1 = trace.packet().Get(0);
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), signalTime1);
+ ASSERT_TRUE(packet1.has_graphics_frame_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+ ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+
+ const auto& packet2 = trace.packet().Get(1);
+ ASSERT_TRUE(packet2.has_timestamp());
+ EXPECT_EQ(packet2.timestamp(), signalTime2);
+ ASSERT_TRUE(packet2.has_graphics_frame_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+ ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+}
+
+TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+ const nsecs_t signalTime = systemTime() - FrameTracer::kFenceSignallingDeadline;
+
+ auto tracingSession = getTracingSessionForTest();
+ auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence, type);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime);
+ // Create extra trace packet to trigger and finalize any previous fence packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+}
+
+TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+ const nsecs_t duration = 1234;
+
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ // traceFence called after fence signalled.
+ const nsecs_t signalTime1 = systemTime();
+ const nsecs_t startTime1 = signalTime1 - duration;
+ auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
+
+ // traceFence called before fence signalled.
+ const nsecs_t signalTime2 = systemTime();
+ const nsecs_t startTime2 = signalTime2 - duration;
+ auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2);
+
+ const auto& packet1 = trace.packet().Get(0);
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), startTime1);
+ ASSERT_TRUE(packet1.has_graphics_frame_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+ const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
+ EXPECT_EQ(buffer_event1.duration_ns(), duration);
+
+ const auto& packet2 = trace.packet().Get(1);
+ ASSERT_TRUE(packet2.has_timestamp());
+ EXPECT_EQ(packet2.timestamp(), startTime2);
+ ASSERT_TRUE(packet2.has_graphics_frame_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+ const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event();
+ EXPECT_EQ(buffer_event2.duration_ns(), duration);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index f01e603..ffacbfe 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -20,8 +20,8 @@
#include <TimeStats/TimeStats.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+
#include <log/log.h>
-#include <perfetto/trace/trace.pb.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -109,15 +109,6 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
-
- // Need to initialize tracing in process for testing, and only once per test suite.
- static bool wasInitialized = false;
- if (!wasInitialized) {
- perfetto::TracingInitArgs args;
- args.backends = perfetto::kInProcessBackend;
- perfetto::Tracing::Initialize(args);
- wasInitialized = true;
- }
}
~TimeStatsTest() {
@@ -126,13 +117,6 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
- void SetUp() override {
- mTimeStats = std::make_unique<impl::TimeStats>();
- mTimeStats->registerTracingDataSource();
- }
-
- void TearDown() override { mTimeStats.reset(); }
-
std::string inputCommand(InputCommand cmd, bool useProto);
void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts);
@@ -147,22 +131,8 @@
}
}
- // Each tracing session can be used for a single block of Start -> Stop.
- static std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest() {
- perfetto::TraceConfig cfg;
- cfg.set_duration_ms(500);
- cfg.add_buffers()->set_size_kb(1024);
- auto* ds_cfg = cfg.add_data_sources()->mutable_config();
- ds_cfg->set_name(TimeStats::kTimeStatsDataSource);
-
- auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
- tracingSession->Setup(cfg);
- return tracingSession;
- }
-
std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
- std::unique_ptr<TimeStats> mTimeStats;
- FenceToFenceTimeMap fenceFactory;
+ std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
};
std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -239,330 +209,6 @@
return distr(mRandomEngine);
}
-TEST_F(TimeStatsTest, traceNewLayerStartsTrackingLayerWhenTracing) {
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- mTimeStats->traceNewLayer(layerID, layerName);
-
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
- mTimeStats->traceNewLayer(layerID, layerName);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n");
- tracingSession->StopBlocking();
-}
-
-TEST_F(TimeStatsTest, onDestroyRemovesTheTrackedLayer) {
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const int32_t secondLayerID = 6;
-
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceNewLayer(secondLayerID, layerName);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 2\n");
- tracingSession->StopBlocking();
-
- mTimeStats->onDestroy(layerID);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n");
- mTimeStats->onDestroy(layerID);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n");
- mTimeStats->onDestroy(secondLayerID);
- EXPECT_EQ(mTimeStats->miniDump(),
- "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of "
- "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n");
-}
-
-TEST_F(TimeStatsTest, canTraceAfterAddingLayer) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 1;
- const uint32_t bufferID = 2;
- const uint64_t frameNumber = 3;
- const nsecs_t timestamp = 4;
- const nsecs_t duration = 5;
- const auto type = TimeStats::FrameEvent::POST;
-
- {
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
-
- mTimeStats->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
- // Create second trace packet to finalize the previous one.
- mTimeStats->traceTimestamp(layerID, 0, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- EXPECT_EQ(raw_trace.size(), 0);
- }
-
- {
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
-
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
- // Create second trace packet to finalize the previous one.
- mTimeStats->traceTimestamp(layerID, 0, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 1);
-
- const auto& packet = trace.packet().Get(0);
- ASSERT_TRUE(packet.has_timestamp());
- EXPECT_EQ(packet.timestamp(), timestamp);
- ASSERT_TRUE(packet.has_graphics_frame_event());
- const auto& frame_event = packet.graphics_frame_event();
- ASSERT_TRUE(frame_event.has_buffer_event());
- const auto& buffer_event = frame_event.buffer_event();
- ASSERT_TRUE(buffer_event.has_buffer_id());
- EXPECT_EQ(buffer_event.buffer_id(), bufferID);
- ASSERT_TRUE(buffer_event.has_frame_number());
- EXPECT_EQ(buffer_event.frame_number(), frameNumber);
- ASSERT_TRUE(buffer_event.has_type());
- EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
- ASSERT_TRUE(buffer_event.has_duration_ns());
- EXPECT_EQ(buffer_event.duration_ns(), duration);
- }
-}
-
-TEST_F(TimeStatsTest, traceFenceTriggersOnNextTraceAfterFenceFired) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
-
- {
- auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING);
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- // Trace.
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
- // Create extra trace packet to (hopefully not) trigger and finalize the fence packet.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- EXPECT_EQ(raw_trace.size(), 0);
- }
-
- {
- auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- auto tracingSession = getTracingSessionForTest();
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
- const nsecs_t timestamp = systemTime();
- fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp);
- // Create extra trace packet to trigger and finalize fence trace packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above.
-
- const auto& packet = trace.packet().Get(1);
- ASSERT_TRUE(packet.has_timestamp());
- EXPECT_EQ(packet.timestamp(), timestamp);
- ASSERT_TRUE(packet.has_graphics_frame_event());
- const auto& frame_event = packet.graphics_frame_event();
- ASSERT_TRUE(frame_event.has_buffer_event());
- const auto& buffer_event = frame_event.buffer_event();
- ASSERT_TRUE(buffer_event.has_buffer_id());
- EXPECT_EQ(buffer_event.buffer_id(), bufferID);
- ASSERT_TRUE(buffer_event.has_frame_number());
- EXPECT_EQ(buffer_event.frame_number(), frameNumber);
- ASSERT_TRUE(buffer_event.has_type());
- EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
- EXPECT_FALSE(buffer_event.has_duration_ns());
- }
-}
-
-TEST_F(TimeStatsTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
-
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
-
- // traceFence called after fence signalled.
- const nsecs_t signalTime1 = systemTime();
- const nsecs_t startTime1 = signalTime1 + 100000;
- auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
-
- // traceFence called before fence signalled.
- const nsecs_t signalTime2 = systemTime();
- const nsecs_t startTime2 = signalTime2 + 100000;
- auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
-
- // Create extra trace packet to trigger and finalize fence trace packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 2);
-
- const auto& packet1 = trace.packet().Get(0);
- ASSERT_TRUE(packet1.has_timestamp());
- EXPECT_EQ(packet1.timestamp(), signalTime1);
- ASSERT_TRUE(packet1.has_graphics_frame_event());
- ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
- ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
-
- const auto& packet2 = trace.packet().Get(1);
- ASSERT_TRUE(packet2.has_timestamp());
- EXPECT_EQ(packet2.timestamp(), signalTime2);
- ASSERT_TRUE(packet2.has_graphics_frame_event());
- ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
- ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
-}
-
-TEST_F(TimeStatsTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
- const nsecs_t signalTime = systemTime() - TimeStats::kFenceSignallingDeadline;
-
- auto tracingSession = getTracingSessionForTest();
- auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence, type);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime);
- // Create extra trace packet to trigger and finalize any previous fence packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- EXPECT_EQ(raw_trace.size(), 0);
-}
-
-TEST_F(TimeStatsTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
- const std::string layerName = "co.layername#0";
- const int32_t layerID = 5;
- const uint32_t bufferID = 4;
- const uint64_t frameNumber = 3;
- const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE;
- const nsecs_t duration = 1234;
-
- auto tracingSession = getTracingSessionForTest();
-
- tracingSession->StartBlocking();
- // Clean up irrelevant traces.
- tracingSession->ReadTraceBlocking();
- mTimeStats->traceNewLayer(layerID, layerName);
-
- // traceFence called after fence signalled.
- const nsecs_t signalTime1 = systemTime();
- const nsecs_t startTime1 = signalTime1 - duration;
- auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
-
- // traceFence called before fence signalled.
- const nsecs_t signalTime2 = systemTime();
- const nsecs_t startTime2 = signalTime2 - duration;
- auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- mTimeStats->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
- fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
-
- // Create extra trace packet to trigger and finalize fence trace packets.
- mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED);
- tracingSession->StopBlocking();
-
- std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
- ASSERT_GT(raw_trace.size(), 0);
-
- perfetto::protos::Trace trace;
- ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
- ASSERT_FALSE(trace.packet().empty());
- EXPECT_EQ(trace.packet().size(), 2);
-
- const auto& packet1 = trace.packet().Get(0);
- ASSERT_TRUE(packet1.has_timestamp());
- EXPECT_EQ(packet1.timestamp(), startTime1);
- ASSERT_TRUE(packet1.has_graphics_frame_event());
- ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
- ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
- const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
- EXPECT_EQ(buffer_event1.duration_ns(), duration);
-
- const auto& packet2 = trace.packet().Get(1);
- ASSERT_TRUE(packet2.has_timestamp());
- EXPECT_EQ(packet2.timestamp(), startTime2);
- ASSERT_TRUE(packet2.has_graphics_frame_event());
- ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
- ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
- const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event();
- EXPECT_EQ(buffer_event2.duration_ns(), duration);
-}
-
TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
ASSERT_TRUE(mTimeStats->isEnabled());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
new file mode 100644
index 0000000..358dfdb
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#include "mock/MockFrameTracer.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+FrameTracer::FrameTracer() = default;
+FrameTracer::~FrameTracer() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
new file mode 100644
index 0000000..f768b81
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
@@ -0,0 +1,43 @@
+/*
+ * 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 <gmock/gmock.h>
+
+#include "FrameTracer/FrameTracer.h"
+
+namespace android {
+namespace mock {
+
+class FrameTracer : public android::FrameTracer {
+public:
+ FrameTracer();
+ ~FrameTracer();
+
+ MOCK_METHOD0(initialize, void());
+ MOCK_METHOD0(registerDataSource, void());
+ MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&));
+ MOCK_METHOD6(traceTimestamp,
+ void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t));
+ MOCK_METHOD6(traceFence,
+ void(int32_t, uint64_t, uint64_t, const std::shared_ptr<FenceTime>&,
+ FrameEvent::BufferEventType, nsecs_t));
+ MOCK_METHOD0(miniDump, std::string());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 542c70a..b1634a8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -28,14 +28,6 @@
TimeStats();
~TimeStats() override;
- MOCK_METHOD0(initializeTracing, void());
- MOCK_METHOD0(registerTracingDataSource, void());
- MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&));
- MOCK_METHOD6(traceTimestamp,
- void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t));
- MOCK_METHOD6(traceFence,
- void(int32_t, uint64_t, uint64_t, const std::shared_ptr<FenceTime>&,
- FrameEvent::BufferEventType, nsecs_t));
MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
MOCK_METHOD0(isEnabled, bool());
MOCK_METHOD0(miniDump, std::string());