Merge "Fixing triple buffer bug"
diff --git a/cmds/installd/.gitignore b/cmds/installd/.gitignore
new file mode 100644
index 0000000..abc921c
--- /dev/null
+++ b/cmds/installd/.gitignore
@@ -0,0 +1,2 @@
+# ignore the files generated by intellij
+.idea
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 75dec37..8ff4dd8 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -13,6 +13,7 @@
srcs: [
"CacheItem.cpp",
"CacheTracker.cpp",
+ "CrateManager.cpp",
"InstalldNativeService.cpp",
"QuotaUtils.cpp",
"dexopt.cpp",
@@ -163,6 +164,7 @@
name: "installd_aidl",
srcs: [
"binder/android/os/IInstalld.aidl",
+ "binder/android/os/storage/CrateMetadata.aidl",
],
path: "binder",
}
diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp
new file mode 100644
index 0000000..344aefb
--- /dev/null
+++ b/cmds/installd/CrateManager.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#include "CrateManager.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android/log.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <string>
+#include <utils.h>
+
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+CrateManager::CrateManager(const char* uuid, userid_t userId, const std::string& packageName) {
+ mPackageName = packageName;
+ mRoot = create_data_user_ce_package_path(uuid, userId, (const char*)packageName.c_str());
+ mCratedFoldersRoot = StringPrintf("%s/crates", mRoot.c_str());
+}
+
+CrateManager::~CrateManager() {}
+
+static std::string getValidatedCratedPath(std::string path) {
+ size_t pos = path.rfind("/");
+ if (pos == std::string::npos) {
+ return path;
+ }
+
+ return path.substr(pos + 1, path.length());
+}
+
+void CrateManager::traverseChildDir(const std::string& targetDir,
+ std::function<void(FTSENT*)>& onVisitChildDir) {
+ char* argv[] = {(char*)targetDir.c_str(), nullptr};
+ FTS* fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr);
+ if (fts == nullptr) {
+ PLOG(WARNING) << "Failed to fts_open " << targetDir;
+ return;
+ }
+
+ FTSENT* p;
+ while ((p = fts_read(fts)) != nullptr) {
+ switch (p->fts_info) {
+ case FTS_D:
+ if (p->fts_level == 1) {
+ onVisitChildDir(p);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (p->fts_level == 1) {
+ fts_set(fts, p, FTS_SKIP);
+ }
+ }
+ fts_close(fts);
+}
+
+void CrateManager::traverseAllPackagesForUser(
+ const std::unique_ptr<std::string>& uuid, userid_t userId,
+ std::function<void(FTSENT*)>& onHandlingPackage) {
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ auto ce_path = create_data_user_ce_path(uuid_, userId);
+ traverseChildDir(ce_path, onHandlingPackage);
+}
+
+void CrateManager::createCrate(
+ CratedFolder cratedFolder,
+ std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate) {
+ const char* path = cratedFolder->fts_path;
+ if (path == nullptr || *path == '\0') {
+ return;
+ }
+
+ std::unique_ptr<CrateMetadata> crateMetadata = std::make_unique<CrateMetadata>();
+ crateMetadata->uid = cratedFolder->fts_statp->st_uid;
+ crateMetadata->packageName = mPackageName;
+ crateMetadata->id = getValidatedCratedPath(path);
+
+ onCreateCrate(cratedFolder, crateMetadata);
+}
+
+void CrateManager::traverseAllCrates(std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate) {
+ std::function<void(FTSENT*)> onVisitCrateDir = [&](FTSENT* cratedFolder) -> void {
+ createCrate(cratedFolder, onCreateCrate);
+ };
+ traverseChildDir(mCratedFoldersRoot, onVisitCrateDir);
+}
+
+#if CRATE_DEBUG
+void CrateManager::dump(std::unique_ptr<CrateMetadata>& CrateMetadata) {
+ LOG(DEBUG) << "CrateMetadata = {"
+ << "uid : \"" << CrateMetadata->uid
+ << "\", packageName : \"" << CrateMetadata->packageName
+ << "\", id : \"" << CrateMetadata->id
+ << "\"}";
+}
+#endif
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h
new file mode 100644
index 0000000..1776622
--- /dev/null
+++ b/cmds/installd/CrateManager.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INSTALLD_CRATE_INFO_MANAGER_H
+#define ANDROID_INSTALLD_CRATE_INFO_MANAGER_H
+
+#include <android/os/storage/CrateMetadata.h>
+#include <cutils/multiuser.h>
+#include <fts.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#ifndef CRATE_DEBUG
+#define CRATE_DEBUG 1
+#endif
+
+namespace android {
+namespace installd {
+
+using android::os::storage::CrateMetadata;
+
+/**
+ * The crated folder actually is a folder that is the first level child director. In order to
+ * distingish between the crated folder and the other FTSENT*, to define the type "CratedFolder"
+ * make the code easy to identify the difference.
+ */
+typedef FTSENT* CratedFolder;
+
+/**
+ * In order to give the users more fine-grained files controlling, the crate information can help
+ * applications' developers to show the more detail information to the users. The crate information
+ * include the Label, Expiration etc..
+ */
+class CrateManager {
+public:
+ CrateManager(const char* uuid, userid_t userId, const std::string& packageName);
+ ~CrateManager();
+
+ void traverseAllCrates(std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate);
+
+ static void traverseChildDir(const std::string& targetDir,
+ std::function<void(FTSENT*)>& onVisitChildDir);
+
+ static void traverseAllPackagesForUser(
+ const std::unique_ptr<std::string>& uuid,
+ userid_t userId,
+ std::function<void(FTSENT*)>& onHandlingPackage);
+
+#if CRATE_DEBUG
+ static void dump(std::unique_ptr<CrateMetadata>& CrateMetadata);
+#endif
+private:
+ std::string mRoot;
+ std::string mCratedFoldersRoot;
+ std::string mPackageName;
+
+ void createCrate(
+ CratedFolder cratedFolder,
+ std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate);
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_CRATE_INFO_MANAGER_H
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 8c8d94d..f8a68b4 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -31,6 +31,7 @@
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <sys/mount.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
@@ -65,6 +66,7 @@
#include "view_compiler.h"
#include "CacheTracker.h"
+#include "CrateManager.h"
#include "MatchExtensionGen.h"
#include "QuotaUtils.h"
@@ -86,6 +88,9 @@
static constexpr const char* kCpPath = "/system/bin/cp";
static constexpr const char* kXattrDefault = "user.default";
+static constexpr const char* kDataMirrorCePath = "/data_mirror/data_ce";
+static constexpr const char* kDataMirrorDePath = "/data_mirror/data_de";
+
static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
static constexpr const char* PKG_LIB_POSTFIX = "/lib";
@@ -99,6 +104,13 @@
static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
static constexpr const char* kFuseProp = "persist.sys.fuse";
+/**
+ * Property to control if app data isolation is enabled.
+ */
+static constexpr const char* kAppDataIsolationEnabledProperty = "persist.zygote.app_data_isolation";
+
+static std::atomic<bool> sAppDataIsolationEnabled(false);
+
namespace {
constexpr const char* kDump = "android.permission.DUMP";
@@ -258,6 +270,8 @@
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
+ sAppDataIsolationEnabled = android::base::GetBoolProperty(
+ kAppDataIsolationEnabledProperty, false);
return android::OK;
}
@@ -450,9 +464,12 @@
// And return the CE inode of the top-level data directory so we can
// clear contents while CE storage is locked
- if ((_aidl_return != nullptr)
- && get_path_inode(path, reinterpret_cast<ino_t*>(_aidl_return)) != 0) {
- return error("Failed to get_path_inode for " + path);
+ if (_aidl_return != nullptr) {
+ ino_t result;
+ if (get_path_inode(path, &result) != 0) {
+ return error("Failed to get_path_inode for " + path);
+ }
+ *_aidl_return = static_cast<uint64_t>(result);
}
}
if (flags & FLAG_STORAGE_DE) {
@@ -2029,6 +2046,82 @@
return ok();
}
+binder::Status InstalldNativeService::getAppCrates(
+ const std::unique_ptr<std::string>& uuid,
+ const std::vector<std::string>& packageNames, int32_t userId,
+ std::unique_ptr<std::vector<std::unique_ptr<CrateMetadata>>>* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ for (const auto& packageName : packageNames) {
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ }
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ auto retVector = std::make_unique<std::vector<std::unique_ptr<CrateMetadata>>>();
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ std::function<void(CratedFolder, std::unique_ptr<CrateMetadata> &)> onCreateCrate =
+ [&](CratedFolder cratedFolder, std::unique_ptr<CrateMetadata> &crateMetadata) -> void {
+ if (cratedFolder == nullptr) {
+ return;
+ }
+ retVector->push_back(std::move(crateMetadata));
+ };
+
+ for (const auto& packageName : packageNames) {
+#if CRATE_DEBUG
+ LOG(DEBUG) << "packageName = " << packageName;
+#endif
+ auto crateManager = std::make_unique<CrateManager>(uuid_, userId, packageName);
+ crateManager->traverseAllCrates(onCreateCrate);
+ }
+
+#if CRATE_DEBUG
+ LOG(WARNING) << "retVector->size() =" << retVector->size();
+ for (auto iter = retVector->begin(); iter != retVector->end(); ++iter) {
+ CrateManager::dump(*iter);
+ }
+#endif
+
+ *_aidl_return = std::move(retVector);
+ return ok();
+}
+
+binder::Status InstalldNativeService::getUserCrates(
+ const std::unique_ptr<std::string>& uuid, int32_t userId,
+ std::unique_ptr<std::vector<std::unique_ptr<CrateMetadata>>>* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ auto retVector = std::make_unique<std::vector<std::unique_ptr<CrateMetadata>>>();
+
+ std::function<void(CratedFolder, std::unique_ptr<CrateMetadata> &)> onCreateCrate =
+ [&](CratedFolder cratedFolder, std::unique_ptr<CrateMetadata> &crateMetadata) -> void {
+ if (cratedFolder == nullptr) {
+ return;
+ }
+ retVector->push_back(std::move(crateMetadata));
+ };
+
+ std::function<void(FTSENT*)> onHandingPackage = [&](FTSENT* packageDir) -> void {
+ auto crateManager = std::make_unique<CrateManager>(uuid_, userId, packageDir->fts_name);
+ crateManager->traverseAllCrates(onCreateCrate);
+ };
+ CrateManager::traverseAllPackagesForUser(uuid, userId, onHandingPackage);
+
+#if CRATE_DEBUG
+ LOG(DEBUG) << "retVector->size() =" << retVector->size();
+ for (auto iter = retVector->begin(); iter != retVector->end(); ++iter) {
+ CrateManager::dump(*iter);
+ }
+#endif
+
+ *_aidl_return = std::move(retVector);
+ return ok();
+}
+
binder::Status InstalldNativeService::setAppQuota(const std::unique_ptr<std::string>& uuid,
int32_t userId, int32_t appId, int64_t cacheQuota) {
ENFORCE_UID(AID_SYSTEM);
@@ -2613,6 +2706,89 @@
return ok();
}
+// Mount volume's CE and DE storage to mirror
+binder::Status InstalldNativeService::onPrivateVolumeMounted(
+ const std::unique_ptr<std::string>& uuid) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ if (!sAppDataIsolationEnabled) {
+ return ok();
+ }
+ if (!uuid) {
+ return error("Should not happen, mounting uuid == null");
+ }
+
+ const char* uuid_ = uuid->c_str();
+ // Mount CE mirror
+ std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+ if (fs_prepare_dir(mirrorVolCePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+ return error("Failed to create CE mirror");
+ }
+ auto cePath = StringPrintf("%s/user_ce", create_data_path(uuid_).c_str());
+ if (TEMP_FAILURE_RETRY(mount(cePath.c_str(), mirrorVolCePath.c_str(), NULL,
+ MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
+ return error("Failed to mount " + mirrorVolCePath);
+ }
+
+ // Mount DE mirror
+ std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+ if (fs_prepare_dir(mirrorVolDePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+ return error("Failed to create DE mirror");
+ }
+ auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
+ if (TEMP_FAILURE_RETRY(mount(dePath.c_str(), mirrorVolDePath.c_str(), NULL,
+ MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
+ return error("Failed to mount " + mirrorVolDePath);
+ }
+ return ok();
+}
+
+// Unmount volume's CE and DE storage from mirror
+binder::Status InstalldNativeService::onPrivateVolumeRemoved(
+ const std::unique_ptr<std::string>& uuid) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ if (!sAppDataIsolationEnabled) {
+ return ok();
+ }
+ if (!uuid) {
+ // It happens when private volume failed to mount.
+ LOG(INFO) << "Ignore unmount uuid=null";
+ return ok();
+ }
+ const char* uuid_ = uuid->c_str();
+
+ binder::Status res = ok();
+
+ std::string mirrorCeVolPath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
+ std::string mirrorDeVolPath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+
+ // Unmount CE storage
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+ if (TEMP_FAILURE_RETRY(umount(mirrorCeVolPath.c_str())) != 0) {
+ if (errno != ENOENT) {
+ res = error(StringPrintf("Failed to umount %s %s", mirrorCeVolPath.c_str(),
+ strerror(errno)));
+ }
+ }
+ if (delete_dir_contents_and_dir(mirrorCeVolPath, true) != 0) {
+ res = error("Failed to delete " + mirrorCeVolPath);
+ }
+
+ // Unmount DE storage
+ if (TEMP_FAILURE_RETRY(umount(mirrorDeVolPath.c_str())) != 0) {
+ if (errno != ENOENT) {
+ res = error(StringPrintf("Failed to umount %s %s", mirrorDeVolPath.c_str(),
+ strerror(errno)));
+ }
+ }
+ if (delete_dir_contents_and_dir(mirrorDeVolPath, true) != 0) {
+ res = error("Failed to delete " + mirrorDeVolPath);
+ }
+ return res;
+}
+
std::string InstalldNativeService::findDataMediaPath(
const std::unique_ptr<std::string>& uuid, userid_t userid) {
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index fb02730..bf11002 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -81,6 +81,16 @@
int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
std::vector<int64_t>* _aidl_return);
+ binder::Status getAppCrates(const std::unique_ptr<std::string>& uuid,
+ const std::vector<std::string>& packageNames,
+ int32_t userId,
+ std::unique_ptr<std::vector<std::unique_ptr<android::os::storage::CrateMetadata>>>*
+ _aidl_return);
+ binder::Status getUserCrates(
+ const std::unique_ptr<std::string>& uuid, int32_t userId,
+ std::unique_ptr<std::vector<std::unique_ptr<android::os::storage::CrateMetadata>>>*
+ _aidl_return);
+
binder::Status setAppQuota(const std::unique_ptr<std::string>& uuid,
int32_t userId, int32_t appId, int64_t cacheQuota);
@@ -146,6 +156,8 @@
binder::Status invalidateMounts();
binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid,
bool* _aidl_return);
+ binder::Status onPrivateVolumeMounted(const std::unique_ptr<std::string>& volumeUuid);
+ binder::Status onPrivateVolumeRemoved(const std::unique_ptr<std::string>& volumeUuid);
binder::Status prepareAppProfile(const std::string& packageName,
int32_t userId, int32_t appId, const std::string& profileName,
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
index b238dd3..a71e01c 100644
--- a/cmds/installd/QuotaUtils.cpp
+++ b/cmds/installd/QuotaUtils.cpp
@@ -61,6 +61,10 @@
std::getline(in, target, ' ');
std::getline(in, ignored);
+ if (target.compare(0, 13, "/data_mirror/") == 0) {
+ continue;
+ }
+
if (source.compare(0, 11, "/dev/block/") == 0) {
struct dqblk dq;
if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 6cc4bde..891b26d 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -40,6 +40,14 @@
long[] getUserSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds);
long[] getExternalSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds);
+ @nullable
+ android.os.storage.CrateMetadata[] getAppCrates(
+ @nullable @utf8InCpp String uuid, in @utf8InCpp String[] packageNames,
+ int userId);
+ @nullable
+ android.os.storage.CrateMetadata[] getUserCrates(
+ @nullable @utf8InCpp String uuid, int userId);
+
void setAppQuota(@nullable @utf8InCpp String uuid, int userId, int appId, long cacheQuota);
void moveCompleteApp(@nullable @utf8InCpp String fromUuid, @nullable @utf8InCpp String toUuid,
@@ -109,6 +117,8 @@
int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
+ void onPrivateVolumeMounted(@nullable @utf8InCpp String volumeUuid);
+ void onPrivateVolumeRemoved(@nullable @utf8InCpp String volumeUuid);
void migrateLegacyObbData();
diff --git a/cmds/installd/binder/android/os/storage/CrateMetadata.aidl b/cmds/installd/binder/android/os/storage/CrateMetadata.aidl
new file mode 100644
index 0000000..bd6d12d
--- /dev/null
+++ b/cmds/installd/binder/android/os/storage/CrateMetadata.aidl
@@ -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.
+ */
+package android.os.storage;
+
+/** {@hide} */
+parcelable CrateMetadata {
+ /**
+ * To tell which uid the crate belong to.
+ * <p>Because installd query all of crates in specified userId, the install may return the list
+ * whose elements have the same crate id but different uid and package name.
+ * It needs to tell the caller the difference between these elements.
+ */
+ int uid;
+
+ /**
+ * To tell which the package the crate belong to.
+ * <p>Because installd query all of crates in specified uid, the install may return the list
+ * whose elements have the same uid and crate id but different package name.
+ * It needs to tell the caller the difference between these elements.
+ */
+ @utf8InCpp String packageName;
+
+ /**
+ * To tell the crate id that is the child directory/folder name in crates
+ * root.
+ */
+ @utf8InCpp String id;
+}
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 4eb1df0..6012822 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -278,6 +278,15 @@
return "/data/dalvik-cache";
}
+std::string create_system_user_ce_path(userid_t userId) {
+ return StringPrintf("%s/system_ce/%u", create_data_path(nullptr).c_str(), userId);
+}
+
+std::string create_system_user_ce_package_path(userid_t userId, const char* package_name) {
+ check_package_name(package_name);
+ return StringPrintf("%s/%s", create_system_user_ce_path(userId).c_str(), package_name);
+}
+
// Keep profile paths in sync with ActivityThread and LoadedApk.
const std::string PROFILE_EXT = ".prof";
const std::string CURRENT_PROFILE_EXT = ".cur";
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 6a42026..6a39adc 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -82,6 +82,10 @@
std::string create_data_dalvik_cache_path();
+std::string create_system_user_ce_path(userid_t userId);
+
+std::string create_system_user_ce_package_path(userid_t userId, const char* package_name);
+
std::string create_primary_cur_profile_dir_path(userid_t userid);
std::string create_primary_current_profile_package_dir_path(
userid_t user, const std::string& package_name);
diff --git a/libs/binder/include/binder/Enums.h b/libs/binder/include/binder/Enums.h
new file mode 100644
index 0000000..aec6f70
--- /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 79d9b79..3a401ad 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -253,7 +253,6 @@
"android.media.IDrmClient",
"android.media.IEffect",
"android.media.IEffectClient",
- "android.media.IMediaAnalyticsService",
"android.media.IMediaCodecList",
"android.media.IMediaDrmService",
"android.media.IMediaExtractor",
@@ -262,6 +261,7 @@
"android.media.IMediaHTTPService",
"android.media.IMediaLogService",
"android.media.IMediaMetadataRetriever",
+ "android.media.IMediaMetricsService",
"android.media.IMediaPlayer",
"android.media.IMediaPlayerClient",
"android.media.IMediaPlayerService",
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 946ccb7..2b61cf1 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 @@
*/
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 0000000..ee819c0
--- /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_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
index 7871667..2ef97a3 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,41 @@
}
/**
+ * 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);
+}
+
+/**
* 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 +465,7 @@
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 78d70f8..ab9a144 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 @@
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 d59d6e4..71d8103 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -103,6 +103,8 @@
global:
AIBinder_getExtension;
AIBinder_setExtension;
+ AStatus_getDescription;
+ AStatus_deleteDescription;
AIBinder_markSystemStability; # apex
AIBinder_markVendorStability; # llndk
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
index 1f75b0b..87e1341 100644
--- a/libs/binder/ndk/status.cpp
+++ b/libs/binder/ndk/status.cpp
@@ -66,6 +66,17 @@
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/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
index d3ccdc2..ad78e31 100644
--- a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
+++ b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
@@ -105,7 +105,8 @@
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/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 34254e0..4f96ad3 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -62,8 +62,11 @@
class ComposerCallbackBridge : public Hwc2::IComposerCallback {
public:
- ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId)
- : mCallback(callback), mSequenceId(sequenceId) {}
+ ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId,
+ bool vsyncSwitchingSupported)
+ : mCallback(callback),
+ mSequenceId(sequenceId),
+ mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
Return<void> onHotplug(Hwc2::Display display,
IComposerCallback::Connection conn) override
@@ -81,15 +84,23 @@
Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
{
- mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::nullopt);
+ if (!mVsyncSwitchingSupported) {
+ mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::nullopt);
+ } else {
+ ALOGW("Unexpected onVsync callback on composer >= 2.4, ignoring.");
+ }
return Void();
}
Return<void> onVsync_2_4(Hwc2::Display display, int64_t timestamp,
Hwc2::VsyncPeriodNanos vsyncPeriodNanos) override {
- // TODO(b/140201379): use vsyncPeriodNanos in the new DispSync
- mCallback->onVsyncReceived(mSequenceId, display, timestamp,
- std::make_optional(vsyncPeriodNanos));
+ if (mVsyncSwitchingSupported) {
+ // TODO(b/140201379): use vsyncPeriodNanos in the new DispSync
+ mCallback->onVsyncReceived(mSequenceId, display, timestamp,
+ std::make_optional(vsyncPeriodNanos));
+ } else {
+ ALOGW("Unexpected onVsync_2_4 callback on composer <= 2.3, ignoring.");
+ }
return Void();
}
@@ -107,6 +118,7 @@
private:
ComposerCallback* mCallback;
int32_t mSequenceId;
+ const bool mVsyncSwitchingSupported;
};
} // namespace anonymous
@@ -126,7 +138,8 @@
}
mRegisteredCallback = true;
sp<ComposerCallbackBridge> callbackBridge(
- new ComposerCallbackBridge(callback, sequenceId));
+ new ComposerCallbackBridge(callback, sequenceId,
+ mComposer->isVsyncPeriodSwitchSupported()));
mComposer->registerCallback(callbackBridge);
}
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 38a80a7..6598bd8 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -18,26 +18,139 @@
#include "Client.h"
#include "Layer.h"
+#include <gui/IProducerListener.h>
+
+#undef LOG_TAG
+#define LOG_TAG "RefreshRateOverlay"
+
namespace android {
+void RefreshRateOverlay::SevenSegmentDrawer::drawRect(const Rect& r, const half4& color,
+ const sp<GraphicBuffer>& buffer,
+ uint8_t* pixels) {
+ for (int32_t j = r.top; j < r.bottom; j++) {
+ if (j >= buffer->getHeight()) {
+ break;
+ }
+
+ for (int32_t i = r.left; i < r.right; i++) {
+ if (i >= buffer->getWidth()) {
+ break;
+ }
+
+ uint8_t* iter = pixels + 4 * (i + (buffer->getStride() * j));
+ iter[0] = uint8_t(color.r * 255);
+ iter[1] = uint8_t(color.g * 255);
+ iter[2] = uint8_t(color.b * 255);
+ iter[3] = uint8_t(color.a * 255);
+ }
+ }
+}
+
+void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left,
+ const half4& color,
+ const sp<GraphicBuffer>& buffer,
+ uint8_t* pixels) {
+ const Rect rect = [&]() {
+ switch (segment) {
+ case Segment::Upper:
+ return Rect(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
+ case Segment::UpperLeft:
+ return Rect(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
+ case Segment::UpperRight:
+ return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
+ DIGIT_HEIGHT / 2);
+ case Segment::Middle:
+ return Rect(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2, left + DIGIT_WIDTH,
+ DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
+ case Segment::LowerLeft:
+ return Rect(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
+ case Segment::LowerRight:
+ return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2, left + DIGIT_WIDTH,
+ DIGIT_HEIGHT);
+ case Segment::Buttom:
+ return Rect(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH, DIGIT_HEIGHT);
+ }
+ }();
+
+ drawRect(rect, color, buffer, pixels);
+}
+
+void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, const half4& color,
+ const sp<GraphicBuffer>& buffer,
+ uint8_t* pixels) {
+ if (digit < 0 || digit > 9) return;
+
+ if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
+ digit == 8 || digit == 9)
+ drawSegment(Segment::Upper, left, color, buffer, pixels);
+ if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
+ drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
+ if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
+ digit == 8 || digit == 9)
+ drawSegment(Segment::UpperRight, left, color, buffer, pixels);
+ if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
+ digit == 9)
+ drawSegment(Segment::Middle, left, color, buffer, pixels);
+ if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
+ drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
+ if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
+ digit == 7 || digit == 8 || digit == 9)
+ drawSegment(Segment::LowerRight, left, color, buffer, pixels);
+ if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
+ digit == 9)
+ drawSegment(Segment::Buttom, left, color, buffer, pixels);
+}
+
+sp<GraphicBuffer> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number,
+ const half4& color) {
+ if (number < 0 || number > 1000) return nullptr;
+
+ const auto hundreds = number / 100;
+ const auto tens = (number / 10) % 10;
+ const auto ones = number % 10;
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_SW_WRITE_RARELY, "RefreshRateOverlayBuffer");
+ uint8_t* pixels;
+ buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
+ int left = 0;
+ if (hundreds != 0) {
+ drawDigit(hundreds, left, color, buffer, pixels);
+ left += DIGIT_WIDTH + DIGIT_SPACE;
+ }
+
+ if (tens != 0) {
+ drawDigit(tens, left, color, buffer, pixels);
+ left += DIGIT_WIDTH + DIGIT_SPACE;
+ }
+
+ drawDigit(ones, left, color, buffer, pixels);
+ buffer->unlock();
+ return buffer;
+}
+
RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger)
: mFlinger(flinger), mClient(new Client(&mFlinger)) {
createLayer();
+ primeCache();
}
bool RefreshRateOverlay::createLayer() {
const status_t ret =
- mFlinger.createLayer(String8("RefreshRateOverlay"), mClient, 0, 0,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor,
- LayerMetadata(), &mIBinder, &mGbp, nullptr);
+ mFlinger.createLayer(String8("RefreshRateOverlay"), mClient,
+ SevenSegmentDrawer::getWidth(), SevenSegmentDrawer::getHeight(),
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState, LayerMetadata(),
+ &mIBinder, &mGbp, nullptr);
if (ret) {
- ALOGE("failed to create color layer");
+ ALOGE("failed to create buffer state layer");
return false;
}
Mutex::Autolock _l(mFlinger.mStateLock);
mLayer = mClient->getLayerUser(mIBinder);
- mLayer->setCrop_legacy(Rect(50, 70, 200, 100));
// setting Layer's Z requires resorting layersSortedByZ
ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
@@ -49,9 +162,41 @@
return true;
}
+void RefreshRateOverlay::primeCache() {
+ auto allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates();
+ if (allRefreshRates.size() == 1) {
+ auto fps = allRefreshRates.begin()->second.fps;
+ half4 color = {LOW_FPS_COLOR, ALPHA};
+ mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
+ return;
+ }
+
+ std::vector<uint32_t> supportedFps;
+ supportedFps.reserve(allRefreshRates.size());
+ for (auto [ignored, refreshRate] : allRefreshRates) {
+ supportedFps.push_back(refreshRate.fps);
+ }
+
+ std::sort(supportedFps.begin(), supportedFps.end());
+ const auto mLowFps = supportedFps[0];
+ const auto mHighFps = supportedFps[supportedFps.size() - 1];
+ for (auto fps : supportedFps) {
+ const auto fpsScale = float(fps - mLowFps) / (mHighFps - mLowFps);
+ half4 color;
+ color.r = HIGH_FPS_COLOR.r * fpsScale + LOW_FPS_COLOR.r * (1 - fpsScale);
+ color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale);
+ color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale);
+ color.a = ALPHA;
+ mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
+ }
+}
+
void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
- const half3& color = (refreshRate.fps > 65.0f) ? GREEN : RED;
- mLayer->setColor(color);
+ auto buffer = mBufferCache[refreshRate.fps];
+ mLayer->setBuffer(buffer, 0, 0, {});
+ mLayer->setFrame(Rect(20, 120, 20 + SevenSegmentDrawer::getWidth(),
+ 120 + SevenSegmentDrawer::getHeight()));
+
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index 414bc47..6d34df2 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -28,7 +28,32 @@
void changeRefreshRate(const RefreshRate& refreshRate);
private:
+ class SevenSegmentDrawer {
+ public:
+ static sp<GraphicBuffer> drawNumber(int number, const half4& color);
+ static uint32_t getHeight() { return BUFFER_HEIGHT; }
+ static uint32_t getWidth() { return BUFFER_WIDTH; }
+
+ private:
+ enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Buttom };
+
+ static void drawRect(const Rect& r, const half4& color, const sp<GraphicBuffer>& buffer,
+ uint8_t* pixels);
+ static void drawSegment(Segment segment, int left, const half4& color,
+ const sp<GraphicBuffer>& buffer, uint8_t* pixels);
+ static void drawDigit(int digit, int left, const half4& color,
+ const sp<GraphicBuffer>& buffer, uint8_t* pixels);
+
+ static constexpr uint32_t DIGIT_HEIGHT = 100;
+ static constexpr uint32_t DIGIT_WIDTH = 64;
+ static constexpr uint32_t DIGIT_SPACE = 16;
+ static constexpr uint32_t BUFFER_HEIGHT = DIGIT_HEIGHT;
+ static constexpr uint32_t BUFFER_WIDTH =
+ 3 * DIGIT_WIDTH + 2 * DIGIT_SPACE; // Digit|Space|Digit|Space|Digit
+ };
+
bool createLayer();
+ void primeCache();
SurfaceFlinger& mFlinger;
sp<Client> mClient;
@@ -36,8 +61,11 @@
sp<IBinder> mIBinder;
sp<IGraphicBufferProducer> mGbp;
- const half3 RED = half3(1.0f, 0.0f, 0.0f);
- const half3 GREEN = half3(0.0f, 1.0f, 0.0f);
+ std::unordered_map<int, sp<GraphicBuffer>> mBufferCache;
+
+ static constexpr float ALPHA = 0.8f;
+ const half3 LOW_FPS_COLOR = half3(1.0f, 0.0f, 0.0f);
+ const half3 HIGH_FPS_COLOR = half3(0.0f, 1.0f, 0.0f);
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9d5081c..537489f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4844,15 +4844,15 @@
return NO_ERROR;
}
case 1034: {
- // TODO(b/129297325): expose this via developer menu option
n = data.readInt32();
- if (n && !mRefreshRateOverlay &&
- mRefreshRateConfigs->refreshRateSwitchingSupported()) {
+ if (n == 1 && !mRefreshRateOverlay) {
mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
auto current = mRefreshRateConfigs->getCurrentRefreshRate();
mRefreshRateOverlay->changeRefreshRate(current);
- } else if (!n) {
+ } else if (n == 0) {
mRefreshRateOverlay.reset();
+ } else {
+ reply->writeBool(mRefreshRateOverlay != nullptr);
}
return NO_ERROR;
}
diff --git a/services/surfaceflinger/tests/CommonTypes_test.cpp b/services/surfaceflinger/tests/CommonTypes_test.cpp
index a3e16f9..ab4af09 100644
--- a/services/surfaceflinger/tests/CommonTypes_test.cpp
+++ b/services/surfaceflinger/tests/CommonTypes_test.cpp
@@ -100,21 +100,21 @@
static_cast<uint32_t>(HidlDataspace::RANGE_LIMITED));
static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_EXTENDED) ==
static_cast<uint32_t>(HidlDataspace::RANGE_EXTENDED));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_SRGB_LINEAR) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::SRGB_LINEAR) ==
static_cast<uint32_t>(HidlDataspace::V0_SRGB_LINEAR));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_SCRGB_LINEAR) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::SCRGB_LINEAR) ==
static_cast<uint32_t>(HidlDataspace::V0_SCRGB_LINEAR));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_SRGB) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::SRGB) ==
static_cast<uint32_t>(HidlDataspace::V0_SRGB));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_SCRGB) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::SCRGB) ==
static_cast<uint32_t>(HidlDataspace::V0_SCRGB));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_JFIF) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::JFIF) ==
static_cast<uint32_t>(HidlDataspace::V0_JFIF));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_BT601_625) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::BT601_625) ==
static_cast<uint32_t>(HidlDataspace::V0_BT601_625));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_BT601_525) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::BT601_525) ==
static_cast<uint32_t>(HidlDataspace::V0_BT601_525));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_BT709) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::BT709) ==
static_cast<uint32_t>(HidlDataspace::V0_BT709));
static_assert(static_cast<uint32_t>(AidlDataspace::DCI_P3_LINEAR) ==
static_cast<uint32_t>(HidlDataspace::DCI_P3_LINEAR));
@@ -152,19 +152,3 @@
static_cast<uint32_t>(HidlDataspace::JPEG_APP_SEGMENTS));
static_assert(static_cast<uint32_t>(AidlDataspace::HEIF) ==
static_cast<uint32_t>(HidlDataspace::HEIF));
-
-// Below are the dataspaces that have been deprecated for sometime. They are required to behave
-// the same as their V0_* counterparts. We redefined them in AIDL to be the same as the
-// their V0_* counterparts.
-static_assert(static_cast<uint32_t>(AidlDataspace::SRGB_LINEAR) ==
- static_cast<uint32_t>(AidlDataspace::V0_SRGB_LINEAR));
-static_assert(static_cast<uint32_t>(AidlDataspace::SRGB) ==
- static_cast<uint32_t>(AidlDataspace::V0_SRGB));
-static_assert(static_cast<uint32_t>(AidlDataspace::JFIF) ==
- static_cast<uint32_t>(AidlDataspace::V0_JFIF));
-static_assert(static_cast<uint32_t>(AidlDataspace::BT601_625) ==
- static_cast<uint32_t>(AidlDataspace::V0_BT601_625));
-static_assert(static_cast<uint32_t>(AidlDataspace::BT601_525) ==
- static_cast<uint32_t>(AidlDataspace::V0_BT601_525));
-static_assert(static_cast<uint32_t>(AidlDataspace::BT709) ==
- static_cast<uint32_t>(AidlDataspace::V0_BT709));
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index a020e74..aa7c19a 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -694,20 +694,6 @@
const InstanceData& instance_data = GetData(pdev);
- // TODO(b/143296550): 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(),
@@ -720,43 +706,72 @@
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;
}