diff options
102 files changed, 2098 insertions, 410 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 36a53bbbe2..db297a0a2e 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -13,10 +13,12 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp libs/renderengine/ libs/ui/ libs/vr/ + opengl/libs/ services/bufferhub/ services/inputflinger/ services/surfaceflinger/ services/vr/ + vulkan/ [Hook Scripts] owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$" diff --git a/aidl/binder/android/os/PersistableBundle.aidl b/aidl/binder/android/os/PersistableBundle.aidl index 94e8607630..493ecb414c 100644 --- a/aidl/binder/android/os/PersistableBundle.aidl +++ b/aidl/binder/android/os/PersistableBundle.aidl @@ -17,4 +17,4 @@ package android.os; -parcelable PersistableBundle cpp_header "binder/PersistableBundle.h"; +@JavaOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h"; diff --git a/build/phone-xhdpi-2048-dalvik-heap.mk b/build/phone-xhdpi-2048-dalvik-heap.mk index 042a6e69ef..7ccfc13702 100644 --- a/build/phone-xhdpi-2048-dalvik-heap.mk +++ b/build/phone-xhdpi-2048-dalvik-heap.mk @@ -14,7 +14,7 @@ # limitations under the License. # -# Provides overrides to configure the Dalvik heap for a 2G phone +# Provides overrides to configure the Dalvik heap for a 2GB phone # 192m of RAM gives enough space for 5 8 megapixel camera bitmaps in RAM. PRODUCT_PROPERTY_OVERRIDES += \ diff --git a/build/phone-xhdpi-4096-dalvik-heap.mk b/build/phone-xhdpi-4096-dalvik-heap.mk new file mode 100644 index 0000000000..2b848413fb --- /dev/null +++ b/build/phone-xhdpi-4096-dalvik-heap.mk @@ -0,0 +1,25 @@ +# +# Copyright 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Provides overrides to configure the Dalvik heap for a 4GB phone + +PRODUCT_PROPERTY_OVERRIDES += \ + dalvik.vm.heapstartsize=8m \ + dalvik.vm.heapgrowthlimit=192m \ + dalvik.vm.heapsize=512m \ + dalvik.vm.heaptargetutilization=0.6 \ + dalvik.vm.heapminfree=8m \ + dalvik.vm.heapmaxfree=16m diff --git a/build/phone-xhdpi-6144-dalvik-heap.mk b/build/phone-xhdpi-6144-dalvik-heap.mk new file mode 100644 index 0000000000..2bacc4a9ab --- /dev/null +++ b/build/phone-xhdpi-6144-dalvik-heap.mk @@ -0,0 +1,25 @@ +# +# Copyright 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Provides overrides to configure the Dalvik heap for a 6GB phone + +PRODUCT_PROPERTY_OVERRIDES += \ + dalvik.vm.heapstartsize=16m \ + dalvik.vm.heapgrowthlimit=256m \ + dalvik.vm.heapsize=512m \ + dalvik.vm.heaptargetutilization=0.5 \ + dalvik.vm.heapminfree=8m \ + dalvik.vm.heapmaxfree=32m diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 5186ad3a1f..cf75bbab3b 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -854,7 +854,6 @@ static bool setUpUserspaceTracing() tags |= c.tags; } } - ok &= setTagsProperty(tags); bool coreServicesTagEnabled = false; for (size_t i = 0; i < arraysize(k_categories); i++) { @@ -876,9 +875,11 @@ static bool setUpUserspaceTracing() packageList += android::base::GetProperty(k_coreServicesProp, ""); } ok &= setAppCmdlineProperty(&packageList[0]); + ok &= setTagsProperty(tags); +#if !ATRACE_SHMEM ok &= pokeBinderServices(); pokeHalServices(); - +#endif if (g_tracePdx) { ok &= ServiceUtility::PokeServices(); } diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp index 7b4aeb2cc2..8dad47502f 100644 --- a/cmds/cmd/cmd.cpp +++ b/cmds/cmd/cmd.cpp @@ -223,7 +223,8 @@ int cmdMain(const std::vector<std::string_view>& argv, TextOutput& outputLog, Te sp<MyResultReceiver> result = new MyResultReceiver(); #if DEBUG - ALOGD("cmd: Invoking %s in=%d, out=%d, err=%d", cmd, in, out, err); + ALOGD("cmd: Invoking %.*s in=%d, out=%d, err=%d", + static_cast<int>(cmd.size()), cmd.data(), in, out, err); #endif // TODO: block until a result is returned to MyResultReceiver. diff --git a/cmds/dumpstate/DumpstateInternal.h b/cmds/dumpstate/DumpstateInternal.h index 10db5d65e3..c1ec55ee61 100644 --- a/cmds/dumpstate/DumpstateInternal.h +++ b/cmds/dumpstate/DumpstateInternal.h @@ -49,6 +49,7 @@ // TODO: use functions from <chrono> instead const uint64_t NANOS_PER_SEC = 1000000000; +const uint64_t NANOS_PER_MILLI = 1000000; uint64_t Nanotime(); // Switches to non-root user and group. diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index f98df99534..10d3d1756b 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -115,8 +115,8 @@ binder::Status DumpstateService::setListener(const std::string& name, binder::Status DumpstateService::startBugreport(int32_t calling_uid, const std::string& calling_package, - const android::base::unique_fd& bugreport_fd, - const android::base::unique_fd& screenshot_fd, + android::base::unique_fd bugreport_fd, + android::base::unique_fd screenshot_fd, int bugreport_mode, const sp<IDumpstateListener>& listener) { MYLOGI("startBugreport() with mode: %d\n", bugreport_mode); diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h index 68eda4763a..aaaa4286cc 100644 --- a/cmds/dumpstate/DumpstateService.h +++ b/cmds/dumpstate/DumpstateService.h @@ -43,8 +43,8 @@ class DumpstateService : public BinderService<DumpstateService>, public BnDumpst sp<IDumpstateToken>* returned_token) override; binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package, - const android::base::unique_fd& bugreport_fd, - const android::base::unique_fd& screenshot_fd, int bugreport_mode, + android::base::unique_fd bugreport_fd, + android::base::unique_fd screenshot_fd, int bugreport_mode, const sp<IDumpstateListener>& listener) override; // No-op diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index c5bfb42bde..585a98e0be 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -660,7 +660,7 @@ UserConsentResult Dumpstate::ConsentCallback::getResult() { } uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const { - return Nanotime() - start_time_; + return (Nanotime() - start_time_) / NANOS_PER_MILLI; } void Dumpstate::PrintHeader() const { @@ -2913,15 +2913,13 @@ DurationReporter::DurationReporter(const std::string& title, bool logcat_only, b DurationReporter::~DurationReporter() { if (!title_.empty()) { float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC; - if (elapsed < .5f && !verbose_) { - return; + if (elapsed >= .5f || verbose_) { + MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed); } - MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed); - if (logcat_only_) { - return; + if (!logcat_only_) { + // Use "Yoda grammar" to make it easier to grep|sort sections. + printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str()); } - // Use "Yoda grammar" to make it easier to grep|sort sections. - printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str()); } } diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp index 7e6f6f53e5..256dc055e1 100644 --- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -449,7 +449,7 @@ TEST_F(DumpstateBinderTest, Baseline) { sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)))); android::binder::Status status = - ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd, + ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener); // startBugreport is an async call. Verify binder call succeeded first, then wait till listener // gets expected callbacks. @@ -485,7 +485,7 @@ TEST_F(DumpstateBinderTest, ServiceDies_OnInvalidInput) { // Call startBugreport with bad arguments. sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)))); android::binder::Status status = - ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd, + ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), 2000, // invalid bugreport mode listener); EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); @@ -506,20 +506,24 @@ TEST_F(DumpstateBinderTest, SimultaneousBugreportsNotAllowed) { // Prepare arguments unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip")); + unique_fd bugreport_fd2(dup(bugreport_fd.get())); unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png")); + unique_fd screenshot_fd2(dup(screenshot_fd.get())); EXPECT_NE(bugreport_fd.get(), -1); + EXPECT_NE(bugreport_fd2.get(), -1); EXPECT_NE(screenshot_fd.get(), -1); + EXPECT_NE(screenshot_fd2.get(), -1); sp<DumpstateListener> listener1(new DumpstateListener(dup(fileno(stdout)))); android::binder::Status status = - ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd, + ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1); EXPECT_TRUE(status.isOk()); // try to make another call to startBugreport. This should fail. sp<DumpstateListener> listener2(new DumpstateListener(dup(fileno(stdout)))); - status = ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd, + status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd2), std::move(screenshot_fd2), Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2); EXPECT_FALSE(status.isOk()); WaitTillExecutionComplete(listener2.get()); diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp index abdf168233..5597bcd915 100644 --- a/cmds/dumpsys/dumpsys.cpp +++ b/cmds/dumpsys/dumpsys.cpp @@ -364,7 +364,7 @@ status_t Dumpsys::startDumpThread(Type type, const String16& serviceName, } if (err != OK) { - aerr << "Error dumping service info status_t: (" << err << ") " + aerr << "Error dumping service info status_t: " << statusToString(err) << " " << serviceName << endl; } }); diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp index 5476319f31..402767a426 100644 --- a/cmds/idlcli/Android.bp +++ b/cmds/idlcli/Android.bp @@ -15,20 +15,21 @@ cc_defaults { name: "idlcli-defaults", shared_libs: [ + "android.hardware.vibrator-ndk_platform", "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", "android.hardware.vibrator@1.3", "libbase", - "libbinder", + "libbinder_ndk", "libhidlbase", "liblog", "libutils", - "vintf-vibrator-cpp", ], cflags: [ "-DLOG_TAG=\"idlcli\"", ], + vendor_available: true, } cc_library { diff --git a/cmds/idlcli/vibrator.h b/cmds/idlcli/vibrator.h index 2f119234c1..ca5142dee9 100644 --- a/cmds/idlcli/vibrator.h +++ b/cmds/idlcli/vibrator.h @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #ifndef FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_ #define FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_ +#include <aidl/android/hardware/vibrator/IVibrator.h> +#include <android/binder_manager.h> #include <android/hardware/vibrator/1.3/IVibrator.h> -#include <android/hardware/vibrator/IVibrator.h> -#include <binder/IServiceManager.h> #include "utils.h" @@ -39,22 +38,27 @@ inline R NullptrStatus() { } template <> -inline binder::Status NullptrStatus() { - using binder::Status; - return Status::fromExceptionCode(Status::EX_NULL_POINTER); +inline ndk::ScopedAStatus NullptrStatus() { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_NULL_POINTER)); } template <typename I> -inline sp<I> getService() { +inline auto getService() { return I::getService(); } template <> -inline sp<hardware::vibrator::IVibrator> getService() { - return waitForVintfService<hardware::vibrator::IVibrator>(); +inline auto getService<aidl::android::hardware::vibrator::IVibrator>() { + const auto instance = + std::string() + aidl::android::hardware::vibrator::IVibrator::descriptor + "/default"; + auto vibBinder = ndk::SpAIBinder(AServiceManager_getService(instance.c_str())); + return aidl::android::hardware::vibrator::IVibrator::fromBinder(vibBinder); } template <typename I> +using shared_ptr = std::result_of_t<decltype(getService<I>)&()>; + +template <typename I> class HalWrapper { public: static std::unique_ptr<HalWrapper> Create() { @@ -70,10 +74,10 @@ public: } private: - HalWrapper(sp<I>&& hal) : mHal(std::move(hal)) {} + HalWrapper(shared_ptr<I>&& hal) : mHal(std::move(hal)) {} private: - sp<I> mHal; + shared_ptr<I> mHal; }; template <typename I> @@ -95,7 +99,7 @@ namespace V1_0 = ::android::hardware::vibrator::V1_0; namespace V1_1 = ::android::hardware::vibrator::V1_1; namespace V1_2 = ::android::hardware::vibrator::V1_2; namespace V1_3 = ::android::hardware::vibrator::V1_3; -namespace aidl = ::android::hardware::vibrator; +namespace aidl = ::aidl::android::hardware::vibrator; } // namespace vibrator } // namespace idlcli diff --git a/cmds/idlcli/vibrator/CommandCompose.cpp b/cmds/idlcli/vibrator/CommandCompose.cpp index 705e40bbf2..4721a5f9ae 100644 --- a/cmds/idlcli/vibrator/CommandCompose.cpp +++ b/cmds/idlcli/vibrator/CommandCompose.cpp @@ -80,7 +80,7 @@ class CommandCompose : public Command { Status ret; if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::compose, mComposite, nullptr); - statusStr = status.toString8(); + statusStr = status.getDescription(); ret = status.isOk() ? OK : ERROR; } else { return UNAVAILABLE; diff --git a/cmds/idlcli/vibrator/CommandGetCapabilities.cpp b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp index 30d85873c0..303a9895e4 100644 --- a/cmds/idlcli/vibrator/CommandGetCapabilities.cpp +++ b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp @@ -48,7 +48,7 @@ class CommandGetCapabilities : public Command { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::getCapabilities, &cap); - statusStr = status.toString8(); + statusStr = status.getDescription(); ret = status.isOk() ? OK : ERROR; } else { return UNAVAILABLE; diff --git a/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp index b4143075b3..10508bd4dc 100644 --- a/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp +++ b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp @@ -50,7 +50,7 @@ class CommandGetCompositionDelayMax : public Command { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::getCompositionDelayMax, &maxDelayMs); - statusStr = status.toString8(); + statusStr = status.getDescription(); ret = status.isOk() ? OK : ERROR; } else { return UNAVAILABLE; diff --git a/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp index 360fc9d9e2..900cb18809 100644 --- a/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp +++ b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp @@ -50,7 +50,7 @@ class CommandGetCompositionSizeMax : public Command { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::getCompositionSizeMax, &maxSize); - statusStr = status.toString8(); + statusStr = status.getDescription(); ret = status.isOk() ? OK : ERROR; } else { return UNAVAILABLE; diff --git a/cmds/idlcli/vibrator/CommandOff.cpp b/cmds/idlcli/vibrator/CommandOff.cpp index 53fada0f86..cedb9fec06 100644 --- a/cmds/idlcli/vibrator/CommandOff.cpp +++ b/cmds/idlcli/vibrator/CommandOff.cpp @@ -47,7 +47,7 @@ class CommandOff : public Command { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::off); - statusStr = status.toString8(); + statusStr = status.getDescription(); ret = status.isOk() ? OK : ERROR; } else if (auto hal = getHal<V1_0::IVibrator>()) { auto status = hal->call(&V1_0::IVibrator::off); diff --git a/cmds/idlcli/vibrator/CommandOn.cpp b/cmds/idlcli/vibrator/CommandOn.cpp index ccb3c19ca8..4e7e493d6d 100644 --- a/cmds/idlcli/vibrator/CommandOn.cpp +++ b/cmds/idlcli/vibrator/CommandOn.cpp @@ -55,7 +55,7 @@ class CommandOn : public Command { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::on, mDuration, nullptr); - statusStr = status.toString8(); + statusStr = status.getDescription(); ret = status.isOk() ? OK : ERROR; } else if (auto hal = getHal<V1_0::IVibrator>()) { auto status = hal->call(&V1_0::IVibrator::on, mDuration); diff --git a/cmds/idlcli/vibrator/CommandPerform.cpp b/cmds/idlcli/vibrator/CommandPerform.cpp index 58d4e0ac16..69c7e37744 100644 --- a/cmds/idlcli/vibrator/CommandPerform.cpp +++ b/cmds/idlcli/vibrator/CommandPerform.cpp @@ -99,7 +99,7 @@ class CommandPerform : public Command { auto status = hal->call(&aidl::IVibrator::perform, static_cast<aidl::Effect>(mEffect), static_cast<aidl::EffectStrength>(mStrength), nullptr, &aidlLengthMs); - statusStr = status.toString8(); + statusStr = status.getDescription(); lengthMs = static_cast<uint32_t>(aidlLengthMs); ret = status.isOk() ? OK : ERROR; } else { diff --git a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp index 33d7eed5be..8b8058c4fd 100644 --- a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp +++ b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp @@ -56,7 +56,7 @@ class CommandSetAmplitude : public Command { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::setAmplitude, static_cast<float>(mAmplitude) / UINT8_MAX); - statusStr = status.toString8(); + statusStr = status.getDescription(); ret = status.isOk() ? OK : ERROR; } else if (auto hal = getHal<V1_0::IVibrator>()) { auto status = hal->call(&V1_0::IVibrator::setAmplitude, mAmplitude); diff --git a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp index 5bc827e707..179579310a 100644 --- a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp +++ b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp @@ -53,7 +53,7 @@ class CommandSetExternalControl : public Command { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::setExternalControl, mEnable); - statusStr = status.toString8(); + statusStr = status.getDescription(); ret = status.isOk() ? OK : ERROR; } else if (auto hal = getHal<V1_3::IVibrator>()) { auto status = hal->call(&V1_3::IVibrator::setExternalControl, mEnable); diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index b23d69c52f..0fde31a5cc 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -103,6 +103,9 @@ static constexpr size_t kSha256Size = 32; static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode"; static constexpr const char* kFuseProp = "persist.sys.fuse"; +static constexpr const char* kMntSdcardfs = "/mnt/runtime/default/"; +static constexpr const char* kMntFuse = "/mnt/pass_through/0/"; + namespace { constexpr const char* kDump = "android.permission.DUMP"; @@ -626,10 +629,8 @@ binder::Status InstalldNativeService::clearAppData(const std::unique_ptr<std::st if (delete_dir_contents(path, true) != 0) { res = error("Failed to delete contents of " + path); } - path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname); - if (delete_dir_contents(path, true) != 0) { - res = error("Failed to delete contents of " + path); - } + // Note that we explicitly don't delete OBBs - those are only removed on + // app uninstall. } } } @@ -2625,7 +2626,7 @@ struct fsverity_measurement { #endif binder::Status InstalldNativeService::installApkVerity(const std::string& filePath, - const ::android::base::unique_fd& verityInputAshmem, int32_t contentSize) { + android::base::unique_fd verityInputAshmem, int32_t contentSize) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_PATH(filePath); std::lock_guard<std::recursive_mutex> lock(mLock); @@ -2799,13 +2800,13 @@ binder::Status InstalldNativeService::invalidateMounts() { std::getline(in, ignored); if (android::base::GetBoolProperty(kFuseProp, false)) { - if (target.compare(0, 17, "/mnt/pass_through") == 0) { + if (target.find(kMntFuse) == 0) { LOG(DEBUG) << "Found storage mount " << source << " at " << target; mStorageMounts[source] = target; } } else { #if !BYPASS_SDCARDFS - if (target.compare(0, 21, "/mnt/runtime/default/") == 0) { + if (target.find(kMntSdcardfs) == 0) { LOG(DEBUG) << "Found storage mount " << source << " at " << target; mStorageMounts[source] = target; } diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 2b7bf33cbc..149936dbaf 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -136,7 +136,7 @@ public: binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet, const std::unique_ptr<std::string>& outputPath); binder::Status installApkVerity(const std::string& filePath, - const ::android::base::unique_fd& verityInput, int32_t contentSize); + android::base::unique_fd verityInput, int32_t contentSize); binder::Status assertFsverityRootHashMatches(const std::string& filePath, const std::vector<uint8_t>& expectedHash); binder::Status reconcileSecondaryDexFile(const std::string& dexPath, diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp index b238dd36e3..f2abf3aea3 100644 --- a/cmds/installd/QuotaUtils.cpp +++ b/cmds/installd/QuotaUtils.cpp @@ -97,6 +97,26 @@ int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid) { } } +int64_t GetOccupiedSpaceForProjectId(const std::string& uuid, int projectId) { + const std::string device = FindQuotaDeviceForUuid(uuid); + if (device == "") { + return -1; + } + struct dqblk dq; + if (quotactl(QCMD(Q_GETQUOTA, PRJQUOTA), device.c_str(), projectId, + reinterpret_cast<char*>(&dq)) != 0) { + if (errno != ESRCH) { + PLOG(ERROR) << "Failed to quotactl " << device << " for Project ID " << projectId; + } + return -1; + } else { +#if MEASURE_DEBUG + LOG(DEBUG) << "quotactl() for Project ID " << projectId << " " << dq.dqb_curspace; +#endif + return dq.dqb_curspace; + } +} + int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) { const std::string device = FindQuotaDeviceForUuid(uuid); if (device == "") { diff --git a/cmds/installd/QuotaUtils.h b/cmds/installd/QuotaUtils.h index 9ad170fcbb..96aca0448e 100644 --- a/cmds/installd/QuotaUtils.h +++ b/cmds/installd/QuotaUtils.h @@ -35,6 +35,8 @@ int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid); /* Get the current occupied space in bytes for a gid or -1 if fails */ int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid); +/* Get the current occupied space in bytes for a project id or -1 if fails */ +int64_t GetOccupiedSpaceForProjectId(const std::string& uuid, int projectId); } // namespace installd } // namespace android diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 26e9984f11..d99bcc8d13 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -127,4 +127,6 @@ interface IInstalld { const int FLAG_USE_QUOTA = 0x1000; const int FLAG_FORCE = 0x2000; + + const int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES = 0x20000; } diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 141171bf68..ae74ac3847 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -18,6 +18,9 @@ #include <android-base/logging.h> #include <android-base/properties.h> +#include <binder/BpBinder.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> #include <binder/Stability.h> #include <cutils/android_filesystem_config.h> #include <cutils/multiuser.h> @@ -80,7 +83,7 @@ ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std:: ServiceManager::~ServiceManager() { // this should only happen in tests - for (const auto& [name, callbacks] : mNameToCallback) { + for (const auto& [name, callbacks] : mNameToRegistrationCallback) { CHECK(!callbacks.empty()) << name; for (const auto& callback : callbacks) { CHECK(callback != nullptr) << name; @@ -108,10 +111,11 @@ sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfN auto ctx = mAccess->getCallingContext(); sp<IBinder> out; + Service* service = nullptr; if (auto it = mNameToService.find(name); it != mNameToService.end()) { - const Service& service = it->second; + service = &(it->second); - if (!service.allowIsolated) { + if (!service->allowIsolated) { uid_t appid = multiuser_get_app_id(ctx.uid); bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; @@ -119,7 +123,7 @@ sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfN return nullptr; } } - out = service.binder; + out = service->binder; } if (!mAccess->canFind(ctx, name)) { @@ -130,6 +134,12 @@ sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfN tryStartService(name); } + if (out) { + // Setting this guarantee each time we hand out a binder ensures that the client-checking + // loop knows about the event even if the client immediately drops the service + service->guaranteeClient = true; + } + return out; } @@ -182,15 +192,17 @@ Status ServiceManager::addService(const std::string& name, const sp<IBinder>& bi return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } - mNameToService[name] = Service { + auto entry = mNameToService.emplace(name, Service { .binder = binder, .allowIsolated = allowIsolated, .dumpPriority = dumpPriority, - }; + .debugPid = ctx.debugPid, + }); - auto it = mNameToCallback.find(name); - if (it != mNameToCallback.end()) { + auto it = mNameToRegistrationCallback.find(name); + if (it != mNameToRegistrationCallback.end()) { for (const sp<IServiceCallback>& cb : it->second) { + entry.first->second.guaranteeClient = true; // permission checked in registerForNotifications cb->onRegistration(name, binder); } @@ -247,7 +259,7 @@ Status ServiceManager::registerForNotifications( return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } - mNameToCallback[name].push_back(callback); + mNameToRegistrationCallback[name].push_back(callback); if (auto it = mNameToService.find(name); it != mNameToService.end()) { const sp<IBinder>& binder = it->second.binder; @@ -269,9 +281,9 @@ Status ServiceManager::unregisterForNotifications( bool found = false; - auto it = mNameToCallback.find(name); - if (it != mNameToCallback.end()) { - removeCallback(IInterface::asBinder(callback), &it, &found); + auto it = mNameToRegistrationCallback.find(name); + if (it != mNameToRegistrationCallback.end()) { + removeRegistrationCallback(IInterface::asBinder(callback), &it, &found); } if (!found) { @@ -297,8 +309,8 @@ Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) { return Status::ok(); } -void ServiceManager::removeCallback(const wp<IBinder>& who, - CallbackMap::iterator* it, +void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who, + ServiceCallbackMap::iterator* it, bool* found) { std::vector<sp<IServiceCallback>>& listeners = (*it)->second; @@ -312,7 +324,7 @@ void ServiceManager::removeCallback(const wp<IBinder>& who, } if (listeners.empty()) { - *it = mNameToCallback.erase(*it); + *it = mNameToRegistrationCallback.erase(*it); } else { (*it)++; } @@ -327,8 +339,12 @@ void ServiceManager::binderDied(const wp<IBinder>& who) { } } - for (auto it = mNameToCallback.begin(); it != mNameToCallback.end();) { - removeCallback(who, &it, nullptr /*found*/); + for (auto it = mNameToRegistrationCallback.begin(); it != mNameToRegistrationCallback.end();) { + removeRegistrationCallback(who, &it, nullptr /*found*/); + } + + for (auto it = mNameToClientCallback.begin(); it != mNameToClientCallback.end();) { + removeClientCallback(who, &it); } } @@ -341,4 +357,183 @@ void ServiceManager::tryStartService(const std::string& name) { }).detach(); } -} // namespace android +Status ServiceManager::registerClientCallback(const std::string& name, const sp<IBinder>& service, + const sp<IClientCallback>& cb) { + if (cb == nullptr) { + return Status::fromExceptionCode(Status::EX_NULL_POINTER); + } + + auto ctx = mAccess->getCallingContext(); + if (!mAccess->canAdd(ctx, name)) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + auto serviceIt = mNameToService.find(name); + if (serviceIt == mNameToService.end()) { + LOG(ERROR) << "Could not add callback for nonexistent service: " << name; + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) { + LOG(WARNING) << "Only a server can register for client callbacks (for " << name << ")"; + return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION); + } + + if (serviceIt->second.binder != service) { + LOG(WARNING) << "Tried to register client callback for " << name + << " but a different service is registered under this name."; + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + if (OK != IInterface::asBinder(cb)->linkToDeath(this)) { + LOG(ERROR) << "Could not linkToDeath when adding client callback for " << name; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + + mNameToClientCallback[name].push_back(cb); + + return Status::ok(); +} + +void ServiceManager::removeClientCallback(const wp<IBinder>& who, + ClientCallbackMap::iterator* it) { + std::vector<sp<IClientCallback>>& listeners = (*it)->second; + + for (auto lit = listeners.begin(); lit != listeners.end();) { + if (IInterface::asBinder(*lit) == who) { + lit = listeners.erase(lit); + } else { + ++lit; + } + } + + if (listeners.empty()) { + *it = mNameToClientCallback.erase(*it); + } else { + (*it)++; + } +} + +ssize_t ServiceManager::Service::getNodeStrongRefCount() { + sp<BpBinder> bpBinder = binder->remoteBinder(); + if (bpBinder == nullptr) return -1; + + return ProcessState::self()->getStrongRefCountForNodeByHandle(bpBinder->handle()); +} + +void ServiceManager::handleClientCallbacks() { + for (const auto& [name, service] : mNameToService) { + handleServiceClientCallback(name); + } +} + +ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName) { + auto serviceIt = mNameToService.find(serviceName); + if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) { + return -1; + } + + Service& service = serviceIt->second; + ssize_t count = service.getNodeStrongRefCount(); + + // binder driver doesn't support this feature + if (count == -1) return count; + + bool hasClients = count > 1; // this process holds a strong count + + if (service.guaranteeClient) { + // we have no record of this client + if (!service.hasClients && !hasClients) { + sendClientCallbackNotifications(serviceName, true); + } + + // guarantee is temporary + service.guaranteeClient = false; + } + + if (hasClients && !service.hasClients) { + // client was retrieved in some other way + sendClientCallbackNotifications(serviceName, true); + } + + // there are no more clients, but the callback has not been called yet + if (!hasClients && service.hasClients) { + sendClientCallbackNotifications(serviceName, false); + } + + return count; +} + +void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, bool hasClients) { + auto serviceIt = mNameToService.find(serviceName); + if (serviceIt == mNameToService.end()) { + LOG(WARNING) << "sendClientCallbackNotifications could not find service " << serviceName; + return; + } + Service& service = serviceIt->second; + + CHECK(hasClients != service.hasClients) << "Record shows: " << service.hasClients + << " so we can't tell clients again that we have client: " << hasClients; + + LOG(INFO) << "Notifying " << serviceName << " they have clients: " << hasClients; + + auto ccIt = mNameToClientCallback.find(serviceName); + CHECK(ccIt != mNameToClientCallback.end()) + << "sendClientCallbackNotifications could not find callbacks for service "; + + for (const auto& callback : ccIt->second) { + callback->onClients(service.binder, hasClients); + } + + service.hasClients = hasClients; +} + +Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IBinder>& binder) { + if (binder == nullptr) { + return Status::fromExceptionCode(Status::EX_NULL_POINTER); + } + + auto ctx = mAccess->getCallingContext(); + if (!mAccess->canAdd(ctx, name)) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + auto serviceIt = mNameToService.find(name); + if (serviceIt == mNameToService.end()) { + LOG(WARNING) << "Tried to unregister " << name + << ", but that service wasn't registered to begin with."; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + + if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) { + LOG(WARNING) << "Only a server can unregister itself (for " << name << ")"; + return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION); + } + + sp<IBinder> storedBinder = serviceIt->second.binder; + + if (binder != storedBinder) { + LOG(WARNING) << "Tried to unregister " << name + << ", but a different service is registered under this name."; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + + int clients = handleServiceClientCallback(name); + + // clients < 0: feature not implemented or other error. Assume clients. + // Otherwise: + // - kernel driver will hold onto one refcount (during this transaction) + // - servicemanager has a refcount (guaranteed by this transaction) + // So, if clients > 2, then at least one other service on the system must hold a refcount. + if (clients < 0 || clients > 2) { + // client callbacks are either disabled or there are other clients + LOG(INFO) << "Tried to unregister " << name << " but there are clients: " << clients; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + + mNameToService.erase(name); + + return Status::ok(); +} + +} // namespace android
\ No newline at end of file diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h index 7dcdaa4661..77f52506b9 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -17,12 +17,14 @@ #pragma once #include <android/os/BnServiceManager.h> +#include <android/os/IClientCallback.h> #include <android/os/IServiceCallback.h> #include "Access.h" namespace android { +using os::IClientCallback; using os::IServiceCallback; class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { @@ -40,9 +42,13 @@ public: const sp<IServiceCallback>& callback) override; binder::Status unregisterForNotifications(const std::string& name, const sp<IServiceCallback>& callback) override; - binder::Status isDeclared(const std::string& name, bool* outReturn) override; + binder::Status isDeclared(const std::string& name, bool* outReturn) override; + binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service, + const sp<IClientCallback>& cb) override; + binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override; void binderDied(const wp<IBinder>& who) override; + void handleClientCallbacks(); protected: virtual void tryStartService(const std::string& name); @@ -52,20 +58,35 @@ private: sp<IBinder> binder; // not null bool allowIsolated; int32_t dumpPriority; + bool hasClients = false; // notifications sent on true -> false. + bool guaranteeClient = false; // forces the client check to true + pid_t debugPid = 0; // the process in which this service runs + + // the number of clients of the service, including servicemanager itself + ssize_t getNodeStrongRefCount(); }; - using CallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>; + using ServiceCallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>; + using ClientCallbackMap = std::map<std::string, std::vector<sp<IClientCallback>>>; using ServiceMap = std::map<std::string, Service>; - // removes a callback from mNameToCallback, removing it if the vector is empty + // removes a callback from mNameToRegistrationCallback, removing it if the vector is empty // this updates iterator to the next location - void removeCallback(const wp<IBinder>& who, - CallbackMap::iterator* it, + void removeRegistrationCallback(const wp<IBinder>& who, + ServiceCallbackMap::iterator* it, bool* found); + ssize_t handleServiceClientCallback(const std::string& serviceName); + // Also updates mHasClients (of what the last callback was) + void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients); + // removes a callback from mNameToClientCallback, deleting the entry if the vector is empty + // this updates the iterator to the next location + void removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it); + sp<IBinder> tryGetService(const std::string& name, bool startIfNotFound); - CallbackMap mNameToCallback; ServiceMap mNameToService; + ServiceCallbackMap mNameToRegistrationCallback; + ClientCallbackMap mNameToClientCallback; std::unique_ptr<Access> mAccess; }; diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index 4b12fc6e72..2618906261 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -18,18 +18,101 @@ #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/Status.h> +#include <sys/timerfd.h> +#include <utils/Looper.h> #include <utils/StrongPointer.h> #include "Access.h" #include "ServiceManager.h" using ::android::Access; +using ::android::sp; +using ::android::Looper; +using ::android::LooperCallback; +using ::android::ProcessState; using ::android::IPCThreadState; using ::android::ProcessState; using ::android::ServiceManager; using ::android::os::IServiceManager; using ::android::sp; +class BinderCallback : public LooperCallback { +public: + static sp<BinderCallback> setupTo(const sp<Looper>& looper) { + sp<BinderCallback> cb = new BinderCallback; + + int binder_fd = -1; + IPCThreadState::self()->setupPolling(&binder_fd); + LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd); + + // Flush after setupPolling(), to make sure the binder driver + // knows about this thread handling commands. + IPCThreadState::self()->flushCommands(); + + int ret = looper->addFd(binder_fd, + Looper::POLL_CALLBACK, + Looper::EVENT_INPUT, + cb, + nullptr /*data*/); + LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper"); + + return cb; + } + + int handleEvent(int /* fd */, int /* events */, void* /* data */) override { + IPCThreadState::self()->handlePolledCommands(); + return 1; // Continue receiving callbacks. + } +}; + +// LooperCallback for IClientCallback +class ClientCallbackCallback : public LooperCallback { +public: + static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) { + sp<ClientCallbackCallback> cb = new ClientCallbackCallback(manager); + + int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/); + LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno); + + itimerspec timespec { + .it_interval = { + .tv_sec = 5, + .tv_nsec = 0, + }, + .it_value = { + .tv_sec = 5, + .tv_nsec = 0, + }, + }; + + int timeRes = timerfd_settime(fdTimer, 0 /*flags*/, ×pec, nullptr); + LOG_ALWAYS_FATAL_IF(timeRes < 0, "Failed to timerfd_settime: res: %d err: %d", timeRes, errno); + + int addRes = looper->addFd(fdTimer, + Looper::POLL_CALLBACK, + Looper::EVENT_INPUT, + cb, + nullptr); + LOG_ALWAYS_FATAL_IF(addRes != 1, "Failed to add client callback FD to Looper"); + + return cb; + } + + int handleEvent(int fd, int /*events*/, void* /*data*/) override { + uint64_t expirations; + int ret = read(fd, &expirations, sizeof(expirations)); + if (ret != sizeof(expirations)) { + ALOGE("Read failed to callback FD: ret: %d err: %d", ret, errno); + } + + mManager->handleClientCallbacks(); + return 1; // Continue receiving callbacks. + } +private: + ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {} + sp<ServiceManager> mManager; +}; + int main(int argc, char** argv) { if (argc > 2) { LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; @@ -49,7 +132,14 @@ int main(int argc, char** argv) { IPCThreadState::self()->setTheContextObject(manager); ps->becomeContextManager(nullptr, nullptr); - IPCThreadState::self()->joinThreadPool(); + sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/); + + BinderCallback::setupTo(looper); + ClientCallbackCallback::setupTo(looper, manager); + + while(true) { + looper->pollAll(-1); + } // should not be reached return EXIT_FAILURE; diff --git a/include/android/configuration.h b/include/android/configuration.h index 331072238b..05f43407fb 100644 --- a/include/android/configuration.h +++ b/include/android/configuration.h @@ -645,10 +645,14 @@ int32_t AConfiguration_getScreenLong(AConfiguration* config); */ void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong); +#if __ANDROID_API__ >= 30 /** * Return the current ACONFIGURATION_SCREENROUND_* set in the configuration. + * + * Available since API level 30. */ -int32_t AConfiguration_getScreenRound(AConfiguration* config); +int32_t AConfiguration_getScreenRound(AConfiguration* config) __INTRODUCED_IN(30); +#endif /** * Set the current screen round in the configuration. diff --git a/include/binder/ActivityManager.h b/include/binder/ActivityManager.h deleted file mode 120000 index 018f7a50ad..0000000000 --- a/include/binder/ActivityManager.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/ActivityManager.h
\ No newline at end of file diff --git a/include/binder/AppOpsManager.h b/include/binder/AppOpsManager.h deleted file mode 120000 index 465826933c..0000000000 --- a/include/binder/AppOpsManager.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/AppOpsManager.h
\ No newline at end of file diff --git a/include/binder/BpBinder.h b/include/binder/BpBinder.h deleted file mode 120000 index bc1f3d5b3d..0000000000 --- a/include/binder/BpBinder.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/BpBinder.h
\ No newline at end of file diff --git a/include/binder/BufferedTextOutput.h b/include/binder/BufferedTextOutput.h deleted file mode 120000 index fcad4fa40f..0000000000 --- a/include/binder/BufferedTextOutput.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/BufferedTextOutput.h
\ No newline at end of file diff --git a/include/binder/Debug.h b/include/binder/Debug.h deleted file mode 120000 index d76a7f184a..0000000000 --- a/include/binder/Debug.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/Debug.h
\ No newline at end of file diff --git a/include/binder/IActivityManager.h b/include/binder/IActivityManager.h deleted file mode 120000 index 4a868e02be..0000000000 --- a/include/binder/IActivityManager.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/IActivityManager.h
\ No newline at end of file diff --git a/include/binder/IAppOpsCallback.h b/include/binder/IAppOpsCallback.h deleted file mode 120000 index d587a0c692..0000000000 --- a/include/binder/IAppOpsCallback.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/IAppOpsCallback.h
\ No newline at end of file diff --git a/include/binder/IAppOpsService.h b/include/binder/IAppOpsService.h deleted file mode 120000 index 9e1c15af8b..0000000000 --- a/include/binder/IAppOpsService.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/IAppOpsService.h
\ No newline at end of file diff --git a/include/binder/IBatteryStats.h b/include/binder/IBatteryStats.h deleted file mode 120000 index 689b540795..0000000000 --- a/include/binder/IBatteryStats.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/IBatteryStats.h
\ No newline at end of file diff --git a/include/binder/IMediaResourceMonitor.h b/include/binder/IMediaResourceMonitor.h deleted file mode 120000 index d23a4daf28..0000000000 --- a/include/binder/IMediaResourceMonitor.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/IMediaResourceMonitor.h
\ No newline at end of file diff --git a/include/binder/IPermissionController.h b/include/binder/IPermissionController.h deleted file mode 120000 index 6f33c58da8..0000000000 --- a/include/binder/IPermissionController.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/IPermissionController.h
\ No newline at end of file diff --git a/include/binder/IProcessInfoService.h b/include/binder/IProcessInfoService.h deleted file mode 120000 index be0933fde5..0000000000 --- a/include/binder/IProcessInfoService.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/IProcessInfoService.h
\ No newline at end of file diff --git a/include/binder/IResultReceiver.h b/include/binder/IResultReceiver.h deleted file mode 120000 index b10d19a1a6..0000000000 --- a/include/binder/IResultReceiver.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/IResultReceiver.h
\ No newline at end of file diff --git a/include/binder/IShellCallback.h b/include/binder/IShellCallback.h deleted file mode 120000 index 893119586f..0000000000 --- a/include/binder/IShellCallback.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/IShellCallback.h
\ No newline at end of file diff --git a/include/binder/IUidObserver.h b/include/binder/IUidObserver.h deleted file mode 120000 index 1382897a91..0000000000 --- a/include/binder/IUidObserver.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/IUidObserver.h
\ No newline at end of file diff --git a/include/binder/IpPrefix.h b/include/binder/IpPrefix.h deleted file mode 120000 index 655c774a98..0000000000 --- a/include/binder/IpPrefix.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/IpPrefix.h
\ No newline at end of file diff --git a/include/binder/MemoryBase.h b/include/binder/MemoryBase.h deleted file mode 120000 index 3fd3e994b1..0000000000 --- a/include/binder/MemoryBase.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/MemoryBase.h
\ No newline at end of file diff --git a/include/binder/PermissionController.h b/include/binder/PermissionController.h deleted file mode 120000 index b6e1928a7f..0000000000 --- a/include/binder/PermissionController.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/PermissionController.h
\ No newline at end of file diff --git a/include/binder/ProcessInfoService.h b/include/binder/ProcessInfoService.h deleted file mode 120000 index e67eb19456..0000000000 --- a/include/binder/ProcessInfoService.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/ProcessInfoService.h
\ No newline at end of file diff --git a/include/binder/SafeInterface.h b/include/binder/SafeInterface.h deleted file mode 120000 index 7cefe94d0f..0000000000 --- a/include/binder/SafeInterface.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/SafeInterface.h
\ No newline at end of file diff --git a/include/binder/TextOutput.h b/include/binder/TextOutput.h deleted file mode 120000 index 2abd209e10..0000000000 --- a/include/binder/TextOutput.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/binder/include/binder/TextOutput.h
\ No newline at end of file diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp index 64791098ee..a9c23110c9 100644 --- a/libs/adbd_auth/adbd_auth.cpp +++ b/libs/adbd_auth/adbd_auth.cpp @@ -178,6 +178,10 @@ public: this->callbacks_.key_authorized(arg, id); this->dispatched_prompt_ = std::nullopt; + + // We need to dispatch pending prompts here upon success as well, + // since we might have multiple queued prompts. + DispatchPendingPrompt(); } else if (packet[0] == 'N' && packet[1] == 'O') { CHECK_EQ(2UL, packet.length()); // TODO: Do we want a callback if the key is denied? diff --git a/libs/android_runtime_lazy/android_runtime_lazy.cpp b/libs/android_runtime_lazy/android_runtime_lazy.cpp index 98d8e8a511..8062be676d 100644 --- a/libs/android_runtime_lazy/android_runtime_lazy.cpp +++ b/libs/android_runtime_lazy/android_runtime_lazy.cpp @@ -15,6 +15,7 @@ */ #define LOG_TAG "ANDROID_RUNTIME_LAZY" #include "android_runtime/AndroidRuntime.h" +#include "android_os_Parcel.h" #include "android_util_Binder.h" #include <dlfcn.h> @@ -28,12 +29,18 @@ namespace { std::once_flag loadFlag; typedef JNIEnv* (*getJNIEnv_t)(); + +// android_util_Binder.h typedef sp<IBinder> (*ibinderForJavaObject_t)(JNIEnv* env, jobject obj); typedef jobject (*javaObjectForIBinder_t)(JNIEnv* env, const sp<IBinder>& val); +// android_os_Parcel.h +typedef Parcel* (*parcelForJavaObject_t)(JNIEnv* env, jobject obj); + getJNIEnv_t _getJNIEnv; ibinderForJavaObject_t _ibinderForJavaObject; javaObjectForIBinder_t _javaObjectForIBinder; +parcelForJavaObject_t _parcelForJavaObject; void load() { std::call_once(loadFlag, []() { @@ -64,6 +71,13 @@ void load() { ALOGW("Could not find javaObjectForIBinder."); // no return } + + _parcelForJavaObject = reinterpret_cast<parcelForJavaObject_t>( + dlsym(handle, "_ZN7android19parcelForJavaObjectEP7_JNIEnvP8_jobject")); + if (_parcelForJavaObject == nullptr) { + ALOGW("Could not find parcelForJavaObject."); + // no return + } }); } @@ -95,4 +109,12 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) { return _javaObjectForIBinder(env, val); } +Parcel* parcelForJavaObject(JNIEnv* env, jobject obj) { + load(); + if (_parcelForJavaObject == nullptr) { + return nullptr; + } + return _parcelForJavaObject(env, obj); +} + } // namespace android diff --git a/libs/android_runtime_lazy/include/android_os_Parcel.h b/libs/android_runtime_lazy/include/android_os_Parcel.h new file mode 100644 index 0000000000..19b094d02a --- /dev/null +++ b/libs/android_runtime_lazy/include/android_os_Parcel.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <binder/Parcel.h> +#include "jni.h" + +namespace android { + +// The name of this file is same with the file in frameworks/base/core/jni/ +// This is intentional to make the client use these exported functions +// in the same way with the original. + +Parcel* parcelForJavaObject(JNIEnv* env, jobject obj); + +} // namespace android diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 7ee4882b6a..079dd82ecd 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -90,6 +90,7 @@ cc_library { "IResultReceiver.cpp", "IServiceManager.cpp", "IShellCallback.cpp", + "LazyServiceRegistrar.cpp", "MemoryBase.cpp", "MemoryDealer.cpp", "MemoryHeapBase.cpp", @@ -160,6 +161,7 @@ filegroup { name: "libbinder_aidl", srcs: [ "aidl/android/content/pm/IPackageManagerNative.aidl", + "aidl/android/os/IClientCallback.aidl", "aidl/android/os/IServiceCallback.aidl", "aidl/android/os/IServiceManager.aidl", ], diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index bac8b6604b..5ca9156fb2 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -271,6 +271,8 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) std::unique_lock<std::mutex> lock(mMutex); mBinder = binder; lock.unlock(); + // Flushing here helps ensure the service's ref count remains accurate + IPCThreadState::self()->flushCommands(); mCv.notify_one(); return Status::ok(); } diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp new file mode 100644 index 0000000000..dc9482c536 --- /dev/null +++ b/libs/binder/LazyServiceRegistrar.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AidlLazyServiceRegistrar" + +#include <binder/LazyServiceRegistrar.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <android/os/BnClientCallback.h> +#include <android/os/IServiceManager.h> +#include <utils/Log.h> + +namespace android { +namespace binder { +namespace internal { + +using AidlServiceManager = android::os::IServiceManager; + +class ClientCounterCallback : public ::android::os::BnClientCallback { +public: + ClientCounterCallback() : mNumConnectedServices(0) {} + + bool registerService(const sp<IBinder>& service, const std::string& name, + bool allowIsolated, int dumpFlags); + +protected: + Status onClients(const sp<IBinder>& service, bool clients) override; + +private: + /** + * Unregisters all services that we can. If we can't unregister all, re-register other + * services. + */ + void tryShutdown(); + + /** + * Counter of the number of services that currently have at least one client. + */ + size_t mNumConnectedServices; + + struct Service { + sp<IBinder> service; + std::string name; + bool allowIsolated; + int dumpFlags; + }; + /** + * Number of services that have been registered. + */ + std::vector<Service> mRegisteredServices; +}; + +bool ClientCounterCallback::registerService(const sp<IBinder>& service, const std::string& name, + bool allowIsolated, int dumpFlags) { + auto manager = interface_cast<AidlServiceManager>( + ProcessState::self()->getContextObject(nullptr)); + + ALOGI("Registering service %s", name.c_str()); + + if (!manager->addService(name.c_str(), service, allowIsolated, dumpFlags).isOk()) { + ALOGE("Failed to register service %s", name.c_str()); + return false; + } + + if (!manager->registerClientCallback(name, service, this).isOk()) + { + ALOGE("Failed to add client callback for service %s", name.c_str()); + return false; + } + + mRegisteredServices.push_back({service, name, allowIsolated, dumpFlags}); + + return true; +} + +/** + * onClients is oneway, so no need to worry about multi-threading. Note that this means multiple + * invocations could occur on different threads however. + */ +Status ClientCounterCallback::onClients(const sp<IBinder>& service, bool clients) { + if (clients) { + mNumConnectedServices++; + } else { + mNumConnectedServices--; + } + + ALOGI("Process has %zu (of %zu available) client(s) in use after notification %s has clients: %d", + mNumConnectedServices, mRegisteredServices.size(), + String8(service->getInterfaceDescriptor()).string(), clients); + + if (mNumConnectedServices == 0) { + tryShutdown(); + } + + return Status::ok(); +} + +void ClientCounterCallback::tryShutdown() { + ALOGI("Trying to shut down the service. No clients in use for any service in process."); + + // This makes the same assumption as IServiceManager.cpp. Could dedupe if used in more places. + auto manager = interface_cast<AidlServiceManager>( + ProcessState::self()->getContextObject(nullptr)); + + auto unRegisterIt = mRegisteredServices.begin(); + for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) { + auto& entry = (*unRegisterIt); + + bool success = manager->tryUnregisterService(entry.name, entry.service).isOk(); + + if (!success) { + ALOGI("Failed to unregister service %s", entry.name.c_str()); + break; + } + } + + if (unRegisterIt == mRegisteredServices.end()) { + ALOGI("Unregistered all clients and exiting"); + exit(EXIT_SUCCESS); + } + + for (auto reRegisterIt = mRegisteredServices.begin(); reRegisterIt != unRegisterIt; + reRegisterIt++) { + auto& entry = (*reRegisterIt); + + // re-register entry + if (!registerService(entry.service, entry.name, entry.allowIsolated, entry.dumpFlags)) { + // Must restart. Otherwise, clients will never be able to get a hold of this service. + ALOGE("Bad state: could not re-register services"); + } + } +} + +} // namespace internal + +LazyServiceRegistrar::LazyServiceRegistrar() { + mClientCC = std::make_shared<internal::ClientCounterCallback>(); +} + +LazyServiceRegistrar& LazyServiceRegistrar::getInstance() { + static auto registrarInstance = new LazyServiceRegistrar(); + return *registrarInstance; +} + +status_t LazyServiceRegistrar::registerService(const sp<IBinder>& service, const std::string& name, + bool allowIsolated, int dumpFlags) { + if (!mClientCC->registerService(service, name, allowIsolated, dumpFlags)) { + return UNKNOWN_ERROR; + } + return OK; +} + +} // namespace hardware +} // namespace android
\ No newline at end of file diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index b3afd817c1..55419eb609 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -19,6 +19,9 @@ "name": "binderStabilityTest" }, { + "name": "libbinder_ndk_unit_test" + }, + { "name": "CtsNdkBinderTestCases" } ] diff --git a/libs/binder/aidl/android/os/IClientCallback.aidl b/libs/binder/aidl/android/os/IClientCallback.aidl new file mode 100644 index 0000000000..36d7ee61fb --- /dev/null +++ b/libs/binder/aidl/android/os/IClientCallback.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +/** + * @hide + */ +oneway interface IClientCallback { + /** + * This is called when there is a transition between having >= 1 clients and having 0 clients + * (or vice versa). + * + * Upon receiving hasClients false, if the process decides to exit, it is recommended to try to + * unregister using IServiceManager's tryUnregister before quitting in case another client + * associates. + * + * @param registered binder 'server' registered with IServiceManager's registerClientCallback + * @param hasClients whether there are currently clients + * true - when there are >= 1 clients. This must be called as soon as IServiceManager::get + * is called (no race). + * false - when there are 0 clients. This may be delayed if it is thought that another + * may be used again soon. + */ + void onClients(IBinder registered, boolean hasClients); +} diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl index b965881e7f..ff154603e4 100644 --- a/libs/binder/aidl/android/os/IServiceManager.aidl +++ b/libs/binder/aidl/android/os/IServiceManager.aidl @@ -16,6 +16,7 @@ package android.os; +import android.os.IClientCallback; import android.os.IServiceCallback; /** @@ -96,4 +97,15 @@ interface IServiceManager { * manifest. */ boolean isDeclared(@utf8InCpp String name); + + /** + * Request a callback when the number of clients of the service changes. + * Used by LazyServiceRegistrar to dynamically stop services that have no clients. + */ + void registerClientCallback(@utf8InCpp String name, IBinder service, IClientCallback callback); + + /** + * Attempt to unregister and remove a service. Will fail if the service is still in use. + */ + void tryUnregisterService(@utf8InCpp String name, IBinder service); } diff --git a/libs/binder/include/binder/Enums.h b/libs/binder/include/binder/Enums.h new file mode 100644 index 0000000000..aec6f7038d --- /dev/null +++ b/libs/binder/include/binder/Enums.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <iterator> +#include <type_traits> + +namespace android { + +namespace internal { + +// Never instantiated. Used as a placeholder for template variables. +template <typename T> +struct invalid_type; + +// AIDL generates specializations of this for enums. +template <typename EnumType, typename = std::enable_if_t<std::is_enum<EnumType>::value>> +constexpr invalid_type<EnumType> enum_values; +} // namespace internal + +// Usage: for (const auto v : enum_range<EnumType>() ) { ... } +template <typename EnumType, typename = std::enable_if_t<std::is_enum<EnumType>::value>> +struct enum_range { + constexpr auto begin() const { return std::begin(internal::enum_values<EnumType>); } + constexpr auto end() const { return std::end(internal::enum_values<EnumType>); } +}; + +} // namespace android
\ No newline at end of file diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 8d72a6b98b..79d9b79915 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -109,7 +109,27 @@ public: \ #define __IINTF_CONCAT(x, y) (x ## y) + +#ifndef DO_NOT_CHECK_MANUAL_BINDER_INTERFACES + +#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ + static_assert(internal::allowedManualInterface(NAME), \ + "b/64223827: Manually written binder interfaces are " \ + "considered error prone and frequently have bugs. " \ + "The preferred way to add interfaces is to define " \ + "an .aidl file to auto-generate the interface. If " \ + "an interface must be manually written, add its " \ + "name to the whitelist."); \ + DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ + +#else + #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ + DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ + +#endif + +#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)\ const ::android::StaticString16 \ I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));\ const ::android::String16 I##INTERFACE::descriptor( \ @@ -192,6 +212,122 @@ inline IBinder* BpInterface<INTERFACE>::onAsBinder() // ---------------------------------------------------------------------- +namespace internal { +constexpr const char* const kManualInterfaces[] = { + "android.app.IActivityManager", + "android.app.IUidObserver", + "android.drm.IDrm", + "android.dvr.IVsyncCallback", + "android.dvr.IVsyncService", + "android.gfx.tests.ICallback", + "android.gfx.tests.IIPCTest", + "android.gfx.tests.ISafeInterfaceTest", + "android.graphicsenv.IGpuService", + "android.gui.DisplayEventConnection", + "android.gui.IConsumerListener", + "android.gui.IGraphicBufferConsumer", + "android.gui.IRegionSamplingListener", + "android.gui.ITransactionComposerListener", + "android.gui.SensorEventConnection", + "android.gui.SensorServer", + "android.hardware.ICamera", + "android.hardware.ICameraClient", + "android.hardware.ICameraRecordingProxy", + "android.hardware.ICameraRecordingProxyListener", + "android.hardware.ICrypto", + "android.hardware.IOMXObserver", + "android.hardware.ISoundTrigger", + "android.hardware.ISoundTriggerClient", + "android.hardware.ISoundTriggerHwService", + "android.hardware.IStreamListener", + "android.hardware.IStreamSource", + "android.input.IInputFlinger", + "android.input.ISetInputWindowsListener", + "android.media.IAudioFlinger", + "android.media.IAudioFlingerClient", + "android.media.IAudioPolicyService", + "android.media.IAudioPolicyServiceClient", + "android.media.IAudioService", + "android.media.IAudioTrack", + "android.media.IDataSource", + "android.media.IDrmClient", + "android.media.IEffect", + "android.media.IEffectClient", + "android.media.IMediaAnalyticsService", + "android.media.IMediaCodecList", + "android.media.IMediaDrmService", + "android.media.IMediaExtractor", + "android.media.IMediaExtractorService", + "android.media.IMediaHTTPConnection", + "android.media.IMediaHTTPService", + "android.media.IMediaLogService", + "android.media.IMediaMetadataRetriever", + "android.media.IMediaPlayer", + "android.media.IMediaPlayerClient", + "android.media.IMediaPlayerService", + "android.media.IMediaRecorder", + "android.media.IMediaRecorderClient", + "android.media.IMediaResourceMonitor", + "android.media.IMediaSource", + "android.media.IRemoteDisplay", + "android.media.IRemoteDisplayClient", + "android.media.IResourceManagerClient", + "android.media.IResourceManagerService", + "android.os.IComplexTypeInterface", + "android.os.IPermissionController", + "android.os.IPingResponder", + "android.os.IPowerManager", + "android.os.IProcessInfoService", + "android.os.ISchedulingPolicyService", + "android.os.IStringConstants", + "android.os.storage.IObbActionListener", + "android.os.storage.IStorageEventListener", + "android.os.storage.IStorageManager", + "android.os.storage.IStorageShutdownObserver", + "android.service.vr.IPersistentVrStateCallbacks", + "android.service.vr.IVrManager", + "android.service.vr.IVrStateCallbacks", + "android.ui.ISurfaceComposer", + "android.ui.ISurfaceComposerClient", + "android.utils.IMemory", + "android.utils.IMemoryHeap", + "com.android.car.procfsinspector.IProcfsInspector", + "com.android.internal.app.IAppOpsCallback", + "com.android.internal.app.IAppOpsService", + "com.android.internal.app.IBatteryStats", + "com.android.internal.os.IResultReceiver", + "com.android.internal.os.IShellCallback", + "drm.IDrmManagerService", + "drm.IDrmServiceListener", + "IAAudioClient", + "IAAudioService", + "VtsFuzzer", + nullptr, +}; + +constexpr const char* const kDownstreamManualInterfaces[] = { + // Add downstream interfaces here. + nullptr, +}; + +constexpr bool equals(const char* a, const char* b) { + if (*a != *b) return false; + if (*a == '\0') return true; + return equals(a + 1, b + 1); +} + +constexpr bool inList(const char* a, const char* const* whitelist) { + if (*whitelist == nullptr) return false; + if (equals(a, *whitelist)) return true; + return inList(a, whitelist + 1); +} + +constexpr bool allowedManualInterface(const char* name) { + return inList(name, kManualInterfaces) || + inList(name, kDownstreamManualInterfaces); +} + +} // namespace internal } // namespace android #endif // ANDROID_IINTERFACE_H diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h new file mode 100644 index 0000000000..efdecc4eca --- /dev/null +++ b/libs/binder/include/binder/LazyServiceRegistrar.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <binder/IServiceManager.h> +#include <binder/Status.h> +#include <utils/StrongPointer.h> + +namespace android { +namespace binder { +namespace internal { +class ClientCounterCallback; +} // namespace internal + +/** Exits when all services registered through this object have 0 clients */ +class LazyServiceRegistrar { + public: + static LazyServiceRegistrar& getInstance(); + status_t registerService(const sp<IBinder>& service, + const std::string& name = "default", + bool allowIsolated = false, + int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT); + + private: + std::shared_ptr<internal::ClientCounterCallback> mClientCC; + LazyServiceRegistrar(); +}; + +} // namespace binder +} // namespace android
\ No newline at end of file diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index c0ea6d7b1e..e66e425aee 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -50,6 +50,7 @@ cc_library_shared { "ibinder.cpp", "ibinder_jni.cpp", "parcel.cpp", + "parcel_jni.cpp", "process.cpp", "stability.cpp", "status.cpp", diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h index 946ccb79a5..2b61cf18c2 100644 --- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h @@ -34,6 +34,7 @@ #include <unistd.h> #include <cstddef> +#include <string> namespace ndk { @@ -228,6 +229,13 @@ class ScopedAStatus : public impl::ScopedAResource<AStatus*, void, AStatus_delet */ const char* getMessage() const { return AStatus_getMessage(get()); } + std::string getDescription() const { + const char* cStr = AStatus_getDescription(get()); + std::string ret = cStr; + AStatus_deleteDescription(cStr); + return ret; + } + /** * Convenience methods for creating scoped statuses. */ diff --git a/libs/binder/ndk/include_ndk/android/binder_enums.h b/libs/binder/ndk/include_ndk/android/binder_enums.h new file mode 100644 index 0000000000..ee819c0b23 --- /dev/null +++ b/libs/binder/ndk/include_ndk/android/binder_enums.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup NdkBinder + * @{ + */ + +/** + * @file binder_enums.h + * @brief Helpers for AIDL enum types. + */ + +#pragma once + +#include <iterator> +#include <type_traits> + +namespace ndk { + +namespace internal { +/** + * Never instantiated. Used as a placeholder for template variables. + */ +template <typename T> +struct invalid_type; + +/** + * AIDL generates specializations of this for enums. + */ +template <typename EnumType, typename = std::enable_if_t<std::is_enum<EnumType>::value>> +constexpr invalid_type<EnumType> enum_values; +} // namespace internal + +/** + * Iterable interface to enumerate all values of AIDL enum types. + */ +template <typename EnumType, typename = std::enable_if_t<std::is_enum<EnumType>::value>> +struct enum_range { + /** + * Return an iterator pointing to the first enum value. + */ + constexpr auto begin() const { return std::begin(internal::enum_values<EnumType>); } + /** + * Return an iterator pointing to one past the last enum value. + */ + constexpr auto end() const { return std::end(internal::enum_values<EnumType>); } +}; + +} // namespace ndk + +/** @} */
\ No newline at end of file diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h index be3029c3ff..cd1ff1fd79 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h @@ -36,13 +36,13 @@ __BEGIN_DECLS /** * Converts an android.os.IBinder object into an AIBinder* object. * - * If either env or the binder is null, null is returned. If this binder object was originally an + * If the binder is null, null is returned. If this binder object was originally an * AIBinder object, the original object is returned. The returned object has one refcount * associated with it, and so this should be accompanied with an AIBinder_decStrong call. * * Available since API level 29. * - * \param env Java environment. + * \param env Java environment. Must not be null. * \param binder android.os.IBinder java object. * * \return an AIBinder object representing the Java binder object. If either parameter is null, or @@ -54,12 +54,12 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* en /** * Converts an AIBinder* object into an android.os.IBinder object. * - * If either env or the binder is null, null is returned. If this binder object was originally an - * IBinder object, the original java object will be returned. + * If the binder is null, null is returned. If this binder object was originally an IBinder object, + * the original java object will be returned. * * Available since API level 29. * - * \param env Java environment. + * \param env Java environment. Must not be null. * \param binder the object to convert. * * \return an android.os.IBinder object or null if the parameters were null. diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h b/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h new file mode 100644 index 0000000000..65e1704439 --- /dev/null +++ b/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +/** + * @addtogroup NdkBinder + * @{ + */ + +/** + * @file binder_parcel_jni.h + * @brief Conversions between AParcel and android.os.Parcel + */ + +#pragma once + +#include <android/binder_parcel.h> + +#include <jni.h> + +__BEGIN_DECLS +#if __ANDROID_API__ >= 30 + +/** + * Converts an android.os.Parcel object into an AParcel* object. + * + * If the parcel is null, null is returned. + * + * Available since API level 30. + * + * \param env Java environment. Must not be null. + * \param parcel android.os.Parcel java object. + * + * \return an AParcel object representing the Java parcel object. If either parameter is null, this + * will return null. This must be deleted with AParcel_delete. This does not take ownership of the + * jobject and is only good for as long as the jobject is alive. + */ +__attribute__((warn_unused_result)) AParcel* AParcel_fromJavaParcel(JNIEnv* env, jobject parcel) + __INTRODUCED_IN(30); + +#endif //__ANDROID_API__ >= 30 +__END_DECLS + +/** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h index 787166762b..df5df13c19 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h @@ -421,13 +421,76 @@ static inline binder_status_t AParcel_readVector( } /** + * Convenience API for writing a non-null parcelable. + */ +template <typename P> +static inline binder_status_t AParcel_writeParcelable(AParcel* parcel, const P& p) { + binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null + if (status != STATUS_OK) { + return status; + } + return p.writeToParcel(parcel); +} + +/** + * Convenience API for reading a non-null parcelable. + */ +template <typename P> +static inline binder_status_t AParcel_readParcelable(const AParcel* parcel, P* p) { + int32_t null; + binder_status_t status = AParcel_readInt32(parcel, &null); + if (status != STATUS_OK) { + return status; + } + if (null == 0) { + return STATUS_UNEXPECTED_NULL; + } + return p->readFromParcel(parcel); +} + +/** + * Convenience API for writing a nullable parcelable. + */ +template <typename P> +static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel, + const std::optional<P>& p) { + if (p == std::nullopt) { + return AParcel_writeInt32(parcel, 0); // null + } + binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null + if (status != STATUS_OK) { + return status; + } + return p->writeToParcel(parcel); +} + +/** + * Convenience API for reading a nullable parcelable. + */ +template <typename P> +static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel, + std::optional<P>* p) { + int32_t null; + binder_status_t status = AParcel_readInt32(parcel, &null); + if (status != STATUS_OK) { + return status; + } + if (null == 0) { + *p = std::nullopt; + return STATUS_OK; + } + *p = std::optional<P>(P{}); + return (*p)->readFromParcel(parcel); +} + +/** * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'. */ template <typename P> binder_status_t AParcel_writeStdVectorParcelableElement(AParcel* parcel, const void* vectorData, size_t index) { const std::vector<P>* vector = static_cast<const std::vector<P>*>(vectorData); - return vector->at(index).writeToParcel(parcel); + return AParcel_writeParcelable(parcel, vector->at(index)); } /** @@ -437,7 +500,7 @@ template <typename P> binder_status_t AParcel_readStdVectorParcelableElement(const AParcel* parcel, void* vectorData, size_t index) { std::vector<P>* vector = static_cast<std::vector<P>*>(vectorData); - return vector->at(index).readFromParcel(parcel); + return AParcel_readParcelable(parcel, &vector->at(index)); } /** diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h index 78d70f87ba..ab9a144c53 100644 --- a/libs/binder/ndk/include_ndk/android/binder_status.h +++ b/libs/binder/ndk/include_ndk/android/binder_status.h @@ -247,6 +247,25 @@ binder_status_t AStatus_getStatus(const AStatus* status) __INTRODUCED_IN(29); const char* AStatus_getMessage(const AStatus* status) __INTRODUCED_IN(29); /** + * Get human-readable description for debugging. + * + * Available since API level 30. + * + * \param status the status being queried. + * + * \return a description, must be deleted with AStatus_deleteDescription. + */ +__attribute__((warn_unused_result)) const char* AStatus_getDescription(const AStatus* status) + __INTRODUCED_IN(30); + +/** + * Delete description. + * + * \param description value from AStatus_getDescription + */ +void AStatus_deleteDescription(const char* description) __INTRODUCED_IN(30); + +/** * Deletes memory associated with the status instance. * * Available since API level 29. diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index d59d6e42c6..f3158d7e18 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -103,6 +103,9 @@ LIBBINDER_NDK30 { # introduced=30 global: AIBinder_getExtension; AIBinder_setExtension; + AStatus_getDescription; + AStatus_deleteDescription; + AParcel_fromJavaParcel; AIBinder_markSystemStability; # apex AIBinder_markVendorStability; # llndk diff --git a/libs/binder/ndk/parcel_jni.cpp b/libs/binder/ndk/parcel_jni.cpp new file mode 100644 index 0000000000..53b2d7c4da --- /dev/null +++ b/libs/binder/ndk/parcel_jni.cpp @@ -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. + */ + +#include <android/binder_parcel_jni.h> +#include "parcel_internal.h" + +#include <android_os_Parcel.h> + +using ::android::Parcel; +using ::android::parcelForJavaObject; + +AParcel* AParcel_fromJavaParcel(JNIEnv* env, jobject jbinder) { + if (jbinder == nullptr) { + return nullptr; + } + + Parcel* parcel = parcelForJavaObject(env, jbinder); + + if (parcel == nullptr) { + return nullptr; + } + + return new AParcel(nullptr /*binder*/, parcel, false /*shouldOwn*/); +} diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh deleted file mode 100755 index a0c49fb167..0000000000 --- a/libs/binder/ndk/runtests.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (C) 2018 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -if [ -z $ANDROID_BUILD_TOP ]; then - echo "You need to source and lunch before you can use this script" - exit 1 -fi - -set -ex - -function run_libbinder_ndk_test() { - adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server & - - # avoid getService 1s delay for most runs, non-critical - sleep 0.1 - - adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \ - adb shell killall libbinder_ndk_test_server -} - -[ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \ - MODULES-IN-frameworks-native-libs-binder-ndk - -adb root -adb wait-for-device -adb sync data - -# very simple unit tests, tests things outside of the NDK as well -run_libbinder_ndk_test - -# CTS tests (much more comprehensive, new tests should ideally go here) -atest android.binder.cts diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp index 1f75b0b05d..87e1341f36 100644 --- a/libs/binder/ndk/status.cpp +++ b/libs/binder/ndk/status.cpp @@ -66,6 +66,17 @@ const char* AStatus_getMessage(const AStatus* status) { return status->get()->exceptionMessage().c_str(); } +const char* AStatus_getDescription(const AStatus* status) { + android::String8 description = status->get()->toString8(); + char* cStr = new char[description.size() + 1]; + memcpy(cStr, description.c_str(), description.size() + 1); + return cStr; +} + +void AStatus_deleteDescription(const char* description) { + delete[] const_cast<char*>(description); +} + void AStatus_delete(AStatus* status) { delete status; } diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp index ebd08b2f71..8c8382d600 100644 --- a/libs/binder/ndk/test/Android.bp +++ b/libs/binder/ndk/test/Android.bp @@ -56,16 +56,10 @@ cc_defaults { // specifically the parts which are outside of the NDK. Actual users should // also instead use AIDL to generate these stubs. See android.binder.cts. cc_test { - name: "libbinder_ndk_test_client", + name: "libbinder_ndk_unit_test", defaults: ["test_libbinder_ndk_test_defaults"], - srcs: ["main_client.cpp"], -} - -cc_test { - name: "libbinder_ndk_test_server", - defaults: ["test_libbinder_ndk_test_defaults"], - srcs: ["main_server.cpp"], - gtest: false, + srcs: ["libbinder_ndk_unit_test.cpp"], + test_suites: ["general-tests"], } cc_test { @@ -85,13 +79,12 @@ cc_test { "libbinder_ndk", "libutils", ], - test_suites: ["device-tests"], + test_suites: ["general-tests"], } aidl_interface { name: "IBinderVendorDoubleLoadTest", - // TODO(b/119771576): only vendor is needed - vendor_available: true, + vendor: true, srcs: [ "IBinderVendorDoubleLoadTest.aidl", ], diff --git a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp index d3ccdc2878..ad78e319a2 100644 --- a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp +++ b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp @@ -105,7 +105,8 @@ TEST(DoubleBinder, CallIntoNdk) { std::string outString; ScopedAStatus status = server->RepeatString("foo", &outString); - EXPECT_EQ(STATUS_OK, AStatus_getExceptionCode(status.get())) << serviceName; + EXPECT_EQ(STATUS_OK, AStatus_getExceptionCode(status.get())) + << serviceName << " " << status.getDescription(); EXPECT_EQ("foo", outString) << serviceName; } } diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp index 8467734c75..8aba411101 100644 --- a/libs/binder/ndk/test/main_client.cpp +++ b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp @@ -21,6 +21,7 @@ #include <gtest/gtest.h> #include <iface/iface.h> +#include <sys/prctl.h> #include <chrono> #include <condition_variable> #include <mutex> @@ -29,6 +30,34 @@ using ::android::sp; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; +class MyFoo : public IFoo { + binder_status_t doubleNumber(int32_t in, int32_t* out) override { + *out = 2 * in; + LOG(INFO) << "doubleNumber (" << in << ") => " << *out; + return STATUS_OK; + } + + binder_status_t die() override { + LOG(FATAL) << "IFoo::die called!"; + return STATUS_UNKNOWN_ERROR; + } +}; + +int service(const char* instance) { + ABinderProcess_setThreadPoolMaxThreadCount(0); + + // Strong reference to MyFoo kept by service manager. + binder_status_t status = (new MyFoo)->addService(instance); + + if (status != STATUS_OK) { + LOG(FATAL) << "Could not register: " << status << " " << instance; + } + + ABinderProcess_joinThreadPool(); + + return 1; // should not return +} + // This is too slow // TEST(NdkBinder, GetServiceThatDoesntExist) { // sp<IFoo> foo = IFoo::getService("asdfghkl;"); @@ -87,14 +116,14 @@ TEST(NdkBinder, DeathRecipient) { EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die()); foo = nullptr; - AIBinder_decStrong(binder); - binder = nullptr; std::unique_lock<std::mutex> lock(deathMutex); EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; })); EXPECT_TRUE(deathRecieved); AIBinder_DeathRecipient_delete(recipient); + AIBinder_decStrong(binder); + binder = nullptr; } TEST(NdkBinder, RetrieveNonNdkService) { @@ -199,6 +228,15 @@ TEST(NdkBinder, AddServiceMultipleTimes) { int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); + if (fork() == 0) { + prctl(PR_SET_PDEATHSIG, SIGHUP); + return service(IFoo::kInstanceNameToDieFor); + } + if (fork() == 0) { + prctl(PR_SET_PDEATHSIG, SIGHUP); + return service(IFoo::kSomeInstanceName); + } + ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks ABinderProcess_startThreadPool(); diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp deleted file mode 100644 index a6e17e8d98..0000000000 --- a/libs/binder/ndk/test/main_server.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <android-base/logging.h> -#include <android/binder_process.h> -#include <iface/iface.h> - -using ::android::sp; - -class MyFoo : public IFoo { - binder_status_t doubleNumber(int32_t in, int32_t* out) override { - *out = 2 * in; - LOG(INFO) << "doubleNumber (" << in << ") => " << *out; - return STATUS_OK; - } - - binder_status_t die() override { - LOG(FATAL) << "IFoo::die called!"; - return STATUS_UNKNOWN_ERROR; - } -}; - -int service(const char* instance) { - ABinderProcess_setThreadPoolMaxThreadCount(0); - - // Strong reference to MyFoo kept by service manager. - binder_status_t status = (new MyFoo)->addService(instance); - - if (status != STATUS_OK) { - LOG(FATAL) << "Could not register: " << status << " " << instance; - } - - ABinderProcess_joinThreadPool(); - - return 1; // should not return -} - -int main() { - if (fork() == 0) { - return service(IFoo::kInstanceNameToDieFor); - } - - return service(IFoo::kSomeInstanceName); -} diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp index 28cb13827d..b1943a4afd 100644 --- a/libs/cputimeinstate/Android.bp +++ b/libs/cputimeinstate/Android.bp @@ -8,19 +8,26 @@ cc_library { "liblog", "libnetdutils" ], + header_libs: ["bpf_prog_headers"], cflags: [ "-Werror", "-Wall", "-Wextra", ], + export_include_dirs: ["."], } cc_test { name: "libtimeinstate_test", srcs: ["testtimeinstate.cpp"], shared_libs: [ + "libbase", + "libbpf", + "libbpf_android", "libtimeinstate", + "libnetdutils", ], + header_libs: ["bpf_prog_headers"], cflags: [ "-Werror", "-Wall", diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 5fd4a95d7b..1465296bac 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -17,12 +17,16 @@ #define LOG_TAG "libtimeinstate" #include "cputimeinstate.h" +#include <bpf_timeinstate.h> #include <dirent.h> #include <errno.h> #include <inttypes.h> +#include <sys/sysinfo.h> #include <mutex> +#include <numeric> +#include <optional> #include <set> #include <string> #include <unordered_map> @@ -37,44 +41,38 @@ #include <libbpf.h> #include <log/log.h> -#define BPF_FS_PATH "/sys/fs/bpf/" - using android::base::StringPrintf; using android::base::unique_fd; namespace android { namespace bpf { -struct time_key_t { - uint32_t uid; - uint32_t freq; -}; - -struct val_t { - uint64_t ar[100]; -}; - static std::mutex gInitializedMutex; static bool gInitialized = false; +static std::mutex gTrackingMutex; +static bool gTracking = false; static uint32_t gNPolicies = 0; +static uint32_t gNCpus = 0; static std::vector<std::vector<uint32_t>> gPolicyFreqs; static std::vector<std::vector<uint32_t>> gPolicyCpus; static std::set<uint32_t> gAllFreqs; -static unique_fd gMapFd; +static unique_fd gTisMapFd; +static unique_fd gConcurrentMapFd; -static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) { +static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) { std::string data; - if (!android::base::ReadFileToString(path, &data)) return false; + if (!android::base::ReadFileToString(path, &data)) return {}; auto strings = android::base::Split(data, " \n"); + std::vector<uint32_t> ret; for (const auto &s : strings) { if (s.empty()) continue; uint32_t n; - if (!android::base::ParseUint(s, &n)) return false; - out->emplace_back(n); + if (!android::base::ParseUint(s, &n)) return {}; + ret.emplace_back(n); } - return true; + return ret; } static int isPolicyFile(const struct dirent *d) { @@ -89,10 +87,22 @@ static int comparePolicyFiles(const struct dirent **d1, const struct dirent **d2 return policyN1 - policyN2; } +static int bpf_obj_get_wronly(const char *pathname) { + union bpf_attr attr; + + memset(&attr, 0, sizeof(attr)); + attr.pathname = ptr_to_u64((void *)pathname); + attr.file_flags = BPF_F_WRONLY; + + return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr)); +} + static bool initGlobals() { std::lock_guard<std::mutex> guard(gInitializedMutex); if (gInitialized) return true; + gNCpus = get_nprocs_conf(); + struct dirent **dirlist; const char basepath[] = "/sys/devices/system/cpu/cpufreq"; int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles); @@ -111,21 +121,28 @@ static bool initGlobals() { for (const auto &name : {"available", "boost"}) { std::string path = StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name); - if (!readNumbersFromFile(path, &freqs)) return false; + auto nums = readNumbersFromFile(path); + if (!nums) continue; + freqs.insert(freqs.end(), nums->begin(), nums->end()); } + if (freqs.empty()) return false; std::sort(freqs.begin(), freqs.end()); gPolicyFreqs.emplace_back(freqs); for (auto freq : freqs) gAllFreqs.insert(freq); - std::vector<uint32_t> cpus; std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus"); - if (!readNumbersFromFile(path, &cpus)) return false; - gPolicyCpus.emplace_back(cpus); + auto cpus = readNumbersFromFile(path); + if (!cpus) return false; + gPolicyCpus.emplace_back(*cpus); } - gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")}; - if (gMapFd < 0) return false; + gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")}; + if (gTisMapFd < 0) return false; + + gConcurrentMapFd = + unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")}; + if (gConcurrentMapFd < 0) return false; gInitialized = true; return true; @@ -145,97 +162,289 @@ static bool attachTracepointProgram(const std::string &eventType, const std::str // process dies then it must be called again to resume tracking. // This function should *not* be called while tracking is already active; doing so is unnecessary // and can lead to accounting errors. -bool startTrackingUidCpuFreqTimes() { - return attachTracepointProgram("sched", "sched_switch") && +bool startTrackingUidTimes() { + std::lock_guard<std::mutex> guard(gTrackingMutex); + if (!initGlobals()) return false; + if (gTracking) return true; + + unique_fd cpuPolicyFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_policy_map")); + if (cpuPolicyFd < 0) return false; + + for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) { + for (auto &cpu : gPolicyCpus[i]) { + if (writeToMapEntry(cpuPolicyFd, &cpu, &i, BPF_ANY)) return false; + } + } + + unique_fd freqToIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_freq_to_idx_map")); + if (freqToIdxFd < 0) return false; + freq_idx_key_t key; + for (uint32_t i = 0; i < gNPolicies; ++i) { + key.policy = i; + for (uint32_t j = 0; j < gPolicyFreqs[i].size(); ++j) { + key.freq = gPolicyFreqs[i][j]; + // Start indexes at 1 so that uninitialized state is distinguishable from lowest freq. + // The uid_times map still uses 0-based indexes, and the sched_switch program handles + // conversion between them, so this does not affect our map reading code. + uint32_t idx = j + 1; + if (writeToMapEntry(freqToIdxFd, &key, &idx, BPF_ANY)) return false; + } + } + + unique_fd cpuLastUpdateFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_last_update_map")); + if (cpuLastUpdateFd < 0) return false; + std::vector<uint64_t> zeros(get_nprocs_conf(), 0); + uint32_t zero = 0; + if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false; + + unique_fd nrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_nr_active_map")); + if (nrActiveFd < 0) return false; + if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false; + + unique_fd policyNrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_nr_active_map")); + if (policyNrActiveFd < 0) return false; + for (uint32_t i = 0; i < gNPolicies; ++i) { + if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false; + } + + unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map")); + if (policyFreqIdxFd < 0) return false; + for (uint32_t i = 0; i < gNPolicies; ++i) { + if (writeToMapEntry(policyFreqIdxFd, &i, &zero, BPF_ANY)) return false; + } + + gTracking = attachTracepointProgram("sched", "sched_switch") && attachTracepointProgram("power", "cpu_frequency"); + return gTracking; } -// Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes. -// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors -// using the format: +std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs() { + if (!gInitialized && !initGlobals()) return {}; + return gPolicyFreqs; +} + +// Retrieve the times in ns that uid spent running at each CPU frequency. +// Return contains no value on error, otherwise it contains a vector of vectors using the format: // [[t0_0, t0_1, ...], // [t1_0, t1_1, ...], ...] // where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq. -bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTimes) { - if (!gInitialized && !initGlobals()) return false; - time_key_t key = {.uid = uid, .freq = 0}; - - freqTimes->clear(); - freqTimes->resize(gNPolicies); - std::vector<uint32_t> idxs(gNPolicies, 0); - - val_t value; - for (uint32_t freq : gAllFreqs) { - key.freq = freq; - int ret = findMapEntry(gMapFd, &key, &value); - if (ret) { - if (errno == ENOENT) - memset(&value.ar, 0, sizeof(value.ar)); - else - return false; +std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid) { + if (!gInitialized && !initGlobals()) return {}; + + std::vector<std::vector<uint64_t>> out; + uint32_t maxFreqCount = 0; + for (const auto &freqList : gPolicyFreqs) { + if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size(); + out.emplace_back(freqList.size(), 0); + } + + std::vector<tis_val_t> vals(gNCpus); + time_key_t key = {.uid = uid}; + for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) { + key.bucket = i; + if (findMapEntry(gTisMapFd, &key, vals.data())) { + if (errno != ENOENT) return {}; + continue; } - for (uint32_t i = 0; i < gNPolicies; ++i) { - if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue; - uint64_t time = 0; - for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu]; - idxs[i] += 1; - (*freqTimes)[i].emplace_back(time); + + auto offset = i * FREQS_PER_ENTRY; + auto nextOffset = (i + 1) * FREQS_PER_ENTRY; + for (uint32_t j = 0; j < gNPolicies; ++j) { + if (offset >= gPolicyFreqs[j].size()) continue; + auto begin = out[j].begin() + offset; + auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY : out[j].end(); + + for (const auto &cpu : gPolicyCpus[j]) { + std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus<uint64_t>()); + } } } - return true; + return out; } -// Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap. -// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to -// vectors of vectors using the format: +// Retrieve the times in ns that each uid spent running at each CPU freq. +// Return contains no value on error, otherwise it contains a map from uids to vectors of vectors +// using the format: // { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...], // uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... } // where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq. -bool getUidsCpuFreqTimes( - std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *freqTimeMap) { - if (!gInitialized && !initGlobals()) return false; +std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> +getUidsCpuFreqTimes() { + if (!gInitialized && !initGlobals()) return {}; + time_key_t key, prevKey; + std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map; + if (getFirstMapKey(gTisMapFd, &key)) { + if (errno == ENOENT) return map; + return std::nullopt; + } - int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times"); - if (fd < 0) return false; - BpfMap<time_key_t, val_t> m(fd); + std::vector<std::vector<uint64_t>> mapFormat; + for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0); - std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs; - for (uint32_t i = 0; i < gNPolicies; ++i) { - std::unordered_map<uint32_t, uint32_t> freqIdxs; - for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j; - policyFreqIdxs.emplace_back(freqIdxs); + std::vector<tis_val_t> vals(gNCpus); + do { + if (findMapEntry(gTisMapFd, &key, vals.data())) return {}; + if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat); + + auto offset = key.bucket * FREQS_PER_ENTRY; + auto nextOffset = (key.bucket + 1) * FREQS_PER_ENTRY; + for (uint32_t i = 0; i < gNPolicies; ++i) { + if (offset >= gPolicyFreqs[i].size()) continue; + auto begin = map[key.uid][i].begin() + offset; + auto end = nextOffset < gPolicyFreqs[i].size() ? begin + FREQS_PER_ENTRY : + map[key.uid][i].end(); + for (const auto &cpu : gPolicyCpus[i]) { + std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus<uint64_t>()); + } + } + prevKey = key; + } while (!getNextMapKey(gTisMapFd, &prevKey, &key)); + if (errno != ENOENT) return {}; + return map; +} + +static bool verifyConcurrentTimes(const concurrent_time_t &ct) { + uint64_t activeSum = std::accumulate(ct.active.begin(), ct.active.end(), (uint64_t)0); + uint64_t policySum = 0; + for (const auto &vec : ct.policy) { + policySum += std::accumulate(vec.begin(), vec.end(), (uint64_t)0); } + return activeSum == policySum; +} + +// Retrieve the times in ns that uid spent running concurrently with each possible number of other +// tasks on each cluster (policy times) and overall (active times). +// Return contains no value on error, otherwise it contains a concurrent_time_t with the format: +// {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...]} +// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent +// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster +std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry) { + if (!gInitialized && !initGlobals()) return {}; + concurrent_time_t ret = {.active = std::vector<uint64_t>(gNCpus, 0)}; + for (const auto &cpuList : gPolicyCpus) ret.policy.emplace_back(cpuList.size(), 0); + std::vector<concurrent_val_t> vals(gNCpus); + time_key_t key = {.uid = uid}; + for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) { + if (findMapEntry(gConcurrentMapFd, &key, vals.data())) { + if (errno != ENOENT) return {}; + continue; + } + auto offset = key.bucket * CPUS_PER_ENTRY; + auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY; - auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val, - const BpfMap<time_key_t, val_t> &) { - if (freqTimeMap->find(key.uid) == freqTimeMap->end()) { - (*freqTimeMap)[key.uid].resize(gNPolicies); - for (uint32_t i = 0; i < gNPolicies; ++i) { - (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0); + auto activeBegin = ret.active.begin() + offset; + auto activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret.active.end(); + + for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) { + std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin, + std::plus<uint64_t>()); + } + + for (uint32_t policy = 0; policy < gNPolicies; ++policy) { + if (offset >= gPolicyCpus[policy].size()) continue; + auto policyBegin = ret.policy[policy].begin() + offset; + auto policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY + : ret.policy[policy].end(); + + for (const auto &cpu : gPolicyCpus[policy]) { + std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin, + std::plus<uint64_t>()); } } + } + if (!verifyConcurrentTimes(ret) && retry) return getUidConcurrentTimes(uid, false); + return ret; +} + +// Retrieve the times in ns that each uid spent running concurrently with each possible number of +// other tasks on each cluster (policy times) and overall (active times). +// Return contains no value on error, otherwise it contains a map from uids to concurrent_time_t's +// using the format: +// { uid0 -> {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...] }, ...} +// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent +// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster. +std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes() { + if (!gInitialized && !initGlobals()) return {}; + time_key_t key, prevKey; + std::unordered_map<uint32_t, concurrent_time_t> ret; + if (getFirstMapKey(gConcurrentMapFd, &key)) { + if (errno == ENOENT) return ret; + return {}; + } + + concurrent_time_t retFormat = {.active = std::vector<uint64_t>(gNCpus, 0)}; + for (const auto &cpuList : gPolicyCpus) retFormat.policy.emplace_back(cpuList.size(), 0); + + std::vector<concurrent_val_t> vals(gNCpus); + std::vector<uint64_t>::iterator activeBegin, activeEnd, policyBegin, policyEnd; + + do { + if (findMapEntry(gConcurrentMapFd, &key, vals.data())) return {}; + if (ret.find(key.uid) == ret.end()) ret.emplace(key.uid, retFormat); + + auto offset = key.bucket * CPUS_PER_ENTRY; + auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY; + + activeBegin = ret[key.uid].active.begin(); + activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret[key.uid].active.end(); + + for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) { + std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin, + std::plus<uint64_t>()); + } + + for (uint32_t policy = 0; policy < gNPolicies; ++policy) { + if (offset >= gPolicyCpus[policy].size()) continue; + policyBegin = ret[key.uid].policy[policy].begin() + offset; + policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY + : ret[key.uid].policy[policy].end(); - for (size_t policy = 0; policy < gNPolicies; ++policy) { for (const auto &cpu : gPolicyCpus[policy]) { - auto freqIdx = policyFreqIdxs[policy][key.freq]; - (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu]; + std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin, + std::plus<uint64_t>()); } } - return android::netdutils::status::ok; - }; - return isOk(m.iterateWithValue(fn)); + prevKey = key; + } while (!getNextMapKey(gConcurrentMapFd, &prevKey, &key)); + if (errno != ENOENT) return {}; + for (const auto &[key, value] : ret) { + if (!verifyConcurrentTimes(value)) { + auto val = getUidConcurrentTimes(key, false); + if (val.has_value()) ret[key] = val.value(); + } + } + return ret; } // Clear all time in state data for a given uid. Returns false on error, true otherwise. -bool clearUidCpuFreqTimes(uint32_t uid) { +// This is only suitable for clearing data when an app is uninstalled; if called on a UID with +// running tasks it will cause time in state vs. concurrent time totals to be inconsistent for that +// UID. +bool clearUidTimes(uint32_t uid) { if (!gInitialized && !initGlobals()) return false; - time_key_t key = {.uid = uid, .freq = 0}; - std::vector<uint32_t> idxs(gNPolicies, 0); - for (auto freq : gAllFreqs) { - key.freq = freq; - if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false; + time_key_t key = {.uid = uid}; + + uint32_t maxFreqCount = 0; + for (const auto &freqList : gPolicyFreqs) { + if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size(); + } + + tis_val_t zeros = {0}; + std::vector<tis_val_t> vals(gNCpus, zeros); + for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) { + if (writeToMapEntry(gTisMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT) + return false; + if (deleteMapEntry(gTisMapFd, &key) && errno != ENOENT) return false; + } + + concurrent_val_t czeros = {.policy = {0}, .active = {0}}; + std::vector<concurrent_val_t> cvals(gNCpus, czeros); + for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) { + if (writeToMapEntry(gConcurrentMapFd, &key, cvals.data(), BPF_EXIST) && errno != ENOENT) + return false; + if (deleteMapEntry(gConcurrentMapFd, &key) && errno != ENOENT) return false; } return true; } diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h index 9f6103ed9b..49469d8e04 100644 --- a/libs/cputimeinstate/cputimeinstate.h +++ b/libs/cputimeinstate/cputimeinstate.h @@ -22,10 +22,20 @@ namespace android { namespace bpf { -bool startTrackingUidCpuFreqTimes(); -bool getUidCpuFreqTimes(unsigned int uid, std::vector<std::vector<uint64_t>> *freqTimes); -bool getUidsCpuFreqTimes(std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *tisMap); -bool clearUidCpuFreqTimes(unsigned int uid); +bool startTrackingUidTimes(); +std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid); +std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> + getUidsCpuFreqTimes(); +std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs(); + +struct concurrent_time_t { + std::vector<uint64_t> active; + std::vector<std::vector<uint64_t>> policy; +}; + +std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry = true); +std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes(); +bool clearUidTimes(unsigned int uid); } // namespace bpf } // namespace android diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 9837865dfb..23d87fd646 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -1,57 +1,381 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <bpf_timeinstate.h> + +#include <sys/sysinfo.h> + +#include <numeric> #include <unordered_map> #include <vector> #include <gtest/gtest.h> +#include <android-base/unique_fd.h> +#include <bpf/BpfMap.h> #include <cputimeinstate.h> +#include <libbpf.h> namespace android { namespace bpf { +static constexpr uint64_t NSEC_PER_SEC = 1000000000; +static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365; + using std::vector; -TEST(TimeInStateTest, SingleUid) { - vector<vector<uint64_t>> times; - ASSERT_TRUE(getUidCpuFreqTimes(0, ×)); - EXPECT_FALSE(times.empty()); +TEST(TimeInStateTest, SingleUidTimeInState) { + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + EXPECT_FALSE(times->empty()); +} + +TEST(TimeInStateTest, SingleUidConcurrentTimes) { + auto concurrentTimes = getUidConcurrentTimes(0); + ASSERT_TRUE(concurrentTimes.has_value()); + ASSERT_FALSE(concurrentTimes->active.empty()); + ASSERT_FALSE(concurrentTimes->policy.empty()); + + uint64_t policyEntries = 0; + for (const auto &policyTimeVec : concurrentTimes->policy) policyEntries += policyTimeVec.size(); + ASSERT_EQ(concurrentTimes->active.size(), policyEntries); +} + +static void TestConcurrentTimesConsistent(const struct concurrent_time_t &concurrentTime) { + size_t maxPolicyCpus = 0; + for (const auto &vec : concurrentTime.policy) { + maxPolicyCpus = std::max(maxPolicyCpus, vec.size()); + } + uint64_t policySum = 0; + for (size_t i = 0; i < maxPolicyCpus; ++i) { + for (const auto &vec : concurrentTime.policy) { + if (i < vec.size()) policySum += vec[i]; + } + ASSERT_LE(concurrentTime.active[i], policySum); + policySum -= concurrentTime.active[i]; + } + policySum = 0; + for (size_t i = 0; i < concurrentTime.active.size(); ++i) { + for (const auto &vec : concurrentTime.policy) { + if (i < vec.size()) policySum += vec[vec.size() - 1 - i]; + } + auto activeSum = concurrentTime.active[concurrentTime.active.size() - 1 - i]; + // This check is slightly flaky because we may read a map entry in the middle of an update + // when active times have been updated but policy times have not. This happens infrequently + // and can be distinguished from more serious bugs by re-running the test: if the underlying + // data itself is inconsistent, the test will fail every time. + ASSERT_LE(activeSum, policySum); + policySum -= activeSum; + } +} + +static void TestUidTimesConsistent(const std::vector<std::vector<uint64_t>> &timeInState, + const struct concurrent_time_t &concurrentTime) { + ASSERT_NO_FATAL_FAILURE(TestConcurrentTimesConsistent(concurrentTime)); + ASSERT_EQ(timeInState.size(), concurrentTime.policy.size()); + uint64_t policySum = 0; + for (uint32_t i = 0; i < timeInState.size(); ++i) { + uint64_t tisSum = + std::accumulate(timeInState[i].begin(), timeInState[i].end(), (uint64_t)0); + uint64_t concurrentSum = std::accumulate(concurrentTime.policy[i].begin(), + concurrentTime.policy[i].end(), (uint64_t)0); + if (tisSum < concurrentSum) + ASSERT_LE(concurrentSum - tisSum, NSEC_PER_SEC); + else + ASSERT_LE(tisSum - concurrentSum, NSEC_PER_SEC); + policySum += concurrentSum; + } + uint64_t activeSum = std::accumulate(concurrentTime.active.begin(), concurrentTime.active.end(), + (uint64_t)0); + EXPECT_EQ(activeSum, policySum); +} + +TEST(TimeInStateTest, SingleUidTimesConsistent) { + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + + auto concurrentTimes = getUidConcurrentTimes(0); + ASSERT_TRUE(concurrentTimes.has_value()); + + ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(*times, *concurrentTimes)); } -TEST(TimeInStateTest, AllUid) { +TEST(TimeInStateTest, AllUidTimeInState) { vector<size_t> sizes; - std::unordered_map<uint32_t, vector<vector<uint64_t>>> map; - ASSERT_TRUE(getUidsCpuFreqTimes(&map)); + auto map = getUidsCpuFreqTimes(); + ASSERT_TRUE(map.has_value()); - ASSERT_FALSE(map.empty()); + ASSERT_FALSE(map->empty()); - auto firstEntry = map.begin()->second; + auto firstEntry = map->begin()->second; for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size()); - for (const auto &vec : map) { + for (const auto &vec : *map) { ASSERT_EQ(vec.second.size(), sizes.size()); for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]); } } +TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) { + auto map = getUidsCpuFreqTimes(); + ASSERT_TRUE(map.has_value()); + ASSERT_FALSE(map->empty()); + + for (const auto &kv : *map) { + uint32_t uid = kv.first; + auto times1 = kv.second; + auto times2 = getUidCpuFreqTimes(uid); + ASSERT_TRUE(times2.has_value()); + + ASSERT_EQ(times1.size(), times2->size()); + for (uint32_t i = 0; i < times1.size(); ++i) { + ASSERT_EQ(times1[i].size(), (*times2)[i].size()); + for (uint32_t j = 0; j < times1[i].size(); ++j) { + ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC); + } + } + } +} + +TEST(TimeInStateTest, AllUidConcurrentTimes) { + auto map = getUidsConcurrentTimes(); + ASSERT_TRUE(map.has_value()); + ASSERT_FALSE(map->empty()); + + auto firstEntry = map->begin()->second; + for (const auto &kv : *map) { + ASSERT_EQ(kv.second.active.size(), firstEntry.active.size()); + ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size()); + for (size_t i = 0; i < kv.second.policy.size(); ++i) { + ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size()); + } + } +} + +TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) { + auto map = getUidsConcurrentTimes(); + ASSERT_TRUE(map.has_value()); + for (const auto &kv : *map) { + uint32_t uid = kv.first; + auto times1 = kv.second; + auto times2 = getUidConcurrentTimes(uid); + ASSERT_TRUE(times2.has_value()); + for (uint32_t i = 0; i < times1.active.size(); ++i) { + ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC); + } + for (uint32_t i = 0; i < times1.policy.size(); ++i) { + for (uint32_t j = 0; j < times1.policy[i].size(); ++j) { + ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC); + } + } + } +} + +void TestCheckDelta(uint64_t before, uint64_t after) { + // Times should never decrease + ASSERT_LE(before, after); + // UID can't have run for more than ~1s on each CPU + ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf()); +} + +TEST(TimeInStateTest, AllUidTimeInStateMonotonic) { + auto map1 = getUidsCpuFreqTimes(); + ASSERT_TRUE(map1.has_value()); + sleep(1); + auto map2 = getUidsCpuFreqTimes(); + ASSERT_TRUE(map2.has_value()); + + for (const auto &kv : *map1) { + uint32_t uid = kv.first; + auto times = kv.second; + ASSERT_NE(map2->find(uid), map2->end()); + for (uint32_t policy = 0; policy < times.size(); ++policy) { + for (uint32_t freqIdx = 0; freqIdx < times[policy].size(); ++freqIdx) { + auto before = times[policy][freqIdx]; + auto after = (*map2)[uid][policy][freqIdx]; + ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after)); + } + } + } +} + +TEST(TimeInStateTest, AllUidConcurrentTimesMonotonic) { + auto map1 = getUidsConcurrentTimes(); + ASSERT_TRUE(map1.has_value()); + ASSERT_FALSE(map1->empty()); + sleep(1); + auto map2 = getUidsConcurrentTimes(); + ASSERT_TRUE(map2.has_value()); + ASSERT_FALSE(map2->empty()); + + for (const auto &kv : *map1) { + uint32_t uid = kv.first; + auto times = kv.second; + ASSERT_NE(map2->find(uid), map2->end()); + for (uint32_t i = 0; i < times.active.size(); ++i) { + auto before = times.active[i]; + auto after = (*map2)[uid].active[i]; + ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after)); + } + for (uint32_t policy = 0; policy < times.policy.size(); ++policy) { + for (uint32_t idx = 0; idx < times.policy[policy].size(); ++idx) { + auto before = times.policy[policy][idx]; + auto after = (*map2)[uid].policy[policy][idx]; + ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after)); + } + } + } +} + +TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) { + auto map = getUidsCpuFreqTimes(); + ASSERT_TRUE(map.has_value()); + + bool foundLargeValue = false; + for (const auto &kv : *map) { + for (const auto &timeVec : kv.second) { + for (const auto &time : timeVec) { + ASSERT_LE(time, NSEC_PER_YEAR); + if (time > UINT32_MAX) foundLargeValue = true; + } + } + } + // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using + // uint64_t as expected, we should have some times higher than that. + ASSERT_TRUE(foundLargeValue); +} + +TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) { + auto concurrentMap = getUidsConcurrentTimes(); + ASSERT_TRUE(concurrentMap); + + bool activeFoundLargeValue = false; + bool policyFoundLargeValue = false; + for (const auto &kv : *concurrentMap) { + for (const auto &time : kv.second.active) { + ASSERT_LE(time, NSEC_PER_YEAR); + if (time > UINT32_MAX) activeFoundLargeValue = true; + } + for (const auto &policyTimeVec : kv.second.policy) { + for (const auto &time : policyTimeVec) { + ASSERT_LE(time, NSEC_PER_YEAR); + if (time > UINT32_MAX) policyFoundLargeValue = true; + } + } + } + // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using + // uint64_t as expected, we should have some times higher than that. + ASSERT_TRUE(activeFoundLargeValue); + ASSERT_TRUE(policyFoundLargeValue); +} + +TEST(TimeInStateTest, AllUidTimesConsistent) { + auto tisMap = getUidsCpuFreqTimes(); + ASSERT_TRUE(tisMap.has_value()); + + auto concurrentMap = getUidsConcurrentTimes(); + ASSERT_TRUE(concurrentMap.has_value()); + + ASSERT_EQ(tisMap->size(), concurrentMap->size()); + for (const auto &kv : *tisMap) { + uint32_t uid = kv.first; + auto times = kv.second; + ASSERT_NE(concurrentMap->find(uid), concurrentMap->end()); + + auto concurrentTimes = (*concurrentMap)[uid]; + ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(times, concurrentTimes)); + } +} + TEST(TimeInStateTest, RemoveUid) { - vector<vector<uint64_t>> times, times2; - ASSERT_TRUE(getUidCpuFreqTimes(0, ×)); - ASSERT_FALSE(times.empty()); + uint32_t uid = 0; + { + // Find an unused UID + auto times = getUidsCpuFreqTimes(); + ASSERT_TRUE(times.has_value()); + ASSERT_FALSE(times->empty()); + for (const auto &kv : *times) uid = std::max(uid, kv.first); + ++uid; + } + { + // Add a map entry for our fake UID by copying a real map entry + android::base::unique_fd fd{ + bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")}; + ASSERT_GE(fd, 0); + time_key_t k; + ASSERT_FALSE(getFirstMapKey(fd, &k)); + std::vector<tis_val_t> vals(get_nprocs_conf()); + ASSERT_FALSE(findMapEntry(fd, &k, vals.data())); + uint32_t copiedUid = k.uid; + k.uid = uid; + ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST)); + + android::base::unique_fd fd2{ + bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")}; + k.uid = copiedUid; + k.bucket = 0; + std::vector<concurrent_val_t> cvals(get_nprocs_conf()); + ASSERT_FALSE(findMapEntry(fd2, &k, cvals.data())); + k.uid = uid; + ASSERT_FALSE(writeToMapEntry(fd2, &k, cvals.data(), BPF_NOEXIST)); + } + auto times = getUidCpuFreqTimes(uid); + ASSERT_TRUE(times.has_value()); + ASSERT_FALSE(times->empty()); + + auto concurrentTimes = getUidConcurrentTimes(0); + ASSERT_TRUE(concurrentTimes.has_value()); + ASSERT_FALSE(concurrentTimes->active.empty()); + ASSERT_FALSE(concurrentTimes->policy.empty()); uint64_t sum = 0; - for (size_t i = 0; i < times.size(); ++i) { - for (auto x : times[i]) sum += x; + for (size_t i = 0; i < times->size(); ++i) { + for (auto x : (*times)[i]) sum += x; } ASSERT_GT(sum, (uint64_t)0); - ASSERT_TRUE(clearUidCpuFreqTimes(0)); - - ASSERT_TRUE(getUidCpuFreqTimes(0, ×2)); - ASSERT_EQ(times2.size(), times.size()); - for (size_t i = 0; i < times.size(); ++i) { - ASSERT_EQ(times2[i].size(), times[i].size()); - for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]); + uint64_t activeSum = 0; + for (size_t i = 0; i < concurrentTimes->active.size(); ++i) { + activeSum += concurrentTimes->active[i]; } + ASSERT_GT(activeSum, (uint64_t)0); + + ASSERT_TRUE(clearUidTimes(uid)); + + auto allTimes = getUidsCpuFreqTimes(); + ASSERT_TRUE(allTimes.has_value()); + ASSERT_FALSE(allTimes->empty()); + ASSERT_EQ(allTimes->find(uid), allTimes->end()); + + auto allConcurrentTimes = getUidsConcurrentTimes(); + ASSERT_TRUE(allConcurrentTimes.has_value()); + ASSERT_FALSE(allConcurrentTimes->empty()); + ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end()); +} + +TEST(TimeInStateTest, GetCpuFreqs) { + auto freqs = getCpuFreqs(); + ASSERT_TRUE(freqs.has_value()); + + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + + ASSERT_EQ(freqs->size(), times->size()); + for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size()); } } // namespace bpf diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index 250f902f9d..0ede8b1916 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -16,7 +16,9 @@ #include <set> #include <android-base/file.h> +#include <android-base/properties.h> #include <android-base/stringprintf.h> +#include <android-base/strings.h> #include <android/hidl/manager/1.0/IServiceManager.h> #include <dumputils/dump_utils.h> #include <log/log.h> @@ -32,7 +34,6 @@ static const char* native_processes_to_dump[] = { "/system/bin/mediametrics", // media.metrics "/system/bin/mediaserver", "/system/bin/netd", - "/system/bin/vold", "/system/bin/sdcard", "/system/bin/statsd", "/system/bin/surfaceflinger", @@ -42,11 +43,19 @@ static const char* native_processes_to_dump[] = { NULL, }; + +// Native processes to dump on debuggable builds. +static const char* debuggable_native_processes_to_dump[] = { + "/system/bin/vold", + NULL, +}; + /* list of hal interface to dump containing process during native dumps */ static const char* hal_interfaces_to_dump[] { "android.hardware.audio@2.0::IDevicesFactory", "android.hardware.audio@4.0::IDevicesFactory", "android.hardware.audio@5.0::IDevicesFactory", + "android.hardware.audio@6.0::IDevicesFactory", "android.hardware.biometrics.face@1.0::IBiometricsFace", "android.hardware.bluetooth@1.0::IBluetoothHci", "android.hardware.camera.provider@2.4::ICameraProvider", @@ -65,13 +74,34 @@ static const char* hal_interfaces_to_dump[] { NULL, }; -bool should_dump_hal_interface(const char* interface) { +/* list of extra hal interfaces to dump containing process during native dumps */ +// This is filled when dumpstate is called. +static std::set<const std::string> extra_hal_interfaces_to_dump; + +static void read_extra_hals_to_dump_from_property() { + // extra hals to dump are already filled + if (extra_hal_interfaces_to_dump.size() > 0) { + return; + } + std::string value = android::base::GetProperty("ro.dump.hals.extra", ""); + std::vector<std::string> tokens = android::base::Split(value, ","); + for (const auto &token : tokens) { + std::string trimmed_token = android::base::Trim(token); + if (trimmed_token.length() == 0) { + continue; + } + extra_hal_interfaces_to_dump.insert(trimmed_token); + } +} + +// check if interface is included in either default hal list or extra hal list +bool should_dump_hal_interface(const std::string& interface) { for (const char** i = hal_interfaces_to_dump; *i; i++) { - if (!strcmp(*i, interface)) { + if (interface == *i) { return true; } } - return false; + return extra_hal_interfaces_to_dump.find(interface) != extra_hal_interfaces_to_dump.end(); } bool should_dump_native_traces(const char* path) { @@ -80,6 +110,15 @@ bool should_dump_native_traces(const char* path) { return true; } } + + if (android::base::GetBoolProperty("ro.debuggable", false)) { + for (const char** p = debuggable_native_processes_to_dump; *p; p++) { + if (!strcmp(*p, path)) { + return true; + } + } + } + return false; } @@ -91,13 +130,15 @@ std::set<int> get_interesting_hal_pids() { sp<IServiceManager> manager = IServiceManager::getService(); std::set<int> pids; + read_extra_hals_to_dump_from_property(); + Return<void> ret = manager->debugDump([&](auto& hals) { for (const auto &info : hals) { if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) { continue; } - if (!should_dump_hal_interface(info.interfaceName.c_str())) { + if (!should_dump_hal_interface(info.interfaceName)) { continue; } diff --git a/libs/gralloc/OWNERS b/libs/gralloc/OWNERS new file mode 100644 index 0000000000..67743cdb0e --- /dev/null +++ b/libs/gralloc/OWNERS @@ -0,0 +1,2 @@ +marissaw@google.com +vhau@google.com diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 92ab41019e..3efb1b6acb 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -981,6 +981,17 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mGraphicBuffer.clear(); } + // Update and get FrameEventHistory. + nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC); + NewFrameEventsEntry newFrameEventsEntry = { + currentFrameNumber, + postedTime, + requestedPresentTimestamp, + std::move(acquireFenceTime) + }; + addAndGetFrameTimestamps(&newFrameEventsEntry, + getFrameTimestamps ? &output->frameTimestamps : nullptr); + // Call back without the main BufferQueue lock held, but with the callback // lock held so we can ensure that callbacks occur in order @@ -1010,17 +1021,6 @@ status_t BufferQueueProducer::queueBuffer(int slot, mCallbackCondition.notify_all(); } - // Update and get FrameEventHistory. - nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC); - NewFrameEventsEntry newFrameEventsEntry = { - currentFrameNumber, - postedTime, - requestedPresentTimestamp, - std::move(acquireFenceTime) - }; - addAndGetFrameTimestamps(&newFrameEventsEntry, - getFrameTimestamps ? &output->frameTimestamps : nullptr); - // Wait without lock held if (connectedApi == NATIVE_WINDOW_API_EGL) { // Waiting here allows for two full buffers to be queued but not a diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS index 73150dcb58..c13401dc5c 100644 --- a/libs/gui/OWNERS +++ b/libs/gui/OWNERS @@ -1,7 +1,12 @@ +adyabr@google.com +akrulec@google.com +alecmouri@google.com jessehall@google.com jwcai@google.com lpy@google.com marissaw@google.com mathias@google.com racarr@google.com +steventhomas@google.com stoza@google.com +vhau@google.com diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp index 139987e6a9..abc910302c 100644 --- a/libs/sensor/Sensor.cpp +++ b/libs/sensor/Sensor.cpp @@ -577,7 +577,8 @@ void Sensor::flattenString8(void*& buffer, size_t& size, uint32_t len = static_cast<uint32_t>(string8.length()); FlattenableUtils::write(buffer, size, len); memcpy(static_cast<char*>(buffer), string8.string(), len); - FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len)); + FlattenableUtils::advance(buffer, size, len); + size -= FlattenableUtils::align<4>(buffer); } bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& outputString8) { diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 42b578cce8..080336b890 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -32,12 +32,6 @@ cc_library_shared { sanitize: { integer_overflow: true, misc_undefined: ["bounds"], - diag: { - misc_undefined: ["bounds"], - no_recover: [ - "bounds", - ], - }, }, srcs: [ diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index f1aa89ca36..5f1c71ec4f 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -61,9 +61,9 @@ GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper:: GraphicBufferAllocator::~GraphicBufferAllocator() {} -size_t GraphicBufferAllocator::getTotalSize() const { +uint64_t GraphicBufferAllocator::getTotalSize() const { Mutex::Autolock _l(sLock); - size_t total = 0; + uint64_t total = 0; for (size_t i = 0; i < sAllocList.size(); ++i) { total += sAllocList.valueAt(i).size; } @@ -73,7 +73,7 @@ size_t GraphicBufferAllocator::getTotalSize() const { void GraphicBufferAllocator::dump(std::string& result) const { Mutex::Autolock _l(sLock); KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList); - size_t total = 0; + uint64_t total = 0; result.append("Allocated buffers:\n"); const size_t c = list.size(); for (size_t i=0 ; i<c ; i++) { diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h index 25d4512859..faec97855a 100644 --- a/libs/ui/include/ui/GraphicBufferAllocator.h +++ b/libs/ui/include/ui/GraphicBufferAllocator.h @@ -49,7 +49,7 @@ public: status_t free(buffer_handle_t handle); - size_t getTotalSize() const; + uint64_t getTotalSize() const; void dump(std::string& res) const; static void dumpToSystemLog(); diff --git a/libs/vr/OWNERS b/libs/vr/OWNERS index ec2d712ffd..098c80e557 100644 --- a/libs/vr/OWNERS +++ b/libs/vr/OWNERS @@ -1,4 +1,4 @@ hendrikw@google.com jwcai@google.com steventhomas@google.com - +patplunkett@google.com diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp index 1a9d7274a1..23a4224e05 100644 --- a/libs/vr/libpdx/Android.bp +++ b/libs/vr/libpdx/Android.bp @@ -53,6 +53,8 @@ cc_test { "libpdx", "liblog", "libutils", + ], + shared_libs: [ "libvndksupport", ], } diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index eb90c8b45b..3c741ab4fb 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -161,6 +161,10 @@ cc_library_shared { ], ldflags: ["-Wl,--exclude-libs=ALL"], export_include_dirs: ["EGL/include"], + stubs: { + symbol_file: "libEGL.map.txt", + versions: ["29"], + }, } cc_test { diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen index da9bb49495..41fcf1bd95 100755 --- a/opengl/tools/glgen/gen +++ b/opengl/tools/glgen/gen @@ -91,8 +91,8 @@ fi rm src/*.class # Add UnsupportedAppUsage.java to known sources. -mkdir -p out/android/annotation -cp ../../../../base/core/java/android/annotation/UnsupportedAppUsage.java out/android/annotation +mkdir -p out/android/compat/annotation +cp ../../../../../tools/platform-compat/annotation/src/java/android/compat/annotation/UnsupportedAppUsage.java out/android/compat/annotation pushd out > /dev/null mkdir classes @@ -114,7 +114,7 @@ javac -d classes android/opengl/EGL14.java \ android/opengl/GLES31.java \ android/opengl/GLES31Ext.java \ android/opengl/GLES32.java \ - android/annotation/UnsupportedAppUsage.java + android/compat/annotation/UnsupportedAppUsage.java popd > /dev/null JAVA_RESULT=$? if [ $JAVA_RESULT -ne 0 ]; then diff --git a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if index 12728f588f..9932556d27 100644 --- a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if +++ b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if @@ -18,7 +18,7 @@ package android.opengl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.SurfaceTexture; import android.view.Surface; import android.view.SurfaceView; diff --git a/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if index c2711aa4db..7db11015ad 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if +++ b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if @@ -19,7 +19,7 @@ package android.opengl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** OpenGL ES 2.0 */ diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS index 69d8c89b45..f2bc65db35 100644 --- a/services/surfaceflinger/OWNERS +++ b/services/surfaceflinger/OWNERS @@ -5,4 +5,6 @@ chaviw@google.com lpy@google.com marissaw@google.com racarr@google.com -stoza@google.com
\ No newline at end of file +steventhomas@google.com +stoza@google.com +vhau@google.com diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc index aea602bba4..d3942e8bbe 100644 --- a/services/surfaceflinger/surfaceflinger.rc +++ b/services/surfaceflinger/surfaceflinger.rc @@ -2,6 +2,7 @@ service surfaceflinger /system/bin/surfaceflinger class core animation user system group graphics drmrpc readproc + capabilities SYS_NICE onrestart restart zygote writepid /dev/stune/foreground/tasks socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0 diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 766d9ff8be..14191197c2 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -708,20 +708,6 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, const InstanceData& instance_data = GetData(pdev); - // TODO(jessehall): Fill out the set of supported formats. Longer term, add - // a new gralloc method to query whether a (format, usage) pair is - // supported, and check that for each gralloc format that corresponds to a - // Vulkan format. Shorter term, just add a few more formats to the ones - // hardcoded below. - - const VkSurfaceFormatKHR kFormats[] = { - {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, - {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, - {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, - }; - const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); - uint32_t total_num_formats = kNumFormats; - bool wide_color_support = false; Surface& surface = *SurfaceFromHandle(surface_handle); int err = native_window_get_wide_color_support(surface.window.get(), @@ -735,43 +721,72 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, wide_color_support && instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace); - const VkSurfaceFormatKHR kWideColorFormats[] = { - {VK_FORMAT_R8G8B8A8_UNORM, - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}, - {VK_FORMAT_R8G8B8A8_SRGB, - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}, - {VK_FORMAT_R16G16B16A16_SFLOAT, - VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT}, - {VK_FORMAT_R16G16B16A16_SFLOAT, - VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT}, - {VK_FORMAT_A2B10G10R10_UNORM_PACK32, - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}, - }; - const uint32_t kNumWideColorFormats = - sizeof(kWideColorFormats) / sizeof(kWideColorFormats[0]); + AHardwareBuffer_Desc desc = {}; + desc.width = 1; + desc.height = 1; + desc.layers = 1; + desc.usage = surface.consumer_usage | + AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | + AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER; + + // We must support R8G8B8A8 + std::vector<VkSurfaceFormatKHR> all_formats = { + {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, + {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}}; + if (wide_color_support) { - total_num_formats += kNumWideColorFormats; + all_formats.emplace_back(VkSurfaceFormatKHR{ + VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}); + all_formats.emplace_back(VkSurfaceFormatKHR{ + VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}); + } + + desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM; + if (AHardwareBuffer_isSupported(&desc)) { + all_formats.emplace_back(VkSurfaceFormatKHR{ + VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}); + } + + desc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT; + if (AHardwareBuffer_isSupported(&desc)) { + all_formats.emplace_back(VkSurfaceFormatKHR{ + VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}); + if (wide_color_support) { + all_formats.emplace_back( + VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT, + VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT}); + all_formats.emplace_back( + VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT, + VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT}); + } + } + + desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM; + if (AHardwareBuffer_isSupported(&desc)) { + all_formats.emplace_back( + VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32, + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}); + if (wide_color_support) { + all_formats.emplace_back( + VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32, + VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}); + } } VkResult result = VK_SUCCESS; if (formats) { - uint32_t out_count = 0; - uint32_t transfer_count = 0; - if (*count < total_num_formats) + uint32_t transfer_count = all_formats.size(); + if (transfer_count > *count) { + transfer_count = *count; result = VK_INCOMPLETE; - transfer_count = std::min(*count, kNumFormats); - std::copy(kFormats, kFormats + transfer_count, formats); - out_count += transfer_count; - if (wide_color_support) { - transfer_count = std::min(*count - out_count, kNumWideColorFormats); - std::copy(kWideColorFormats, kWideColorFormats + transfer_count, - formats + out_count); - out_count += transfer_count; } - *count = out_count; + std::copy(all_formats.begin(), all_formats.begin() + transfer_count, + formats); + *count = transfer_count; } else { - *count = total_num_formats; + *count = all_formats.size(); } + return result; } |