diff options
43 files changed, 623 insertions, 218 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 7ab2a8d03f..e2ffd02c54 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -2175,14 +2175,13 @@ void Dumpstate::DumpstateBoard(int out_fd) { } /* - * mount debugfs for non-user builds which launch with S and unmount it - * after invoking dumpstateBoard_* methods. This is to enable debug builds - * to not have debugfs mounted during runtime. It will also ensure that - * debugfs is only accessed by the dumpstate HAL. + * mount debugfs for non-user builds with ro.product.enforce_debugfs_restrictions + * set to true and unmount it after invoking dumpstateBoard_* methods. + * This is to enable debug builds to not have debugfs mounted during runtime. + * It will also ensure that debugfs is only accessed by the dumpstate HAL. */ - auto api_level = android::base::GetIntProperty("ro.product.first_api_level", 0); - bool mount_debugfs = !PropertiesHelper::IsUserBuild() && api_level >= 31; - + auto mount_debugfs = + android::base::GetBoolProperty("ro.product.enforce_debugfs_restrictions", false); if (mount_debugfs) { RunCommand("mount debugfs", {"mount", "-t", "debugfs", "debugfs", "/sys/kernel/debug"}, AS_ROOT_20); @@ -2290,7 +2289,10 @@ void Dumpstate::DumpstateBoard(int out_fd) { } if (mount_debugfs) { - RunCommand("unmount debugfs", {"umount", "/sys/kernel/debug"}, AS_ROOT_20); + auto keep_debugfs_mounted = + android::base::GetProperty("persist.dbg.keep_debugfs_mounted", ""); + if (keep_debugfs_mounted.empty()) + RunCommand("unmount debugfs", {"umount", "/sys/kernel/debug"}, AS_ROOT_20); } auto file_sizes = std::make_unique<ssize_t[]>(paths.size()); diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 2c573e4f4a..db508b52bd 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -1032,12 +1032,12 @@ class ZippedBugReportStreamTest : public DumpstateBaseTest { ZipArchiveHandle handle_; }; -// Generate a quick wifi report redirected to a file, open it and verify entry exist. -TEST_F(ZippedBugReportStreamTest, StreamWifiReport) { - std::string out_path = kTestDataPath + "out.zip"; +// Generate a quick LimitedOnly report redirected to a file, open it and verify entry exist. +TEST_F(ZippedBugReportStreamTest, StreamLimitedOnlyReport) { + std::string out_path = kTestDataPath + "StreamLimitedOnlyReportOut.zip"; android::base::unique_fd out_fd; CreateFd(out_path, &out_fd); - ds_.options_->wifi_only = true; + ds_.options_->limited_only = true; ds_.options_->stream_to_socket = true; RedirectOutputToFd(out_fd); @@ -1051,7 +1051,7 @@ TEST_F(ZippedBugReportStreamTest, StreamWifiReport) { ExtractToMemory(handle_, &entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()), entry.uncompressed_length); EXPECT_THAT(bugreport_txt_name, - testing::ContainsRegex("(bugreport-.+-wifi(-[[:digit:]]+){6}\\.txt)")); + testing::ContainsRegex("(bugreport-.+(-[[:digit:]]+){6}\\.txt)")); VerifyEntry(handle_, bugreport_txt_name, &entry); } diff --git a/include/android/bitmap.h b/include/android/bitmap.h index a70dffd756..6704a1ddf2 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -241,6 +241,7 @@ typedef struct AHardwareBuffer AHardwareBuffer; * * Available since API level 30. * + * @param env Handle to the JNI environment pointer. * @param bitmap Handle to an android.graphics.Bitmap. * @param outBuffer On success, is set to a pointer to the * {@link AHardwareBuffer} associated with bitmap. This acquires diff --git a/include/android/choreographer.h b/include/android/choreographer.h index cc5420e239..b743f491e4 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -32,6 +32,11 @@ __BEGIN_DECLS struct AChoreographer; +/** + * Opaque type that provides access to an AChoreographer object. + * + * A pointer can be obtained using {@link AChoreographer_getInstance()}. + */ typedef struct AChoreographer AChoreographer; /** diff --git a/include/android/font.h b/include/android/font.h index a172618829..8a3a474f25 100644 --- a/include/android/font.h +++ b/include/android/font.h @@ -189,7 +189,7 @@ const char* _Nonnull AFont_getFontFilePath(const AFont* _Nonnull font) __INTRODU * Available since API level 29. * * \param font a font object. Passing NULL is not allowed. - * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned. + * \return a positive integer less than or equal to {@link AFONT_WEIGHT_MAX} is returned. */ uint16_t AFont_getWeight(const AFont* _Nonnull font) __INTRODUCED_IN(29); @@ -241,7 +241,7 @@ size_t AFont_getCollectionIndex(const AFont* _Nonnull font) __INTRODUCED_IN(29); * In this case, AFont_getAxisCount returns 2 and AFont_getAxisTag * and AFont_getAxisValue will return following values. * \code{.cpp} - * AFont* font = AFontIterator_next(ite); + * AFont* font = ASystemFontIterator_next(ite); * * // Returns the number of axes * AFont_getAxisCount(font); // Returns 2 @@ -289,7 +289,7 @@ uint32_t AFont_getAxisTag(const AFont* _Nonnull font, uint32_t axisIndex) * * \param font a font object. Passing NULL is not allowed. * \param axisIndex an index to the font variation settings. Passing value larger than or - * equal to {@link ASYstemFont_getAxisCount} is not allwed. + * equal to {@link AFont_getAxisCount} is not allowed. * \return a float value for the given font variation setting. */ float AFont_getAxisValue(const AFont* _Nonnull font, uint32_t axisIndex) diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h index 49e478c2f3..4417422687 100644 --- a/include/android/font_matcher.h +++ b/include/android/font_matcher.h @@ -36,7 +36,7 @@ * // Simple font query for the ASCII character. * std::vector<uint16_t> text = { 'A' }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a valid font file. * AFontMatcher_destroy(matcher); * @@ -44,17 +44,17 @@ * std::vector<uint16_t> text = { 0x9AA8 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); * AFontMatcher_setLocales(matcher, "zh-CN,ja-JP"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Simplified Chinese font. * AFontMatcher_setLocales(matcher, "ja-JP,zh-CN"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Japanese font. * AFontMatcher_destroy(matcher); * * // Querying font for text/color emoji * std::vector<uint16_t> text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 8 and the font will points a color emoji font. * AFontMatcher_destroy(matcher); * @@ -62,7 +62,7 @@ * // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character. * std::vector<uint16_t> text = { 0x05D0, 0x0E01 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Hebrew font. * AFontMatcher_destroy(matcher); * \endcode @@ -146,7 +146,7 @@ void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29); /** * Set font style to matcher. * - * If this function is not called, the matcher performs with {@link ASYSTEM_FONT_WEIGHT_NORMAL} + * If this function is not called, the matcher performs with {@link AFONT_WEIGHT_NORMAL} * with non-italic style. * * Available since API level 29. @@ -206,7 +206,7 @@ void AFontMatcher_setFamilyVariant( * \param textLength a length of the given text buffer. This must not be zero. * \param runLengthOut if not null, the font run length will be filled. * \return a font to be used for given text and params. You need to release the returned font by - * ASystemFont_close when it is no longer needed. + * AFont_close when it is no longer needed. */ AFont* _Nonnull AFontMatcher_match( const AFontMatcher* _Nonnull matcher, diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index e980dd04ec..6da4e9eff9 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -160,6 +160,7 @@ cc_library { "-Werror", "-Wzero-as-null-pointer-constant", "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION", + "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", ], product_variables: { binder32bit: { diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index de42f36d74..baa9d75116 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -37,7 +37,7 @@ static const sp<IBinder>& getClientId() { pthread_mutex_lock(&gClientIdMutex); if (gClientId == nullptr) { - gClientId = new BBinder(); + gClientId = sp<BBinder>::make(); } pthread_mutex_unlock(&gClientIdMutex); return gClientId; diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 53b36fffdc..fdcf94acfa 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -107,8 +107,7 @@ void BpBinder::ObjectManager::kill() // --------------------------------------------------------------------------- - -BpBinder* BpBinder::create(int32_t handle) { +sp<BpBinder> BpBinder::create(int32_t handle) { int32_t trackedUid = -1; if (sCountByUidEnabled) { trackedUid = IPCThreadState::self()->getCallingUid(); @@ -134,10 +133,10 @@ BpBinder* BpBinder::create(int32_t handle) { } sTrackingMap[trackedUid]++; } - return new BpBinder(BinderHandle{handle}, trackedUid); + return sp<BpBinder>::make(BinderHandle{handle}, trackedUid); } -BpBinder* BpBinder::create(const sp<RpcConnection>& connection, const RpcAddress& address) { +sp<BpBinder> BpBinder::create(const sp<RpcConnection>& connection, const RpcAddress& address) { LOG_ALWAYS_FATAL_IF(connection == nullptr, "BpBinder::create null connection"); // These are not currently tracked, since there is no UID or other @@ -145,7 +144,7 @@ BpBinder* BpBinder::create(const sp<RpcConnection>& connection, const RpcAddress // needed, connection objects keep track of all BpBinder objects on a // per-connection basis. - return new BpBinder(SocketHandle{connection, address}); + return sp<BpBinder>::make(SocketHandle{connection, address}); } BpBinder::BpBinder(Handle&& handle) @@ -194,7 +193,7 @@ bool BpBinder::isDescriptorCached() const { const String16& BpBinder::getInterfaceDescriptor() const { if (isDescriptorCached() == false) { - sp<BpBinder> thiz = const_cast<BpBinder*>(this); + sp<BpBinder> thiz = sp<BpBinder>::fromExisting(const_cast<BpBinder*>(this)); Parcel data; data.markForBinder(thiz); @@ -226,7 +225,7 @@ bool BpBinder::isBinderAlive() const status_t BpBinder::pingBinder() { Parcel data; - data.markForBinder(this); + data.markForBinder(sp<BpBinder>::fromExisting(this)); Parcel reply; return transact(PING_TRANSACTION, data, &reply); } @@ -403,7 +402,7 @@ void BpBinder::reportOneDeath(const Obituary& obit) ALOGV("Reporting death to recipient: %p\n", recipient.get()); if (recipient == nullptr) return; - recipient->binderDied(this); + recipient->binderDied(wp<BpBinder>::fromExisting(this)); } diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp index 349658ecfa..a90bfd29ba 100644 --- a/libs/binder/BufferedTextOutput.cpp +++ b/libs/binder/BufferedTextOutput.cpp @@ -254,7 +254,7 @@ BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const BufferState* bs = ts.states[mIndex].get(); if (bs != nullptr && bs->seq == mSeq) return bs; - ts.states.editItemAt(mIndex) = new BufferState(mIndex); + ts.states.editItemAt(mIndex) = sp<BufferState>::make(mIndex); bs = ts.states[mIndex].get(); if (bs != nullptr) return bs; } diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp index b19004d454..2780bd4cd9 100644 --- a/libs/binder/IInterface.cpp +++ b/libs/binder/IInterface.cpp @@ -33,14 +33,14 @@ IInterface::~IInterface() { sp<IBinder> IInterface::asBinder(const IInterface* iface) { if (iface == nullptr) return nullptr; - return const_cast<IInterface*>(iface)->onAsBinder(); + return sp<IBinder>::fromExisting(const_cast<IInterface*>(iface)->onAsBinder()); } // static sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface) { if (iface == nullptr) return nullptr; - return iface->onAsBinder(); + return sp<IBinder>::fromExisting(iface->onAsBinder()); } diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index cca8f81e45..bd974b02b1 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -68,7 +68,7 @@ private: // TODO: Reimplemement based on standard C++ container? }; -static sp<HeapCache> gHeapCache = new HeapCache(); +static sp<HeapCache> gHeapCache = sp<HeapCache>::make(); /******************************************************************************/ @@ -288,7 +288,7 @@ void BpMemoryHeap::assertMapped() const int32_t heapId = mHeapId.load(memory_order_acquire); if (heapId == -1) { sp<IBinder> binder(IInterface::asBinder(const_cast<BpMemoryHeap*>(this))); - sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get())); + sp<BpMemoryHeap> heap = sp<BpMemoryHeap>::cast(find_heap(binder)); heap->assertReallyMapped(); if (heap->mBase != MAP_FAILED) { Mutex::Autolock _l(mLock); diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index ca067e2d7f..61f4581df3 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -102,7 +102,7 @@ sp<IServiceManager> defaultServiceManager() } } - gDefaultServiceManager = new ServiceManagerShim(sm); + gDefaultServiceManager = sp<ServiceManagerShim>::make(sm); }); return gDefaultServiceManager; @@ -324,7 +324,7 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) } if (out != nullptr) return out; - sp<Waiter> waiter = new Waiter; + sp<Waiter> waiter = sp<Waiter>::make(); if (!mTheRealServiceManager->registerForNotifications( name, waiter).isOk()) { return nullptr; diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp index f96b6bb4eb..b503bebc5e 100644 --- a/libs/binder/LazyServiceRegistrar.cpp +++ b/libs/binder/LazyServiceRegistrar.cpp @@ -129,7 +129,9 @@ bool ClientCounterCallbackImpl::registerService(const sp<IBinder>& service, cons } if (!reRegister) { - if(!manager->registerClientCallback(name, service, this).isOk()) { + if (!manager->registerClientCallback(name, service, + sp<android::os::IClientCallback>::fromExisting(this)) + .isOk()) { ALOGE("Failed to add client callback for service %s", name.c_str()); return false; } diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp index b46b3e88fc..c4475c7780 100644 --- a/libs/binder/MemoryDealer.cpp +++ b/libs/binder/MemoryDealer.cpp @@ -228,10 +228,8 @@ Allocation::~Allocation() // ---------------------------------------------------------------------------- MemoryDealer::MemoryDealer(size_t size, const char* name, uint32_t flags) - : mHeap(new MemoryHeapBase(size, flags, name)), - mAllocator(new SimpleBestFitAllocator(size)) -{ -} + : mHeap(sp<MemoryHeapBase>::make(size, flags, name)), + mAllocator(new SimpleBestFitAllocator(size)) {} MemoryDealer::~MemoryDealer() { @@ -243,7 +241,7 @@ sp<IMemory> MemoryDealer::allocate(size_t size) sp<IMemory> memory; const ssize_t offset = allocator()->allocate(size); if (offset >= 0) { - memory = new Allocation(this, heap(), offset, size); + memory = sp<Allocation>::make(sp<MemoryDealer>::fromExisting(this), heap(), offset, size); } return memory; } diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 0425159f63..a73530938c 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -293,7 +293,8 @@ status_t Parcel::unflattenBinder(sp<IBinder>* out) const if (flat) { switch (flat->hdr.type) { case BINDER_TYPE_BINDER: { - sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie); + sp<IBinder> binder = + sp<IBinder>::fromExisting(reinterpret_cast<IBinder*>(flat->cookie)); return finishUnflattenBinder(binder, out); } case BINDER_TYPE_HANDLE: { diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index abb792eda0..7647a8c0df 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -105,7 +105,7 @@ sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault) } std::lock_guard<std::mutex> l(gProcessMutex); - gProcess = new ProcessState(driver); + gProcess = sp<ProcessState>::make(driver); }); if (requireDefault) { @@ -299,8 +299,8 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) return nullptr; } - b = BpBinder::create(handle); - e->binder = b; + sp<BpBinder> b = BpBinder::create(handle); + e->binder = b.get(); if (b) e->refs = b->getWeakRefs(); result = b; } else { @@ -340,7 +340,7 @@ void ProcessState::spawnPooledThread(bool isMain) if (mThreadPoolStarted) { String8 name = makeBinderThreadName(); ALOGV("Spawning new pooled thread, name=%s\n", name.string()); - sp<Thread> t = new PoolThread(isMain); + sp<Thread> t = sp<PoolThread>::make(isMain); t->run(name.string()); } } diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp index dab3246fc5..1bf3d889a5 100644 --- a/libs/binder/RpcConnection.cpp +++ b/libs/binder/RpcConnection.cpp @@ -54,7 +54,7 @@ RpcConnection::~RpcConnection() { } sp<RpcConnection> RpcConnection::make() { - return new RpcConnection; + return sp<RpcConnection>::make(); } class UnixSocketAddress : public RpcConnection::SocketAddress { @@ -120,20 +120,21 @@ bool RpcConnection::addVsockClient(unsigned int cid, unsigned int port) { #endif // __BIONIC__ sp<IBinder> RpcConnection::getRootObject() { - ExclusiveSocket socket(this, SocketUse::CLIENT); - return state()->getRootObject(socket.fd(), this); + ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT); + return state()->getRootObject(socket.fd(), sp<RpcConnection>::fromExisting(this)); } status_t RpcConnection::transact(const RpcAddress& address, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - ExclusiveSocket socket(this, + ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), (flags & IBinder::FLAG_ONEWAY) ? SocketUse::CLIENT_ASYNC : SocketUse::CLIENT); - return state()->transact(socket.fd(), address, code, data, this, reply, flags); + return state()->transact(socket.fd(), address, code, data, + sp<RpcConnection>::fromExisting(this), reply, flags); } status_t RpcConnection::sendDecStrong(const RpcAddress& address) { - ExclusiveSocket socket(this, SocketUse::CLIENT_REFCOUNT); + ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT_REFCOUNT); return state()->sendDecStrong(socket.fd(), address); } @@ -157,10 +158,11 @@ void RpcConnection::join() { // We may not use the connection we just established (two threads might // establish connections for each other), but for now, just use one // server/socket connection. - ExclusiveSocket socket(this, SocketUse::SERVER); + ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::SERVER); while (true) { - status_t error = state()->getAndExecuteCommand(socket.fd(), this); + status_t error = + state()->getAndExecuteCommand(socket.fd(), sp<RpcConnection>::fromExisting(this)); if (error != OK) { ALOGI("Binder socket thread closing w/ status %s", statusToString(error).c_str()); @@ -221,7 +223,7 @@ bool RpcConnection::addClient(const SocketAddress& addr) { LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get()); std::lock_guard<std::mutex> _l(mSocketMutex); - sp<ConnectionSocket> connection = new ConnectionSocket(); + sp<ConnectionSocket> connection = sp<ConnectionSocket>::make(); connection->fd = std::move(serverFd); mClients.push_back(connection); return true; @@ -229,7 +231,7 @@ bool RpcConnection::addClient(const SocketAddress& addr) { void RpcConnection::assignServerToThisThread(base::unique_fd&& fd) { std::lock_guard<std::mutex> _l(mSocketMutex); - sp<ConnectionSocket> connection = new ConnectionSocket(); + sp<ConnectionSocket> connection = sp<ConnectionSocket>::make(); connection->fd = std::move(fd); mServers.push_back(connection); } diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index df07916f7a..1fa37bacb3 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -36,7 +36,7 @@ RpcServer::RpcServer() {} RpcServer::~RpcServer() {} sp<RpcServer> RpcServer::make() { - return new RpcServer; + return sp<RpcServer>::make(); } void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() { @@ -47,7 +47,7 @@ sp<RpcConnection> RpcServer::addClientConnection() { LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!"); auto connection = RpcConnection::make(); - connection->setForServer(this); + connection->setForServer(sp<RpcServer>::fromExisting(this)); mConnections.push_back(connection); return connection; } diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index 7079544080..7e9be417e1 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -131,8 +131,8 @@ protected: virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id); - inline IBinder* remote() { return mRemote; } - inline IBinder* remote() const { return mRemote; } + inline IBinder* remote() const { return mRemote; } + inline sp<IBinder> remoteStrong() const { return sp<IBinder>::fromExisting(mRemote); } private: BpRefBase(const BpRefBase& o); diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 8ab789318d..ad618f9de4 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -40,8 +40,8 @@ using binder_proxy_limit_callback = void(*)(int); class BpBinder : public IBinder { public: - static BpBinder* create(int32_t handle); - static BpBinder* create(const sp<RpcConnection>& connection, const RpcAddress& address); + static sp<BpBinder> create(int32_t handle); + static sp<BpBinder> create(const sp<RpcConnection>& connection, const RpcAddress& address); /** * Return value: @@ -143,6 +143,7 @@ public: private: friend PrivateAccessorForId; + friend class sp<BpBinder>; struct BinderHandle { int32_t handle; diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index b86fc0b629..ff90b30380 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -143,11 +143,10 @@ public: \ { \ ::android::sp<I##INTERFACE> intr; \ if (obj != nullptr) { \ - intr = static_cast<I##INTERFACE*>( \ - obj->queryLocalInterface( \ - I##INTERFACE::descriptor).get()); \ + intr = ::android::sp<I##INTERFACE>::cast( \ + obj->queryLocalInterface(I##INTERFACE::descriptor)); \ if (intr == nullptr) { \ - intr = new Bp##INTERFACE(obj); \ + intr = ::android::sp<Bp##INTERFACE>::make(obj); \ } \ } \ return intr; \ diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index ca29440e7c..0919648541 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -88,7 +88,8 @@ private: static sp<ProcessState> init(const char *defaultDriver, bool requireDefault); friend class IPCThreadState; - + friend class sp<ProcessState>; + explicit ProcessState(const char* driver); ~ProcessState(); diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index a2c2aee7b8..d29b651f0b 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -72,6 +72,7 @@ public: ~RpcServer(); private: + friend sp<RpcServer>; RpcServer(); bool mAgreedExperimental = false; diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index ff059d7e2b..64203f78a8 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -39,12 +39,50 @@ cc_library_headers { min_sdk_version: "29", } +cc_library_headers { + name: "libgui_aidl_headers", + vendor_available: true, + static_libs: [ + "libgui_aidl_static", + ], + + export_static_lib_headers: [ + "libgui_aidl_static", + ], +} + filegroup { name: "libgui_aidl", srcs: ["aidl/**/*.aidl"], path: "aidl/", } +cc_library_static { + name: "libgui_aidl_static", + vendor_available: true, + srcs: [ + ":libgui_aidl", + ], + + shared_libs: [ + "libbinder", + "libui", + ], + + local_include_dirs: [ + "include", + ], + + export_shared_lib_headers: [ + "libbinder", + ], + + aidl: { + export_aidl_headers: true + } +} + + cc_library_shared { name: "libgui", vendor_available: true, @@ -56,10 +94,16 @@ cc_library_shared { defaults: ["libgui_bufferqueue-defaults"], + static_libs: [ + "libgui_aidl_static", + ], + export_static_lib_headers: [ + "libgui_aidl_static", + ], + srcs: [ ":framework_native_aidl", ":inputconstants_aidl", - ":libgui_aidl", ":libgui_bufferqueue_sources", "BitTube.cpp", @@ -115,6 +159,10 @@ cc_library_shared { "libinput", ], + export_header_lib_headers: [ + "libgui_aidl_headers", + ], + // bufferhub is not used when building libgui for vendors target: { vendor: { @@ -136,15 +184,16 @@ cc_library_shared { }, }, + aidl: { + export_aidl_headers: true, + }, + header_libs: [ "libdvr_headers", + "libgui_aidl_headers", "libpdx_headers", ], - aidl: { - export_aidl_headers: true, - }, - pgo: { sampling: true, profile_file: "libgui/libgui.profdata", @@ -175,8 +224,8 @@ cc_library_static { srcs: [ ":inputconstants_aidl", - ":libgui_aidl", ":libgui_bufferqueue_sources", + ":libgui_aidl", ], } diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/include/gui/FrameTimelineInfo.h index 3b4c009609..a23c20248c 100644 --- a/libs/gui/include/gui/FrameTimelineInfo.h +++ b/libs/gui/include/gui/FrameTimelineInfo.h @@ -18,7 +18,6 @@ #include <stdint.h> -#include <android/os/IInputConstants.h> #include <binder/Parcel.h> namespace android { @@ -31,7 +30,11 @@ struct FrameTimelineInfo { int64_t vsyncId = INVALID_VSYNC_ID; // The id of the input event that caused this buffer - int32_t inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID; + // Default is android::os::IInputConstants::INVALID_INPUT_EVENT_ID = 0 + // We copy the value of the input event ID instead of including the header, because libgui + // header libraries containing FrameTimelineInfo must be available to vendors, but libinput is + // not directly vendor available. + int32_t inputEventId = 0; status_t write(Parcel& output) const; status_t read(const Parcel& input); diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 50e9d53604..61b3f94aab 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -157,6 +157,7 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window); * For all of these parameters, if 0 is supplied then the window's base * value will come back in force. * + * \param window pointer to an ANativeWindow object. * \param width width of the buffers in pixels. * \param height height of the buffers in pixels. * \param format one of the AHardwareBuffer_Format constants. @@ -191,6 +192,7 @@ int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); * * Available since API level 26. * + * \param window pointer to an ANativeWindow object. * \param transform combination of {@link ANativeWindowTransform} flags * \return 0 for success, or -EINVAL if \p transform is invalid */ @@ -208,6 +210,7 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo * * Available since API level 28. * + * \param window pointer to an ANativeWindow object. * \param dataSpace data space of all buffers queued after this call. * \return 0 for success, -EINVAL if window is invalid or the dataspace is not * supported. @@ -306,6 +309,8 @@ enum ANativeWindow_ChangeFrameRateStrategy { * valid refresh rate for this device's display - e.g., it's fine to pass 30fps * to a device that can only run the display at 60fps. * + * \param window pointer to an ANativeWindow object. + * * \param compatibility The frame rate compatibility of this window. The * compatibility value may influence the system's choice of display refresh * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info. diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 026b19a75a..ec39137e24 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -91,6 +91,7 @@ filegroup { "skia/debug/CaptureTimer.cpp", "skia/debug/CommonPool.cpp", "skia/debug/SkiaCapture.cpp", + "skia/debug/SkiaMemoryReporter.cpp", "skia/filters/BlurFilter.cpp", "skia/filters/LinearEffect.cpp", ], diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index a69d1f0da0..8dd98c3ba3 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -141,7 +141,7 @@ public: // do any work. virtual bool cleanupPostRender(CleanupMode mode = CleanupMode::CLEAN_OUTPUT_RESOURCES) = 0; - // queries + // queries that are required to be thread safe virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; @@ -149,8 +149,11 @@ public: // ----- BEGIN NEW INTERFACE ----- + // queries that are required to be thread safe virtual bool isProtected() const = 0; virtual bool supportsProtectedContent() const = 0; + + // Attempt to switch RenderEngine into and out of protectedContext mode virtual bool useProtectedContext(bool useProtectedContext) = 0; // Notify RenderEngine of changes to the dimensions of the primary display @@ -197,7 +200,8 @@ public: virtual int getContextPriority() = 0; // Returns true if blur was requested in the RenderEngineCreationArgs and the implementation - // also supports background blur. If false, no blur will be applied when drawing layers. + // also supports background blur. If false, no blur will be applied when drawing layers. This + // query is required to be thread safe. virtual bool supportsBackgroundBlur() = 0; // Returns the current type of RenderEngine instance that was created. diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 0cd3b622fa..1db20c0be0 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -25,8 +25,6 @@ #include "ui/Rect.h" #include "utils/Timers.h" -#include <android/hardware_buffer.h> - namespace android::renderengine::skia { namespace { @@ -183,41 +181,6 @@ static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings } } -namespace { - -struct AHardwareBuffer_deleter { - void operator()(AHardwareBuffer* ahb) const { AHardwareBuffer_release(ahb); } -}; - -std::unique_ptr<AHardwareBuffer, AHardwareBuffer_deleter> makeAHardwareBuffer() { - AHardwareBuffer* buffer = nullptr; - - int w = 32; - int h = 32; - - AHardwareBuffer_Desc hwbDesc; - hwbDesc.width = w; - hwbDesc.height = h; - hwbDesc.layers = 1; - hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER | - AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; - hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; - // The following three are not used in the allocate - hwbDesc.stride = 0; - hwbDesc.rfu0 = 0; - hwbDesc.rfu1 = 0; - - if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) { - ALOGE("Failed to allocated hardware buffer, error: %d", error); - if (buffer) { - AHardwareBuffer_release(buffer); - } - return nullptr; - } - return std::unique_ptr<AHardwareBuffer, AHardwareBuffer_deleter>(buffer); -} -} // namespace - // // The collection of shaders cached here were found by using perfetto to record shader compiles // during actions that involve RenderEngine, logging the layer settings, and the shader code @@ -265,14 +228,16 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { // The majority of shaders are related to sampling images. drawImageLayers(renderengine, display, dstBuffer, srcBuffer); - // Draw image layers again sampling from an AHardwareBuffer if it is possible to create one. - if (auto ahb = makeAHardwareBuffer()) { - sp<GraphicBuffer> externalBuffer = GraphicBuffer::fromAHardwareBuffer(ahb.get()); - // TODO(b/184665179) doubles number of image shader compilations, but only somewhere - // between 6 and 8 will occur in real uses. - drawImageLayers(renderengine, display, dstBuffer, externalBuffer); - renderengine->unbindExternalTextureBuffer(externalBuffer->getId()); - } + // should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; + const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE; + + sp<GraphicBuffer> externalBuffer = + new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, + usageExternal, "primeShaderCache_external"); + // TODO(b/184665179) doubles number of image shader compilations, but only somewhere + // between 6 and 8 will occur in real uses. + drawImageLayers(renderengine, display, dstBuffer, externalBuffer); + renderengine->unbindExternalTextureBuffer(externalBuffer->getId()); renderengine->unbindExternalTextureBuffer(srcBuffer->getId()); diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index fb7e2856e4..3b2c7e5f66 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -28,6 +28,7 @@ #include <SkColorFilter.h> #include <SkColorMatrix.h> #include <SkColorSpace.h> +#include <SkGraphics.h> #include <SkImage.h> #include <SkImageFilters.h> #include <SkRegion.h> @@ -40,13 +41,13 @@ #include <ui/DebugUtils.h> #include <ui/GraphicBuffer.h> #include <utils/Trace.h> -#include "Cache.h" #include <cmath> #include <cstdint> #include <memory> #include "../gl/GLExtensions.h" +#include "Cache.h" #include "ColorSpaces.h" #include "SkBlendMode.h" #include "SkImageInfo.h" @@ -54,6 +55,7 @@ #include "filters/LinearEffect.h" #include "log/log_main.h" #include "skia/debug/SkiaCapture.h" +#include "skia/debug/SkiaMemoryReporter.h" #include "system/graphics-base-v1.0.h" namespace { @@ -1249,9 +1251,38 @@ void SkiaGLRenderEngine::dump(std::string& result) { StringAppendF(&result, "RenderEngine shaders cached since last dump/primeCache: %d\n", mSkSLCacheMonitor.shadersCachedSinceLastCall()); + std::vector<ResourcePair> cpuResourceMap = { + {"skia/sk_resource_cache/bitmap_", "Bitmaps"}, + {"skia/sk_resource_cache/rrect-blur_", "Masks"}, + {"skia/sk_resource_cache/rects-blur_", "Masks"}, + {"skia/sk_resource_cache/tessellated", "Shadows"}, + {"skia", "Other"}, + }; + SkiaMemoryReporter cpuReporter(cpuResourceMap, false); + SkGraphics::DumpMemoryStatistics(&cpuReporter); + StringAppendF(&result, "Skia CPU Caches: "); + cpuReporter.logTotals(result); + cpuReporter.logOutput(result); + { std::lock_guard<std::mutex> lock(mRenderingMutex); - StringAppendF(&result, "RenderEngine texture cache size: %zu\n", mTextureCache.size()); + + std::vector<ResourcePair> gpuResourceMap = { + {"texture_renderbuffer", "Texture/RenderBuffer"}, + {"texture", "Texture"}, + {"gr_text_blob_cache", "Text"}, + {"skia", "Other"}, + }; + SkiaMemoryReporter gpuReporter(gpuResourceMap, true); + mGrContext->dumpMemoryStatistics(&gpuReporter); + StringAppendF(&result, "Skia's GPU Caches: "); + gpuReporter.logTotals(result); + gpuReporter.logOutput(result); + StringAppendF(&result, "Skia's Wrapped Objects:\n"); + gpuReporter.logOutput(result, true); + + StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n", + mTextureCache.size()); StringAppendF(&result, "Dumping buffer ids...\n"); // TODO(178539829): It would be nice to know which layer these are coming from and what // the texture sizes are. @@ -1259,7 +1290,16 @@ void SkiaGLRenderEngine::dump(std::string& result) { StringAppendF(&result, "- 0x%" PRIx64 "\n", id); } StringAppendF(&result, "\n"); - StringAppendF(&result, "RenderEngine protected texture cache size: %zu\n", + + SkiaMemoryReporter gpuProtectedReporter(gpuResourceMap, true); + mProtectedGrContext->dumpMemoryStatistics(&gpuProtectedReporter); + StringAppendF(&result, "Skia's GPU Protected Caches: "); + gpuProtectedReporter.logTotals(result); + gpuProtectedReporter.logOutput(result); + StringAppendF(&result, "Skia's Protected Wrapped Objects:\n"); + gpuProtectedReporter.logOutput(result, true); + + StringAppendF(&result, "RenderEngine protected AHB/BackendTexture cache size: %zu\n", mProtectedTextureCache.size()); StringAppendF(&result, "Dumping buffer ids...\n"); for (const auto& [id, unused] : mProtectedTextureCache) { diff --git a/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp b/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp new file mode 100644 index 0000000000..f24a4f1c05 --- /dev/null +++ b/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#undef LOG_TAG +#define LOG_TAG "RenderEngine" + +#include "SkiaMemoryReporter.h" + +#include <SkString.h> +#include <android-base/stringprintf.h> +#include <log/log_main.h> + +namespace android { +namespace renderengine { +namespace skia { + +using base::StringAppendF; + +SkiaMemoryReporter::SkiaMemoryReporter(const std::vector<ResourcePair>& resourceMap, bool itemize) + : mResourceMap(resourceMap), + mItemize(itemize), + mTotalSize("bytes", 0), + mPurgeableSize("bytes", 0) {} + +const char* SkiaMemoryReporter::mapName(const char* resourceName) { + for (auto& resource : mResourceMap) { + if (SkStrContains(resourceName, resource.first)) { + return resource.second; + } + } + return nullptr; +} + +void SkiaMemoryReporter::resetCurrentElement() { + mCurrentElement.clear(); + mCurrentValues.clear(); + mIsCurrentValueWrapped = false; +} + +void SkiaMemoryReporter::processCurrentElement() { + // compute the top level element name using the map + const char* resourceName = mCurrentElement.empty() ? nullptr : mapName(mCurrentElement.c_str()); + + // if we don't have a resource name then we don't know how to label the + // data and should abort. + if (resourceName == nullptr) { + resetCurrentElement(); + return; + } + + // Only count elements that contain "size"; other values just provide metadata. + auto sizeResult = mCurrentValues.find("size"); + if (sizeResult != mCurrentValues.end() && sizeResult->second.value > 0) { + if (!mIsCurrentValueWrapped) { + mTotalSize.value += sizeResult->second.value; + mTotalSize.count++; + } + } else { + resetCurrentElement(); + return; + } + + // find the purgeable size if one exists + auto purgeableResult = mCurrentValues.find("purgeable_size"); + if (!mIsCurrentValueWrapped && purgeableResult != mCurrentValues.end()) { + mPurgeableSize.value += purgeableResult->second.value; + mPurgeableSize.count++; + } + + // do we store this element in the wrapped list or the skia managed list + auto& results = mIsCurrentValueWrapped ? mWrappedResults : mResults; + + // insert a copy of the element and all of its keys. We must make a copy here instead of + // std::move() as we will continue to use these values later in the function and again + // when we move on to process the next element. + results.insert({mCurrentElement, mCurrentValues}); + + // insert the item into its mapped category + auto result = results.find(resourceName); + if (result != results.end()) { + auto& resourceValues = result->second; + auto totalResult = resourceValues.find(sizeResult->first); + if (totalResult != resourceValues.end()) { + ALOGE_IF(sizeResult->second.units != totalResult->second.units, + "resource units do not match so the sum of resource type (%s) will be invalid", + resourceName); + totalResult->second.value += sizeResult->second.value; + totalResult->second.count++; + } else { + ALOGE("an entry (%s) should not exist in the results without a size", resourceName); + } + } else { + // only store the size for the top level resource + results.insert({resourceName, {{sizeResult->first, sizeResult->second}}}); + } + + resetCurrentElement(); +} + +void SkiaMemoryReporter::dumpNumericValue(const char* dumpName, const char* valueName, + const char* units, uint64_t value) { + if (mCurrentElement != dumpName) { + processCurrentElement(); + mCurrentElement = dumpName; + } + mCurrentValues.insert({valueName, {units, value}}); +} + +void SkiaMemoryReporter::dumpWrappedState(const char* dumpName, bool isWrappedObject) { + if (mCurrentElement != dumpName) { + processCurrentElement(); + mCurrentElement = dumpName; + } + mIsCurrentValueWrapped = isWrappedObject; +} + +void SkiaMemoryReporter::logOutput(std::string& log, bool wrappedResources) { + // process the current element before logging + processCurrentElement(); + + const auto& resultsMap = wrappedResources ? mWrappedResults : mResults; + + // log each individual element based on the resource map + for (const auto& resourceCategory : mResourceMap) { + // find the named item and print the totals + const auto categoryItem = resultsMap.find(resourceCategory.second); + if (categoryItem != resultsMap.end()) { + auto result = categoryItem->second.find("size"); + if (result != categoryItem->second.end()) { + TraceValue traceValue = convertUnits(result->second); + const char* entry = (traceValue.count > 1) ? "entries" : "entry"; + StringAppendF(&log, " %s: %.2f %s (%d %s)\n", categoryItem->first.c_str(), + traceValue.value, traceValue.units, traceValue.count, entry); + } + if (mItemize) { + for (const auto& individualItem : resultsMap) { + // if the individual item matches the category then print all its details or + // in the case of wrapped resources just print the wrapped size + const char* categoryMatch = mapName(individualItem.first.c_str()); + if (categoryMatch && strcmp(categoryMatch, resourceCategory.second) == 0) { + auto result = individualItem.second.find("size"); + TraceValue size = convertUnits(result->second); + StringAppendF(&log, " %s: size[%.2f %s]", individualItem.first.c_str(), + size.value, size.units); + if (!wrappedResources) { + for (const auto& itemValues : individualItem.second) { + if (strcmp("size", itemValues.first) == 0) { + continue; + } + TraceValue traceValue = convertUnits(itemValues.second); + if (traceValue.value == 0.0f) { + StringAppendF(&log, " %s[%s]", itemValues.first, + traceValue.units); + } else { + StringAppendF(&log, " %s[%.2f %s]", itemValues.first, + traceValue.value, traceValue.units); + } + } + } + StringAppendF(&log, "\n"); + } + } + } + } + } +} + +void SkiaMemoryReporter::logTotals(std::string& log) { + // process the current element before logging + processCurrentElement(); + + TraceValue total = convertUnits(mTotalSize); + TraceValue purgeable = convertUnits(mPurgeableSize); + StringAppendF(&log, " %.0f bytes, %.2f %s (%.2f %s is purgeable)\n", mTotalSize.value, + total.value, total.units, purgeable.value, purgeable.units); +} + +SkiaMemoryReporter::TraceValue SkiaMemoryReporter::convertUnits(const TraceValue& value) { + TraceValue output(value); + if (SkString("bytes") == SkString(output.units) && output.value >= 1024) { + output.value = output.value / 1024.0f; + output.units = "KB"; + } + if (SkString("KB") == SkString(output.units) && output.value >= 1024) { + output.value = output.value / 1024.0f; + output.units = "MB"; + } + return output; +} + +} /* namespace skia */ +} /* namespace renderengine */ +} /* namespace android */ diff --git a/libs/renderengine/skia/debug/SkiaMemoryReporter.h b/libs/renderengine/skia/debug/SkiaMemoryReporter.h new file mode 100644 index 0000000000..dbbd65b3da --- /dev/null +++ b/libs/renderengine/skia/debug/SkiaMemoryReporter.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <SkTraceMemoryDump.h> + +#include <string> +#include <unordered_map> +#include <vector> + +namespace android { +namespace renderengine { +namespace skia { + +// Mapping of resource substrings (1st element) that if found within a trace "dumpName" +// should be mapped to the category name (2nd element). All char* used in a resourcePair +// are expected to have a lifetime longer than the SkiaMemoryReporter in which they are used. +typedef std::pair<const char*, const char*> ResourcePair; + +/* + * Utility class for logging the CPU/GPU usage of Skia caches in a format that is specific + * to RenderEngine. HWUI has a similar logging class, but the data collected and the way + * it is formatted and reported on are intended to be unique to each use case. + */ +class SkiaMemoryReporter : public SkTraceMemoryDump { +public: + /** + * Creates the reporter class that can be populated by various Skia entry points, like + * SkGraphics and GrContext, as well as format and log the results. + * @param resourceMap An array of values that maps a Skia dumpName into a user defined category. + * The first vector entry that matches the dumpName is used for the mapping. + * @param itemize if true when logging the categories the individual elements will be printed + * directly after the category details are printed. Otherwise, only the category + * totals will be printed. + */ + SkiaMemoryReporter(const std::vector<ResourcePair>& resourceMap, bool itemize); + ~SkiaMemoryReporter() override {} + + void logOutput(std::string& log, bool wrappedResources = false); + void logTotals(std::string& log); + + void dumpNumericValue(const char* dumpName, const char* valueName, const char* units, + uint64_t value) override; + + void dumpStringValue(const char* dumpName, const char* valueName, const char* value) override { + // for convenience we just store this in the same format as numerical values + dumpNumericValue(dumpName, valueName, value, 0); + } + void dumpWrappedState(const char* dumpName, bool isWrappedObject) override; + + LevelOfDetail getRequestedDetails() const override { + return SkTraceMemoryDump::kLight_LevelOfDetail; + } + + bool shouldDumpWrappedObjects() const override { return true; } + void setMemoryBacking(const char*, const char*, const char*) override {} + void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override {} + +private: + struct TraceValue { + TraceValue(const char* units, uint64_t value) : units(units), value(value), count(1) {} + TraceValue(const TraceValue& v) : units(v.units), value(v.value), count(v.count) {} + + const char* units; + float value; + int count; + }; + + const char* mapName(const char* resourceName); + void processCurrentElement(); + void resetCurrentElement(); + TraceValue convertUnits(const TraceValue& value); + + const std::vector<ResourcePair>& mResourceMap; + const bool mItemize; + + // variables storing the size of all non-wrapped elements being dumped + TraceValue mTotalSize; + TraceValue mPurgeableSize; + + // variables storing information on the current node being dumped + std::string mCurrentElement; + std::unordered_map<const char*, TraceValue> mCurrentValues; + bool mIsCurrentValueWrapped = false; + + // variable that stores the final format of the data after the individual elements are processed + std::unordered_map<std::string, std::unordered_map<const char*, TraceValue>> mResults; + std::unordered_map<std::string, std::unordered_map<const char*, TraceValue>> mWrappedResults; +}; + +} /* namespace skia */ +} /* namespace renderengine */ +} /* namespace android */
\ No newline at end of file diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index 63aa4c891c..b093e88d4f 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -49,6 +49,9 @@ TEST_F(RenderEngineThreadedTest, dump) { TEST_F(RenderEngineThreadedTest, primeCache) { EXPECT_CALL(*mRenderEngine, primeCache()); mThreadedRE->primeCache(); + // need to call ANY synchronous function after primeCache to ensure that primeCache has + // completed asynchronously before the test completes execution. + mThreadedRE->getContextPriority(); } TEST_F(RenderEngineThreadedTest, genTextures) { diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 783e37fc22..194c7da1c7 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -74,6 +74,12 @@ void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_S std::unique_lock<std::mutex> lock(mThreadMutex); pthread_setname_np(pthread_self(), mThreadName); + { + std::unique_lock<std::mutex> lock(mInitializedMutex); + mIsInitialized = true; + } + mInitializedCondition.notify_all(); + while (mRunning) { if (!mFunctionCalls.empty()) { auto task = mFunctionCalls.front(); @@ -86,19 +92,22 @@ void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_S } } +void RenderEngineThreaded::waitUntilInitialized() const { + std::unique_lock<std::mutex> lock(mInitializedMutex); + mInitializedCondition.wait(lock, [=] { return mIsInitialized; }); +} + void RenderEngineThreaded::primeCache() { - std::promise<void> resultPromise; - std::future<void> resultFuture = resultPromise.get_future(); + // This function is designed so it can run asynchronously, so we do not need to wait + // for the futures. { std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { + mFunctionCalls.push([](renderengine::RenderEngine& instance) { ATRACE_NAME("REThreaded::primeCache"); instance.primeCache(); - resultPromise.set_value(); }); } mCondition.notify_one(); - resultFuture.wait(); } void RenderEngineThreaded::dump(std::string& result) { @@ -175,63 +184,26 @@ void RenderEngineThreaded::unbindExternalTextureBuffer(uint64_t bufferId) { } size_t RenderEngineThreaded::getMaxTextureSize() const { - std::promise<size_t> resultPromise; - std::future<size_t> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::getMaxTextureSize"); - size_t size = instance.getMaxTextureSize(); - resultPromise.set_value(size); - }); - } - mCondition.notify_one(); - return resultFuture.get(); + waitUntilInitialized(); + return mRenderEngine->getMaxTextureSize(); } size_t RenderEngineThreaded::getMaxViewportDims() const { - std::promise<size_t> resultPromise; - std::future<size_t> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::getMaxViewportDims"); - size_t size = instance.getMaxViewportDims(); - resultPromise.set_value(size); - }); - } - mCondition.notify_one(); - return resultFuture.get(); + waitUntilInitialized(); + return mRenderEngine->getMaxViewportDims(); } bool RenderEngineThreaded::isProtected() const { - std::promise<bool> resultPromise; - std::future<bool> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::isProtected"); - bool returnValue = instance.isProtected(); - resultPromise.set_value(returnValue); - }); - } - mCondition.notify_one(); - return resultFuture.get(); + waitUntilInitialized(); + // ensure that useProtectedContext is not currently being changed by some + // other thread. + std::lock_guard lock(mThreadMutex); + return mRenderEngine->isProtected(); } bool RenderEngineThreaded::supportsProtectedContent() const { - std::promise<bool> resultPromise; - std::future<bool> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::supportsProtectedContent"); - bool returnValue = instance.supportsProtectedContent(); - resultPromise.set_value(returnValue); - }); - } - mCondition.notify_one(); - return resultFuture.get(); + waitUntilInitialized(); + return mRenderEngine->supportsProtectedContent(); } bool RenderEngineThreaded::useProtectedContext(bool useProtectedContext) { @@ -288,18 +260,16 @@ status_t RenderEngineThreaded::drawLayers(const DisplaySettings& display, } void RenderEngineThreaded::cleanFramebufferCache() { - std::promise<void> resultPromise; - std::future<void> resultFuture = resultPromise.get_future(); + // This function is designed so it can run asynchronously, so we do not need to wait + // for the futures. { std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { + mFunctionCalls.push([](renderengine::RenderEngine& instance) { ATRACE_NAME("REThreaded::cleanFramebufferCache"); instance.cleanFramebufferCache(); - resultPromise.set_value(); }); } mCondition.notify_one(); - resultFuture.wait(); } int RenderEngineThreaded::getContextPriority() { @@ -318,33 +288,21 @@ int RenderEngineThreaded::getContextPriority() { } bool RenderEngineThreaded::supportsBackgroundBlur() { - std::promise<bool> resultPromise; - std::future<bool> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::supportsBackgroundBlur"); - bool returnValue = instance.supportsBackgroundBlur(); - resultPromise.set_value(returnValue); - }); - } - mCondition.notify_one(); - return resultFuture.get(); + waitUntilInitialized(); + return mRenderEngine->supportsBackgroundBlur(); } void RenderEngineThreaded::onPrimaryDisplaySizeChanged(ui::Size size) { - std::promise<void> resultPromise; - std::future<void> resultFuture = resultPromise.get_future(); + // This function is designed so it can run asynchronously, so we do not need to wait + // for the futures. { std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise, size](renderengine::RenderEngine& instance) { + mFunctionCalls.push([size](renderengine::RenderEngine& instance) { ATRACE_NAME("REThreaded::onPrimaryDisplaySizeChanged"); instance.onPrimaryDisplaySizeChanged(size); - resultPromise.set_value(); }); } mCondition.notify_one(); - resultFuture.wait(); } } // namespace threaded diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 117257a90e..61ae9b8cf8 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -70,6 +70,7 @@ public: private: void threadMain(CreateInstanceFactory factory); + void waitUntilInitialized() const; /* ------------------------------------------------------------------------ * Threading @@ -83,6 +84,12 @@ private: GUARDED_BY(mThreadMutex); mutable std::condition_variable mCondition; + // Used to allow select thread safe methods to be accessed without requiring the + // method to be invoked on the RenderEngine thread + bool mIsInitialized = false; + mutable std::mutex mInitializedMutex; + mutable std::condition_variable mInitializedCondition; + /* ------------------------------------------------------------------------ * Render Engine */ diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h index afa02cd0c2..c5d03a7218 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h @@ -108,7 +108,7 @@ public: private: CachedSet() = default; - NonBufferHash mFingerprint = 0; + const NonBufferHash mFingerprint; std::chrono::steady_clock::time_point mLastUpdate = std::chrono::steady_clock::now(); std::vector<Layer> mLayers; Rect mBounds = Rect::EMPTY_RECT; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h index 313a180f4f..2f2ad4c9b5 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h @@ -54,7 +54,7 @@ private: void resetActivities(NonBufferHash, std::chrono::steady_clock::time_point now); - void updateLayersHash(); + NonBufferHash computeLayersHash() const; bool mergeWithCachedSets(const std::vector<const LayerState*>& layers, std::chrono::steady_clock::time_point now); @@ -69,7 +69,6 @@ private: std::chrono::steady_clock::time_point mLastGeometryUpdate; std::vector<CachedSet> mLayers; - NonBufferHash mLayersHash = 0; std::optional<CachedSet> mNewCachedSet; // Statistics diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp index ffca5baab7..9c9649ccbe 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp @@ -40,13 +40,17 @@ NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& lay ++mInitialLayerCounts[layers.size()]; - if (mergeWithCachedSets(layers, now)) { - hash = mLayersHash; - } + // Only buildCachedSets if these layers are already stored in mLayers. + // Otherwise (i.e. mergeWithCachedSets returns false), the time has not + // changed, so buildCachedSets will never find any runs. + const bool alreadyHadCachedSets = mergeWithCachedSets(layers, now); ++mFinalLayerCounts[mLayers.size()]; - buildCachedSets(now); + if (alreadyHadCachedSets) { + buildCachedSets(now); + hash = computeLayersHash(); + } return hash; } @@ -157,14 +161,17 @@ void Flattener::resetActivities(NonBufferHash hash, time_point now) { } } -void Flattener::updateLayersHash() { +NonBufferHash Flattener::computeLayersHash() const{ size_t hash = 0; for (const auto& layer : mLayers) { android::hashCombineSingleHashed(hash, layer.getNonBufferHash()); } - mLayersHash = hash; + return hash; } +// Only called if the geometry matches the last frame. Return true if mLayers +// was already populated with these layers, i.e. on the second and following +// calls with the same geometry. bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers, time_point now) { std::vector<CachedSet> merged; @@ -272,7 +279,6 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers } mLayers = std::move(merged); - updateLayersHash(); return true; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6038658ee6..829b91676b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2264,8 +2264,13 @@ int32_t Layer::getBackgroundBlurRadius() const { return parentAlpha * getDrawingState().backgroundBlurRadius; } -const std::vector<BlurRegion>& Layer::getBlurRegions() const { - return getDrawingState().blurRegions; +const std::vector<BlurRegion> Layer::getBlurRegions() const { + auto regionsCopy(getDrawingState().blurRegions); + int layerAlpha = getAlpha(); + for (auto& region : regionsCopy) { + region.alpha = region.alpha * layerAlpha; + } + return regionsCopy; } Layer::RoundedCornerState Layer::getRoundedCornerState() const { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 5528a8190f..64986afd61 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -1191,7 +1191,7 @@ private: float mEffectiveShadowRadius = 0.f; // A list of regions on this layer that should have blurs. - const std::vector<BlurRegion>& getBlurRegions() const; + const std::vector<BlurRegion> getBlurRegions() const; }; std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index 2b8424c987..9686523525 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -89,13 +89,47 @@ int main(int, char**) { // binder threads to 4. ProcessState::self()->setThreadPoolMaxThreadCount(4); + // The binder threadpool we start will inherit sched policy and priority + // of (this) creating thread. We want the binder thread pool to have + // SCHED_FIFO policy and priority 1 (lowest RT priority) + // Once the pool is created we reset this thread's priority back to + // original. + int newPriority = 0; + int origPolicy = sched_getscheduler(0); + struct sched_param origSchedParam; + + int errorInPriorityModification = sched_getparam(0, &origSchedParam); + if (errorInPriorityModification == 0) { + int policy = SCHED_FIFO; + newPriority = sched_get_priority_min(policy); + + struct sched_param param; + param.sched_priority = newPriority; + + errorInPriorityModification = sched_setscheduler(0, policy, ¶m); + } + // start the thread pool sp<ProcessState> ps(ProcessState::self()); ps->startThreadPool(); + // Reset current thread's policy and priority + if (errorInPriorityModification == 0) { + errorInPriorityModification = sched_setscheduler(0, origPolicy, &origSchedParam); + } else { + ALOGE("Failed to set SurfaceFlinger binder threadpool priority to SCHED_FIFO"); + } + // instantiate surfaceflinger sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger(); + // Set the minimum policy of surfaceflinger node to be SCHED_FIFO. + // So any thread with policy/priority lower than {SCHED_FIFO, 1}, will run + // at least with SCHED_FIFO policy and priority 1. + if (errorInPriorityModification == 0) { + flinger->setMinSchedulerPolicy(SCHED_FIFO, newPriority); + } + setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY); set_sched_policy(0, SP_FOREGROUND); diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 020b520a7c..8d6681c9f4 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -1086,7 +1086,8 @@ VkResult CreateSwapchainKHR(VkDevice device, ALOGW_IF(err != android::OK, "native_window_api_connect failed: %s (%d)", strerror(-err), err); - err = window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, -1); + err = + window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, nsecs_t{-1}); if (err != android::OK) { ALOGE("window->perform(SET_DEQUEUE_TIMEOUT) failed: %s (%d)", strerror(-err), err); |