diff options
38 files changed, 854 insertions, 269 deletions
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index 2618906261..b1bc6dc7d5 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -130,7 +130,7 @@ int main(int argc, char** argv) { } IPCThreadState::self()->setTheContextObject(manager); - ps->becomeContextManager(nullptr, nullptr); + ps->becomeContextManager(); sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/); diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h index 6efa4f71cb..5f74682b40 100644 --- a/include/android/sharedmem.h +++ b/include/android/sharedmem.h @@ -65,6 +65,10 @@ extern "C" { * another process. File descriptors may also be sent to other processes over a Unix domain * socket with sendmsg and SCM_RIGHTS. See sendmsg(3) and cmsg(3) man pages for more information. * + * If you intend to share this file descriptor with a child process after + * calling exec(3), note that you will need to use fcntl(2) with FD_SETFD + * to clear the FD_CLOEXEC flag for this to work on all versions of Android. + * * Available since API level 26. * * \param name an optional name. diff --git a/include/attestation/HmacKeyManager.h b/include/attestation/HmacKeyManager.h new file mode 100644 index 0000000000..571a361889 --- /dev/null +++ b/include/attestation/HmacKeyManager.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <array> + +namespace android { +/** + * Invalid value of HMAC - SHA256. Any events with this HMAC value will be marked as not verified. + */ +constexpr std::array<uint8_t, 32> INVALID_HMAC = {0}; + +class HmacKeyManager { +public: + HmacKeyManager(); + std::array<uint8_t, 32> sign(const uint8_t* data, size_t size) const; +private: + const std::array<uint8_t, 128> mHmacKey; +}; +} // namespace android
\ No newline at end of file diff --git a/include/input/Input.h b/include/input/Input.h index d40ba439db..7b66d3cac8 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -312,11 +312,6 @@ private: */ constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits<float>::quiet_NaN(); -/** - * Invalid value of HMAC - SHA256. Any events with this HMAC value will be marked as not verified. - */ -constexpr std::array<uint8_t, 32> INVALID_HMAC = {0}; - /* * Pointer coordinate data. */ diff --git a/libs/attestation/Android.bp b/libs/attestation/Android.bp new file mode 100644 index 0000000000..b85aecd16d --- /dev/null +++ b/libs/attestation/Android.bp @@ -0,0 +1,31 @@ +// 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. +cc_library_static { + name: "libattestation", + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + srcs: [ + "HmacKeyManager.cpp" + ], + + clang: true, + + shared_libs: [ + "liblog", + "libcrypto", + ], +}
\ No newline at end of file diff --git a/libs/attestation/HmacKeyManager.cpp b/libs/attestation/HmacKeyManager.cpp new file mode 100644 index 0000000000..b15f143014 --- /dev/null +++ b/libs/attestation/HmacKeyManager.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <attestation/HmacKeyManager.h> +#include <log/log.h> +#include <openssl/hmac.h> +#include <openssl/rand.h> + +namespace android { + +static std::array<uint8_t, 128> getRandomKey() { + std::array<uint8_t, 128> key; + if (RAND_bytes(key.data(), key.size()) != 1) { + LOG_ALWAYS_FATAL("Can't generate HMAC key"); + } + return key; +} + +HmacKeyManager::HmacKeyManager() : mHmacKey(getRandomKey()) {} + +std::array<uint8_t, 32> HmacKeyManager::sign(const uint8_t* data, size_t size) const { + // SHA256 always generates 32-bytes result + std::array<uint8_t, 32> hash; + unsigned int hashLen = 0; + uint8_t* result = + HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data, size, hash.data(), &hashLen); + if (result == nullptr) { + ALOGE("Could not sign the data using HMAC"); + return INVALID_HMAC; + } + + if (hashLen != hash.size()) { + ALOGE("HMAC-SHA256 has unexpected length"); + return INVALID_HMAC; + } + + return hash; +} +} // namespace android
\ No newline at end of file diff --git a/libs/attestation/OWNERS b/libs/attestation/OWNERS new file mode 100644 index 0000000000..4dbb0eae5c --- /dev/null +++ b/libs/attestation/OWNERS @@ -0,0 +1,2 @@ +chaviw@google.com +svv@google.com
\ No newline at end of file diff --git a/libs/attestation/TEST_MAPPING b/libs/attestation/TEST_MAPPING new file mode 100644 index 0000000000..43be638d91 --- /dev/null +++ b/libs/attestation/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "libattestation_tests" + } + ] +}
\ No newline at end of file diff --git a/libs/attestation/tests/Android.bp b/libs/attestation/tests/Android.bp new file mode 100644 index 0000000000..6ce5ea1b2d --- /dev/null +++ b/libs/attestation/tests/Android.bp @@ -0,0 +1,28 @@ +// 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. + +cc_test { + name: "libattestation_tests", + test_suites: ["device-tests"], + srcs: [ + "HmacKeyManager_test.cpp", + ], + static_libs: [ + "libattestation", + ], + shared_libs: [ + "liblog", + "libcrypto", + ], +} diff --git a/libs/attestation/tests/HmacKeyManager_test.cpp b/libs/attestation/tests/HmacKeyManager_test.cpp new file mode 100644 index 0000000000..7f7a408886 --- /dev/null +++ b/libs/attestation/tests/HmacKeyManager_test.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <attestation/HmacKeyManager.h> +#include <gtest/gtest.h> + +namespace android { + +class HmacKeyManagerTest : public testing::Test { +protected: + HmacKeyManager mHmacKeyManager; +}; + +/** + * Ensure that separate calls to sign the same data are generating the same key. + * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance + * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky + * tests. + */ +TEST_F(HmacKeyManagerTest, GeneratedHmac_IsConsistent) { + std::array<uint8_t, 10> data = {4, 3, 5, 1, 8, 5, 2, 7, 1, 8}; + + std::array<uint8_t, 32> hmac1 = mHmacKeyManager.sign(data.data(), sizeof(data)); + std::array<uint8_t, 32> hmac2 = mHmacKeyManager.sign(data.data(), sizeof(data)); + ASSERT_EQ(hmac1, hmac2); +} + +/** + * Ensure that changes in the hmac verification data produce a different hmac. + */ +TEST_F(HmacKeyManagerTest, GeneratedHmac_ChangesWhenFieldsChange) { + std::array<uint8_t, 10> data = {4, 3, 5, 1, 8, 5, 2, 7, 1, 8}; + std::array<uint8_t, 32> initialHmac = mHmacKeyManager.sign(data.data(), sizeof(data)); + + data[2] = 2; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(data.data(), sizeof(data))); +} + +} // namespace android
\ No newline at end of file diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 157538e63f..9aaca65615 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -679,7 +679,7 @@ status_t IPCThreadState::transact(int32_t handle, CallStack::logStack("non-oneway call", CallStack::getCurrent(10).get(), ANDROID_LOG_ERROR); } else /* FATAL_IF_NOT_ONEWAY */ { - LOG_ALWAYS_FATAL("Process may not make oneway calls (code: %u).", code); + LOG_ALWAYS_FATAL("Process may not make non-oneway calls (code: %u).", code); } } diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index ef93ba1cc6..a53056560e 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -144,11 +144,9 @@ void ProcessState::startThreadPool() } } -bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData) +bool ProcessState::becomeContextManager() { AutoMutex _l(mLock); - mBinderContextCheckFunc = checkFunc; - mBinderContextUserData = userData; flat_binder_object obj { .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX, @@ -165,8 +163,6 @@ bool ProcessState::becomeContextManager(context_check_func checkFunc, void* user } if (result == -1) { - mBinderContextCheckFunc = nullptr; - mBinderContextUserData = nullptr; ALOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno)); } @@ -397,8 +393,6 @@ ProcessState::ProcessState(const char *driver) , mExecutingThreadsCount(0) , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) , mStarvationStartTimeMs(0) - , mBinderContextCheckFunc(nullptr) - , mBinderContextUserData(nullptr) , mThreadPoolStarted(false) , mThreadPoolSeq(1) , mCallRestriction(CallRestriction::NONE) diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index 9f5346ac27..efb95f4316 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -50,14 +50,8 @@ public: sp<IBinder> getContextObject(const sp<IBinder>& caller); void startThreadPool(); - - typedef bool (*context_check_func)(const String16& name, - const sp<IBinder>& caller, - void* userData); - bool becomeContextManager( - context_check_func checkFunc, - void* userData); + bool becomeContextManager(); sp<IBinder> getStrongProxyForHandle(int32_t handle); void expungeHandle(int32_t handle, IBinder* binder); @@ -128,9 +122,6 @@ private: Vector<handle_entry>mHandleToObject; - context_check_func mBinderContextCheckFunc; - void* mBinderContextUserData; - String8 mRootDir; bool mThreadPoolStarted; volatile int32_t mThreadPoolSeq; diff --git a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h index d4feabac8a..5811760d3a 100644 --- a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h +++ b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h @@ -32,7 +32,8 @@ __BEGIN_DECLS * * \param binder local server binder to request security contexts on */ -void AIBinder_setRequestingSid(AIBinder* binder, bool requestingSid) __INTRODUCED_IN(31); +__attribute__((weak)) void AIBinder_setRequestingSid(AIBinder* binder, bool requestingSid) + __INTRODUCED_IN(31); /** * Returns the selinux context of the callee. @@ -45,7 +46,7 @@ void AIBinder_setRequestingSid(AIBinder* binder, bool requestingSid) __INTRODUCE * \return security context or null if unavailable. The lifetime of this context * is the lifetime of the transaction. */ -__attribute__((warn_unused_result)) const char* AIBinder_getCallingSid() __INTRODUCED_IN(31); +__attribute__((weak, warn_unused_result)) const char* AIBinder_getCallingSid() __INTRODUCED_IN(31); __END_DECLS diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index 52bcd20d9e..2784aa823d 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -29,9 +29,9 @@ __BEGIN_DECLS * \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. + * \return EX_NONE on success. */ -binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance); +binder_exception_t AServiceManager_addService(AIBinder* binder, const char* instance); /** * Gets a binder object with this specific instance name. Will return nullptr immediately if the diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp index 6b2184ebaa..c782d47c1c 100644 --- a/libs/binder/ndk/service_manager.cpp +++ b/libs/binder/ndk/service_manager.cpp @@ -29,14 +29,14 @@ using ::android::sp; using ::android::status_t; using ::android::String16; -binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance) { +binder_exception_t AServiceManager_addService(AIBinder* binder, const char* instance) { if (binder == nullptr || instance == nullptr) { - return STATUS_UNEXPECTED_NULL; + return EX_ILLEGAL_ARGUMENT; } sp<IServiceManager> sm = defaultServiceManager(); - status_t status = sm->addService(String16(instance), binder->getBinder()); - return PruneStatusT(status); + status_t exception = sm->addService(String16(instance), binder->getBinder()); + return PruneException(exception); } AIBinder* AServiceManager_checkService(const char* instance) { if (instance == nullptr) { diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp index 87e1341f36..d889593474 100644 --- a/libs/binder/ndk/status.cpp +++ b/libs/binder/ndk/status.cpp @@ -123,8 +123,8 @@ binder_status_t PruneStatusT(status_t status) { return STATUS_UNKNOWN_ERROR; default: - LOG(WARNING) << __func__ - << ": Unknown status_t pruned into STATUS_UNKNOWN_ERROR: " << status; + LOG(WARNING) << __func__ << ": Unknown status_t (" << status + << ") pruned into STATUS_UNKNOWN_ERROR"; return STATUS_UNKNOWN_ERROR; } } @@ -155,8 +155,8 @@ binder_exception_t PruneException(int32_t exception) { return EX_TRANSACTION_FAILED; default: - LOG(WARNING) << __func__ - << ": Unknown status_t pruned into EX_TRANSACTION_FAILED: " << exception; + LOG(WARNING) << __func__ << ": Unknown binder exception (" << exception + << ") pruned into EX_TRANSACTION_FAILED"; return EX_TRANSACTION_FAILED; } } diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 1424b6cfca..2bd52483c9 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -84,10 +84,11 @@ int generatedService() { AIBinder_setRequestingSid(binder.get(), true); - binder_status_t status = AServiceManager_addService(binder.get(), kBinderNdkUnitTestService); + binder_exception_t exception = + AServiceManager_addService(binder.get(), kBinderNdkUnitTestService); - if (status != STATUS_OK) { - LOG(FATAL) << "Could not register: " << status << " " << kBinderNdkUnitTestService; + if (exception != EX_NONE) { + LOG(FATAL) << "Could not register: " << exception << " " << kBinderNdkUnitTestService; } ABinderProcess_joinThreadPool(); @@ -111,10 +112,10 @@ class MyFoo : public IFoo { void manualService(const char* instance) { // Strong reference to MyFoo kept by service manager. - binder_status_t status = (new MyFoo)->addService(instance); + binder_exception_t exception = (new MyFoo)->addService(instance); - if (status != STATUS_OK) { - LOG(FATAL) << "Could not register: " << status << " " << instance; + if (exception != EX_NONE) { + LOG(FATAL) << "Could not register: " << exception << " " << instance; } } int manualPollingService(const char* instance) { @@ -322,11 +323,20 @@ class MyTestFoo : public IFoo { } }; +TEST(NdkBinder, AddNullService) { + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, AServiceManager_addService(nullptr, "any-service-name")); +} + +TEST(NdkBinder, AddInvalidServiceName) { + sp<IFoo> foo = new MyTestFoo; + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, foo->addService("!@#$%^&")); +} + TEST(NdkBinder, GetServiceInProcess) { static const char* kInstanceName = "test-get-service-in-process"; sp<IFoo> foo = new MyTestFoo; - EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName)); + EXPECT_EQ(EX_NONE, foo->addService(kInstanceName)); sp<IFoo> getFoo = IFoo::getService(kInstanceName); EXPECT_EQ(foo.get(), getFoo.get()); @@ -373,8 +383,8 @@ TEST(NdkBinder, AddServiceMultipleTimes) { static const char* kInstanceName1 = "test-multi-1"; static const char* kInstanceName2 = "test-multi-2"; sp<IFoo> foo = new MyTestFoo; - EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName1)); - EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName2)); + EXPECT_EQ(EX_NONE, foo->addService(kInstanceName1)); + EXPECT_EQ(EX_NONE, foo->addService(kInstanceName2)); EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2)); } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 51910fe6f9..692c65dc46 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "Input" //#define LOG_NDEBUG 0 +#include <attestation/HmacKeyManager.h> #include <cutils/compiler.h> #include <limits.h> #include <string.h> diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index fd35131b6b..7ac8a2e02c 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -24,9 +24,10 @@ #endif #include <android/keycodes.h> +#include <attestation/HmacKeyManager.h> #include <input/InputEventLabels.h> -#include <input/Keyboard.h> #include <input/KeyCharacterMap.h> +#include <input/Keyboard.h> #include <utils/Log.h> #include <utils/Errors.h> diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 069bc0eb4e..601d8dabf7 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -17,6 +17,7 @@ #include <array> #include <math.h> +#include <attestation/HmacKeyManager.h> #include <binder/Parcel.h> #include <gtest/gtest.h> #include <input/Input.h> diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index e1f2562129..1452745d01 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -20,11 +20,12 @@ #include <sys/mman.h> #include <time.h> +#include <attestation/HmacKeyManager.h> #include <cutils/ashmem.h> #include <gtest/gtest.h> #include <input/InputTransport.h> -#include <utils/Timers.h> #include <utils/StopWatch.h> +#include <utils/Timers.h> namespace android { diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index e7db4b06a4..d049d05ac5 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -21,6 +21,7 @@ #include <math.h> #include <android-base/stringprintf.h> +#include <attestation/HmacKeyManager.h> #include <gtest/gtest.h> #include <input/VelocityTracker.h> diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp index 21cfe8c36e..36f87b8a6a 100644 --- a/libs/input/tests/VerifiedInputEvent_test.cpp +++ b/libs/input/tests/VerifiedInputEvent_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <attestation/HmacKeyManager.h> #include <gtest/gtest.h> #include <input/Input.h> diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index a0de607864..96e62079c6 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -59,6 +59,9 @@ cc_defaults { "libutils", "libui", ], + static_libs: [ + "libattestation", + ], } cc_library_shared { diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp index 066a816069..9abf8b179f 100644 --- a/services/inputflinger/benchmarks/Android.bp +++ b/services/inputflinger/benchmarks/Android.bp @@ -18,6 +18,7 @@ cc_benchmark { "libutils", ], static_libs: [ + "libattestation", "libinputdispatcher", ], } diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index d29d8dfda3..ff9aac9961 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -48,6 +48,9 @@ cc_defaults { "libui", "libutils", ], + static_libs: [ + "libattestation", + ], header_libs: [ "libinputdispatcher_headers", ], diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 9c8481c99f..b428c4ec1f 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -53,8 +53,6 @@ static constexpr bool DEBUG_FOCUS = false; #include <input/InputWindow.h> #include <log/log.h> #include <log/log_event_list.h> -#include <openssl/hmac.h> -#include <openssl/rand.h> #include <powermanager/PowerManager.h> #include <statslog.h> #include <unistd.h> @@ -344,53 +342,6 @@ static void addGestureMonitors(const std::vector<Monitor>& monitors, } } -static std::array<uint8_t, 128> getRandomKey() { - std::array<uint8_t, 128> key; - if (RAND_bytes(key.data(), key.size()) != 1) { - LOG_ALWAYS_FATAL("Can't generate HMAC key"); - } - return key; -} - -// --- HmacKeyManager --- - -HmacKeyManager::HmacKeyManager() : mHmacKey(getRandomKey()) {} - -std::array<uint8_t, 32> HmacKeyManager::sign(const VerifiedInputEvent& event) const { - size_t size; - switch (event.type) { - case VerifiedInputEvent::Type::KEY: { - size = sizeof(VerifiedKeyEvent); - break; - } - case VerifiedInputEvent::Type::MOTION: { - size = sizeof(VerifiedMotionEvent); - break; - } - } - const uint8_t* start = reinterpret_cast<const uint8_t*>(&event); - return sign(start, size); -} - -std::array<uint8_t, 32> HmacKeyManager::sign(const uint8_t* data, size_t size) const { - // SHA256 always generates 32-bytes result - std::array<uint8_t, 32> hash; - unsigned int hashLen = 0; - uint8_t* result = - HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data, size, hash.data(), &hashLen); - if (result == nullptr) { - ALOGE("Could not sign the data using HMAC"); - return INVALID_HMAC; - } - - if (hashLen != hash.size()) { - ALOGE("HMAC-SHA256 has unexpected length"); - return INVALID_HMAC; - } - - return hash; -} - // --- InputDispatcher --- InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) @@ -2682,6 +2633,22 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } } +std::array<uint8_t, 32> InputDispatcher::sign(const VerifiedInputEvent& event) const { + size_t size; + switch (event.type) { + case VerifiedInputEvent::Type::KEY: { + size = sizeof(VerifiedKeyEvent); + break; + } + case VerifiedInputEvent::Type::MOTION: { + size = sizeof(VerifiedMotionEvent); + break; + } + } + const uint8_t* start = reinterpret_cast<const uint8_t*>(&event); + return mHmacKeyManager.sign(start, size); +} + const std::array<uint8_t, 32> InputDispatcher::getSignature( const MotionEntry& motionEntry, const DispatchEntry& dispatchEntry) const { int32_t actionMasked = dispatchEntry.resolvedAction & AMOTION_EVENT_ACTION_MASK; @@ -2691,7 +2658,7 @@ const std::array<uint8_t, 32> InputDispatcher::getSignature( VerifiedMotionEvent verifiedEvent = verifiedMotionEventFromMotionEntry(motionEntry); verifiedEvent.actionMasked = actionMasked; verifiedEvent.flags = dispatchEntry.resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS; - return mHmacKeyManager.sign(verifiedEvent); + return sign(verifiedEvent); } return INVALID_HMAC; } @@ -2701,7 +2668,7 @@ const std::array<uint8_t, 32> InputDispatcher::getSignature( VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEntry(keyEntry); verifiedEvent.flags = dispatchEntry.resolvedFlags & VERIFIED_KEY_EVENT_FLAGS; verifiedEvent.action = dispatchEntry.resolvedAction; - return mHmacKeyManager.sign(verifiedEvent); + return sign(verifiedEvent); } void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, @@ -3549,7 +3516,7 @@ std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const Inpu const KeyEvent& keyEvent = static_cast<const KeyEvent&>(event); VerifiedKeyEvent verifiedKeyEvent = verifiedKeyEventFromKeyEvent(keyEvent); result = std::make_unique<VerifiedKeyEvent>(verifiedKeyEvent); - calculatedHmac = mHmacKeyManager.sign(verifiedKeyEvent); + calculatedHmac = sign(verifiedKeyEvent); break; } case AINPUT_EVENT_TYPE_MOTION: { @@ -3557,7 +3524,7 @@ std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const Inpu VerifiedMotionEvent verifiedMotionEvent = verifiedMotionEventFromMotionEvent(motionEvent); result = std::make_unique<VerifiedMotionEvent>(verifiedMotionEvent); - calculatedHmac = mHmacKeyManager.sign(verifiedMotionEvent); + calculatedHmac = sign(verifiedMotionEvent); break; } default: { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index c52d256dc3..93d3fdefd8 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -31,6 +31,7 @@ #include "TouchState.h" #include "TouchedWindow.h" +#include <attestation/HmacKeyManager.h> #include <input/Input.h> #include <input/InputApplication.h> #include <input/InputTransport.h> @@ -58,16 +59,6 @@ namespace android::inputdispatcher { class Connection; -class HmacKeyManager { -public: - HmacKeyManager(); - std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const; - -private: - std::array<uint8_t, 32> sign(const uint8_t* data, size_t size) const; - const std::array<uint8_t, 128> mHmacKey; -}; - /* Dispatches events to input targets. Some functions of the input dispatcher, such as * identifying input targets, are controlled by a separate policy object. * @@ -133,6 +124,8 @@ public: virtual status_t unregisterInputChannel(const InputChannel& inputChannel) override; virtual status_t pilferPointers(const sp<IBinder>& token) override; + std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const; + private: enum class DropReason { NOT_DROPPED, diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index da50af5c5f..3e0b5e867d 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -294,70 +294,6 @@ private: } }; -// --- HmacKeyManagerTest --- - -class HmacKeyManagerTest : public testing::Test { -protected: - HmacKeyManager mHmacKeyManager; -}; - -/** - * Ensure that separate calls to sign the same data are generating the same key. - * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance - * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky - * tests. - */ -TEST_F(HmacKeyManagerTest, GeneratedHmac_IsConsistent) { - KeyEvent event = getTestKeyEvent(); - VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event); - - std::array<uint8_t, 32> hmac1 = mHmacKeyManager.sign(verifiedEvent); - std::array<uint8_t, 32> hmac2 = mHmacKeyManager.sign(verifiedEvent); - ASSERT_EQ(hmac1, hmac2); -} - -/** - * Ensure that changes in VerifiedKeyEvent produce a different hmac. - */ -TEST_F(HmacKeyManagerTest, GeneratedHmac_ChangesWhenFieldsChange) { - KeyEvent event = getTestKeyEvent(); - VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event); - std::array<uint8_t, 32> initialHmac = mHmacKeyManager.sign(verifiedEvent); - - verifiedEvent.deviceId += 1; - ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); - - verifiedEvent.source += 1; - ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); - - verifiedEvent.eventTimeNanos += 1; - ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); - - verifiedEvent.displayId += 1; - ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); - - verifiedEvent.action += 1; - ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); - - verifiedEvent.downTimeNanos += 1; - ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); - - verifiedEvent.flags += 1; - ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); - - verifiedEvent.keyCode += 1; - ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); - - verifiedEvent.scanCode += 1; - ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); - - verifiedEvent.metaState += 1; - ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); - - verifiedEvent.repeatCount += 1; - ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); -} - // --- InputDispatcherTest --- class InputDispatcherTest : public testing::Test { @@ -2027,6 +1963,63 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); } +/** + * Ensure that separate calls to sign the same data are generating the same key. + * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance + * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky + * tests. + */ +TEST_F(InputDispatcherTest, GeneratedHmac_IsConsistent) { + KeyEvent event = getTestKeyEvent(); + VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event); + + std::array<uint8_t, 32> hmac1 = mDispatcher->sign(verifiedEvent); + std::array<uint8_t, 32> hmac2 = mDispatcher->sign(verifiedEvent); + ASSERT_EQ(hmac1, hmac2); +} + +/** + * Ensure that changes in VerifiedKeyEvent produce a different hmac. + */ +TEST_F(InputDispatcherTest, GeneratedHmac_ChangesWhenFieldsChange) { + KeyEvent event = getTestKeyEvent(); + VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event); + std::array<uint8_t, 32> initialHmac = mDispatcher->sign(verifiedEvent); + + verifiedEvent.deviceId += 1; + ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); + + verifiedEvent.source += 1; + ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); + + verifiedEvent.eventTimeNanos += 1; + ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); + + verifiedEvent.displayId += 1; + ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); + + verifiedEvent.action += 1; + ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); + + verifiedEvent.downTimeNanos += 1; + ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); + + verifiedEvent.flags += 1; + ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); + + verifiedEvent.keyCode += 1; + ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); + + verifiedEvent.scanCode += 1; + ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); + + verifiedEvent.metaState += 1; + ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); + + verifiedEvent.repeatCount += 1; + ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent)); +} + class InputDispatcherKeyRepeatTest : public InputDispatcherTest { protected: static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms diff --git a/services/powermanager/benchmarks/AndroidTest.xml b/services/powermanager/benchmarks/AndroidTest.xml deleted file mode 100644 index 40f4872c96..0000000000 --- a/services/powermanager/benchmarks/AndroidTest.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ 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. - --> -<configuration description="Config for libpowermanager benchmarks"> - <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> - <option name="cleanup" value="true" /> - <option name="push" value="libpowermanager_benchmarks->/data/benchmarktest/benchmark" /> - </target_preparer> - <option name="test-suite-tag" value="apct" /> - <option name="test-suite-tag" value="apct-metric-instrumentation" /> - <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" > - <option name="native-benchmark-device-path" value="/data/benchmarktest" /> - <option name="benchmark-module-name" value="benchmark" /> - </test> -</configuration> diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 6ba1942e2b..a2fc6925b8 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -446,9 +446,26 @@ void RegionSamplingThread::captureSample() { PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); } - ScreenCaptureResults captureResults; + class SyncScreenCaptureListener : public BnScreenCaptureListener { + public: + status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override { + resultsPromise.set_value(captureResults); + return NO_ERROR; + } + + ScreenCaptureResults waitForResults() { + std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future(); + return resultsFuture.get(); + } + + private: + std::promise<ScreenCaptureResults> resultsPromise; + }; + + const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - true /* regionSampling */, captureResults); + true /* regionSampling */, captureListener); + ScreenCaptureResults captureResults = captureListener->waitForResults(); std::vector<Descriptor> activeDescriptors; for (const auto& descriptor : descriptors) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a3e1a17244..65017491b7 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5531,12 +5531,9 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, auto traverseLayers = [this, args, layerStack](const LayerVector::Visitor& visitor) { traverseLayersInLayerStack(layerStack, args.uid, visitor); }; - ScreenCaptureResults captureResults; - status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, captureResults); - captureResults.result = status; - captureListener->onScreenCaptureComplete(captureResults); - return status; + + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, captureListener); } status_t SurfaceFlinger::setSchedFifo(bool enabled) { @@ -5609,12 +5606,8 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor); }; - ScreenCaptureResults captureResults; - status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, - ui::PixelFormat::RGBA_8888, captureResults); - captureResults.result = status; - captureListener->onScreenCaptureComplete(captureResults); - return status; + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, + ui::PixelFormat::RGBA_8888, captureListener); } status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -5705,7 +5698,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, captureSecureLayers); }); - auto traverseLayers = [parent, args, &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; @@ -5727,18 +5720,14 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, }); }; - ScreenCaptureResults captureResults; - status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, captureResults); - captureResults.result = status; - captureListener->onScreenCaptureComplete(captureResults); - return status; + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, captureListener); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, - ScreenCaptureResults& captureResults) { + const sp<IScreenCaptureListener>& captureListener) { ATRACE_CALL(); // TODO(b/116112787) Make buffer usage a parameter. @@ -5748,54 +5737,56 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(), static_cast<android_pixel_format>(reqPixelFormat), 1 /* layerCount */, usage, "screenshot"); - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - false /* regionSampling */, captureResults); + false /* regionSampling */, captureListener); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, - const sp<GraphicBuffer>& buffer, bool regionSampling, - ScreenCaptureResults& captureResults) { - const int uid = IPCThreadState::self()->getCallingUid(); - const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM; + sp<GraphicBuffer>& buffer, bool regionSampling, + const sp<IScreenCaptureListener>& captureListener) { + ATRACE_CALL(); - status_t result; - int syncFd; - - do { - std::tie(result, syncFd) = - schedule([&]() -> std::pair<status_t, int> { - if (mRefreshPending) { - ALOGW("Skipping screenshot for now"); - return {EAGAIN, -1}; - } - std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get(); - if (!renderArea) { - ALOGW("Skipping screen capture because of invalid render area."); - return {NO_MEMORY, -1}; - } + if (captureListener == nullptr) { + ALOGE("capture screen must provide a capture listener callback"); + return BAD_VALUE; + } - status_t result = NO_ERROR; - int fd = -1; + const int uid = IPCThreadState::self()->getCallingUid(); + const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM; - Mutex::Autolock lock(mStateLock); - renderArea->render([&] { - result = renderScreenImplLocked(*renderArea, traverseLayers, buffer.get(), - forSystem, &fd, regionSampling, - captureResults); - }); + static_cast<void>(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable { + if (mRefreshPending) { + ALOGW("Skipping screenshot for now"); + captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling, + captureListener); + return; + } + ScreenCaptureResults captureResults; + std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get(); + if (!renderArea) { + ALOGW("Skipping screen capture because of invalid render area."); + captureResults.result = NO_MEMORY; + captureListener->onScreenCaptureComplete(captureResults); + return; + } - return {result, fd}; - }).get(); - } while (result == EAGAIN); + status_t result = NO_ERROR; + int syncFd = -1; + renderArea->render([&] { + result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, forSystem, &syncFd, + regionSampling, captureResults); + }); - if (result == NO_ERROR) { - sync_wait(syncFd, -1); - close(syncFd); - } + if (result == NO_ERROR) { + sync_wait(syncFd, -1); + close(syncFd); + } + captureResults.result = result; + captureListener->onScreenCaptureComplete(captureResults); + })); - return result; + return NO_ERROR; } status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 37cafe9d75..e0a6073279 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -781,14 +781,14 @@ private: // Boot animation, on/off animations and screen capture void startBootAnim(); - status_t renderScreenImplLocked(const RenderArea& renderArea, - TraverseLayersFunction traverseLayers, - const sp<GraphicBuffer>& buffer, bool forSystem, int* outSyncFd, - bool regionSampling, ScreenCaptureResults& captureResults); + status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, + const sp<GraphicBuffer>&, bool forSystem, int* outSyncFd, + bool regionSampling, ScreenCaptureResults&); status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, - ui::PixelFormat, ScreenCaptureResults& captureResults); - status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, const sp<GraphicBuffer>&, - bool regionSampling, ScreenCaptureResults& captureResults); + ui::PixelFormat, const sp<IScreenCaptureListener>&); + status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&, + bool regionSampling, const sp<IScreenCaptureListener>&); + sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock); diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp index ce20aeb7dc..9672644d8d 100644 --- a/services/vibratorservice/VibratorHalWrapper.cpp +++ b/services/vibratorservice/VibratorHalWrapper.cpp @@ -501,6 +501,10 @@ HalResult<Capabilities> HidlHalWrapperV1_3::getCapabilitiesInternal() { } if (externalControlResult.withDefault(false)) { capabilities |= Capabilities::EXTERNAL_CONTROL; + + if (amplitudeResult.withDefault(false)) { + capabilities |= Capabilities::EXTERNAL_AMPLITUDE_CONTROL; + } } return HalResult<Capabilities>::fromReturn(externalControlResult, capabilities); diff --git a/services/vibratorservice/benchmarks/Android.bp b/services/vibratorservice/benchmarks/Android.bp new file mode 100644 index 0000000000..c1a03a16a7 --- /dev/null +++ b/services/vibratorservice/benchmarks/Android.bp @@ -0,0 +1,37 @@ +// 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. + +cc_benchmark { + name: "libvibratorservice_benchmarks", + srcs: [ + "VibratorHalControllerBenchmarks.cpp", + ], + shared_libs: [ + "libbinder", + "libhidlbase", + "liblog", + "libutils", + "libvibratorservice", + "android.hardware.vibrator-cpp", + "android.hardware.vibrator@1.0", + "android.hardware.vibrator@1.1", + "android.hardware.vibrator@1.2", + "android.hardware.vibrator@1.3", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], +} diff --git a/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp new file mode 100644 index 0000000000..0d4c55ebe1 --- /dev/null +++ b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp @@ -0,0 +1,398 @@ +/* + * 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 "PowerHalControllerBenchmarks" + +#include <benchmark/benchmark.h> +#include <vibratorservice/VibratorHalController.h> + +using ::android::enum_range; +using ::benchmark::Counter; +using ::benchmark::Fixture; +using ::benchmark::kMicrosecond; +using ::benchmark::State; +using ::benchmark::internal::Benchmark; + +using namespace android; +using namespace std::chrono_literals; + +class VibratorBench : public Fixture { +public: + void SetUp(State& /*state*/) override { mController.init(); } + + void TearDown(State& /*state*/) override { mController.off(); } + + static void DefaultConfig(Benchmark* b) { b->Unit(kMicrosecond); } + + static void DefaultArgs(Benchmark* /*b*/) { + // none + } + +protected: + vibrator::HalController mController; + + auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); } + + bool hasCapabilities(vibrator::HalResult<vibrator::Capabilities> result, + vibrator::Capabilities query) { + if (!result.isOk()) { + return false; + } + return (result.value() & query) == query; + } +}; + +#define BENCHMARK_WRAPPER(fixt, test, code) \ + BENCHMARK_DEFINE_F(fixt, test) \ + /* NOLINTNEXTLINE */ \ + (State& state){code} BENCHMARK_REGISTER_F(fixt, test) \ + ->Apply(fixt::DefaultConfig) \ + ->Apply(fixt::DefaultArgs) + +BENCHMARK_WRAPPER(VibratorBench, init, { + for (auto _ : state) { + state.PauseTiming(); + vibrator::HalController controller; + state.ResumeTiming(); + controller.init(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, initCached, { + for (auto _ : state) { + mController.init(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, ping, { + for (auto _ : state) { + mController.ping(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, tryReconnect, { + for (auto _ : state) { + mController.tryReconnect(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, on, { + auto duration = 60s; + auto callback = []() {}; + + for (auto _ : state) { + state.ResumeTiming(); + mController.on(duration, callback); + state.PauseTiming(); + mController.off(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, off, { + auto duration = 60s; + auto callback = []() {}; + + for (auto _ : state) { + state.PauseTiming(); + mController.on(duration, callback); + state.ResumeTiming(); + mController.off(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, setAmplitude, { + auto capabilitiesResult = mController.getCapabilities(); + + if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::AMPLITUDE_CONTROL)) { + return; + } + + auto duration = 60s; + auto callback = []() {}; + auto amplitude = UINT8_MAX; + + for (auto _ : state) { + state.PauseTiming(); + vibrator::HalController controller; + controller.init(); + controller.on(duration, callback); + state.ResumeTiming(); + controller.setAmplitude(amplitude); + state.PauseTiming(); + controller.off(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, setAmplitudeCached, { + auto capabilitiesResult = mController.getCapabilities(); + + if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::AMPLITUDE_CONTROL)) { + return; + } + + auto duration = 6000s; + auto callback = []() {}; + auto amplitude = UINT8_MAX; + + mController.on(duration, callback); + + for (auto _ : state) { + mController.setAmplitude(amplitude); + } + + mController.off(); +}); + +BENCHMARK_WRAPPER(VibratorBench, setExternalControl, { + auto capabilitiesResult = mController.getCapabilities(); + + if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::EXTERNAL_CONTROL)) { + return; + } + + for (auto _ : state) { + state.PauseTiming(); + vibrator::HalController controller; + controller.init(); + state.ResumeTiming(); + controller.setExternalControl(true); + state.PauseTiming(); + controller.setExternalControl(false); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, setExternalControlCached, { + auto capabilitiesResult = mController.getCapabilities(); + + if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::EXTERNAL_CONTROL)) { + return; + } + + for (auto _ : state) { + state.ResumeTiming(); + mController.setExternalControl(true); + state.PauseTiming(); + mController.setExternalControl(false); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, setExternalAmplitudeCached, { + auto capabilitiesResult = mController.getCapabilities(); + + if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::EXTERNAL_AMPLITUDE_CONTROL)) { + return; + } + + auto amplitude = UINT8_MAX; + + mController.setExternalControl(true); + + for (auto _ : state) { + mController.setAmplitude(amplitude); + } + + mController.setExternalControl(false); +}); + +BENCHMARK_WRAPPER(VibratorBench, getCapabilities, { + for (auto _ : state) { + state.PauseTiming(); + vibrator::HalController controller; + controller.init(); + state.ResumeTiming(); + controller.getCapabilities(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, getCapabilitiesCached, { + // First call to cache values. + mController.getCapabilities(); + + for (auto _ : state) { + mController.getCapabilities(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, getSupportedEffects, { + for (auto _ : state) { + state.PauseTiming(); + vibrator::HalController controller; + controller.init(); + state.ResumeTiming(); + controller.getSupportedEffects(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, getSupportedEffectsCached, { + // First call to cache values. + mController.getSupportedEffects(); + + for (auto _ : state) { + mController.getSupportedEffects(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, getSupportedPrimitives, { + for (auto _ : state) { + state.PauseTiming(); + vibrator::HalController controller; + controller.init(); + state.ResumeTiming(); + controller.getSupportedPrimitives(); + } +}); + +BENCHMARK_WRAPPER(VibratorBench, getSupportedPrimitivesCached, { + // First call to cache values. + mController.getSupportedPrimitives(); + + for (auto _ : state) { + mController.getSupportedPrimitives(); + } +}); + +class VibratorEffectsBench : public VibratorBench { +public: + static void DefaultArgs(Benchmark* b) { + vibrator::HalController controller; + auto effectsResult = controller.getSupportedEffects(); + if (!effectsResult.isOk()) { + return; + } + + std::vector<hardware::vibrator::Effect> supported = effectsResult.value(); + b->ArgNames({"Effect", "Strength"}); + for (const auto& effect : enum_range<hardware::vibrator::Effect>()) { + if (std::find(supported.begin(), supported.end(), effect) == supported.end()) { + continue; + } + for (const auto& strength : enum_range<hardware::vibrator::EffectStrength>()) { + b->Args({static_cast<long>(effect), static_cast<long>(strength)}); + } + } + } + +protected: + auto getEffect(const State& state) const { + return static_cast<hardware::vibrator::Effect>(this->getOtherArg(state, 0)); + } + + auto getStrength(const State& state) const { + return static_cast<hardware::vibrator::EffectStrength>(this->getOtherArg(state, 1)); + } +}; + +BENCHMARK_WRAPPER(VibratorEffectsBench, alwaysOnEnable, { + auto capabilitiesResult = mController.getCapabilities(); + + if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::ALWAYS_ON_CONTROL)) { + return; + } + + int32_t id = 1; + auto effect = getEffect(state); + auto strength = getStrength(state); + + for (auto _ : state) { + state.ResumeTiming(); + mController.alwaysOnEnable(id, effect, strength); + state.PauseTiming(); + mController.alwaysOnDisable(id); + } +}); + +BENCHMARK_WRAPPER(VibratorEffectsBench, alwaysOnDisable, { + auto capabilitiesResult = mController.getCapabilities(); + + if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::ALWAYS_ON_CONTROL)) { + return; + } + + int32_t id = 1; + auto effect = getEffect(state); + auto strength = getStrength(state); + + for (auto _ : state) { + state.PauseTiming(); + mController.alwaysOnEnable(id, effect, strength); + state.ResumeTiming(); + mController.alwaysOnDisable(id); + } +}); + +BENCHMARK_WRAPPER(VibratorEffectsBench, performEffect, { + auto effect = getEffect(state); + auto strength = getStrength(state); + auto callback = []() {}; + + for (auto _ : state) { + state.ResumeTiming(); + mController.performEffect(effect, strength, callback); + state.PauseTiming(); + mController.off(); + } +}); + +class VibratorPrimitivesBench : public VibratorBench { +public: + static void DefaultArgs(Benchmark* b) { + vibrator::HalController controller; + auto primitivesResult = controller.getSupportedPrimitives(); + if (!primitivesResult.isOk()) { + return; + } + + std::vector<hardware::vibrator::CompositePrimitive> supported = primitivesResult.value(); + b->ArgNames({"Primitive"}); + for (const auto& primitive : enum_range<hardware::vibrator::CompositePrimitive>()) { + if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) { + continue; + } + b->Args({static_cast<long>(primitive)}); + } + } + +protected: + auto getPrimitive(const State& state) const { + return static_cast<hardware::vibrator::CompositePrimitive>(this->getOtherArg(state, 0)); + } +}; + +BENCHMARK_WRAPPER(VibratorPrimitivesBench, performComposedEffect, { + auto capabilitiesResult = mController.getCapabilities(); + + if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::COMPOSE_EFFECTS)) { + return; + } + + hardware::vibrator::CompositeEffect effect; + effect.primitive = getPrimitive(state); + effect.scale = 1.0f; + effect.delayMs = 0; + + std::vector<hardware::vibrator::CompositeEffect> effects; + effects.push_back(effect); + auto callback = []() {}; + + for (auto _ : state) { + state.ResumeTiming(); + mController.performComposedEffect(effects, callback); + state.PauseTiming(); + mController.off(); + } +}); + +BENCHMARK_MAIN();
\ No newline at end of file diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp index 5de6257176..08652f4e24 100644 --- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp +++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp @@ -118,7 +118,8 @@ TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesSuccessful) { auto result = mWrapper->getCapabilities(); ASSERT_TRUE(result.isOk()); - ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL | vibrator::Capabilities::EXTERNAL_CONTROL, + ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL | vibrator::Capabilities::EXTERNAL_CONTROL | + vibrator::Capabilities::EXTERNAL_AMPLITUDE_CONTROL, result.value()); } |