Merge "Fix result check of IBinder::pingBinder on vibrator HAl wrapper"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 4058934..1f055f3 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -105,6 +105,7 @@
name: "dumpstate",
defaults: ["dumpstate_defaults"],
srcs: [
+ "DumpPool.cpp",
"dumpstate.cpp",
"main.cpp",
],
@@ -132,6 +133,7 @@
name: "dumpstate_test",
defaults: ["dumpstate_defaults"],
srcs: [
+ "DumpPool.cpp",
"dumpstate.cpp",
"tests/dumpstate_test.cpp",
],
@@ -148,6 +150,7 @@
name: "dumpstate_smoke_test",
defaults: ["dumpstate_defaults"],
srcs: [
+ "DumpPool.cpp",
"dumpstate.cpp",
"tests/dumpstate_smoke_test.cpp",
],
diff --git a/cmds/dumpstate/DumpPool.cpp b/cmds/dumpstate/DumpPool.cpp
new file mode 100644
index 0000000..7324ead
--- /dev/null
+++ b/cmds/dumpstate/DumpPool.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "dumpstate"
+
+#include "DumpPool.h"
+
+#include <array>
+#include <thread>
+
+#include <log/log.h>
+
+#include "dumpstate.h"
+#include "DumpstateInternal.h"
+#include "DumpstateUtil.h"
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+const std::string DumpPool::PREFIX_TMPFILE_NAME = "dump-tmp.";
+
+DumpPool::DumpPool(const std::string& tmp_root) : tmp_root_(tmp_root), shutdown_(false) {
+ assert(!tmp_root.empty());
+ deleteTempFiles(tmp_root_);
+}
+
+DumpPool::~DumpPool() {
+ shutdown();
+}
+
+void DumpPool::start(int thread_counts) {
+ assert(thread_counts > 0);
+ assert(threads_.empty());
+ if (thread_counts > MAX_THREAD_COUNT) {
+ thread_counts = MAX_THREAD_COUNT;
+ }
+ MYLOGI("Start thread pool:%d", thread_counts);
+ shutdown_ = false;
+ for (int i = 0; i < thread_counts; i++) {
+ threads_.emplace_back(std::thread([=]() {
+ setThreadName(pthread_self(), i + 1);
+ loop();
+ }));
+ }
+}
+
+void DumpPool::shutdown() {
+ std::unique_lock lock(lock_);
+ if (shutdown_ || threads_.empty()) {
+ return;
+ }
+ while (!tasks_.empty()) tasks_.pop();
+ futures_map_.clear();
+
+ shutdown_ = true;
+ condition_variable_.notify_all();
+ lock.unlock();
+
+ for (auto& thread : threads_) {
+ thread.join();
+ }
+ threads_.clear();
+ deleteTempFiles(tmp_root_);
+ MYLOGI("shutdown thread pool");
+}
+
+void DumpPool::waitForTask(const std::string& task_name, const std::string& title,
+ int out_fd) {
+ DurationReporter duration_reporter("Wait for " + task_name, true);
+ auto iterator = futures_map_.find(task_name);
+ if (iterator == futures_map_.end()) {
+ MYLOGW("Task %s does not exist", task_name.c_str());
+ return;
+ }
+ Future future = iterator->second;
+ futures_map_.erase(iterator);
+
+ std::string result = future.get();
+ if (result.empty()) {
+ return;
+ }
+ DumpFileToFd(out_fd, title, result);
+ if (unlink(result.c_str())) {
+ MYLOGE("Failed to unlink (%s): %s\n", result.c_str(), strerror(errno));
+ }
+}
+
+std::unique_ptr<DumpPool::TmpFile> DumpPool::createTempFile() {
+ auto tmp_file_ptr = std::make_unique<TmpFile>();
+ std::string file_name_format = "%s/" + PREFIX_TMPFILE_NAME + "XXXXXX";
+ snprintf(tmp_file_ptr->path, sizeof(tmp_file_ptr->path), file_name_format.c_str(),
+ tmp_root_.c_str());
+ tmp_file_ptr->fd.reset(TEMP_FAILURE_RETRY(
+ mkostemp(tmp_file_ptr->path, O_CLOEXEC)));
+ if (tmp_file_ptr->fd.get() == -1) {
+ MYLOGE("open(%s, %s)\n", tmp_file_ptr->path, strerror(errno));
+ tmp_file_ptr = nullptr;
+ return tmp_file_ptr;
+ }
+ return tmp_file_ptr;
+}
+
+void DumpPool::deleteTempFiles(const std::string& folder) {
+ std::unique_ptr<DIR, decltype(&closedir)> dir_ptr(opendir(folder.c_str()),
+ &closedir);
+ if (!dir_ptr) {
+ MYLOGE("Failed to opendir (%s): %s\n", folder.c_str(), strerror(errno));
+ return;
+ }
+ int dir_fd = dirfd(dir_ptr.get());
+ if (dir_fd < 0) {
+ MYLOGE("Failed to get fd of dir (%s): %s\n", folder.c_str(),
+ strerror(errno));
+ return;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir_ptr.get()))) {
+ if (de->d_type != DT_REG) {
+ continue;
+ }
+ std::string file_name(de->d_name);
+ if (file_name.find(PREFIX_TMPFILE_NAME) != 0) {
+ continue;
+ }
+ if (unlinkat(dir_fd, file_name.c_str(), 0)) {
+ MYLOGE("Failed to unlink (%s): %s\n", file_name.c_str(),
+ strerror(errno));
+ }
+ }
+}
+
+void DumpPool::setThreadName(const pthread_t thread, int id) {
+ std::array<char, 15> name;
+ snprintf(name.data(), name.size(), "dumpstate_%d", id);
+ pthread_setname_np(thread, name.data());
+}
+
+void DumpPool::loop() {
+ std::unique_lock lock(lock_);
+ while (!shutdown_) {
+ if (tasks_.empty()) {
+ condition_variable_.wait(lock);
+ continue;
+ } else {
+ std::packaged_task<std::string()> task = std::move(tasks_.front());
+ tasks_.pop();
+ lock.unlock();
+ std::invoke(task);
+ lock.lock();
+ }
+ }
+}
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
diff --git a/cmds/dumpstate/DumpPool.h b/cmds/dumpstate/DumpPool.h
new file mode 100644
index 0000000..266d519
--- /dev/null
+++ b/cmds/dumpstate/DumpPool.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
+#define FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
+
+#include <future>
+#include <map>
+#include <queue>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/macros.h>
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+/*
+ * A thread pool with the fixed number of threads to execute multiple dump tasks
+ * simultaneously for the dumpstate. The dump task is a callable function
+ * included a file descriptor as a parameter, and the task could dump results to
+ * that fd. For example:
+ *
+ * void DumpXXXX(int out_fd) {
+ * dprintf(out_fd, "Dump result to out_fd ...");
+ * }
+ * ...
+ * DumpPool pool(tmp_root);
+ * pool.enqueueTask("TaskName", &DumpXXXX, std::placeholders::_1);
+ * ...
+ * pool.waitForTask("TaskName");
+ *
+ * DumpXXXX is a callable function included a out_fd parameter. Using the
+ * enqueueTask method in DumpPool to enqueue the task to the pool. The
+ * std::placeholders::_1 is placeholder for DumpPool to pass a fd argument.
+ */
+class DumpPool {
+ public:
+ /*
+ * Creates a thread pool.
+ *
+ * |tmp_root| A path to a temporary folder for threads to create temporary
+ * files.
+ */
+ explicit DumpPool(const std::string& tmp_root);
+ ~DumpPool();
+
+ /*
+ * Starts the threads in the pool.
+ *
+ * |thread_counts| the number of threads to start.
+ */
+ void start(int thread_counts = MAX_THREAD_COUNT);
+
+ /*
+ * Requests to shutdown the pool and waits until all threads exit the loop.
+ */
+ void shutdown();
+
+ /*
+ * Adds a task with a task name into the queue of the thread pool.
+ *
+ * |task_name| The name of the task.
+ * |f| Callable function to execute the task. This function must
+ * include a parameter of file descriptor to output dump result.
+ * |args| A list of arguments.
+ */
+ template<class F, class... Args> void enqueueTask(const std::string& task_name,
+ F&& f, Args&&... args) {
+ auto func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
+ futures_map_[task_name] = post(func);
+ if (threads_.empty()) {
+ start();
+ }
+ }
+
+ /*
+ * Waits until the task is finished. Dumps the task results to the STDOUT_FILENO.
+ */
+ void waitForTask(const std::string& task_name) {
+ waitForTask(task_name, "", STDOUT_FILENO);
+ }
+
+ /*
+ * Waits until the task is finished. Dumps the task results to the specified
+ * out_fd.
+ *
+ * |task_name| The name of the task.
+ * |title| Dump title string to the out_fd, an empty string for nothing.
+ * |out_fd| The target file to dump the result from the task.
+ */
+ void waitForTask(const std::string& task_name, const std::string& title, int out_fd);
+
+ static const std::string PREFIX_TMPFILE_NAME;
+
+ private:
+ using Task = std::packaged_task<std::string()>;
+ using Future = std::shared_future<std::string>;
+
+ template<class T> Future post(T dump_func) {
+ Task packaged_task([=]() {
+ std::unique_ptr<TmpFile> tmp_file_ptr = createTempFile();
+ if (!tmp_file_ptr) {
+ return std::string("");
+ }
+ std::invoke(dump_func, tmp_file_ptr->fd.get());
+ fsync(tmp_file_ptr->fd.get());
+ return std::string(tmp_file_ptr->path);
+ });
+ std::unique_lock lock(lock_);
+ auto future = packaged_task.get_future().share();
+ tasks_.push(std::move(packaged_task));
+ condition_variable_.notify_one();
+ return future;
+ }
+
+ typedef struct {
+ android::base::unique_fd fd;
+ char path[1024];
+ } TmpFile;
+
+ std::unique_ptr<TmpFile> createTempFile();
+ void deleteTempFiles(const std::string& folder);
+ void setThreadName(const pthread_t thread, int id);
+ void loop();
+
+ private:
+ static const int MAX_THREAD_COUNT = 4;
+
+ /* A path to a temporary folder for threads to create temporary files. */
+ std::string tmp_root_;
+ bool shutdown_;
+ std::mutex lock_; // A lock for the tasks_.
+ std::condition_variable condition_variable_;
+
+ std::vector<std::thread> threads_;
+ std::queue<Task> tasks_;
+ std::map<std::string, Future> futures_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(DumpPool);
+};
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
+
+#endif //FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index c7df1bb..d0a4826 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -21,6 +21,7 @@
#include "DumpstateService.h"
#include "android/os/BnDumpstate.h"
#include "dumpstate.h"
+#include "DumpPool.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -46,6 +47,7 @@
using ::android::hardware::dumpstate::V1_1::DumpstateMode;
using ::testing::EndsWith;
+using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::IsEmpty;
using ::testing::IsNull;
@@ -1618,6 +1620,80 @@
EXPECT_THAT(out, EndsWith("skipped on dry run\n"));
}
+class DumpPoolTest : public DumpstateBaseTest {
+ public:
+ void SetUp() {
+ DumpstateBaseTest::SetUp();
+ CreateOutputFile();
+ }
+
+ void CreateOutputFile() {
+ out_path_ = kTestDataPath + "out.txt";
+ out_fd_.reset(TEMP_FAILURE_RETRY(open(out_path_.c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+ ASSERT_GE(out_fd_.get(), 0) << "could not create FD for path "
+ << out_path_;
+ }
+
+ int getTempFileCounts(const std::string& folder) {
+ int count = 0;
+ std::unique_ptr<DIR, decltype(&closedir)> dir_ptr(opendir(folder.c_str()),
+ &closedir);
+ if (!dir_ptr) {
+ return -1;
+ }
+ int dir_fd = dirfd(dir_ptr.get());
+ if (dir_fd < 0) {
+ return -1;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir_ptr.get()))) {
+ if (de->d_type != DT_REG) {
+ continue;
+ }
+ std::string file_name(de->d_name);
+ if (file_name.find(DumpPool::PREFIX_TMPFILE_NAME) != 0) {
+ continue;
+ }
+ count++;
+ }
+ return count;
+ }
+
+ android::base::unique_fd out_fd_;
+ std::string out_path_;
+};
+
+TEST_F(DumpPoolTest, EnqueueTask) {
+ DumpPool pool(kTestDataPath);
+ auto dump_func_1 = [](int out_fd) {
+ dprintf(out_fd, "A");
+ };
+ auto dump_func_2 = [](int out_fd) {
+ dprintf(out_fd, "B");
+ sleep(1);
+ };
+ auto dump_func_3 = [](int out_fd) {
+ dprintf(out_fd, "C");
+ };
+ pool.enqueueTask(/* task_name = */"1", dump_func_1, std::placeholders::_1);
+ pool.enqueueTask(/* task_name = */"2", dump_func_2, std::placeholders::_1);
+ pool.enqueueTask(/* task_name = */"3", dump_func_3, std::placeholders::_1);
+
+ pool.waitForTask("1", "", out_fd_.get());
+ pool.waitForTask("2", "", out_fd_.get());
+ pool.waitForTask("3", "", out_fd_.get());
+
+ std::string result;
+ ReadFileToString(out_path_, &result);
+ EXPECT_THAT(result, StrEq("A\nB\nC\n"));
+ EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
+ pool.shutdown();
+}
+
+
} // namespace dumpstate
} // namespace os
} // namespace android
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 1f9892a..e80c321 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -213,17 +213,18 @@
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
- auto entry = mNameToService.emplace(name, Service {
+ // Overwrite the old service if it exists
+ mNameToService[name] = Service {
.binder = binder,
.allowIsolated = allowIsolated,
.dumpPriority = dumpPriority,
.debugPid = ctx.debugPid,
- });
+ };
auto it = mNameToRegistrationCallback.find(name);
if (it != mNameToRegistrationCallback.end()) {
for (const sp<IServiceCallback>& cb : it->second) {
- entry.first->second.guaranteeClient = true;
+ mNameToService[name].guaranteeClient = true;
// permission checked in registerForNotifications
cb->onRegistration(name, binder);
}
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index 25245be..fb9f9df 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -135,6 +135,26 @@
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
}
+TEST(AddService, OverwriteExistingService) {
+ auto sm = getPermissiveServiceManager();
+ sp<IBinder> serviceA = getBinder();
+ EXPECT_TRUE(sm->addService("foo", serviceA, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ sp<IBinder> outA;
+ EXPECT_TRUE(sm->getService("foo", &outA).isOk());
+ EXPECT_EQ(serviceA, outA);
+
+ // serviceA should be overwritten by serviceB
+ sp<IBinder> serviceB = getBinder();
+ EXPECT_TRUE(sm->addService("foo", serviceB, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ sp<IBinder> outB;
+ EXPECT_TRUE(sm->getService("foo", &outB).isOk());
+ EXPECT_EQ(serviceB, outB);
+}
+
TEST(AddService, NoPermissions) {
std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index d287290..7d9fd51 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -168,7 +168,7 @@
binder_status_t status = getClass()->onTransact(this, code, &in, &out);
return PruneStatusT(status);
- } else if (code == SHELL_COMMAND_TRANSACTION) {
+ } else if (code == SHELL_COMMAND_TRANSACTION && getClass()->handleShellCommand != nullptr) {
int in = data.readFileDescriptor();
int out = data.readFileDescriptor();
int err = data.readFileDescriptor();
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 5779427..902fe79 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -110,13 +110,13 @@
const ::android::String16& getInterfaceDescriptor() const { return mInterfaceDescriptor; }
// required to be non-null, implemented for every class
- const AIBinder_Class_onCreate onCreate;
- const AIBinder_Class_onDestroy onDestroy;
- const AIBinder_Class_onTransact onTransact;
+ const AIBinder_Class_onCreate onCreate = nullptr;
+ const AIBinder_Class_onDestroy onDestroy = nullptr;
+ const AIBinder_Class_onTransact onTransact = nullptr;
// optional methods for a class
- AIBinder_onDump onDump;
- AIBinder_handleShellCommand handleShellCommand;
+ AIBinder_onDump onDump = nullptr;
+ AIBinder_handleShellCommand handleShellCommand = nullptr;
private:
// This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 055c79b..52bcd20 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -18,6 +18,7 @@
#include <android/binder_ibinder.h>
#include <android/binder_status.h>
+#include <sys/cdefs.h>
__BEGIN_DECLS
@@ -50,4 +51,47 @@
*/
__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
+/**
+ * Registers a lazy service with the default service manager under the 'instance' name.
+ * Does not take ownership of binder.
+ * The service must be configured statically with init so it can be restarted with
+ * ctl.interface.* messages from servicemanager.
+ * AServiceManager_registerLazyService cannot safely be used with AServiceManager_addService
+ * in the same process. If one service is registered with AServiceManager_registerLazyService,
+ * the entire process will have its lifetime controlled by servicemanager.
+ * Instead, all services in the process should be registered using
+ * AServiceManager_registerLazyService.
+ *
+ * \param binder object to register globally with the service manager.
+ * \param instance identifier of the service. This will be used to lookup the service.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AServiceManager_registerLazyService(AIBinder* binder, const char* instance)
+ __INTRODUCED_IN(31);
+
+/**
+ * Gets a binder object with this specific instance name. Efficiently waits for the service.
+ * If the service is not declared, it will wait indefinitely. Requires the threadpool
+ * to be started in the service.
+ * This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
+ * for calling AIBinder_decStrong).
+ *
+ * \param instance identifier of the service used to lookup the service.
+ *
+ * \return service if registered, null if not.
+ */
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_waitForService(const char* instance)
+ __INTRODUCED_IN(31);
+
+/**
+ * Check if a service is declared (e.g. VINTF manifest).
+ *
+ * \param instance identifier of the service.
+ *
+ * \return true on success, meaning AServiceManager_waitForService should always
+ * be able to return the service.
+ */
+bool AServiceManager_isDeclared(const char* instance) __INTRODUCED_IN(31);
+
__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index d435382..1701fb5 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -117,6 +117,9 @@
ABinderProcess_setupPolling; # apex
AIBinder_getCallingSid; # apex
AIBinder_setRequestingSid; # apex
+ AServiceManager_isDeclared; # apex llndk
+ AServiceManager_registerLazyService; # llndk
+ AServiceManager_waitForService; # apex llndk
};
LIBBINDER_NDK_PLATFORM {
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index d0b166d..6b2184e 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -20,6 +20,7 @@
#include "status_internal.h"
#include <binder/IServiceManager.h>
+#include <binder/LazyServiceRegistrar.h>
using ::android::defaultServiceManager;
using ::android::IBinder;
@@ -61,3 +62,33 @@
AIBinder_incStrong(ret.get());
return ret.get();
}
+binder_status_t AServiceManager_registerLazyService(AIBinder* binder, const char* instance) {
+ if (binder == nullptr || instance == nullptr) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+
+ auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+ status_t status = serviceRegistrar.registerService(binder->getBinder(), instance);
+
+ return PruneStatusT(status);
+}
+AIBinder* AServiceManager_waitForService(const char* instance) {
+ if (instance == nullptr) {
+ return nullptr;
+ }
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->waitForService(String16(instance));
+
+ sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
+ AIBinder_incStrong(ret.get());
+ return ret.get();
+}
+bool AServiceManager_isDeclared(const char* instance) {
+ if (instance == nullptr) {
+ return false;
+ }
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ return sm->isDeclared(String16(instance));
+}
diff --git a/libs/binder/ndk/tests/iface.cpp b/libs/binder/ndk/tests/iface.cpp
index 64832f3..a588985 100644
--- a/libs/binder/ndk/tests/iface.cpp
+++ b/libs/binder/ndk/tests/iface.cpp
@@ -118,7 +118,7 @@
AIBinder_Weak_delete(mWeakBinder);
}
-binder_status_t IFoo::addService(const char* instance) {
+AIBinder* IFoo::getBinder() {
AIBinder* binder = nullptr;
if (mWeakBinder != nullptr) {
@@ -132,8 +132,18 @@
AIBinder_Weak_delete(mWeakBinder);
}
mWeakBinder = AIBinder_Weak_new(binder);
+
+ // WARNING: it is important that this class does not implement debug or
+ // shell functions because it does not use special C++ wrapper
+ // functions, and so this is how we test those functions.
}
+ return binder;
+}
+
+binder_status_t IFoo::addService(const char* instance) {
+ AIBinder* binder = getBinder();
+
binder_status_t status = AServiceManager_addService(binder, instance);
// Strong references we care about kept by remote process
AIBinder_decStrong(binder);
diff --git a/libs/binder/ndk/tests/include/iface/iface.h b/libs/binder/ndk/tests/include/iface/iface.h
index cdf5493..d9dd64b 100644
--- a/libs/binder/ndk/tests/include/iface/iface.h
+++ b/libs/binder/ndk/tests/include/iface/iface.h
@@ -30,6 +30,9 @@
static AIBinder_Class* kClass;
+ // binder representing this interface with one reference count
+ AIBinder* getBinder();
+
// Takes ownership of IFoo
binder_status_t addService(const char* instance);
static ::android::sp<IFoo> getService(const char* instance, AIBinder** outBinder = nullptr);
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 9b2fcf0..1424b6c 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -43,6 +43,7 @@
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
+constexpr char kLazyBinderNdkUnitTestService[] = "LazyBinderNdkUnitTest";
class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) {
@@ -143,11 +144,31 @@
return 1;
}
-// This is too slow
-// TEST(NdkBinder, GetServiceThatDoesntExist) {
-// sp<IFoo> foo = IFoo::getService("asdfghkl;");
-// EXPECT_EQ(nullptr, foo.get());
-// }
+int lazyService(const char* instance) {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ // Wait to register this service to make sure the main test process will
+ // actually wait for the service to be available. Tested with sleep(60),
+ // and reduced for sake of time.
+ sleep(1);
+ // Strong reference to MyBinderNdkUnitTest kept by service manager.
+ // This is just for testing, it has no corresponding init behavior.
+ auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
+ auto binder = service->asBinder();
+
+ binder_status_t status = AServiceManager_registerLazyService(binder.get(), instance);
+ if (status != STATUS_OK) {
+ LOG(FATAL) << "Could not register: " << status << " " << instance;
+ }
+
+ ABinderProcess_joinThreadPool();
+
+ return 1; // should not return
+}
+
+TEST(NdkBinder, GetServiceThatDoesntExist) {
+ sp<IFoo> foo = IFoo::getService("asdfghkl;");
+ EXPECT_EQ(nullptr, foo.get());
+}
TEST(NdkBinder, CheckServiceThatDoesntExist) {
AIBinder* binder = AServiceManager_checkService("asdfghkl;");
@@ -162,6 +183,26 @@
AIBinder_decStrong(binder);
}
+TEST(NdkBinder, UnimplementedDump) {
+ sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
+ ASSERT_NE(foo, nullptr);
+ AIBinder* binder = foo->getBinder();
+ EXPECT_EQ(OK, AIBinder_dump(binder, STDOUT_FILENO, nullptr, 0));
+ AIBinder_decStrong(binder);
+}
+
+TEST(NdkBinder, UnimplementedShell) {
+ // libbinder_ndk doesn't support calling shell, so we are calling from the
+ // libbinder across processes to the NDK service which doesn't implement
+ // shell
+ static const sp<android::IServiceManager> sm(android::defaultServiceManager());
+ sp<IBinder> testService = sm->getService(String16(IFoo::kSomeInstanceName));
+
+ Vector<String16> argsVec;
+ EXPECT_EQ(OK, IBinder::shellCommand(testService, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO,
+ argsVec, nullptr, nullptr));
+}
+
TEST(NdkBinder, DoubleNumber) {
sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
ASSERT_NE(foo, nullptr);
@@ -171,6 +212,33 @@
EXPECT_EQ(2, out);
}
+TEST(NdkBinder, GetLazyService) {
+ // Not declared in the vintf manifest
+ ASSERT_FALSE(AServiceManager_isDeclared(kLazyBinderNdkUnitTestService));
+ ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
+ std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+ aidl::IBinderNdkUnitTest::fromBinder(binder);
+ ASSERT_NE(service, nullptr);
+
+ EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+}
+
+// This is too slow
+TEST(NdkBinder, CheckLazyServiceShutDown) {
+ ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
+ std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+ aidl::IBinderNdkUnitTest::fromBinder(binder);
+ ASSERT_NE(service, nullptr);
+
+ EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+ binder = nullptr;
+ service = nullptr;
+ IPCThreadState::self()->flushCommands();
+ // Make sure the service is dead after some time of no use
+ sleep(10);
+ ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService));
+}
+
void LambdaOnDeath(void* cookie) {
auto onDeath = static_cast<std::function<void(void)>*>(cookie);
(*onDeath)();
@@ -477,6 +545,10 @@
}
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return lazyService(kLazyBinderNdkUnitTestService);
+ }
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
return generatedService();
}
diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp
index ef7a6f5..351af65 100644
--- a/libs/gui/BitTube.cpp
+++ b/libs/gui/BitTube.cpp
@@ -86,6 +86,10 @@
mReceiveFd = std::move(receiveFd);
}
+void BitTube::setSendFd(base::unique_fd&& sendFd) {
+ mSendFd = std::move(sendFd);
+}
+
ssize_t BitTube::write(void const* vaddr, size_t size) {
ssize_t err, len;
do {
@@ -115,6 +119,11 @@
status_t result = reply->writeDupFileDescriptor(mReceiveFd);
mReceiveFd.reset();
+ if (result != NO_ERROR) {
+ return result;
+ }
+ result = reply->writeDupFileDescriptor(mSendFd);
+ mSendFd.reset();
return result;
}
@@ -126,6 +135,13 @@
ALOGE("BitTube::readFromParcel: can't dup file descriptor (%s)", strerror(error));
return -error;
}
+ mSendFd.reset(dup(parcel->readFileDescriptor()));
+ if (mSendFd < 0) {
+ mSendFd.reset();
+ int error = errno;
+ ALOGE("BitTube::readFromParcel: can't dup file descriptor (%s)", strerror(error));
+ return -error;
+ }
return NO_ERROR;
}
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 51fbb97..2cc7c34 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -89,12 +89,8 @@
return OK;
}
-void DisplayEventDispatcher::requestLatestConfig() {
- status_t status = mReceiver.requestLatestConfig();
- if (status) {
- ALOGW("Failed enable config events, status=%d", status);
- return;
- }
+void DisplayEventDispatcher::injectEvent(const DisplayEventReceiver::Event& event) {
+ mReceiver.sendEvents(&event, 1);
}
int DisplayEventDispatcher::getFd() const {
@@ -156,6 +152,9 @@
dispatchConfigChanged(ev.header.timestamp, ev.header.displayId,
ev.config.configId, ev.config.vsyncPeriod);
break;
+ case DisplayEventReceiver::DISPLAY_EVENT_NULL:
+ dispatchNullEvent(ev.header.timestamp, ev.header.displayId);
+ break;
default:
ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
break;
@@ -167,4 +166,5 @@
}
return gotVsync;
}
+
} // namespace android
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 1fed509..f2b0962 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -79,14 +79,6 @@
return NO_INIT;
}
-status_t DisplayEventReceiver::requestLatestConfig() {
- if (mEventConnection != nullptr) {
- mEventConnection->requestLatestConfig();
- return NO_ERROR;
- }
- return NO_INIT;
-}
-
ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
size_t count) {
return DisplayEventReceiver::getEvents(mDataChannel.get(), events, count);
@@ -98,6 +90,10 @@
return gui::BitTube::recvObjects(dataChannel, events, count);
}
+ssize_t DisplayEventReceiver::sendEvents(Event const* events, size_t count) {
+ return DisplayEventReceiver::sendEvents(mDataChannel.get(), events, count);
+}
+
ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,
Event const* events, size_t count)
{
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index aa74bfd..c0e246f 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -26,8 +26,7 @@
STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
SET_VSYNC_RATE,
REQUEST_NEXT_VSYNC,
- REQUEST_LATEST_CONFIG,
- LAST = REQUEST_LATEST_CONFIG,
+ LAST = REQUEST_NEXT_VSYNC,
};
} // Anonymous namespace
@@ -54,11 +53,6 @@
callRemoteAsync<decltype(&IDisplayEventConnection::requestNextVsync)>(
Tag::REQUEST_NEXT_VSYNC);
}
-
- void requestLatestConfig() override {
- callRemoteAsync<decltype(&IDisplayEventConnection::requestLatestConfig)>(
- Tag::REQUEST_LATEST_CONFIG);
- }
};
// Out-of-line virtual method definition to trigger vtable emission in this translation unit (see
@@ -80,8 +74,6 @@
return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate);
case Tag::REQUEST_NEXT_VSYNC:
return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync);
- case Tag::REQUEST_LATEST_CONFIG:
- return callLocalAsync(data, reply, &IDisplayEventConnection::requestLatestConfig);
}
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index b215756..d07d435 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -509,7 +509,8 @@
status_t status = output.writeInt32(static_cast<int32_t>(pixelFormat)) ?:
output.write(sourceCrop) ?:
output.writeFloat(frameScale) ?:
- output.writeBool(captureSecureLayers);
+ output.writeBool(captureSecureLayers) ?:
+ output.writeInt32(uid);
return status;
}
@@ -518,7 +519,8 @@
status_t status = input.readInt32(&format) ?:
input.read(sourceCrop) ?:
input.readFloat(&frameScale) ?:
- input.readBool(&captureSecureLayers);
+ input.readBool(&captureSecureLayers) ?:
+ input.readInt32(&uid);
pixelFormat = static_cast<ui::PixelFormat>(format);
return status;
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index f210c34..eb5b004 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -31,7 +31,7 @@
status_t initialize();
void dispose();
status_t scheduleVsync();
- void requestLatestConfig();
+ void injectEvent(const DisplayEventReceiver::Event& event);
int getFd() const;
virtual int handleEvent(int receiveFd, int events, void* data);
@@ -48,6 +48,9 @@
bool connected) = 0;
virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
int32_t configId, nsecs_t vsyncPeriod) = 0;
+ // AChoreographer-specific hook for processing null-events so that looper
+ // can be properly poked.
+ virtual void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) = 0;
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
uint32_t* outCount);
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 8d49184..0e10d1a 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -53,6 +53,7 @@
DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
DISPLAY_EVENT_CONFIG_CHANGED = fourcc('c', 'o', 'n', 'f'),
+ DISPLAY_EVENT_NULL = fourcc('n', 'u', 'l', 'l'),
};
struct Event {
@@ -130,6 +131,7 @@
* sendEvents write events to the queue and returns how many events were
* written.
*/
+ ssize_t sendEvents(Event const* events, size_t count);
static ssize_t sendEvents(gui::BitTube* dataChannel, Event const* events, size_t count);
/*
@@ -146,12 +148,6 @@
*/
status_t requestNextVsync();
- /*
- * requestLatestConfig() force-requests the current config for the primary
- * display.
- */
- status_t requestLatestConfig();
-
private:
sp<IDisplayEventConnection> mEventConnection;
std::unique_ptr<gui::BitTube> mDataChannel;
diff --git a/libs/gui/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h
index 674aafd..cff22a3 100644
--- a/libs/gui/include/gui/IDisplayEventConnection.h
+++ b/libs/gui/include/gui/IDisplayEventConnection.h
@@ -51,11 +51,6 @@
* requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0.
*/
virtual void requestNextVsync() = 0; // Asynchronous
-
- /*
- * requestLatestConfig() requests the config for the primary display.
- */
- virtual void requestLatestConfig() = 0; // Asynchronous
};
class BnDisplayEventConnection : public SafeBnInterface<IDisplayEventConnection> {
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index de3a9a7..387ddea 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -314,12 +314,14 @@
bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName);
struct CaptureArgs {
+ const static int32_t UNSET_UID = -1;
virtual ~CaptureArgs() = default;
ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888};
Rect sourceCrop;
float frameScale{1};
bool captureSecureLayers{false};
+ int32_t uid{UNSET_UID};
virtual status_t write(Parcel& output) const;
virtual status_t read(const Parcel& input);
@@ -339,7 +341,7 @@
struct LayerCaptureArgs : CaptureArgs {
sp<IBinder> layerHandle;
std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeHandles;
- bool childrenOnly{true};
+ bool childrenOnly{false};
status_t write(Parcel& output) const override;
status_t read(const Parcel& input) override;
diff --git a/libs/gui/include/private/gui/BitTube.h b/libs/gui/include/private/gui/BitTube.h
index 13c0162..8048518 100644
--- a/libs/gui/include/private/gui/BitTube.h
+++ b/libs/gui/include/private/gui/BitTube.h
@@ -58,6 +58,9 @@
// resets this BitTube's receive file descriptor to receiveFd
void setReceiveFd(base::unique_fd&& receiveFd);
+ // resets this BitTube's send file descriptor to sendFd
+ void setSendFd(base::unique_fd&& sendFd);
+
// send objects (sized blobs). All objects are guaranteed to be written or the call fails.
template <typename T>
static ssize_t sendObjects(BitTube* tube, T const* events, size_t count) {
@@ -85,7 +88,7 @@
// the message, excess data is silently discarded.
ssize_t read(void* vaddr, size_t size);
- base::unique_fd mSendFd;
+ mutable base::unique_fd mSendFd;
mutable base::unique_fd mReceiveFd;
static ssize_t sendObjects(BitTube* tube, void const* events, size_t count, size_t objSize);
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index ebc8909..ff1b5e6 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -136,6 +136,7 @@
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
nsecs_t vsyncPeriod) override;
+ void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override;
void scheduleCallbacks();
@@ -170,7 +171,7 @@
Choreographer::Choreographer(const sp<Looper>& looper)
: DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp,
- ISurfaceComposer::ConfigChanged::eConfigChangedDispatch),
+ ISurfaceComposer::ConfigChanged::eConfigChangedSuppress),
mLooper(looper),
mThreadId(std::this_thread::get_id()) {
std::lock_guard<std::mutex> _l(gChoreographers.lock);
@@ -294,8 +295,14 @@
} else {
// If the looper thread is detached from Choreographer, then refresh rate
// changes will be handled in AChoreographer_handlePendingEvents, so we
- // need to redispatch a config from SF
- requestLatestConfig();
+ // need to wake up the looper thread by writing to the write-end of the
+ // socket the looper is listening on.
+ // Fortunately, these events are small so sending packets across the
+ // socket should be atomic across processes.
+ DisplayEventReceiver::Event event;
+ event.header = DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL,
+ PhysicalDisplayId(0), systemTime()};
+ injectEvent(event);
}
}
@@ -373,27 +380,14 @@
// displays. When multi-display choreographer is properly supported, then
// PhysicalDisplayId should no longer be ignored.
void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId, int32_t configId,
- nsecs_t vsyncPeriod) {
+ nsecs_t) {
ALOGV("choreographer %p ~ received config change event (displayId=%s, configId=%d).",
this, to_string(displayId).c_str(), configId);
+}
- const nsecs_t lastPeriod = mLatestVsyncPeriod;
- std::vector<RefreshRateCallback> callbacks{};
- {
- std::lock_guard<std::mutex> _l{mLock};
- for (auto& cb : mRefreshRateCallbacks) {
- callbacks.push_back(cb);
- cb.firstCallbackFired = true;
- }
- }
-
- for (auto& cb : callbacks) {
- if (!cb.firstCallbackFired || (vsyncPeriod > 0 && vsyncPeriod != lastPeriod)) {
- cb.callback(vsyncPeriod, cb.data);
- }
- }
-
- mLatestVsyncPeriod = vsyncPeriod;
+void Choreographer::dispatchNullEvent(nsecs_t, PhysicalDisplayId) {
+ ALOGV("choreographer %p ~ received null event.", this);
+ handleRefreshRateUpdates();
}
void Choreographer::handleMessage(const Message& message) {
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index c00fbba..b44456b 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,2 +1,4 @@
+alecmouri@google.com
+jreck@google.com
lpy@google.com
stoza@google.com
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
index 203a739..b1317b1 100644
--- a/libs/ui/OWNERS
+++ b/libs/ui/OWNERS
@@ -1,6 +1,7 @@
+alecmouri@google.com
chrisforbes@google.com
+jreck@google.com
lpy@google.com
mathias@google.com
romainguy@google.com
stoza@google.com
-vhau@google.com
diff --git a/services/gpuservice/tracing/GpuMemTracer.cpp b/services/gpuservice/tracing/GpuMemTracer.cpp
index c9bfa57..9e01a64 100644
--- a/services/gpuservice/tracing/GpuMemTracer.cpp
+++ b/services/gpuservice/tracing/GpuMemTracer.cpp
@@ -44,10 +44,6 @@
mGpuMem = gpuMem;
perfetto::TracingInitArgs args;
args.backends = perfetto::kSystemBackend;
- // TODO(b/160016498): Find a better way to wait for traced
- // Sleep for 30 seconds to make sure the data source is registered only
- // after traced starts.
- sleep(30);
perfetto::Tracing::Initialize(args);
registerDataSource();
std::thread tracerThread(&GpuMemTracer::threadLoop, this);
diff --git a/services/inputflinger/VibrationElement.cpp b/services/inputflinger/VibrationElement.cpp
index a69f5d0..aaf5834 100644
--- a/services/inputflinger/VibrationElement.cpp
+++ b/services/inputflinger/VibrationElement.cpp
@@ -25,38 +25,27 @@
namespace android {
-// The sentinel to use the default amplitude
-static const int DEFAULT_AMPLITUDE = -1;
-
-// The vibration magnitude for the "DEFAULT_AMPLITUDE" magnitude constant.
-static const uint16_t DEFAULT_MAGNITUDE = 0xc000;
-
-void VibrationElement::dump(std::string& dump) const {
+const std::string VibrationElement::toString() const {
+ std::string dump;
dump += StringPrintf("[duration=%lldms, channels=[", duration.count());
- if (channels.size()) {
- dump += std::to_string(channels[0]);
- std::for_each(channels.begin() + 1, channels.end(), [&dump](int channel) {
+ for (auto it = channels.begin(); it != channels.end(); ++it) {
+ dump += std::to_string(*it);
+ if (std::next(it) != channels.end()) {
dump += ", ";
- dump += std::to_string(channel);
- });
+ }
}
+
dump += "]]";
+ return dump;
}
-uint16_t VibrationElement::getChannel(int id) const {
- if (id >= (int)channels.size()) {
+uint16_t VibrationElement::getMagnitude(size_t channelIdx) const {
+ if (channelIdx >= channels.size()) {
return 0;
}
-
- // android framework uses DEFAULT_AMPLITUDE to signal that the vibration
- // should use some built-in default value, denoted here as DEFAULT_MAGNITUDE
- if (channels[id] == DEFAULT_AMPLITUDE) {
- return DEFAULT_MAGNITUDE;
- }
-
// convert range [0,255] to [0,65535] (android framework to linux ff ranges)
- return ((uint16_t)channels[id]) << 8;
+ return static_cast<uint16_t>(channels[channelIdx]) << 8;
}
bool VibrationElement::isOn() const {
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 5a832e7..a24b293 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -39,11 +39,6 @@
// Must be at least 2.
#define MAX_VIBRATE_PATTERN_SIZE 100
-// Maximum allowable delay value in a vibration pattern before
-// which the delay will be truncated.
-#define MAX_VIBRATE_PATTERN_DELAY_NSECS (1000000 * 1000000000LL)
-#define MAX_VIBRATE_PATTERN_DELAY_MSECS (1000000 * 1000LL)
-
namespace android {
// --- InputReaderInterface ---
diff --git a/services/inputflinger/include/VibrationElement.h b/services/inputflinger/include/VibrationElement.h
index 8a134ee..b60ffac 100644
--- a/services/inputflinger/include/VibrationElement.h
+++ b/services/inputflinger/include/VibrationElement.h
@@ -17,22 +17,25 @@
#ifndef _VIBRATION_ELEMENT_H
#define _VIBRATION_ELEMENT_H
+#include <array>
#include <chrono>
#include <cstdint>
#include <string>
-#include <vector>
namespace android {
+// evdev FF_RUMBLE effect only supports two channels of vibration.
+constexpr size_t CHANNEL_SIZE = 2;
/*
* Describes a rumble effect
*/
struct VibrationElement {
std::chrono::milliseconds duration;
- std::vector<int> channels;
+ // Channel amplitude range 0-255.
+ std::array<uint8_t, CHANNEL_SIZE> channels = {0, 0};
- void dump(std::string& dump) const;
- uint16_t getChannel(int id) const;
+ const std::string toString() const;
+ uint16_t getMagnitude(size_t channelIndex) const;
bool isOn() const;
};
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 8f34e8a..cde977f 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -61,6 +61,9 @@
// v4l2 devices go directly into /dev
static const char* VIDEO_DEVICE_PATH = "/dev";
+static constexpr size_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0;
+static constexpr size_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1;
+
static inline const char* toString(bool value) {
return value ? "true" : "false";
}
@@ -834,8 +837,8 @@
effect.type = FF_RUMBLE;
effect.id = device->ffEffectId;
// evdev FF_RUMBLE effect only supports two channels of vibration.
- effect.u.rumble.strong_magnitude = element.getChannel(0);
- effect.u.rumble.weak_magnitude = element.getChannel(1);
+ effect.u.rumble.strong_magnitude = element.getMagnitude(FF_STRONG_MAGNITUDE_CHANNEL_IDX);
+ effect.u.rumble.weak_magnitude = element.getMagnitude(FF_WEAK_MAGNITUDE_CHANNEL_IDX);
effect.replay.length = element.duration.count();
effect.replay.delay = 0;
if (ioctl(device->fd, EVIOCSFF, &effect)) {
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index 8c1e224..ac7c266 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -91,8 +91,7 @@
const VibrationElement& element = mPattern[mIndex];
if (element.isOn()) {
#if DEBUG_VIBRATOR
- std::string description;
- element.dump(description);
+ std::string description = element.toString();
ALOGD("nextStep: sending vibrate deviceId=%d, element=%s", getDeviceId(),
description.c_str());
#endif
@@ -135,13 +134,13 @@
void VibratorInputMapper::dumpPattern(std::string& dump) const {
dump += "[";
- if (mPattern.size() > 0) {
- mPattern[0].dump(dump);
- std::for_each(mPattern.begin() + 1, mPattern.end(), [&dump](const auto& element) {
+ for (auto it = mPattern.begin(); it != mPattern.end(); ++it) {
+ dump += it->toString();
+ if (std::next(it) != mPattern.end()) {
dump += ", ";
- element.dump(dump);
- });
+ }
}
+
dump += "]";
}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 4b00ee4..9823a1c 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1137,17 +1137,17 @@
// --- InstrumentedInputReader ---
class InstrumentedInputReader : public InputReader {
- std::shared_ptr<InputDevice> mNextDevice;
+ std::queue<std::shared_ptr<InputDevice>> mNextDevices;
public:
InstrumentedInputReader(std::shared_ptr<EventHubInterface> eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener)
- : InputReader(eventHub, policy, listener), mNextDevice(nullptr) {}
+ : InputReader(eventHub, policy, listener) {}
virtual ~InstrumentedInputReader() {}
- void setNextDevice(std::shared_ptr<InputDevice> device) { mNextDevice = device; }
+ void pushNextDevice(std::shared_ptr<InputDevice> device) { mNextDevices.push(device); }
std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
const std::string& location = "") {
@@ -1164,9 +1164,9 @@
protected:
virtual std::shared_ptr<InputDevice> createDeviceLocked(
int32_t eventHubId, const InputDeviceIdentifier& identifier) {
- if (mNextDevice) {
- std::shared_ptr<InputDevice> device(mNextDevice);
- mNextDevice = nullptr;
+ if (!mNextDevices.empty()) {
+ std::shared_ptr<InputDevice> device(std::move(mNextDevices.front()));
+ mNextDevices.pop();
return device;
}
return InputReader::createDeviceLocked(eventHubId, identifier);
@@ -1415,7 +1415,7 @@
const PropertyMap* configuration) {
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, name);
FakeInputMapper& mapper = device->addMapper<FakeInputMapper>(eventHubId, sources);
- mReader->setNextDevice(device);
+ mReader->pushNextDevice(device);
addDevice(eventHubId, name, classes, configuration);
return mapper;
}
@@ -1452,7 +1452,7 @@
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
// Must add at least one mapper or the device will be ignored!
device->addMapper<FakeInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
- mReader->setNextDevice(device);
+ mReader->pushNextDevice(device);
ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(nullptr));
@@ -1661,7 +1661,7 @@
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
// Must add at least one mapper or the device will be ignored!
device->addMapper<FakeInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
- mReader->setNextDevice(device);
+ mReader->pushNextDevice(device);
ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
NotifyDeviceResetArgs resetArgs;
@@ -1694,7 +1694,7 @@
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
// Must add at least one mapper or the device will be ignored!
device->addMapper<FakeInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
- mReader->setNextDevice(device);
+ mReader->pushNextDevice(device);
ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr));
NotifyDeviceResetArgs resetArgs;
@@ -1710,7 +1710,7 @@
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
FakeInputMapper& mapper =
device->addMapper<FakeInputMapper>(eventHubId, AINPUT_SOURCE_TOUCHSCREEN);
- mReader->setNextDevice(device);
+ mReader->pushNextDevice(device);
const uint8_t hdmi1 = 1;
@@ -1747,6 +1747,73 @@
ASSERT_FALSE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID));
}
+TEST_F(InputReaderTest, WhenEnabledChanges_AllSubdevicesAreUpdated) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
+ // Must add at least one mapper or the device will be ignored!
+ device->addMapper<FakeInputMapper>(eventHubIds[0], AINPUT_SOURCE_KEYBOARD);
+ device->addMapper<FakeInputMapper>(eventHubIds[1], AINPUT_SOURCE_KEYBOARD);
+ mReader->pushNextDevice(device);
+ mReader->pushNextDevice(device);
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "fake1", deviceClass, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[1], "fake2", deviceClass, nullptr));
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(nullptr));
+
+ NotifyDeviceResetArgs resetArgs;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+ ASSERT_EQ(deviceId, resetArgs.deviceId);
+ ASSERT_TRUE(device->isEnabled());
+ ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(eventHubIds[0]));
+ ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(eventHubIds[1]));
+
+ disableDevice(deviceId);
+ mReader->loopOnce();
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+ ASSERT_EQ(deviceId, resetArgs.deviceId);
+ ASSERT_FALSE(device->isEnabled());
+ ASSERT_FALSE(mFakeEventHub->isDeviceEnabled(eventHubIds[0]));
+ ASSERT_FALSE(mFakeEventHub->isDeviceEnabled(eventHubIds[1]));
+
+ enableDevice(deviceId);
+ mReader->loopOnce();
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+ ASSERT_EQ(deviceId, resetArgs.deviceId);
+ ASSERT_TRUE(device->isEnabled());
+ ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(eventHubIds[0]));
+ ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(eventHubIds[1]));
+}
+
+TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToSubdeviceMappers) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+ constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};
+ // Add two subdevices to device
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
+ FakeInputMapper& mapperDevice1 =
+ device->addMapper<FakeInputMapper>(eventHubIds[0], AINPUT_SOURCE_KEYBOARD);
+ FakeInputMapper& mapperDevice2 =
+ device->addMapper<FakeInputMapper>(eventHubIds[1], AINPUT_SOURCE_KEYBOARD);
+ mReader->pushNextDevice(device);
+ mReader->pushNextDevice(device);
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "fake1", deviceClass, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[1], "fake2", deviceClass, nullptr));
+
+ mapperDevice1.setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
+ mapperDevice2.setKeyCodeState(AKEYCODE_B, AKEY_STATE_DOWN);
+
+ ASSERT_EQ(AKEY_STATE_DOWN,
+ mReader->getKeyCodeState(deviceId, AINPUT_SOURCE_KEYBOARD, AKEYCODE_A));
+ ASSERT_EQ(AKEY_STATE_DOWN,
+ mReader->getKeyCodeState(deviceId, AINPUT_SOURCE_KEYBOARD, AKEYCODE_B));
+ ASSERT_EQ(AKEY_STATE_UNKNOWN,
+ mReader->getKeyCodeState(deviceId, AINPUT_SOURCE_KEYBOARD, AKEYCODE_C));
+}
+
// --- InputReaderIntegrationTest ---
// These tests create and interact with the InputReader only through its interface.
diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp
index bcebf23..4bae669 100644
--- a/services/surfaceflinger/DisplayRenderArea.cpp
+++ b/services/surfaceflinger/DisplayRenderArea.cpp
@@ -85,10 +85,9 @@
ui::Size reqSize, ui::Dataspace reqDataSpace,
RotationFlags rotation, bool allowSecureLayers)
: RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, display->getViewport(),
- applyDeviceOrientation(rotation, *display)),
+ allowSecureLayers, applyDeviceOrientation(rotation, *display)),
mDisplay(std::move(display)),
- mSourceCrop(sourceCrop),
- mAllowSecureLayers(allowSecureLayers) {}
+ mSourceCrop(sourceCrop) {}
const ui::Transform& DisplayRenderArea::getTransform() const {
return mTransform;
diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h
index 340efb5..8840973 100644
--- a/services/surfaceflinger/DisplayRenderArea.h
+++ b/services/surfaceflinger/DisplayRenderArea.h
@@ -47,7 +47,6 @@
const sp<const DisplayDevice> mDisplay;
const Rect mSourceCrop;
- const bool mAllowSecureLayers;
const ui::Transform mTransform;
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 89c95d2..9fae1a8 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -39,6 +39,7 @@
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
#include <math.h>
+#include <private/android_filesystem_config.h>
#include <renderengine/RenderEngine.h>
#include <stdint.h>
#include <stdlib.h>
@@ -139,6 +140,14 @@
mCallingPid = args.callingPid;
mCallingUid = args.callingUid;
+
+ if (mCallingUid == AID_GRAPHICS || mCallingUid == AID_SYSTEM) {
+ // If the system didn't send an ownerUid, use the callingUid for the ownerUid.
+ mOwnerUid = args.metadata.getInt32(METADATA_OWNER_UID, mCallingUid);
+ } else {
+ // A create layer request from a non system request cannot specify the owner uid
+ mOwnerUid = mCallingUid;
+ }
}
void Layer::onFirstRef() {
@@ -1669,8 +1678,8 @@
}
void Layer::dumpCallingUidPid(std::string& result) const {
- StringAppendF(&result, "Layer %s (%s) pid:%d uid:%d\n", getName().c_str(), getType(),
- mCallingPid, mCallingUid);
+ StringAppendF(&result, "Layer %s (%s) callingPid:%d callingUid:%d ownerUid:%d\n",
+ getName().c_str(), getType(), mCallingPid, mCallingUid, mOwnerUid);
}
void Layer::onDisconnect() {
@@ -2343,6 +2352,8 @@
}
layerInfo->set_is_relative_of(state.isRelativeOf);
+
+ layerInfo->set_owner_uid(mOwnerUid);
}
if (traceFlags & SurfaceTracing::TRACE_INPUT) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 99b1bb1..8d8ab6d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -436,9 +436,7 @@
// Deprecated, please use compositionengine::Output::belongsInOutput()
// instead.
// TODO(lpique): Move the remaining callers (screencap) to the new function.
- bool belongsToDisplay(uint32_t layerStack, bool isPrimaryDisplay) const {
- return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
- }
+ bool belongsToDisplay(uint32_t layerStack) const { return getLayerStack() == layerStack; }
FloatRect getBounds(const Region& activeTransparentRegion) const;
FloatRect getBounds() const;
@@ -967,6 +965,8 @@
*/
virtual bool needsInputInfo() const { return hasInputInfo(); }
+ uid_t getOwnerUid() { return mOwnerUid; }
+
protected:
compositionengine::OutputLayer* findOutputLayerForDisplay(const DisplayDevice*) const;
@@ -1089,6 +1089,10 @@
pid_t mCallingPid;
uid_t mCallingUid;
+ // The owner of the layer. If created from a non system process, it will be the calling uid.
+ // If created from a system process, the value can be passed in.
+ uid_t mOwnerUid;
+
// The current layer is a clone of mClonedFrom. This means that this layer will update it's
// properties based on mClonedFrom. When mClonedFrom latches a new buffer for BufferLayers,
// this layer will update it's buffer. When mClonedFrom updates it's drawing state, children,
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index c4f8666..555e61d 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -44,8 +44,8 @@
LayerRenderArea::LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop,
ui::Size reqSize, ui::Dataspace reqDataSpace, bool childrenOnly,
- const Rect& displayViewport)
- : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, displayViewport),
+ const Rect& displayViewport, bool allowSecureLayers)
+ : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, displayViewport, allowSecureLayers),
mLayer(std::move(layer)),
mCrop(crop),
mFlinger(flinger),
@@ -68,7 +68,7 @@
}
bool LayerRenderArea::isSecure() const {
- return false;
+ return mAllowSecureLayers;
}
bool LayerRenderArea::needsFiltering() const {
diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h
index 81690b9..71ff1ce 100644
--- a/services/surfaceflinger/LayerRenderArea.h
+++ b/services/surfaceflinger/LayerRenderArea.h
@@ -33,7 +33,8 @@
class LayerRenderArea : public RenderArea {
public:
LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop, ui::Size reqSize,
- ui::Dataspace reqDataSpace, bool childrenOnly, const Rect& displayViewport);
+ ui::Dataspace reqDataSpace, bool childrenOnly, const Rect& displayViewport,
+ bool allowSecureLayers);
const ui::Transform& getTransform() const override;
Rect getBounds() const override;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 17daadb..4e841e9 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -429,7 +429,7 @@
bounds.top, bounds.right, bounds.bottom);
visitor(layer);
};
- mFlinger.traverseLayersInLayerStack(layerStack, filterVisitor);
+ mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, filterVisitor);
};
sp<GraphicBuffer> buffer = nullptr;
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index a6246d9..b4bddac 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -24,8 +24,10 @@
static float getCaptureFillValue(CaptureFill captureFill);
RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace,
- const Rect& displayViewport, RotationFlags rotation = ui::Transform::ROT_0)
- : mReqSize(reqSize),
+ const Rect& displayViewport, bool allowSecureLayers = false,
+ RotationFlags rotation = ui::Transform::ROT_0)
+ : mAllowSecureLayers(allowSecureLayers),
+ mReqSize(reqSize),
mReqDataSpace(reqDataSpace),
mCaptureFill(captureFill),
mRotationFlags(rotation),
@@ -83,6 +85,9 @@
// Returns the source display viewport.
const Rect& getDisplayViewport() const { return mDisplayViewport; }
+protected:
+ const bool mAllowSecureLayers;
+
private:
const ui::Size mReqSize;
const ui::Dataspace mReqDataSpace;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 2020e0c..846190c 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -137,6 +137,7 @@
status_t EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) {
outChannel->setReceiveFd(mChannel.moveReceiveFd());
+ outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd())));
return NO_ERROR;
}
@@ -150,11 +151,6 @@
mEventThread->requestNextVsync(this);
}
-void EventThreadConnection::requestLatestConfig() {
- ATRACE_NAME("requestLatestConfig");
- mEventThread->requestLatestConfig(this);
-}
-
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
return size < 0 ? status_t(size) : status_t(NO_ERROR);
@@ -267,28 +263,6 @@
}
}
-void EventThread::requestLatestConfig(const sp<EventThreadConnection>& connection) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (connection->mForcedConfigChangeDispatch) {
- return;
- }
- connection->mForcedConfigChangeDispatch = true;
- auto pendingConfigChange =
- std::find_if(std::begin(mPendingEvents), std::end(mPendingEvents),
- [&](const DisplayEventReceiver::Event& event) {
- return event.header.type ==
- DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED;
- });
-
- // If we didn't find a pending config change event, then push out the
- // latest one we've ever seen.
- if (pendingConfigChange == std::end(mPendingEvents)) {
- mPendingEvents.push_back(mLastConfigChangeEvent);
- }
-
- mCondition.notify_all();
-}
-
void EventThread::onScreenReleased() {
std::lock_guard<std::mutex> lock(mMutex);
if (!mVSyncState || mVSyncState->synthetic) {
@@ -364,9 +338,6 @@
mInterceptVSyncsCallback(event->header.timestamp);
}
break;
- case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
- mLastConfigChangeEvent = *event;
- break;
}
}
@@ -379,10 +350,6 @@
vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
if (event && shouldConsumeEvent(*event, connection)) {
- if (event->header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED &&
- connection->mForcedConfigChangeDispatch) {
- connection->mForcedConfigChangeDispatch = false;
- }
consumers.push_back(connection);
}
@@ -458,9 +425,7 @@
return true;
case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: {
- const bool oneTimeDispatch = connection->mForcedConfigChangeDispatch;
- return oneTimeDispatch ||
- connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch;
+ return connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch;
}
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 64acbd7..49f624c 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -81,19 +81,13 @@
status_t stealReceiveChannel(gui::BitTube* outChannel) override;
status_t setVsyncRate(uint32_t rate) override;
void requestNextVsync() override; // asynchronous
- void requestLatestConfig() override; // asynchronous
// Called in response to requestNextVsync.
const ResyncCallback resyncCallback;
VSyncRequest vsyncRequest = VSyncRequest::None;
- ISurfaceComposer::ConfigChanged mConfigChanged =
+ const ISurfaceComposer::ConfigChanged mConfigChanged =
ISurfaceComposer::ConfigChanged::eConfigChangedSuppress;
- // Store whether we need to force dispatching a config change separately -
- // if mConfigChanged ever changes before the config change is dispatched
- // then we still need to propagate an initial config to the app if we
- // haven't already.
- bool mForcedConfigChangeDispatch = false;
private:
virtual void onFirstRef();
@@ -129,10 +123,6 @@
virtual void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) = 0;
// Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
- // Dispatches the most recent configuration
- // Usage of this method assumes that only the primary internal display
- // supports multiple display configurations.
- virtual void requestLatestConfig(const sp<EventThreadConnection>& connection) = 0;
// Retrieves the number of event connections tracked by this EventThread.
virtual size_t getEventThreadConnectionCount() = 0;
@@ -153,7 +143,6 @@
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
void requestNextVsync(const sp<EventThreadConnection>& connection) override;
- void requestLatestConfig(const sp<EventThreadConnection>& connection) override;
// called before the screen is turned off from main thread
void onScreenReleased() override;
@@ -201,7 +190,6 @@
std::vector<wp<EventThreadConnection>> mDisplayEventConnections GUARDED_BY(mMutex);
std::deque<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
- DisplayEventReceiver::Event mLastConfigChangeEvent GUARDED_BY(mMutex);
// VSYNC state of connected display.
struct VSyncState {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4e0d375..6fae56a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4958,11 +4958,13 @@
// special permissions.
case SET_FRAME_RATE:
case GET_DISPLAY_BRIGHTNESS_SUPPORT:
+ // captureLayers and captureDisplay will handle the permission check in the function
+ case CAPTURE_LAYERS:
+ case CAPTURE_DISPLAY:
case SET_DISPLAY_BRIGHTNESS: {
return OK;
}
- case CAPTURE_LAYERS:
- case CAPTURE_DISPLAY:
+
case ADD_REGION_SAMPLING_LISTENER:
case REMOVE_REGION_SAMPLING_LISTENER: {
// codes that require permission check
@@ -5434,10 +5436,33 @@
}
}
+static status_t validateScreenshotPermissions(const CaptureArgs& captureArgs) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if (uid == AID_GRAPHICS || PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
+ return OK;
+ }
+
+ // If the caller doesn't have the correct permissions but is only attempting to screenshot
+ // itself, we allow it to continue.
+ if (captureArgs.uid == uid) {
+ return OK;
+ }
+
+ ALOGE("Permission Denial: can't take screenshot pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+}
+
status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
ScreenCaptureResults& captureResults) {
ATRACE_CALL();
+ status_t validate = validateScreenshotPermissions(args);
+ if (validate != OK) {
+ return validate;
+ }
+
if (!args.displayToken) return BAD_VALUE;
auto renderAreaRotation = ui::Transform::toRotationFlags(args.rotation);
@@ -5472,8 +5497,8 @@
renderAreaRotation, args.captureSecureLayers);
});
- auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) {
- traverseLayersInLayerStack(layerStack, visitor);
+ auto traverseLayers = [this, args, layerStack](const LayerVector::Visitor& visitor) {
+ traverseLayersInLayerStack(layerStack, args.uid, visitor);
};
return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
args.pixelFormat, args.useIdentityTransform, captureResults);
@@ -5567,7 +5592,7 @@
});
auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) {
- traverseLayersInLayerStack(layerStack, visitor);
+ traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor);
};
return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
@@ -5579,12 +5604,18 @@
ScreenCaptureResults& captureResults) {
ATRACE_CALL();
+ status_t validate = validateScreenshotPermissions(args);
+ if (validate != OK) {
+ return validate;
+ }
+
ui::Size reqSize;
sp<Layer> parent;
Rect crop(args.sourceCrop);
std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers;
Rect displayViewport;
ui::Dataspace dataspace;
+ bool captureSecureLayers;
{
Mutex::Autolock lock(mStateLock);
@@ -5638,6 +5669,8 @@
const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
dataspace = pickDataspaceFromColorMode(colorMode);
+
+ captureSecureLayers = args.captureSecureLayers && display->isSecure();
} // mStateLock
// really small crop or frameScale
@@ -5649,18 +5682,19 @@
}
bool childrenOnly = args.childrenOnly;
-
RenderAreaFuture renderAreaFuture = promise::defer([=]() -> std::unique_ptr<RenderArea> {
return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace,
- childrenOnly, displayViewport);
+ childrenOnly, displayViewport,
+ captureSecureLayers);
});
- auto traverseLayers = [parent, childrenOnly,
- &excludeLayers](const LayerVector::Visitor& visitor) {
+ auto traverseLayers = [parent, args, &excludeLayers](const LayerVector::Visitor& visitor) {
parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
if (!layer->isVisible()) {
return;
- } else if (childrenOnly && layer == parent.get()) {
+ } else if (args.childrenOnly && layer == parent.get()) {
+ return;
+ } else if (args.uid != CaptureArgs::UNSET_UID && args.uid != layer->getOwnerUid()) {
return;
}
@@ -5886,22 +5920,25 @@
layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
}
-void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack,
+void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, const int32_t uid,
const LayerVector::Visitor& visitor) {
// We loop through the first level of layers without traversing,
// as we need to determine which layers belong to the requested display.
for (const auto& layer : mDrawingState.layersSortedByZ) {
- if (!layer->belongsToDisplay(layerStack, false)) {
+ if (!layer->belongsToDisplay(layerStack)) {
continue;
}
// relative layers are traversed in Layer::traverseInZOrder
layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- if (!layer->belongsToDisplay(layerStack, false)) {
+ if (layer->getPrimaryDisplayOnly()) {
return;
}
if (!layer->isVisible()) {
return;
}
+ if (uid != CaptureArgs::UNSET_UID && layer->getOwnerUid() != uid) {
+ return;
+ }
visitor(layer);
});
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6c00931..a1b9b14 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -731,7 +731,9 @@
sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock);
- void traverseLayersInLayerStack(ui::LayerStack, const LayerVector::Visitor&);
+ // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a
+ // matching ownerUid
+ void traverseLayersInLayerStack(ui::LayerStack, const int32_t uid, const LayerVector::Visitor&);
sp<StartPropertySetThread> mStartPropertySetThread;
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index 8fce0c9..aef670d 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -115,6 +115,7 @@
}
layer.cornerRadiusCrop = generateFloatRect(layerProto.corner_radius_crop());
layer.shadowRadius = layerProto.shadow_radius();
+ layer.ownerUid = layerProto.owner_uid();
return layer;
}
@@ -276,7 +277,7 @@
std::string LayerProtoParser::Layer::to_string() const {
std::string result;
- StringAppendF(&result, "+ %s (%s)\n", type.c_str(), name.c_str());
+ StringAppendF(&result, "+ %s (%s) uid=%d\n", type.c_str(), name.c_str(), ownerUid);
result.append(transparentRegion.to_string("TransparentRegion").c_str());
result.append(visibleRegion.to_string("VisibleRegion").c_str());
result.append(damageRegion.to_string("SurfaceDamageRegion").c_str());
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 52b9165..c48354f 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -114,6 +114,7 @@
LayerMetadata metadata;
LayerProtoParser::FloatRect cornerRadiusCrop;
float shadowRadius;
+ uid_t ownerUid;
std::string to_string() const;
};
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 8458d54..41d6d08 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -123,6 +123,8 @@
bool is_relative_of = 51;
// Layer's background blur radius in pixels.
int32 background_blur_radius = 52;
+
+ uint32 owner_uid = 53;
}
message PositionProto {
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
index 0ef4150..8d715e1 100644
--- a/services/surfaceflinger/tests/LayerTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -18,7 +18,6 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
-#include <private/android_filesystem_config.h>
#include <thread>
#include "LayerTransactionTest.h"
@@ -26,40 +25,6 @@
using android::hardware::graphics::common::V1_1::BufferUsage;
-TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- sp<ISurfaceComposer> composer = ComposerService::getComposerService();
- Transaction()
- .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
- .apply(true);
- ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(mCaptureArgs, mCaptureResults));
-
- UIDFaker f(AID_SYSTEM);
-
- // By default the system can capture screenshots with secure layers but they
- // will be blacked out
- ASSERT_EQ(NO_ERROR, composer->captureDisplay(mCaptureArgs, mCaptureResults));
-
- {
- SCOPED_TRACE("as system");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
- // to receive them...we are expected to take care with the results.
- DisplayCaptureArgs args;
- args.displayToken = mDisplay;
- args.captureSecureLayers = true;
- ASSERT_EQ(NO_ERROR, composer->captureDisplay(args, mCaptureResults));
- ASSERT_EQ(true, mCaptureResults.capturedSecureLayers);
- ScreenCapture sc(mCaptureResults.buffer);
- sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index 2ec4ea4..e3b9489 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -61,8 +61,10 @@
std::unique_ptr<ScreenCapture> screenshot;
// only layerB is in this range
- sp<IBinder> parentHandle = parent->getHandle();
- ScreenCapture::captureLayers(&screenshot, parentHandle, Rect(0, 0, 32, 32));
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = parent->getHandle();
+ captureArgs.sourceCrop = {0, 0, 32, 32};
+ ScreenCapture::captureLayers(&screenshot, captureArgs);
screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
}
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 2a250ff..690f758 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -18,6 +18,8 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#include <private/android_filesystem_config.h>
+
#include "LayerTransactionTest.h"
namespace android {
@@ -72,17 +74,52 @@
std::unique_ptr<ScreenCapture> mCapture;
};
+TEST_F(ScreenCaptureTest, SetFlagsSecureEUidSystem) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32,
+ ISurfaceComposerClient::eSecure |
+ ISurfaceComposerClient::eFXSurfaceBufferQueue));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().show(layer).setLayer(layer, INT32_MAX).apply(true);
+
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(mCaptureArgs, mCaptureResults));
+
+ UIDFaker f(AID_SYSTEM);
+
+ // By default the system can capture screenshots with secure layers but they
+ // will be blacked out
+ ASSERT_EQ(NO_ERROR, composer->captureDisplay(mCaptureArgs, mCaptureResults));
+
+ {
+ SCOPED_TRACE("as system");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
+ // to receive them...we are expected to take care with the results.
+ DisplayCaptureArgs args;
+ args.displayToken = mDisplay;
+ args.captureSecureLayers = true;
+ ASSERT_EQ(NO_ERROR, composer->captureDisplay(args, mCaptureResults));
+ ASSERT_TRUE(mCaptureResults.capturedSecureLayers);
+ ScreenCapture sc(mCaptureResults.buffer);
+ sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
TEST_F(ScreenCaptureTest, CaptureSingleLayer) {
- auto bgHandle = mBGSurfaceControl->getHandle();
- ScreenCapture::captureLayers(&mCapture, bgHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = mBGSurfaceControl->getHandle();
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectBGColor(0, 0);
// Doesn't capture FG layer which is at 64, 64
mCapture->expectBGColor(64, 64);
}
TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
@@ -90,7 +127,9 @@
SurfaceComposerClient::Transaction().show(child).apply(true);
// Captures mFGSurfaceControl layer and its child.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = mFGSurfaceControl->getHandle();
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectFGColor(10, 10);
mCapture->expectChildColor(0, 0);
}
@@ -105,7 +144,10 @@
SurfaceComposerClient::Transaction().show(child).apply(true);
// Captures mFGSurfaceControl's child
- ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = fgHandle;
+ captureArgs.childrenOnly = true;
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->checkPixel(10, 10, 0, 0, 0);
mCapture->expectChildColor(0, 0);
}
@@ -128,7 +170,11 @@
.apply(true);
// Child2 would be visible but its excluded, so we should see child1 color instead.
- ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = fgHandle;
+ captureArgs.childrenOnly = true;
+ captureArgs.excludeHandles = {child2->getHandle()};
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->checkPixel(10, 10, 0, 0, 0);
mCapture->checkPixel(0, 0, 200, 200, 200);
}
@@ -156,7 +202,11 @@
.apply(true);
// Child2 would be visible but its excluded, so we should see child1 color instead.
- ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = fgHandle;
+ captureArgs.childrenOnly = true;
+ captureArgs.excludeHandles = {child2->getHandle()};
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->checkPixel(10, 10, 0, 0, 0);
mCapture->checkPixel(0, 0, 200, 200, 200);
}
@@ -169,18 +219,17 @@
SurfaceComposerClient::Transaction().show(child).apply(true);
- auto childHandle = child->getHandle();
-
// Captures child
- ScreenCapture::captureLayers(&mCapture, childHandle, {0, 0, 10, 20});
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = child->getHandle();
+ captureArgs.sourceCrop = {0, 0, 10, 20};
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectColor(Rect(0, 0, 9, 9), {200, 200, 200, 255});
// Area outside of child's bounds is transparent.
mCapture->expectColor(Rect(0, 10, 9, 19), {0, 0, 0, 0});
}
TEST_F(ScreenCaptureTest, DontCaptureRelativeOutsideTree) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
ASSERT_NE(nullptr, child.get()) << "failed to create surface";
@@ -191,19 +240,19 @@
SurfaceComposerClient::Transaction()
.show(child)
// Set relative layer above fg layer so should be shown above when computing all layers.
- .setRelativeLayer(relative, fgHandle, 1)
+ .setRelativeLayer(relative, mFGSurfaceControl->getHandle(), 1)
.show(relative)
.apply(true);
// Captures mFGSurfaceControl layer and its child. Relative layer shouldn't be captured.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = mFGSurfaceControl->getHandle();
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectFGColor(10, 10);
mCapture->expectChildColor(0, 0);
}
TEST_F(ScreenCaptureTest, CaptureRelativeInTree) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
sp<SurfaceControl> relative = createSurface(mClient, "Relative surface", 10, 10,
@@ -222,7 +271,9 @@
// Captures mFGSurfaceControl layer and its children. Relative layer is a child of fg so its
// relative value should be taken into account, placing it above child layer.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = mFGSurfaceControl->getHandle();
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectFGColor(10, 10);
// Relative layer is showing on top of child layer
mCapture->expectColor(Rect(0, 0, 9, 9), {100, 100, 100, 255});
@@ -232,10 +283,10 @@
sp<SurfaceControl> child = createColorLayer("Child layer", Color::RED, mFGSurfaceControl.get());
SurfaceComposerClient::Transaction().show(child).apply(true);
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- Rect sourceCrop(0, 0, 10, 10);
- sp<IBinder> childHandle = child->getHandle();
- ScreenCapture::captureLayers(&mCapture, childHandle, sourceCrop);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = child->getHandle();
+ captureArgs.sourceCrop = {0, 0, 10, 10};
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectColor(Rect(0, 0, 9, 9), Color::RED);
}
@@ -245,10 +296,9 @@
Rect layerCrop(0, 0, 10, 10);
SurfaceComposerClient::Transaction().setCrop_legacy(child, layerCrop).show(child).apply(true);
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<GraphicBuffer> outBuffer;
- sp<IBinder> childHandle = child->getHandle();
- ScreenCapture::captureLayers(&mCapture, childHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = child->getHandle();
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectColor(Rect(0, 0, 9, 9), Color::RED);
}
@@ -289,8 +339,6 @@
}
TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
@@ -306,7 +354,9 @@
.apply(true);
// Captures mFGSurfaceControl, its child, and the grandchild.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = mFGSurfaceControl->getHandle();
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectFGColor(10, 10);
mCapture->expectChildColor(0, 0);
mCapture->checkPixel(5, 5, 50, 50, 50);
@@ -316,12 +366,13 @@
sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
- auto childHandle = child->getHandle();
SurfaceComposerClient::Transaction().setPosition(child, 5, 5).show(child).apply(true);
// Captures only the child layer, and not the parent.
- ScreenCapture::captureLayers(&mCapture, childHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = child->getHandle();
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectChildColor(0, 0);
mCapture->expectChildColor(9, 9);
}
@@ -342,10 +393,10 @@
.show(grandchild)
.apply(true);
- auto grandchildHandle = grandchild->getHandle();
-
// Captures only the grandchild.
- ScreenCapture::captureLayers(&mCapture, grandchildHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = grandchild->getHandle();
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->checkPixel(0, 0, 50, 50, 50);
mCapture->checkPixel(4, 4, 50, 50, 50);
}
@@ -364,18 +415,18 @@
.show(blueLayer)
.apply(true);
- auto redLayerHandle = redLayer->getHandle();
-
// Capturing full screen should have both red and blue are visible.
- ScreenCapture::captureLayers(&mCapture, redLayerHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = redLayer->getHandle();
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
// red area below the blue area
mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
// red area to the right of the blue area
mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
- const Rect crop = Rect(0, 0, 30, 30);
- ScreenCapture::captureLayers(&mCapture, redLayerHandle, crop);
+ captureArgs.sourceCrop = {0, 0, 30, 30};
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
// Capturing the cropped screen, cropping out the shown red area, should leave only the blue
// area visible.
mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
@@ -396,17 +447,18 @@
.show(blueLayer)
.apply(true);
- auto redLayerHandle = redLayer->getHandle();
-
// Capturing full screen should have both red and blue are visible.
- ScreenCapture::captureLayers(&mCapture, redLayerHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = redLayer->getHandle();
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
// red area below the blue area
mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
// red area to the right of the blue area
mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
- ScreenCapture::captureLayers(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5);
+ captureArgs.frameScale = 0.5f;
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
// Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE);
// red area below the blue area
@@ -435,6 +487,171 @@
ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(args, captureResults));
}
+TEST_F(ScreenCaptureTest, CaputureSecureLayer) {
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+ sp<SurfaceControl> secureLayer =
+ createLayer(String8("Secure surface"), 30, 30,
+ ISurfaceComposerClient::eSecure |
+ ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ redLayer.get());
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(secureLayer, Color::BLUE, 30, 30));
+
+ auto redLayerHandle = redLayer->getHandle();
+ Transaction()
+ .show(redLayer)
+ .show(secureLayer)
+ .setLayerStack(redLayer, 0)
+ .setLayer(redLayer, INT32_MAX)
+ .apply();
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+ LayerCaptureArgs args;
+ args.layerHandle = redLayerHandle;
+ args.childrenOnly = false;
+ ScreenCaptureResults captureResults;
+
+ // Call from outside system with secure layers will result in permission denied
+ ASSERT_EQ(PERMISSION_DENIED, sf->captureLayers(args, captureResults));
+
+ UIDFaker f(AID_SYSTEM);
+
+ // From system request, only red layer will be screenshot since the blue layer is secure.
+ // Black will be present where the secure layer is.
+ ScreenCapture::captureLayers(&mCapture, args);
+ mCapture->expectColor(Rect(0, 0, 30, 30), Color::BLACK);
+ mCapture->expectColor(Rect(30, 30, 60, 60), Color::RED);
+
+ // Passing flag secure so the blue layer should be screenshot too.
+ args.captureSecureLayers = true;
+ ScreenCapture::captureLayers(&mCapture, args);
+ mCapture->expectColor(Rect(0, 0, 30, 30), Color::BLUE);
+ mCapture->expectColor(Rect(30, 30, 60, 60), Color::RED);
+}
+
+TEST_F(ScreenCaptureTest, CaptureDisplayWithUid) {
+ uid_t fakeUid = 12345;
+
+ DisplayCaptureArgs captureArgs;
+ captureArgs.displayToken = mDisplay;
+
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
+ ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ mBGSurfaceControl.get()));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().show(layer).setLayer(layer, INT32_MAX).apply();
+
+ // Make sure red layer with the background layer is screenshot.
+ ScreenCapture::captureDisplay(&mCapture, captureArgs);
+ mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ mCapture->expectBorder(Rect(0, 0, 32, 32), {63, 63, 195, 255});
+
+ // From non system uid, can't request screenshot without a specified uid.
+ UIDFaker f(fakeUid);
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(captureArgs, mCaptureResults));
+
+ // Make screenshot request with current uid set. No layers were created with the current
+ // uid so screenshot will be black.
+ captureArgs.uid = fakeUid;
+ ScreenCapture::captureDisplay(&mCapture, captureArgs);
+ mCapture->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ mCapture->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+
+ sp<SurfaceControl> layerWithFakeUid;
+ // Create a new layer with the current uid
+ ASSERT_NO_FATAL_FAILURE(layerWithFakeUid =
+ createLayer("new test layer", 32, 32,
+ ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ mBGSurfaceControl.get()));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerWithFakeUid, Color::GREEN, 32, 32));
+ Transaction()
+ .show(layerWithFakeUid)
+ .setLayer(layerWithFakeUid, INT32_MAX)
+ .setPosition(layerWithFakeUid, 128, 128)
+ .apply();
+
+ // Screenshot from the fakeUid caller with the uid requested allows the layer
+ // with that uid to be screenshotted. Everything else is black
+ ScreenCapture::captureDisplay(&mCapture, captureArgs);
+ mCapture->expectColor(Rect(128, 128, 160, 160), Color::GREEN);
+ mCapture->expectBorder(Rect(128, 128, 160, 160), Color::BLACK);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithUid) {
+ uid_t fakeUid = 12345;
+
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
+ ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ mBGSurfaceControl.get()));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().show(layer).setLayer(layer, INT32_MAX).apply();
+
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = mBGSurfaceControl->getHandle();
+ captureArgs.childrenOnly = false;
+
+ // Make sure red layer with the background layer is screenshot.
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
+ mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ mCapture->expectBorder(Rect(0, 0, 32, 32), {63, 63, 195, 255});
+
+ // From non system uid, can't request screenshot without a specified uid.
+ std::unique_ptr<UIDFaker> uidFaker = std::make_unique<UIDFaker>(fakeUid);
+
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ ASSERT_EQ(PERMISSION_DENIED, composer->captureLayers(captureArgs, mCaptureResults));
+
+ // Make screenshot request with current uid set. No layers were created with the current
+ // uid so screenshot will be black.
+ captureArgs.uid = fakeUid;
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
+ mCapture->expectColor(Rect(0, 0, 32, 32), Color::TRANSPARENT);
+ mCapture->expectBorder(Rect(0, 0, 32, 32), Color::TRANSPARENT);
+
+ sp<SurfaceControl> layerWithFakeUid;
+ // Create a new layer with the current uid
+ ASSERT_NO_FATAL_FAILURE(layerWithFakeUid =
+ createLayer("new test layer", 32, 32,
+ ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ mBGSurfaceControl.get()));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerWithFakeUid, Color::GREEN, 32, 32));
+ Transaction()
+ .show(layerWithFakeUid)
+ .setLayer(layerWithFakeUid, INT32_MAX)
+ .setPosition(layerWithFakeUid, 128, 128)
+ // reparent a layer that was created with a different uid to the new layer.
+ .reparent(layer, layerWithFakeUid->getHandle())
+ .apply();
+
+ // Screenshot from the fakeUid caller with the uid requested allows the layer
+ // with that uid to be screenshotted. The child layer is skipped since it was created
+ // from a different uid.
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
+ mCapture->expectColor(Rect(128, 128, 160, 160), Color::GREEN);
+ mCapture->expectBorder(Rect(128, 128, 160, 160), Color::TRANSPARENT);
+
+ // Clear fake calling uid so it's back to system.
+ uidFaker = nullptr;
+ // Screenshot from the test caller with the uid requested allows the layer
+ // with that uid to be screenshotted. The child layer is skipped since it was created
+ // from a different uid.
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
+ mCapture->expectColor(Rect(128, 128, 160, 160), Color::GREEN);
+ mCapture->expectBorder(Rect(128, 128, 160, 160), Color::TRANSPARENT);
+
+ // Screenshot from the fakeUid caller with no uid requested allows everything to be screenshot.
+ captureArgs.uid = -1;
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
+ mCapture->expectColor(Rect(128, 128, 160, 160), Color::RED);
+ mCapture->expectBorder(Rect(128, 128, 160, 160), {63, 63, 195, 255});
+}
+
// In the following tests we verify successful skipping of a parent layer,
// so we use the same verification logic and only change how we mutate
// the parent layer to verify that various properties are ignored.
@@ -456,8 +673,10 @@
// Verify child layer does not inherit any of the properties of its
// parent when its screenshot is captured.
- auto fgHandle = mFGSurfaceControl->getHandle();
- ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = mFGSurfaceControl->getHandle();
+ captureArgs.childrenOnly = true;
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->checkPixel(10, 10, 0, 0, 0);
mCapture->expectChildColor(0, 0);
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 48c4e18..dc8b31e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -241,7 +241,8 @@
ui::Dataspace::V0_SRGB, ui::Transform::ROT_0);
auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
- return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(), visitor);
+ return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(),
+ CaptureArgs::UNSET_UID, visitor);
};
// TODO: Eliminate expensive/real allocation if possible.
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 3941d42..8972907 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -343,9 +343,9 @@
regionSampling, captureResults);
}
- auto traverseLayersInLayerStack(ui::LayerStack layerStack,
+ auto traverseLayersInLayerStack(ui::LayerStack layerStack, int32_t uid,
const LayerVector::Visitor& visitor) {
- return mFlinger->SurfaceFlinger::traverseLayersInLayerStack(layerStack, visitor);
+ return mFlinger->SurfaceFlinger::traverseLayersInLayerStack(layerStack, uid, visitor);
}
auto getDisplayNativePrimaries(const sp<IBinder>& displayToken,
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index d73506b..081d18b 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -31,66 +31,29 @@
captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
}
- static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
+ static void captureDisplay(std::unique_ptr<ScreenCapture>* sc,
+ const DisplayCaptureArgs& captureArgs) {
const auto sf = ComposerService::getComposerService();
SurfaceComposerClient::Transaction().apply(true);
+ ScreenCaptureResults captureResults;
+ ASSERT_EQ(NO_ERROR, sf->captureDisplay(captureArgs, captureResults));
+ *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
+ }
+
+ static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
DisplayCaptureArgs args;
args.displayToken = displayToken;
-
- ScreenCaptureResults captureResults;
- ASSERT_EQ(NO_ERROR, sf->captureDisplay(args, captureResults));
- *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
+ captureDisplay(sc, args);
}
- static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
- Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
+ static void captureLayers(std::unique_ptr<ScreenCapture>* sc,
+ const LayerCaptureArgs& captureArgs) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
SurfaceComposerClient::Transaction().apply(true);
- LayerCaptureArgs args;
- args.layerHandle = parentHandle;
- args.sourceCrop = crop;
- args.frameScale = frameScale;
- args.childrenOnly = false;
-
ScreenCaptureResults captureResults;
- ASSERT_EQ(NO_ERROR, sf->captureLayers(args, captureResults));
- *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
- }
-
- static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
- Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- SurfaceComposerClient::Transaction().apply(true);
-
- LayerCaptureArgs args;
- args.layerHandle = parentHandle;
- args.sourceCrop = crop;
- args.frameScale = frameScale;
- args.childrenOnly = true;
-
- ScreenCaptureResults captureResults;
- ASSERT_EQ(NO_ERROR, sf->captureLayers(args, captureResults));
- *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
- }
-
- static void captureChildLayersExcluding(
- std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
- std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeLayers) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- SurfaceComposerClient::Transaction().apply(true);
-
- LayerCaptureArgs args;
- args.layerHandle = parentHandle;
- args.pixelFormat = ui::PixelFormat::RGBA_8888;
- args.sourceCrop = Rect::EMPTY_RECT;
- args.excludeHandles = excludeLayers;
- args.frameScale = 1.0f;
- args.childrenOnly = true;
-
- ScreenCaptureResults captureResults;
- ASSERT_EQ(NO_ERROR, sf->captureLayers(args, captureResults));
+ ASSERT_EQ(NO_ERROR, sf->captureLayers(captureArgs, captureResults));
*sc = std::make_unique<ScreenCapture>(captureResults.buffer);
}