Merge "[RenderEngine] Support extended SRGB transform."
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index b850390..bb84a18 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -18,8 +18,6 @@
"libcutils",
"libz",
"libbase",
- ],
- static_libs: [
"libpdx_default_transport",
],
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 90c7da4..352cf0a 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -92,4 +92,28 @@
],
}
+//
+// Static library for otapreopt used in testing
+//
+cc_library_static {
+ name: "libotapreoptparameters",
+ cflags: [
+ "-Wall",
+ "-Werror"
+ ],
+ clang: true,
+
+ srcs: [
+ "otapreopt_parameters.cpp"],
+
+ export_include_dirs: ["."],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+}
+
subdirs = ["tests"]
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index b3dc5ec..a4f95da 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -23,7 +23,7 @@
LOCAL_CFLAGS += -DART_BASE_ADDRESS_MIN_DELTA=$(LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA)
LOCAL_CFLAGS += -DART_BASE_ADDRESS_MAX_DELTA=$(LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA)
-LOCAL_SRC_FILES := otapreopt.cpp globals.cpp utils.cpp dexopt.cpp
+LOCAL_SRC_FILES := otapreopt.cpp otapreopt_parameters.cpp globals.cpp utils.cpp dexopt.cpp
LOCAL_HEADER_LIBRARIES := dex2oat_headers
LOCAL_SHARED_LIBRARIES := \
libbase \
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a2c8542..0d50b9b 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1895,13 +1895,18 @@
return ok();
}
+static const char* getCStr(const std::unique_ptr<std::string>& data,
+ const char* default_value = nullptr) {
+ return data == nullptr ? default_value : data->c_str();
+}
binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
const std::unique_ptr<std::string>& classLoaderContext,
const std::unique_ptr<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion,
- const std::unique_ptr<std::string>& profileName) {
+ const std::unique_ptr<std::string>& profileName,
+ const std::unique_ptr<std::string>& dexMetadataPath) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
if (packageName && *packageName != "*") {
@@ -1910,17 +1915,18 @@
std::lock_guard<std::recursive_mutex> lock(mLock);
const char* apk_path = apkPath.c_str();
- const char* pkgname = packageName ? packageName->c_str() : "*";
+ const char* pkgname = getCStr(packageName, "*");
const char* instruction_set = instructionSet.c_str();
- const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
+ const char* oat_dir = getCStr(outputPath);
const char* compiler_filter = compilerFilter.c_str();
- const char* volume_uuid = uuid ? uuid->c_str() : nullptr;
- const char* class_loader_context = classLoaderContext ? classLoaderContext->c_str() : nullptr;
- const char* se_info = seInfo ? seInfo->c_str() : nullptr;
- const char* profile_name = profileName ? profileName->c_str() : nullptr;
+ const char* volume_uuid = getCStr(uuid);
+ const char* class_loader_context = getCStr(classLoaderContext);
+ const char* se_info = getCStr(seInfo);
+ const char* profile_name = getCStr(profileName);
+ const char* dm_path = getCStr(dexMetadataPath);
int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
- downgrade, targetSdkVersion, profile_name);
+ downgrade, targetSdkVersion, profile_name, dm_path);
return res ? error(res, "Failed to dexopt") : ok();
}
@@ -2356,8 +2362,8 @@
__u8 root_hash[64];
};
-#define FS_IOC_MEASURE_FSVERITY _IOW('f', 2733, struct fsverity_root_hash)
-#define FS_IOC_SET_FSVERITY _IOW('f', 2734, struct fsverity_set)
+#define FS_IOC_MEASURE_FSVERITY _IOW('f', 133, struct fsverity_root_hash)
+#define FS_IOC_SET_FSVERITY _IOW('f', 134, struct fsverity_set)
#define FSVERITY_FLAG_ENABLED 0x0001
#endif
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 5bf8ae2..22b1d12 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -85,7 +85,8 @@
const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
const std::unique_ptr<std::string>& classLoaderContext,
const std::unique_ptr<std::string>& seInfo, bool downgrade,
- int32_t targetSdkVersion, const std::unique_ptr<std::string>& profileName);
+ int32_t targetSdkVersion, const std::unique_ptr<std::string>& profileName,
+ const std::unique_ptr<std::string>& dexMetadataPath);
binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 3133b4f..e07c847 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -52,7 +52,8 @@
@utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
@nullable @utf8InCpp String sharedLibraries,
@nullable @utf8InCpp String seInfo, boolean downgrade, int targetSdkVersion,
- @nullable @utf8InCpp String profileName);
+ @nullable @utf8InCpp String profileName,
+ @nullable @utf8InCpp String dexMetadataPath);
void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index abbd62d..b456507 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -223,7 +223,8 @@
const char* input_file_name, const char* output_file_name, int swap_fd,
const char* instruction_set, const char* compiler_filter,
bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
- const char* class_loader_context, int target_sdk_version, bool disable_hidden_api_checks) {
+ const char* class_loader_context, int target_sdk_version, bool disable_hidden_api_checks,
+ int dex_metadata_fd) {
static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -420,6 +421,7 @@
sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
}
+ std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
@@ -450,7 +452,8 @@
+ (disable_cdex ? 1 : 0)
+ (generate_minidebug_info ? 1 : 0)
+ (target_sdk_version != 0 ? 2 : 0)
- + (disable_hidden_api_checks ? 2 : 0)];
+ + (disable_hidden_api_checks ? 2 : 0)
+ + (dex_metadata_fd > -1 ? 1 : 0)];
int i = 0;
argv[i++] = dex2oat_bin;
argv[i++] = zip_fd_arg;
@@ -529,6 +532,9 @@
argv[i++] = "-Xno-hidden-api-checks";
}
+ if (dex_metadata_fd > -1) {
+ argv[i++] = dex_metadata_fd_arg.c_str();
+ }
// Do not add after dex2oat_flags, they should override others for debugging.
argv[i] = NULL;
@@ -715,13 +721,20 @@
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
-static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
- const unique_fd& reference_profile_fd, const std::vector<unique_fd>* apk_fds = nullptr) {
+static void run_profman(const std::vector<unique_fd>& profile_fds,
+ const unique_fd& reference_profile_fd,
+ const std::vector<unique_fd>* apk_fds,
+ bool copy_and_update) {
const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
- std::vector<std::string> profile_args(profiles_fd.size());
- for (size_t k = 0; k < profiles_fd.size(); k++) {
- profile_args[k] = "--profile-file-fd=" + std::to_string(profiles_fd[k].get());
+ if (copy_and_update) {
+ CHECK_EQ(1u, profile_fds.size());
+ CHECK(apk_fds != nullptr);
+ CHECK_EQ(1u, apk_fds->size());
+ }
+ std::vector<std::string> profile_args(profile_fds.size());
+ for (size_t k = 0; k < profile_fds.size(); k++) {
+ profile_args[k] = "--profile-file-fd=" + std::to_string(profile_fds[k].get());
}
std::string reference_profile_arg = "--reference-profile-file-fd="
+ std::to_string(reference_profile_fd.get());
@@ -734,7 +747,7 @@
}
// program name, reference profile fd, the final NULL and the profile fds
- const char* argv[3 + profile_args.size() + apk_args.size()];
+ const char* argv[3 + profile_args.size() + apk_args.size() + (copy_and_update ? 1 : 0)];
int i = 0;
argv[i++] = profman_bin;
argv[i++] = reference_profile_arg.c_str();
@@ -744,6 +757,9 @@
for (size_t k = 0; k < apk_args.size(); k++) {
argv[i++] = apk_args[k].c_str();
}
+ if (copy_and_update) {
+ argv[i++] = "--copy-and-update-profile-key";
+ }
// Do not add after dex2oat_flags, they should override others for debugging.
argv[i] = NULL;
@@ -752,6 +768,25 @@
exit(68); /* only get here on exec failure */
}
+
+static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
+ const unique_fd& reference_profile_fd,
+ const std::vector<unique_fd>* apk_fds = nullptr) {
+ run_profman(profiles_fd, reference_profile_fd, apk_fds, /*copy_and_update*/false);
+}
+
+
+static void run_profman_copy_and_update(unique_fd&& profile_fd,
+ unique_fd&& reference_profile_fd,
+ unique_fd&& apk_fd) {
+ std::vector<unique_fd> profiles_fd;
+ profiles_fd.push_back(std::move(profile_fd));
+ std::vector<unique_fd> apk_fds;
+ apk_fds.push_back(std::move(apk_fd));
+
+ run_profman(profiles_fd, reference_profile_fd, &apk_fds, /*copy_and_update*/true);
+}
+
// Decides if profile guided compilation is needed or not based on existing profiles.
// The location is the package name for primary apks or the dex path for secondary dex files.
// Returns true if there is enough information in the current profiles that makes it
@@ -1292,9 +1327,21 @@
Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname,
const std::string& dex_path, const char* profile_name, bool profile_guided,
bool is_public, int uid, bool is_secondary_dex) {
- // Public apps should not be compiled with profile information ever. Same goes for the special
- // package '*' used for the system server.
- if (!profile_guided || is_public || (pkgname[0] == '*')) {
+ // If we are not profile guided compilation, or we are compiling system server
+ // do not bother to open the profiles; we won't be using them.
+ if (!profile_guided || (pkgname[0] == '*')) {
+ return Dex2oatFileWrapper();
+ }
+
+ // If this is a secondary dex path which is public do not open the profile.
+ // We cannot compile public secondary dex paths with profiles. That's because
+ // it will expose how the dex files are used by their owner.
+ //
+ // Note that the PackageManager is responsible to set the is_public flag for
+ // primary apks and we do not check it here. In some cases, e.g. when
+ // compiling with a public profile from the .dm file the PackageManager will
+ // set is_public toghether with the profile guided compilation.
+ if (is_secondary_dex && is_public) {
return Dex2oatFileWrapper();
}
@@ -1817,7 +1864,8 @@
int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* class_loader_context, const char* se_info,
- bool downgrade, int target_sdk_version, const char* profile_name) {
+ bool downgrade, int target_sdk_version, const char* profile_name,
+ const char* dex_metadata_path) {
CHECK(pkgname != nullptr);
CHECK(pkgname[0] != 0);
if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
@@ -1908,6 +1956,14 @@
Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex);
+ unique_fd dex_metadata_fd;
+ if (dex_metadata_path != nullptr) {
+ dex_metadata_fd.reset(TEMP_FAILURE_RETRY(open(dex_metadata_path, O_RDONLY | O_NOFOLLOW)));
+ if (dex_metadata_fd.get() < 0) {
+ PLOG(ERROR) << "Failed to open dex metadata file " << dex_metadata_path;
+ }
+ }
+
ALOGV("DexInv: --- BEGIN '%s' ---\n", dex_path);
pid_t pid = fork();
@@ -1937,7 +1993,8 @@
reference_profile_fd.get(),
class_loader_context,
target_sdk_version,
- disable_hidden_api_checks);
+ disable_hidden_api_checks,
+ dex_metadata_fd.get());
_exit(68); /* only get here on exec failure */
} else {
int res = wait_child(pid);
@@ -2610,7 +2667,7 @@
userid_t user_id,
appid_t app_id,
const std::string& profile_name,
- const std::string& code_path ATTRIBUTE_UNUSED,
+ const std::string& code_path,
const std::unique_ptr<std::string>& dex_metadata) {
// Prepare the current profile.
std::string cur_profile = create_current_profile_path(user_id, package_name, profile_name,
@@ -2631,8 +2688,11 @@
/*read_write*/ true, /*is_secondary_dex*/ false);
unique_fd dex_metadata_fd(TEMP_FAILURE_RETRY(
open(dex_metadata->c_str(), O_RDONLY | O_NOFOLLOW)));
- std::vector<unique_fd> profiles_fd;
- profiles_fd.push_back(std::move(dex_metadata_fd));
+ unique_fd apk_fd(TEMP_FAILURE_RETRY(open(code_path.c_str(), O_RDONLY | O_NOFOLLOW)));
+ if (apk_fd < 0) {
+ PLOG(ERROR) << "Could not open code path " << code_path;
+ return false;
+ }
pid_t pid = fork();
if (pid == 0) {
@@ -2640,10 +2700,10 @@
gid_t app_shared_gid = multiuser_get_shared_gid(user_id, app_id);
drop_capabilities(app_shared_gid);
- // TODO(calin): the dex metadata profile might embed different names for the
- // same code path (e.g. YouTube.apk or base.apk, depending on how the initial
- // profile was captured). We should pass the code path to adjust the names in the profile.
- run_profman_merge(profiles_fd, ref_profile_fd);
+ // The copy and update takes ownership over the fds.
+ run_profman_copy_and_update(std::move(dex_metadata_fd),
+ std::move(ref_profile_fd),
+ std::move(apk_fd));
exit(42); /* only get here on exec failure */
}
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 93cf545..ae1412e 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -105,7 +105,8 @@
int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* class_loader_context, const char* se_info,
- bool downgrade, int target_sdk_version, const char* profile_name);
+ bool downgrade, int target_sdk_version, const char* profile_name,
+ const char* dexMetadataPath);
bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
const char *apk_path, const char *instruction_set);
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 74dca72..72d01a5 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -43,6 +43,7 @@
#include "globals.h"
#include "installd_constants.h"
#include "installd_deps.h" // Need to fill in requirements of commands.
+#include "otapreopt_parameters.h"
#include "otapreopt_utils.h"
#include "system_properties.h"
#include "utils.h"
@@ -158,32 +159,15 @@
}
std::string GetOTADataDirectory() const {
- return StringPrintf("%s/%s", GetOtaDirectoryPrefix().c_str(), target_slot_.c_str());
+ return StringPrintf("%s/%s", GetOtaDirectoryPrefix().c_str(), GetTargetSlot().c_str());
}
const std::string& GetTargetSlot() const {
- return target_slot_;
+ return parameters_.target_slot;
}
private:
- struct Parameters {
- const char *apk_path;
- uid_t uid;
- const char *pkgName;
- const char *instruction_set;
- int dexopt_needed;
- const char* oat_dir;
- int dexopt_flags;
- const char* compiler_filter;
- const char* volume_uuid;
- const char* shared_libraries;
- const char* se_info;
- bool downgrade;
- int target_sdk_version;
- const char* profile_name;
- };
-
bool ReadSystemProperties() {
static constexpr const char* kPropertyFiles[] = {
"/default.prop", "/system/build.prop"
@@ -307,546 +291,7 @@
}
bool ReadArguments(int argc, char** argv) {
- // Expected command line:
- // target-slot [version] dexopt {DEXOPT_PARAMETERS}
-
- const char* target_slot_arg = argv[1];
- if (target_slot_arg == nullptr) {
- LOG(ERROR) << "Missing parameters";
- return false;
- }
- // Sanitize value. Only allow (a-zA-Z0-9_)+.
- target_slot_ = target_slot_arg;
- if (!ValidateTargetSlotSuffix(target_slot_)) {
- LOG(ERROR) << "Target slot suffix not legal: " << target_slot_;
- return false;
- }
-
- // Check for version or "dexopt" next.
- if (argv[2] == nullptr) {
- LOG(ERROR) << "Missing parameters";
- return false;
- }
-
- if (std::string("dexopt").compare(argv[2]) == 0) {
- // This is version 1 (N) or pre-versioning version 2.
- constexpr int kV2ArgCount = 1 // "otapreopt"
- + 1 // slot
- + 1 // "dexopt"
- + 1 // apk_path
- + 1 // uid
- + 1 // pkg
- + 1 // isa
- + 1 // dexopt_needed
- + 1 // oat_dir
- + 1 // dexopt_flags
- + 1 // filter
- + 1 // volume
- + 1 // libs
- + 1; // seinfo
- if (argc == kV2ArgCount) {
- return ReadArgumentsV2(argc, argv, false);
- } else {
- return ReadArgumentsV1(argc, argv);
- }
- }
-
- uint32_t version;
- if (!ParseUInt(argv[2], &version)) {
- LOG(ERROR) << "Could not parse version: " << argv[2];
- return false;
- }
-
- switch (version) {
- case 2:
- return ReadArgumentsV2(argc, argv, true);
- case 3:
- return ReadArgumentsV3(argc, argv);
- case 4:
- return ReadArgumentsV4(argc, argv);
- case 5:
- return ReadArgumentsV5(argc, argv);
-
- default:
- LOG(ERROR) << "Unsupported version " << version;
- return false;
- }
- }
-
- bool ReadArgumentsV2(int argc ATTRIBUTE_UNUSED, char** argv, bool versioned) {
- size_t dexopt_index = versioned ? 3 : 2;
-
- // Check for "dexopt".
- if (argv[dexopt_index] == nullptr) {
- LOG(ERROR) << "Missing parameters";
- return false;
- }
- if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
- LOG(ERROR) << "Expected \"dexopt\"";
- return false;
- }
-
- size_t param_index = 0;
- for (;; ++param_index) {
- const char* param = argv[dexopt_index + 1 + param_index];
- if (param == nullptr) {
- break;
- }
-
- switch (param_index) {
- case 0:
- package_parameters_.apk_path = param;
- break;
-
- case 1:
- package_parameters_.uid = atoi(param);
- break;
-
- case 2:
- package_parameters_.pkgName = param;
- break;
-
- case 3:
- package_parameters_.instruction_set = param;
- break;
-
- case 4:
- package_parameters_.dexopt_needed = atoi(param);
- break;
-
- case 5:
- package_parameters_.oat_dir = param;
- break;
-
- case 6:
- package_parameters_.dexopt_flags = atoi(param);
- break;
-
- case 7:
- package_parameters_.compiler_filter = param;
- break;
-
- case 8:
- package_parameters_.volume_uuid = ParseNull(param);
- break;
-
- case 9:
- package_parameters_.shared_libraries = ParseNull(param);
- break;
-
- case 10:
- package_parameters_.se_info = ParseNull(param);
- break;
-
- default:
- LOG(ERROR) << "Too many arguments, got " << param;
- return false;
- }
- }
-
- // Set downgrade to false. It is only relevant when downgrading compiler
- // filter, which is not the case during ota.
- package_parameters_.downgrade = false;
-
- // Set target_sdk_version to 0, ie the platform SDK version. This is
- // conservative and may force some classes to verify at runtime.
- package_parameters_.target_sdk_version = 0;
-
- // Set the profile name to the primary apk profile.
- package_parameters_.profile_name = "primary.prof";
-
- if (param_index != 11) {
- LOG(ERROR) << "Not enough parameters";
- return false;
- }
-
- return true;
- }
-
- bool ReadArgumentsV3(int argc ATTRIBUTE_UNUSED, char** argv) {
- size_t dexopt_index = 3;
-
- // Check for "dexopt".
- if (argv[dexopt_index] == nullptr) {
- LOG(ERROR) << "Missing parameters";
- return false;
- }
- if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
- LOG(ERROR) << "Expected \"dexopt\"";
- return false;
- }
-
- size_t param_index = 0;
- for (;; ++param_index) {
- const char* param = argv[dexopt_index + 1 + param_index];
- if (param == nullptr) {
- break;
- }
-
- switch (param_index) {
- case 0:
- package_parameters_.apk_path = param;
- break;
-
- case 1:
- package_parameters_.uid = atoi(param);
- break;
-
- case 2:
- package_parameters_.pkgName = param;
- break;
-
- case 3:
- package_parameters_.instruction_set = param;
- break;
-
- case 4:
- package_parameters_.dexopt_needed = atoi(param);
- break;
-
- case 5:
- package_parameters_.oat_dir = param;
- break;
-
- case 6:
- package_parameters_.dexopt_flags = atoi(param);
- break;
-
- case 7:
- package_parameters_.compiler_filter = param;
- break;
-
- case 8:
- package_parameters_.volume_uuid = ParseNull(param);
- break;
-
- case 9:
- package_parameters_.shared_libraries = ParseNull(param);
- break;
-
- case 10:
- package_parameters_.se_info = ParseNull(param);
- break;
-
- case 11:
- package_parameters_.downgrade = ParseBool(param);
- break;
-
- default:
- LOG(ERROR) << "Too many arguments, got " << param;
- return false;
- }
- }
-
- // Set target_sdk_version to 0, ie the platform SDK version. This is
- // conservative and may force some classes to verify at runtime.
- package_parameters_.target_sdk_version = 0;
-
- // Set the profile name to the primary apk profile.
- package_parameters_.profile_name = "primary.prof";
-
- if (param_index != 12) {
- LOG(ERROR) << "Not enough parameters";
- return false;
- }
-
- return true;
- }
-
- bool ReadArgumentsV4(int argc ATTRIBUTE_UNUSED, char** argv) {
- size_t dexopt_index = 3;
-
- // Check for "dexopt".
- if (argv[dexopt_index] == nullptr) {
- LOG(ERROR) << "Missing parameters";
- return false;
- }
- if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
- LOG(ERROR) << "Expected \"dexopt\"";
- return false;
- }
-
- size_t param_index = 0;
- for (;; ++param_index) {
- const char* param = argv[dexopt_index + 1 + param_index];
- if (param == nullptr) {
- break;
- }
-
- switch (param_index) {
- case 0:
- package_parameters_.apk_path = param;
- break;
-
- case 1:
- package_parameters_.uid = atoi(param);
- break;
-
- case 2:
- package_parameters_.pkgName = param;
- break;
-
- case 3:
- package_parameters_.instruction_set = param;
- break;
-
- case 4:
- package_parameters_.dexopt_needed = atoi(param);
- break;
-
- case 5:
- package_parameters_.oat_dir = param;
- break;
-
- case 6:
- package_parameters_.dexopt_flags = atoi(param);
- break;
-
- case 7:
- package_parameters_.compiler_filter = param;
- break;
-
- case 8:
- package_parameters_.volume_uuid = ParseNull(param);
- break;
-
- case 9:
- package_parameters_.shared_libraries = ParseNull(param);
- break;
-
- case 10:
- package_parameters_.se_info = ParseNull(param);
- break;
-
- case 11:
- package_parameters_.downgrade = ParseBool(param);
- break;
-
- case 12:
- package_parameters_.target_sdk_version = atoi(param);
- break;
-
- default:
- LOG(ERROR) << "Too many arguments, got " << param;
- return false;
- }
- }
-
- // Set the profile name to the primary apk profile.
- package_parameters_.profile_name = "primary.prof";
-
- if (param_index != 13) {
- LOG(ERROR) << "Not enough parameters";
- return false;
- }
-
- return true;
- }
-
- // TODO: this pattern does not scale and result in a lot of code duplication.
- // Either find a better pattern or refactor the code to eliminate the duplication.
- bool ReadArgumentsV5(int argc ATTRIBUTE_UNUSED, char** argv) {
- size_t dexopt_index = 3;
-
- // Check for "dexopt".
- if (argv[dexopt_index] == nullptr) {
- LOG(ERROR) << "Missing parameters";
- return false;
- }
- if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
- LOG(ERROR) << "Expected \"dexopt\"";
- return false;
- }
-
- size_t param_index = 0;
- for (;; ++param_index) {
- const char* param = argv[dexopt_index + 1 + param_index];
- if (param == nullptr) {
- break;
- }
-
- switch (param_index) {
- case 0:
- package_parameters_.apk_path = param;
- break;
-
- case 1:
- package_parameters_.uid = atoi(param);
- break;
-
- case 2:
- package_parameters_.pkgName = param;
- break;
-
- case 3:
- package_parameters_.instruction_set = param;
- break;
-
- case 4:
- package_parameters_.dexopt_needed = atoi(param);
- break;
-
- case 5:
- package_parameters_.oat_dir = param;
- break;
-
- case 6:
- package_parameters_.dexopt_flags = atoi(param);
- break;
-
- case 7:
- package_parameters_.compiler_filter = param;
- break;
-
- case 8:
- package_parameters_.volume_uuid = ParseNull(param);
- break;
-
- case 9:
- package_parameters_.shared_libraries = ParseNull(param);
- break;
-
- case 10:
- package_parameters_.se_info = ParseNull(param);
- break;
-
- case 11:
- package_parameters_.downgrade = ParseBool(param);
- break;
-
- case 12:
- package_parameters_.target_sdk_version = atoi(param);
- break;
-
- case 13:
- package_parameters_.profile_name = ParseNull(param);
- break;
-
- default:
- LOG(ERROR) << "Too many arguments, got " << param;
- return false;
- }
- }
-
- if (param_index != 14) {
- LOG(ERROR) << "Not enough parameters";
- return false;
- }
-
- return true;
- }
-
- static int ReplaceMask(int input, int old_mask, int new_mask) {
- return (input & old_mask) != 0 ? new_mask : 0;
- }
-
- bool ReadArgumentsV1(int argc ATTRIBUTE_UNUSED, char** argv) {
- // Check for "dexopt".
- if (argv[2] == nullptr) {
- LOG(ERROR) << "Missing parameters";
- return false;
- }
- if (std::string("dexopt").compare(argv[2]) != 0) {
- LOG(ERROR) << "Expected \"dexopt\"";
- return false;
- }
-
- size_t param_index = 0;
- for (;; ++param_index) {
- const char* param = argv[3 + param_index];
- if (param == nullptr) {
- break;
- }
-
- switch (param_index) {
- case 0:
- package_parameters_.apk_path = param;
- break;
-
- case 1:
- package_parameters_.uid = atoi(param);
- break;
-
- case 2:
- package_parameters_.pkgName = param;
- break;
-
- case 3:
- package_parameters_.instruction_set = param;
- break;
-
- case 4: {
- // Version 1 had:
- // DEXOPT_DEX2OAT_NEEDED = 1
- // DEXOPT_PATCHOAT_NEEDED = 2
- // DEXOPT_SELF_PATCHOAT_NEEDED = 3
- // We will simply use DEX2OAT_FROM_SCRATCH.
- package_parameters_.dexopt_needed = DEX2OAT_FROM_SCRATCH;
- break;
- }
-
- case 5:
- package_parameters_.oat_dir = param;
- break;
-
- case 6: {
- // Version 1 had:
- constexpr int OLD_DEXOPT_PUBLIC = 1 << 1;
- // Note: DEXOPT_SAFEMODE has been removed.
- // constexpr int OLD_DEXOPT_SAFEMODE = 1 << 2;
- constexpr int OLD_DEXOPT_DEBUGGABLE = 1 << 3;
- constexpr int OLD_DEXOPT_BOOTCOMPLETE = 1 << 4;
- constexpr int OLD_DEXOPT_PROFILE_GUIDED = 1 << 5;
- constexpr int OLD_DEXOPT_OTA = 1 << 6;
- int input = atoi(param);
- package_parameters_.dexopt_flags =
- ReplaceMask(input, OLD_DEXOPT_PUBLIC, DEXOPT_PUBLIC) |
- ReplaceMask(input, OLD_DEXOPT_DEBUGGABLE, DEXOPT_DEBUGGABLE) |
- ReplaceMask(input, OLD_DEXOPT_BOOTCOMPLETE, DEXOPT_BOOTCOMPLETE) |
- ReplaceMask(input, OLD_DEXOPT_PROFILE_GUIDED, DEXOPT_PROFILE_GUIDED) |
- ReplaceMask(input, OLD_DEXOPT_OTA, 0);
- break;
- }
-
- case 7:
- package_parameters_.compiler_filter = param;
- break;
-
- case 8:
- package_parameters_.volume_uuid = ParseNull(param);
- break;
-
- case 9:
- package_parameters_.shared_libraries = ParseNull(param);
- break;
-
- default:
- LOG(ERROR) << "Too many arguments, got " << param;
- return false;
- }
- }
-
- if (param_index != 10) {
- LOG(ERROR) << "Not enough parameters";
- return false;
- }
-
- // Set se_info to null. It is only relevant for secondary dex files, which we won't
- // receive from a v1 A side.
- package_parameters_.se_info = nullptr;
-
- // Set downgrade to false. It is only relevant when downgrading compiler
- // filter, which is not the case during ota.
- package_parameters_.downgrade = false;
-
- // Set target_sdk_version to 0, ie the platform SDK version. This is
- // conservative and may force some classes to verify at runtime.
- package_parameters_.target_sdk_version = 0;
-
- // Set the profile name to the primary apk profile.
- package_parameters_.profile_name = "primary.prof";
-
- return true;
+ return parameters_.ReadArguments(argc, const_cast<const char**>(argv));
}
void PrepareEnvironment() {
@@ -862,11 +307,11 @@
// Ensure that we have the right boot image. The first time any app is
// compiled, we'll try to generate it.
bool PrepareBootImage(bool force) const {
- if (package_parameters_.instruction_set == nullptr) {
+ if (parameters_.instruction_set == nullptr) {
LOG(ERROR) << "Instruction set missing.";
return false;
}
- const char* isa = package_parameters_.instruction_set;
+ const char* isa = parameters_.instruction_set;
// Check whether the file exists where expected.
std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
@@ -1090,9 +535,9 @@
// jar content must be exactly the same).
// (This is ugly as it's the only thing where we need to understand the contents
- // of package_parameters_, but it beats postponing the decision or using the call-
+ // of parameters_, but it beats postponing the decision or using the call-
// backs to do weird things.)
- const char* apk_path = package_parameters_.apk_path;
+ const char* apk_path = parameters_.apk_path;
CHECK(apk_path != nullptr);
if (StartsWith(apk_path, android_root_)) {
const char* last_slash = strrchr(apk_path, '/');
@@ -1120,23 +565,24 @@
return false;
}
- // Run dexopt with the parameters of package_parameters_.
+ // Run dexopt with the parameters of parameters_.
// TODO(calin): embed the profile name in the parameters.
int Dexopt() {
- return dexopt(package_parameters_.apk_path,
- package_parameters_.uid,
- package_parameters_.pkgName,
- package_parameters_.instruction_set,
- package_parameters_.dexopt_needed,
- package_parameters_.oat_dir,
- package_parameters_.dexopt_flags,
- package_parameters_.compiler_filter,
- package_parameters_.volume_uuid,
- package_parameters_.shared_libraries,
- package_parameters_.se_info,
- package_parameters_.downgrade,
- package_parameters_.target_sdk_version,
- package_parameters_.profile_name);
+ return dexopt(parameters_.apk_path,
+ parameters_.uid,
+ parameters_.pkgName,
+ parameters_.instruction_set,
+ parameters_.dexopt_needed,
+ parameters_.oat_dir,
+ parameters_.dexopt_flags,
+ parameters_.compiler_filter,
+ parameters_.volume_uuid,
+ parameters_.shared_libraries,
+ parameters_.se_info,
+ parameters_.downgrade,
+ parameters_.target_sdk_version,
+ parameters_.profile_name,
+ parameters_.dex_metadata_path);
}
int RunPreopt() {
@@ -1167,12 +613,12 @@
// If this was a profile-guided run, we may have profile version issues. Try to downgrade,
// if possible.
- if ((package_parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
+ if ((parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
return dexopt_result;
}
LOG(WARNING) << "Downgrading compiler filter in an attempt to progress compilation";
- package_parameters_.dexopt_flags &= ~DEXOPT_PROFILE_GUIDED;
+ parameters_.dexopt_flags &= ~DEXOPT_PROFILE_GUIDED;
return Dexopt();
}
@@ -1297,13 +743,12 @@
SystemProperties system_properties_;
// Some select properties that are always needed.
- std::string target_slot_;
std::string android_root_;
std::string android_data_;
std::string boot_classpath_;
std::string asec_mountpoint_;
- Parameters package_parameters_;
+ OTAPreoptParameters parameters_;
// Store environment values we need to set.
std::vector<std::string> environ_;
diff --git a/cmds/installd/otapreopt_parameters.cpp b/cmds/installd/otapreopt_parameters.cpp
new file mode 100644
index 0000000..5b5f522
--- /dev/null
+++ b/cmds/installd/otapreopt_parameters.cpp
@@ -0,0 +1,347 @@
+/*
+ ** Copyright 2016, 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 "otapreopt_parameters.h"
+
+#include <android-base/logging.h>
+
+#include "dexopt.h"
+#include "installd_constants.h"
+#include "otapreopt_utils.h"
+
+#ifndef LOG_TAG
+#define LOG_TAG "otapreopt"
+#endif
+
+namespace android {
+namespace installd {
+
+static bool ParseBool(const char* in) {
+ if (strcmp(in, "true") == 0) {
+ return true;
+ }
+ return false;
+}
+
+static const char* ParseNull(const char* arg) {
+ return (strcmp(arg, "!") == 0) ? nullptr : arg;
+}
+
+static bool ParseUInt(const char* in, uint32_t* out) {
+ char* end;
+ long long int result = strtoll(in, &end, 0);
+ if (in == end || *end != '\0') {
+ return false;
+ }
+ if (result < std::numeric_limits<uint32_t>::min() ||
+ std::numeric_limits<uint32_t>::max() < result) {
+ return false;
+ }
+ *out = static_cast<uint32_t>(result);
+ return true;
+}
+
+bool OTAPreoptParameters::ReadArguments(int argc, const char** argv) {
+ // Expected command line:
+ // target-slot [version] dexopt {DEXOPT_PARAMETERS}
+
+ const char* target_slot_arg = argv[1];
+ if (target_slot_arg == nullptr) {
+ LOG(ERROR) << "Missing parameters";
+ return false;
+ }
+ // Sanitize value. Only allow (a-zA-Z0-9_)+.
+ target_slot = target_slot_arg;
+ if (!ValidateTargetSlotSuffix(target_slot)) {
+ LOG(ERROR) << "Target slot suffix not legal: " << target_slot;
+ return false;
+ }
+
+ // Check for version or "dexopt" next.
+ if (argv[2] == nullptr) {
+ LOG(ERROR) << "Missing parameters";
+ return false;
+ }
+
+ if (std::string("dexopt").compare(argv[2]) == 0) {
+ // This is version 1 (N) or pre-versioning version 2.
+ constexpr int kV2ArgCount = 1 // "otapreopt"
+ + 1 // slot
+ + 1 // "dexopt"
+ + 1 // apk_path
+ + 1 // uid
+ + 1 // pkg
+ + 1 // isa
+ + 1 // dexopt_needed
+ + 1 // oat_dir
+ + 1 // dexopt_flags
+ + 1 // filter
+ + 1 // volume
+ + 1 // libs
+ + 1; // seinfo
+ if (argc == kV2ArgCount) {
+ return ReadArgumentsPostV1(2, argv, false);
+ } else {
+ return ReadArgumentsV1(argv);
+ }
+ }
+
+ uint32_t version;
+ if (!ParseUInt(argv[2], &version)) {
+ LOG(ERROR) << "Could not parse version: " << argv[2];
+ return false;
+ }
+
+ return ReadArgumentsPostV1(version, argv, true);
+}
+
+static int ReplaceMask(int input, int old_mask, int new_mask) {
+ return (input & old_mask) != 0 ? new_mask : 0;
+}
+
+bool OTAPreoptParameters::ReadArgumentsV1(const char** argv) {
+ // Check for "dexopt".
+ if (argv[2] == nullptr) {
+ LOG(ERROR) << "Missing parameters";
+ return false;
+ }
+ if (std::string("dexopt").compare(argv[2]) != 0) {
+ LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[2];
+ return false;
+ }
+
+ size_t param_index = 0;
+ for (;; ++param_index) {
+ const char* param = argv[3 + param_index];
+ if (param == nullptr) {
+ break;
+ }
+
+ switch (param_index) {
+ case 0:
+ apk_path = param;
+ break;
+
+ case 1:
+ uid = atoi(param);
+ break;
+
+ case 2:
+ pkgName = param;
+ break;
+
+ case 3:
+ instruction_set = param;
+ break;
+
+ case 4: {
+ // Version 1 had:
+ // DEXOPT_DEX2OAT_NEEDED = 1
+ // DEXOPT_PATCHOAT_NEEDED = 2
+ // DEXOPT_SELF_PATCHOAT_NEEDED = 3
+ // We will simply use DEX2OAT_FROM_SCRATCH.
+ dexopt_needed = DEX2OAT_FROM_SCRATCH;
+ break;
+ }
+
+ case 5:
+ oat_dir = param;
+ break;
+
+ case 6: {
+ // Version 1 had:
+ constexpr int OLD_DEXOPT_PUBLIC = 1 << 1;
+ // Note: DEXOPT_SAFEMODE has been removed.
+ // constexpr int OLD_DEXOPT_SAFEMODE = 1 << 2;
+ constexpr int OLD_DEXOPT_DEBUGGABLE = 1 << 3;
+ constexpr int OLD_DEXOPT_BOOTCOMPLETE = 1 << 4;
+ constexpr int OLD_DEXOPT_PROFILE_GUIDED = 1 << 5;
+ constexpr int OLD_DEXOPT_OTA = 1 << 6;
+ int input = atoi(param);
+ dexopt_flags =
+ ReplaceMask(input, OLD_DEXOPT_PUBLIC, DEXOPT_PUBLIC) |
+ ReplaceMask(input, OLD_DEXOPT_DEBUGGABLE, DEXOPT_DEBUGGABLE) |
+ ReplaceMask(input, OLD_DEXOPT_BOOTCOMPLETE, DEXOPT_BOOTCOMPLETE) |
+ ReplaceMask(input, OLD_DEXOPT_PROFILE_GUIDED, DEXOPT_PROFILE_GUIDED) |
+ ReplaceMask(input, OLD_DEXOPT_OTA, 0);
+ break;
+ }
+
+ case 7:
+ compiler_filter = param;
+ break;
+
+ case 8:
+ volume_uuid = ParseNull(param);
+ break;
+
+ case 9:
+ shared_libraries = ParseNull(param);
+ break;
+
+ default:
+ LOG(ERROR) << "Too many arguments, got " << param;
+ return false;
+ }
+ }
+
+ if (param_index != 10) {
+ LOG(ERROR) << "Not enough parameters";
+ return false;
+ }
+
+ // Set se_info to null. It is only relevant for secondary dex files, which we won't
+ // receive from a v1 A side.
+ se_info = nullptr;
+
+ // Set downgrade to false. It is only relevant when downgrading compiler
+ // filter, which is not the case during ota.
+ downgrade = false;
+
+ // Set target_sdk_version to 0, ie the platform SDK version. This is
+ // conservative and may force some classes to verify at runtime.
+ target_sdk_version = 0;
+
+ // Set the profile name to the primary apk profile.
+ profile_name = "primary.prof";
+
+ return true;
+}
+
+bool OTAPreoptParameters::ReadArgumentsPostV1(uint32_t version, const char** argv, bool versioned) {
+ size_t num_args_expected = 0;
+ switch (version) {
+ case 2: num_args_expected = 11; break;
+ case 3: num_args_expected = 12; break;
+ case 4: num_args_expected = 13; break;
+ case 5: num_args_expected = 14; break;
+ case 6: num_args_expected = 15; break;
+ default:
+ LOG(ERROR) << "Don't know how to read arguments for version " << version;
+ return false;
+ }
+ size_t dexopt_index = versioned ? 3 : 2;
+
+ // Check for "dexopt".
+ if (argv[dexopt_index] == nullptr) {
+ LOG(ERROR) << "Missing parameters";
+ return false;
+ }
+ if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
+ LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[dexopt_index];
+ return false;
+ }
+
+ // Validate the number of arguments.
+ size_t num_args_actual = 0;
+ while (argv[dexopt_index + 1 + num_args_actual] != nullptr) {
+ num_args_actual++;
+ }
+
+ if (num_args_actual != num_args_expected) {
+ LOG(ERROR) << "Invalid number of arguments. expected="
+ << num_args_expected << " actual=" << num_args_actual;
+ return false;
+ }
+
+ // The number of arguments is OK.
+ // Configure the default values for the parameters that were added after V1.
+ // The default values will be overwritten in case they are passed as arguments.
+
+ // Set downgrade to false. It is only relevant when downgrading compiler
+ // filter, which is not the case during ota.
+ downgrade = false;
+
+ // Set target_sdk_version to 0, ie the platform SDK version. This is
+ // conservative and may force some classes to verify at runtime.
+ target_sdk_version = 0;
+
+ // Set the profile name to the primary apk profile.
+ profile_name = "primary.prof";
+
+ for (size_t param_index = 0; param_index < num_args_actual; ++param_index) {
+ const char* param = argv[dexopt_index + 1 + param_index];
+ switch (param_index) {
+ case 0:
+ apk_path = param;
+ break;
+
+ case 1:
+ uid = atoi(param);
+ break;
+
+ case 2:
+ pkgName = param;
+ break;
+
+ case 3:
+ instruction_set = param;
+ break;
+
+ case 4:
+ dexopt_needed = atoi(param);
+ break;
+
+ case 5:
+ oat_dir = param;
+ break;
+
+ case 6:
+ dexopt_flags = atoi(param);
+ break;
+
+ case 7:
+ compiler_filter = param;
+ break;
+
+ case 8:
+ volume_uuid = ParseNull(param);
+ break;
+
+ case 9:
+ shared_libraries = ParseNull(param);
+ break;
+
+ case 10:
+ se_info = ParseNull(param);
+ break;
+
+ case 11:
+ downgrade = ParseBool(param);
+ break;
+
+ case 12:
+ target_sdk_version = atoi(param);
+ break;
+
+ case 13:
+ profile_name = ParseNull(param);
+ break;
+
+ case 14:
+ dex_metadata_path = ParseNull(param);
+
+ default:
+ CHECK(false) << "Should not get here. Did you call ReadArguments "
+ << "with the right expectation?";
+ }
+ }
+
+ return true;
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/otapreopt_parameters.h b/cmds/installd/otapreopt_parameters.h
new file mode 100644
index 0000000..0f3bb8c
--- /dev/null
+++ b/cmds/installd/otapreopt_parameters.h
@@ -0,0 +1,59 @@
+/*
+ ** Copyright 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.
+ */
+
+#ifndef OTAPREOPT_PARAMETERS_H_
+#define OTAPREOPT_PARAMETERS_H_
+
+#include <string>
+#include <sys/types.h>
+
+namespace android {
+namespace installd {
+
+class OTAPreoptParameters {
+ public:
+ bool ReadArguments(int argc, const char** argv);
+
+ private:
+ bool ReadArgumentsV1(const char** argv);
+ bool ReadArgumentsPostV1(uint32_t version, const char** argv, bool versioned);
+
+ const char* apk_path;
+ uid_t uid;
+ const char* pkgName;
+ const char* instruction_set;
+ int dexopt_needed;
+ const char* oat_dir;
+ int dexopt_flags;
+ const char* compiler_filter;
+ const char* volume_uuid;
+ const char* shared_libraries;
+ const char* se_info;
+ bool downgrade;
+ int target_sdk_version;
+ const char* profile_name;
+ const char* dex_metadata_path;
+
+ std::string target_slot;
+
+ friend class OTAPreoptService;
+ friend class OTAPreoptTest;
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // OTAPREOPT_PARAMETERS_H_
\ No newline at end of file
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 47346fb..7438d3d 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -78,3 +78,20 @@
"liblogwrap",
],
}
+
+cc_test {
+ name: "installd_otapreopt_test",
+ clang: true,
+ srcs: ["installd_otapreopt_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libutils",
+ ],
+ static_libs: [
+ "liblog",
+ "libotapreoptparameters"
+ ],
+}
+
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 052fcfc..e176871 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -263,6 +263,7 @@
bool downgrade = false;
int32_t target_sdk_version = 0; // default
std::unique_ptr<std::string> profile_name_ptr = nullptr;
+ std::unique_ptr<std::string> dm_path_ptr = nullptr;
binder::Status result = service_->dexopt(path,
uid,
@@ -277,7 +278,8 @@
se_info_ptr,
downgrade,
target_sdk_version,
- profile_name_ptr);
+ profile_name_ptr,
+ dm_path_ptr);
ASSERT_EQ(should_binder_call_succeed, result.isOk());
int expected_access = should_dex_be_compiled ? 0 : -1;
std::string odex = GetSecondaryDexArtifact(path, "odex");
@@ -331,9 +333,10 @@
const char* oat_dir,
int32_t uid,
int32_t dexopt_needed,
+ const char* dm_path = nullptr,
bool downgrade = false) {
return CompilePrimaryDex(
- compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, downgrade, true);
+ compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, dm_path, downgrade, true);
}
void CompilePrimaryDexFail(std::string compiler_filter,
@@ -341,9 +344,10 @@
const char* oat_dir,
int32_t uid,
int32_t dexopt_needed,
+ const char* dm_path = nullptr,
bool downgrade = false) {
return CompilePrimaryDex(
- compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, downgrade, false);
+ compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, dm_path, downgrade, false);
}
void CompilePrimaryDex(std::string compiler_filter,
@@ -351,6 +355,7 @@
const char* oat_dir,
int32_t uid,
int32_t dexopt_needed,
+ const char* dm_path,
bool downgrade,
bool should_binder_call_succeed) {
std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
@@ -360,6 +365,10 @@
std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
int32_t target_sdk_version = 0; // default
std::unique_ptr<std::string> profile_name_ptr(new std::string("primary.prof"));
+ std::unique_ptr<std::string> dm_path_ptr = nullptr;
+ if (dm_path != nullptr) {
+ dm_path_ptr.reset(new std::string(dm_path));
+ }
bool prof_result;
binder::Status prof_binder_result = service_->prepareAppProfile(
@@ -382,7 +391,8 @@
se_info_ptr,
downgrade,
target_sdk_version,
- profile_name_ptr);
+ profile_name_ptr,
+ dm_path_ptr);
ASSERT_EQ(should_binder_call_succeed, result.isOk());
if (!should_binder_call_succeed) {
@@ -395,15 +405,14 @@
std::string vdex = GetPrimaryDexArtifact(oat_dir, apk_path_, "vdex");
std::string art = GetPrimaryDexArtifact(oat_dir, apk_path_, "art");
- mode_t mode = S_IFREG | (compiler_filter == "speed-profile" ? 0640 : 0644);
+ bool is_public = (dex_flags & DEXOPT_PUBLIC) != 0;
+ mode_t mode = S_IFREG | (is_public ? 0644 : 0640);
CheckFileAccess(odex, kSystemUid, uid, mode);
CheckFileAccess(vdex, kSystemUid, uid, mode);
- CheckFileAccess(odex, kSystemUid, uid, mode);
- // empty profiles do not generate an image.
- // todo: add tests with non-empty profiles.
- struct stat st;
- ASSERT_EQ(-1, stat(art.c_str(), &st));
+ if (compiler_filter == "speed-profile") {
+ CheckFileAccess(art, kSystemUid, uid, mode);
+ }
}
std::string GetPrimaryDexArtifact(const char* oat_dir,
@@ -480,10 +489,19 @@
DEX2OAT_FROM_SCRATCH);
}
+TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) {
+ LOG(INFO) << "DexoptPrimaryFailedInvalidFilter";
+ CompilePrimaryDexFail("awesome-filter",
+ DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC,
+ app_oat_dir_.c_str(),
+ kTestAppGid,
+ DEX2OAT_FROM_SCRATCH);
+}
+
TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) {
LOG(INFO) << "DexoptPrimaryProfileNonPublic";
CompilePrimaryDexOk("speed-profile",
- DEXOPT_BOOTCOMPLETE,
+ DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED,
app_oat_dir_.c_str(),
kTestAppGid,
DEX2OAT_FROM_SCRATCH);
@@ -491,8 +509,8 @@
TEST_F(DexoptTest, DexoptPrimaryProfilePublic) {
LOG(INFO) << "DexoptPrimaryProfilePublic";
- CompilePrimaryDexOk("verify",
- DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
+ CompilePrimaryDexOk("speed-profile",
+ DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_PUBLIC,
app_oat_dir_.c_str(),
kTestAppGid,
DEX2OAT_FROM_SCRATCH);
@@ -501,21 +519,12 @@
TEST_F(DexoptTest, DexoptPrimaryBackgroundOk) {
LOG(INFO) << "DexoptPrimaryBackgroundOk";
CompilePrimaryDexOk("speed-profile",
- DEXOPT_IDLE_BACKGROUND_JOB,
+ DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PROFILE_GUIDED,
app_oat_dir_.c_str(),
kTestAppGid,
DEX2OAT_FROM_SCRATCH);
}
-TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) {
- LOG(INFO) << "DexoptPrimaryFailedInvalidFilter";
- CompilePrimaryDexFail("awesome-filter",
- DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC,
- app_oat_dir_.c_str(),
- kTestAppGid,
- DEX2OAT_FROM_SCRATCH);
-}
-
class PrimaryDexReCompilationTest : public DexoptTest {
public:
virtual void SetUp() {
diff --git a/cmds/installd/tests/installd_otapreopt_test.cpp b/cmds/installd/tests/installd_otapreopt_test.cpp
new file mode 100644
index 0000000..1e8ae42
--- /dev/null
+++ b/cmds/installd/tests/installd_otapreopt_test.cpp
@@ -0,0 +1,210 @@
+/**
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+
+#include "otapreopt_parameters.h"
+
+namespace android {
+namespace installd {
+
+static bool ParseBool(const char* in) {
+ if (strcmp(in, "true") == 0) {
+ return true;
+ }
+ return false;
+}
+
+static const char* ParseNull(const char* arg) {
+ return (strcmp(arg, "!") == 0) ? nullptr : arg;
+}
+
+class OTAPreoptTest : public testing::Test {
+protected:
+ virtual void SetUp() {
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(nullptr);
+ }
+
+ void verifyPackageParameters(const OTAPreoptParameters& params,
+ uint32_t version,
+ bool versioned,
+ const char** args) {
+ // otapreopt target-slot [version] dexopt {DEXOPT_PARAMETERS}
+ int i = 0;
+ if (version > 2 || (version == 2 && versioned)) {
+ i += 4;
+ } else {
+ i += 3;
+ }
+ ASSERT_STREQ(params.target_slot.c_str(), args[1]);
+ ASSERT_STREQ(params.apk_path, args[i++]);
+ ASSERT_EQ(params.uid, static_cast<uid_t>(atoi(args[i++])));
+ ASSERT_STREQ(params.pkgName, args[i++]);
+ ASSERT_STREQ(params.instruction_set, args[i++]);
+ ASSERT_EQ(params.dexopt_needed, atoi(args[i++]));
+ ASSERT_STREQ(params.oat_dir, args[i++]);
+ ASSERT_EQ(params.dexopt_flags, atoi(args[i++]));
+ ASSERT_STREQ(params.compiler_filter, args[i++]);
+ ASSERT_STREQ(params.volume_uuid, ParseNull(args[i++]));
+ ASSERT_STREQ(params.shared_libraries, ParseNull(args[i++]));
+ if (version > 1) {
+ ASSERT_STREQ(params.se_info, ParseNull(args[i++]));
+ } else {
+ ASSERT_STREQ(params.se_info, nullptr);
+ }
+ if (version > 2) {
+ ASSERT_EQ(params.downgrade, ParseBool(args[i++]));
+ } else {
+ ASSERT_FALSE(params.downgrade);
+ }
+ if (version > 3) {
+ ASSERT_EQ(params.target_sdk_version, atoi(args[i++]));
+ } else {
+ ASSERT_EQ(params.target_sdk_version, 0);
+ }
+ if (version > 4) {
+ ASSERT_STREQ(params.profile_name, ParseNull(args[i++]));
+ } else {
+ ASSERT_STREQ(params.profile_name, "primary.prof");
+ }
+ if (version > 5) {
+ ASSERT_STREQ(params.dex_metadata_path, ParseNull(args[i++]));
+ } else {
+ ASSERT_STREQ(params.dex_metadata_path, nullptr);
+ }
+ }
+
+ const char* getVersionCStr(uint32_t version) {
+ switch (version) {
+ case 1: return "1";
+ case 2: return "2";
+ case 3: return "3";
+ case 4: return "4";
+ case 5: return "5";
+ case 6: return "6";
+ }
+ return nullptr;
+ }
+
+ std::vector<const char*> getArgs(uint32_t version, bool versioned) {
+ std::vector<const char*> args;
+ args.push_back("otapreopt"); // "otapreopt"
+ args.push_back("a"); // slot
+ if (versioned) {
+ args.push_back(getVersionCStr(version));
+ }
+ args.push_back("dexopt"); // "dexopt"
+ args.push_back("foo.apk"); // apk_path
+ args.push_back("123"); // uid
+ args.push_back("pkgname"); // pkg
+ args.push_back("arm"); // isa
+ args.push_back("1"); // dexopt_needed (DEX2OAT_FROM_SCRATCH)
+ args.push_back("oat_dir"); // oat_dir
+ args.push_back("0"); // dexopt_flags
+ args.push_back("speed"); // filter
+ args.push_back("!"); // volume
+ args.push_back("shared.lib"); // libs
+
+ if (version > 1) {
+ args.push_back("!"); // seinfo
+ }
+ if (version > 2) {
+ args.push_back("true"); // downgrade
+ }
+ if (version > 3) {
+ args.push_back("28"); // sdk_version
+ }
+ if (version > 4) {
+ args.push_back("split_a.prof"); // profile_name
+ }
+ if (version > 5) {
+ args.push_back("dex_metadata.dm"); // dex_metadata_path
+ }
+ args.push_back(nullptr); // we have to end with null.
+ return args;
+ }
+
+ void VerifyReadArguments(uint32_t version, bool versioned) {
+ OTAPreoptParameters params;
+ std::vector<const char*> args = getArgs(version, versioned);
+ ASSERT_TRUE(params.ReadArguments(args.size() - 1, args.data()));
+ verifyPackageParameters(params, version, versioned, args.data());
+ }
+};
+
+TEST_F(OTAPreoptTest, ReadArgumentsV1) {
+ VerifyReadArguments(1, false);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV2Unversioned) {
+ VerifyReadArguments(2, false);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV2) {
+ VerifyReadArguments(2, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV3) {
+ VerifyReadArguments(3, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV4) {
+ VerifyReadArguments(4, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV5) {
+ VerifyReadArguments(5, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV6) {
+ VerifyReadArguments(6, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailToManyArgs) {
+ OTAPreoptParameters params;
+ std::vector<const char*> args = getArgs(5, true);
+ args[2] = "3"; // pretend it's version 3. It should fail since there are too many args.
+ ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailInsufficientArgs) {
+ OTAPreoptParameters params;
+ std::vector<const char*> args = getArgs(4, true);
+ args[2] = "5"; // pretend it's version 5. It should fail since there are insufficient args.
+ ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailInvalidDexopt) {
+ OTAPreoptParameters params;
+ std::vector<const char*> args = getArgs(4, true);
+ args[3] = "dexopt-invalid";
+ ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailInvalidSlot) {
+ OTAPreoptParameters params;
+ std::vector<const char*> args = getArgs(3, true);
+ args[1] = "invalid-slot???";
+ ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+} // namespace installd
+} // namespace android
diff --git a/docs/Doxyfile b/docs/Doxyfile
index 0ec4551..efa639d 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -1580,20 +1580,20 @@
# evaluate all C-preprocessor directives found in the sources and include
# files.
-ENABLE_PREPROCESSING = NO
+ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
# names in the source code. If set to NO (the default) only conditional
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
-MACRO_EXPANSION = NO
+MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_DEFINED tags.
-EXPAND_ONLY_PREDEF = NO
+EXPAND_ONLY_PREDEF = YES
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# pointed to by INCLUDE_PATH will be searched when a #include is found.
@@ -1621,7 +1621,7 @@
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
-PREDEFINED =
+PREDEFINED = __attribute__(x)=
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h
new file mode 100644
index 0000000..56b3342
--- /dev/null
+++ b/include/android/surface_texture.h
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup SurfaceTexture
+ * @{
+ */
+
+/**
+ * @file surface_texture.h
+ */
+
+#ifndef ANDROID_NATIVE_SURFACE_TEXTURE_H
+#define ANDROID_NATIVE_SURFACE_TEXTURE_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is part of Android's set of stable system headers
+ * exposed by the Android NDK (Native Development Kit).
+ *
+ * Third-party source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+#include <stdint.h>
+
+#include <android/native_window.h>
+
+__BEGIN_DECLS
+
+struct ASurfaceTexture;
+
+/**
+ * {@link ASurfaceTexture} is an opaque type to manage SurfaceTexture from native code
+ *
+ * {@link ASurfaceTexture} can be obtained from an android.graphics.SurfaceTexture object using
+ * ASurfaceTexture_fromSurfaceTexture().
+ */
+typedef struct ASurfaceTexture ASurfaceTexture;
+
+/**
+ * Release the reference to the native ASurfaceTexture acquired with
+ * ASurfaceTexture_fromSurfaceTexture().
+ * Failing to do so will result in leaked memory and graphic resources.
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ */
+void ASurfaceTexture_release(ASurfaceTexture* st);
+
+/**
+ * Returns a reference to an ANativeWindow (i.e. the Producer) for this SurfaceTexture.
+ * This is equivalent to Java's: Surface sur = new Surface(surfaceTexture);
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * @return A reference to an ANativeWindow. This reference MUST BE released when no longer needed
+ * using ANativeWindow_release(). Failing to do so will result in leaked resources. nullptr is
+ * returned if \st is null or if it's not an instance of android.graphics.SurfaceTexture
+ */
+ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st);
+
+/**
+ * Attach the SurfaceTexture to the OpenGL ES context that is current on the calling thread. A
+ * new OpenGL ES texture object is created and populated with the SurfaceTexture image frame
+ * that was current at the time of the last call to {@link #detachFromGLContext}. This new
+ * texture is bound to the GL_TEXTURE_EXTERNAL_OES texture target.
+ *
+ * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES
+ * contexts. Note, however, that the image contents are only accessible from one OpenGL ES
+ * context at a time.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \param texName The name of the OpenGL ES texture that will be created. This texture name
+ * must be unusued in the OpenGL ES context that is current on the calling thread.
+ * \return 0 on success, negative posix error code otherwise (see <errno.h>)
+ */
+int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName);
+
+/**
+ * Detach the SurfaceTexture from the OpenGL ES context that owns the OpenGL ES texture object.
+ * This call must be made with the OpenGL ES context current on the calling thread. The OpenGL
+ * ES texture object will be deleted as a result of this call. After calling this method all
+ * calls to {@link #updateTexImage} will fail until a successful call to {@link #attachToGLContext}
+ * is made.
+ *
+ * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES
+ * contexts. Note, however, that the image contents are only accessible from one OpenGL ES
+ * context at a time.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \return 0 on success, negative posix error code otherwise (see <errno.h>)
+ */
+int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st);
+
+/**
+ * Update the texture image to the most recent frame from the image stream. This may only be
+ * called while the OpenGL ES context that owns the texture is current on the calling thread.
+ * It will implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \return 0 on success, negative posix error code otherwise (see <errno.h>)
+ */
+int ASurfaceTexture_updateTexImage(ASurfaceTexture* st);
+
+/**
+ * Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by
+ * the most recent call to updateTexImage.
+ *
+ * This transform matrix maps 2D homogeneous texture coordinates of the form (s, t, 0, 1) with s
+ * and t in the inclusive range [0, 1] to the texture coordinate that should be used to sample
+ * that location from the texture. Sampling the texture outside of the range of this transform
+ * is undefined.
+ *
+ * The matrix is stored in column-major order so that it may be passed directly to OpenGL ES via
+ * the glLoadMatrixf or glUniformMatrix4fv functions.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \param mtx the array into which the 4x4 matrix will be stored. The array must have exactly
+ * 16 elements.
+ */
+void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]);
+
+/**
+ * Retrieve the timestamp associated with the texture image set by the most recent call to
+ * updateTexImage.
+ *
+ * This timestamp is in nanoseconds, and is normally monotonically increasing. The timestamp
+ * should be unaffected by time-of-day adjustments, and for a camera should be strictly
+ * monotonic but for a MediaPlayer may be reset when the position is set. The
+ * specific meaning and zero point of the timestamp depends on the source providing images to
+ * the SurfaceTexture. Unless otherwise specified by the image source, timestamps cannot
+ * generally be compared across SurfaceTexture instances, or across multiple program
+ * invocations. It is mostly useful for determining time offsets between subsequent frames.
+ *
+ * For EGL/Vulkan producers, this timestamp is the desired present time set with the
+ * EGL_ANDROID_presentation_time or VK_GOOGLE_display_timing extensions
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ */
+int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st);
+
+__END_DECLS
+
+#endif /* ANDROID_NATIVE_SURFACE_TEXTURE_H */
diff --git a/include/android/surface_texture_jni.h b/include/android/surface_texture_jni.h
new file mode 100644
index 0000000..b0e1edd
--- /dev/null
+++ b/include/android/surface_texture_jni.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup SurfaceTexture
+ * @{
+ */
+
+/**
+ * @file surface_texture_jni.h
+ */
+
+#ifndef ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H
+#define ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H
+
+#include <android/surface_texture.h>
+
+#include <jni.h>
+
+__BEGIN_DECLS
+
+/**
+ * Get a reference to the native ASurfaceTexture from the corresponding java object.
+ *
+ * The caller must keep a reference to the Java SurfaceTexture during the lifetime of the returned
+ * ASurfaceTexture. Failing to do so could result in the ASurfaceTexture to stop functioning
+ * properly once the Java object gets finalized.
+ * However, this will not result in program termination.
+ *
+ * \param env JNI environment
+ * \param surfacetexture Instance of Java SurfaceTexture object
+ * \return native ASurfaceTexture reference or nullptr if the java object is not a SurfaceTexture.
+ * The returned reference MUST BE released when it's no longer needed using
+ * ASurfaceTexture_release().
+ */
+ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture);
+
+__END_DECLS
+
+#endif /* ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H */
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index ad04d03..065d44d 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -120,6 +120,8 @@
shared_libs: [
"libsync",
"libbinder",
+ "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
+ "libpdx_default_transport",
"libcutils",
"libEGL",
"libGLESv2",
@@ -135,13 +137,6 @@
"android.hardware.configstore-utils",
],
- // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
- static_libs: [
- "libbufferhub",
- "libbufferhubqueue",
- "libpdx_default_transport",
- ],
-
header_libs: [
"libdvr_headers",
"libnativebase_headers",
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 7ea37a7..39814cc 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -22,10 +22,6 @@
"include",
]
-staticLibraries = [
- "libpdx_default_transport",
-]
-
sharedLibraries = [
"libbase",
"libbinder",
@@ -34,7 +30,8 @@
"liblog",
"libui",
"libutils",
- "libnativewindow"
+ "libnativewindow",
+ "libpdx_default_transport",
]
headerLibraries = [
@@ -52,7 +49,6 @@
"-Werror",
],
export_include_dirs: localIncludeFiles,
- static_libs: staticLibraries,
shared_libs: sharedLibraries,
header_libs: headerLibraries,
name: "libbufferhub",
@@ -68,7 +64,7 @@
cc_test {
tags: ["optional"],
srcs: ["buffer_hub-test.cpp"],
- static_libs: ["libbufferhub"] + staticLibraries,
+ static_libs: ["libbufferhub"],
shared_libs: sharedLibraries,
header_libs: headerLibraries,
name: "buffer_hub-test",
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 84e7427..eeec9ec 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -23,7 +23,6 @@
staticLibraries = [
"libbufferhub",
- "libpdx_default_transport",
]
sharedLibraries = [
@@ -34,6 +33,7 @@
"liblog",
"libui",
"libutils",
+ "libpdx_default_transport",
]
headerLibraries = [
@@ -41,7 +41,7 @@
"libnativebase_headers",
]
-cc_library {
+cc_library_shared {
name: "libbufferhubqueue",
cflags: [
"-DLOG_TAG=\"libbufferhubqueue\"",
@@ -65,4 +65,4 @@
},
}
-subdirs = ["tests"]
+subdirs = ["benchmarks", "tests"]
diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
new file mode 100644
index 0000000..8ae7a0b
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
@@ -0,0 +1,27 @@
+
+cc_benchmark {
+ srcs: ["buffer_transport_benchmark.cpp"],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libdvr",
+ "libgui",
+ "liblog",
+ "libhardware",
+ "libui",
+ "libutils",
+ "libnativewindow",
+ "libbufferhubqueue",
+ "libpdx_default_transport",
+ ],
+ cflags: [
+ "-DLOG_TAG=\"buffer_transport_benchmark\"",
+ "-DTRACE=0",
+ "-O2",
+ "-Wall",
+ "-Werror",
+ ],
+ name: "buffer_transport_benchmark",
+ tags: ["optional"],
+}
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
similarity index 76%
rename from libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
rename to libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
index 73932c2..4ca8671 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
+++ b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
@@ -1,14 +1,13 @@
-#include <android/native_window.h>
#include <android-base/logging.h>
+#include <android/native_window.h>
#include <benchmark/benchmark.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <dvr/dvr_api.h>
-#include <dvr/performance_client_api.h>
-#include <gui/BufferHubProducer.h>
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
#include <gui/Surface.h>
+#include <private/dvr/epoll_file_descriptor.h>
#include <utils/Trace.h>
#include <chrono>
@@ -17,7 +16,9 @@
#include <thread>
#include <vector>
+#include <dlfcn.h>
#include <poll.h>
+#include <sys/epoll.h>
#include <sys/wait.h>
// Use ALWAYS at the tag level. Control is performed manually during command
@@ -28,7 +29,6 @@
#define ATRACE_TAG ATRACE_TAG_ALWAYS
using namespace android;
-using namespace android::dvr;
using ::benchmark::State;
static const String16 kBinderService = String16("bufferTransport");
@@ -37,9 +37,11 @@
static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
static const uint64_t kBufferUsage =
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+static const uint32_t kBufferLayer = 1;
static const int kMaxAcquiredImages = 1;
static const int kQueueDepth = 2; // We are double buffering for this test.
static const size_t kMaxQueueCounts = 128;
+static const int kInvalidFence = -1;
enum BufferTransportServiceCode {
CREATE_BUFFER_QUEUE = IBinder::FIRST_CALL_TRANSACTION,
@@ -62,7 +64,7 @@
case CREATE_BUFFER_QUEUE: {
auto new_queue = std::make_shared<BufferQueueHolder>(this);
reply->writeStrongBinder(
- IGraphicBufferProducer::asBinder(new_queue->producer_));
+ IGraphicBufferProducer::asBinder(new_queue->producer));
buffer_queues_.push_back(new_queue);
return NO_ERROR;
}
@@ -109,18 +111,20 @@
struct BufferQueueHolder {
explicit BufferQueueHolder(BufferTransportService* service) {
- BufferQueue::createBufferQueue(&producer_, &consumer_);
+ BufferQueue::createBufferQueue(&producer, &consumer);
sp<BufferItemConsumer> buffer_item_consumer =
- new BufferItemConsumer(consumer_, kBufferUsage, kMaxAcquiredImages,
+ new BufferItemConsumer(consumer, kBufferUsage, kMaxAcquiredImages,
/*controlledByApp=*/true);
buffer_item_consumer->setName(String8("BinderBufferTransport"));
frame_listener_ = new FrameListener(service, buffer_item_consumer);
buffer_item_consumer->setFrameAvailableListener(frame_listener_);
}
- sp<IGraphicBufferProducer> producer_;
- sp<IGraphicBufferConsumer> consumer_;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+
+ private:
sp<FrameListener> frame_listener_;
};
@@ -199,6 +203,28 @@
sp<IBinder> service_;
};
+class DvrApi {
+ public:
+ DvrApi() {
+ handle_ = dlopen("libdvr.so", RTLD_NOW | RTLD_LOCAL);
+ CHECK(handle_);
+
+ auto dvr_get_api =
+ reinterpret_cast<decltype(&dvrGetApi)>(dlsym(handle_, "dvrGetApi"));
+ int ret = dvr_get_api(&api_, sizeof(api_), /*version=*/1);
+
+ CHECK(ret == 0);
+ }
+
+ ~DvrApi() { dlclose(handle_); }
+
+ const DvrApi_v1& Api() { return api_; }
+
+ private:
+ void* handle_ = nullptr;
+ DvrApi_v1 api_;
+};
+
// BufferHub/PDX-based buffer transport.
//
// On Start() a new thread will be swapned to run an epoll polling thread which
@@ -227,16 +253,9 @@
// Create the reader thread.
reader_thread_ = std::thread([this]() {
- int ret = dvrSetSchedulerClass(0, "graphics");
+ int ret = dvr_.Api().PerformanceSetSchedulerPolicy(0, "graphics");
if (ret < 0) {
- LOG(ERROR) << "Failed to set thread priority";
- return;
- }
-
-
- ret = dvrSetCpuPartition(0, "/system/performance");
- if (ret < 0) {
- LOG(ERROR) << "Failed to set thread cpu partition";
+ LOG(ERROR) << "Failed to set scheduler policy, ret=" << ret;
return;
}
@@ -259,8 +278,9 @@
const int num_events = ret;
for (int i = 0; i < num_events; i++) {
- uint32_t surface_index = events[i].data.u32;
- buffer_queues_[surface_index]->consumer_queue_->HandleQueueEvents();
+ uint32_t index = events[i].data.u32;
+ dvr_.Api().ReadBufferQueueHandleEvents(
+ buffer_queues_[index]->GetReadQueue());
}
}
@@ -272,89 +292,123 @@
sp<Surface> CreateSurface() override {
auto new_queue = std::make_shared<BufferQueueHolder>();
- if (new_queue->producer_ == nullptr) {
- LOG(ERROR) << "Failed to create buffer producer.";
+ if (!new_queue->IsReady()) {
+ LOG(ERROR) << "Failed to create BufferHub-based BufferQueue.";
return nullptr;
}
- sp<Surface> surface =
- new Surface(new_queue->producer_, /*controlledByApp=*/true);
-
// Set buffer dimension.
- ANativeWindow* window = static_cast<ANativeWindow*>(surface.get());
- ANativeWindow_setBuffersGeometry(window, kBufferWidth, kBufferHeight,
- kBufferFormat);
+ ANativeWindow_setBuffersGeometry(new_queue->GetSurface(), kBufferWidth,
+ kBufferHeight, kBufferFormat);
// Use the next position as buffer_queue index.
uint32_t index = buffer_queues_.size();
epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u32 = index}};
- const int ret = epoll_fd_.Control(
- EPOLL_CTL_ADD, new_queue->consumer_queue_->queue_fd(), &event);
+ int queue_fd =
+ dvr_.Api().ReadBufferQueueGetEventFd(new_queue->GetReadQueue());
+ const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, queue_fd, &event);
if (ret < 0) {
LOG(ERROR) << "Failed to track consumer queue: " << strerror(-ret)
- << ", consumer queue fd: "
- << new_queue->consumer_queue_->queue_fd();
+ << ", consumer queue fd: " << queue_fd;
return nullptr;
}
- new_queue->queue_index_ = index;
buffer_queues_.push_back(new_queue);
- return surface;
+ ANativeWindow_acquire(new_queue->GetSurface());
+ return static_cast<Surface*>(new_queue->GetSurface());
}
private:
struct BufferQueueHolder {
BufferQueueHolder() {
- ProducerQueueConfigBuilder config_builder;
- producer_queue_ =
- ProducerQueue::Create(config_builder.SetDefaultWidth(kBufferWidth)
- .SetDefaultHeight(kBufferHeight)
- .SetDefaultFormat(kBufferFormat)
- .SetMetadata<DvrNativeBufferMetadata>()
- .Build(),
- UsagePolicy{});
- consumer_queue_ = producer_queue_->CreateConsumerQueue();
- consumer_queue_->SetBufferAvailableCallback([this]() {
- size_t index = 0;
- pdx::LocalHandle fence;
- DvrNativeBufferMetadata meta;
- pdx::Status<std::shared_ptr<BufferConsumer>> status;
+ int ret = 0;
+ ret = dvr_.Api().WriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kBufferLayer,
+ kBufferUsage, 0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to create write buffer queue, ret=" << ret;
+ return;
+ }
- {
- ATRACE_NAME("AcquireBuffer");
- status = consumer_queue_->Dequeue(0, &index, &meta, &fence);
- }
- if (!status.ok()) {
- LOG(ERROR) << "Failed to dequeue consumer buffer, error: "
- << status.GetErrorMessage().c_str();
- return;
- }
+ ret = dvr_.Api().WriteBufferQueueCreateReadQueue(write_queue_,
+ &read_queue_);
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to create read buffer queue, ret=" << ret;
+ return;
+ }
- auto buffer = status.take();
+ ret = dvr_.Api().ReadBufferQueueSetBufferAvailableCallback(
+ read_queue_, BufferAvailableCallback, this);
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to create buffer available callback, ret=" << ret;
+ return;
+ }
- if (buffer) {
- ATRACE_NAME("ReleaseBuffer");
- buffer->ReleaseAsync();
- }
- });
-
- producer_ = BufferHubProducer::Create(producer_queue_);
+ ret =
+ dvr_.Api().WriteBufferQueueGetANativeWindow(write_queue_, &surface_);
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to create surface, ret=" << ret;
+ return;
+ }
}
- int count_ = 0;
- int queue_index_;
- std::shared_ptr<ProducerQueue> producer_queue_;
- std::shared_ptr<ConsumerQueue> consumer_queue_;
- sp<IGraphicBufferProducer> producer_;
+ static void BufferAvailableCallback(void* context) {
+ BufferQueueHolder* thiz = static_cast<BufferQueueHolder*>(context);
+ thiz->HandleBufferAvailable();
+ }
+
+ DvrReadBufferQueue* GetReadQueue() { return read_queue_; }
+
+ ANativeWindow* GetSurface() { return surface_; }
+
+ bool IsReady() {
+ return write_queue_ != nullptr && read_queue_ != nullptr &&
+ surface_ != nullptr;
+ }
+
+ void HandleBufferAvailable() {
+ int ret = 0;
+ DvrNativeBufferMetadata meta;
+ DvrReadBuffer* buffer = nullptr;
+ DvrNativeBufferMetadata metadata;
+ int acquire_fence = kInvalidFence;
+
+ {
+ ATRACE_NAME("AcquireBuffer");
+ ret = dvr_.Api().ReadBufferQueueAcquireBuffer(
+ read_queue_, 0, &buffer, &metadata, &acquire_fence);
+ }
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to acquire consumer buffer, error: " << ret;
+ return;
+ }
+
+ if (buffer != nullptr) {
+ ATRACE_NAME("ReleaseBuffer");
+ ret = dvr_.Api().ReadBufferQueueReleaseBuffer(read_queue_, buffer,
+ &meta, kInvalidFence);
+ }
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to release consumer buffer, error: " << ret;
+ }
+ }
+
+ private:
+ DvrWriteBufferQueue* write_queue_ = nullptr;
+ DvrReadBufferQueue* read_queue_ = nullptr;
+ ANativeWindow* surface_ = nullptr;
};
+ static DvrApi dvr_;
std::atomic<bool> stopped_;
std::thread reader_thread_;
- EpollFileDescriptor epoll_fd_;
+ dvr::EpollFileDescriptor epoll_fd_;
std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
};
+DvrApi BufferHubTransport::dvr_ = {};
+
enum TransportType {
kBinderBufferTransport,
kBufferHubTransport,
@@ -508,8 +562,7 @@
for (int i = 1; i < argc; i++) {
if (std::string(argv[i]) == "--help") {
std::cout << "Usage: binderThroughputTest [OPTIONS]" << std::endl;
- std::cout << "\t--trace: Enable systrace logging."
- << std::endl;
+ std::cout << "\t--trace: Enable systrace logging." << std::endl;
return 0;
}
if (std::string(argv[i]) == "--trace") {
@@ -524,7 +577,7 @@
pid_t pid = fork();
if (pid == 0) {
- // parent, i.e. the client side.
+ // Child, i.e. the client side.
ProcessState::self()->startThreadPool();
::benchmark::Initialize(&argc, argv);
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index 5eba913..ca1e7bd 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -6,6 +6,7 @@
shared_libraries = [
"libbase",
"libbinder",
+ "libbufferhubqueue",
"libcutils",
"libgui",
"liblog",
@@ -13,14 +14,12 @@
"libui",
"libutils",
"libnativewindow",
+ "libpdx_default_transport",
]
static_libraries = [
- "libbufferhubqueue",
- "libbufferhub",
"libchrome",
"libdvrcommon",
- "libpdx_default_transport",
"libperformance",
]
@@ -58,19 +57,3 @@
name: "buffer_hub_queue_producer-test",
tags: ["optional"],
}
-
-cc_benchmark {
- srcs: ["buffer_transport_benchmark.cpp"],
- static_libs: static_libraries,
- shared_libs: shared_libraries,
- header_libs: header_libraries,
- cflags: [
- "-DLOG_TAG=\"buffer_transport_benchmark\"",
- "-DTRACE=0",
- "-O2",
- "-Wall",
- "-Werror",
- ],
- name: "buffer_transport_benchmark",
- tags: ["optional"],
-}
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index 69dbc84..192fb5d 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -27,6 +27,7 @@
sharedLibraries = [
"libbase",
"libbinder",
+ "libbufferhubqueue",
"libcutils",
"liblog",
"libutils",
@@ -35,14 +36,12 @@
"libhardware",
"libsync",
"libnativewindow",
+ "libpdx_default_transport",
]
staticLibraries = [
"libdvrcommon",
- "libbufferhubqueue",
- "libbufferhub",
"libbroadcastring",
- "libpdx_default_transport",
]
headerLibraries = [
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 4f0e561..d0e34ee 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -44,8 +44,6 @@
static_libs = [
"libbroadcastring",
- "libbufferhub",
- "libbufferhubqueue",
"libvrsensor",
"libdisplay",
"libvirtualtouchpadclient",
@@ -53,13 +51,13 @@
"libvr_hwc-binder",
"libgrallocusage",
"libperformance",
- "libpdx_default_transport",
]
shared_libs = [
"android.hardware.graphics.bufferqueue@1.0",
"android.hidl.token@1.0-utils",
"libbase",
+ "libbufferhubqueue",
"libbinder",
"liblog",
"libcutils",
@@ -67,6 +65,7 @@
"libnativewindow",
"libgui",
"libui",
+ "libpdx_default_transport",
]
cc_library_shared {
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 887766a..e8aa6b7 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -15,6 +15,7 @@
shared_libraries = [
"libbase",
"libbinder",
+ "libbufferhubqueue",
"libcutils",
"libgui",
"liblog",
@@ -22,16 +23,14 @@
"libui",
"libutils",
"libnativewindow",
+ "libpdx_default_transport",
]
static_libraries = [
"libdvr_static",
- "libbufferhubqueue",
- "libbufferhub",
"libchrome",
"libdvrcommon",
"libdisplay",
- "libpdx_default_transport",
"libbroadcastring",
]
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index c7d808b..32b793a 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -26,9 +26,10 @@
"libui",
"libgui",
"libhardware",
+ "libpdx_default_transport",
]
-staticLibraries = ["libpdx_default_transport", "libbroadcastring"]
+staticLibraries = ["libbroadcastring"]
headerLibraries = [
"libeigen",
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 779e3a1..475eb50 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -30,13 +30,25 @@
whole_static_libs: ["libpdx_uds"],
}
-cc_library_static {
+cc_library_shared {
name: "libpdx_default_transport",
defaults: [
"pdx_default_transport_compiler_defaults",
"pdx_default_transport_lib_defaults",
"pdx_use_transport_uds",
],
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libcrypto",
+ ],
}
cc_binary {
@@ -49,8 +61,6 @@
"libbinder",
"libcutils",
"liblog",
- ],
- static_libs: [
"libpdx_default_transport",
],
}
@@ -69,8 +79,6 @@
"libcutils",
"liblog",
"libutils",
- ],
- static_libs: [
"libpdx_default_transport",
],
}
diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp
index 7c32dbb..35d3dea 100644
--- a/libs/vr/libperformance/Android.bp
+++ b/libs/vr/libperformance/Android.bp
@@ -19,14 +19,13 @@
includeFiles = [ "include" ]
-staticLibraries = ["libpdx_default_transport"]
-
sharedLibraries = [
"libbase",
"libbinder",
"libcutils",
"liblog",
"libutils",
+ "libpdx_default_transport",
]
cc_library {
@@ -38,7 +37,6 @@
"-Werror",
],
export_include_dirs: includeFiles,
- static_libs: staticLibraries,
shared_libs: sharedLibraries,
name: "libperformance",
}
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 9b6f0c5..23a9853 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -26,14 +26,11 @@
includeFiles = [ "include" ]
staticLibraries = [
- "libbufferhub",
- "libbufferhubqueue",
"libdisplay",
"libdvrcommon",
"libperformance",
"libvrsensor",
"libbroadcastring",
- "libpdx_default_transport",
"libvr_manager",
"libbroadcastring",
]
@@ -44,6 +41,7 @@
"android.hardware.graphics.composer@2.1",
"libbinder",
"libbase",
+ "libbufferhubqueue",
"libcutils",
"liblog",
"libhardware",
@@ -59,6 +57,7 @@
"libhidlbase",
"libhidltransport",
"libfmq",
+ "libpdx_default_transport",
]
headerLibraries = [
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index fe54b4b..8542790 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -23,21 +23,20 @@
staticLibraries = [
"libdisplay",
- "libbufferhub",
- "libbufferhubqueue",
"libdvrcommon",
"libbroadcastring",
- "libpdx_default_transport",
]
sharedLibraries = [
"libbase",
"libbinder",
+ "libbufferhubqueue",
"libcutils",
"libhardware",
"liblog",
"libutils",
"libui",
+ "libpdx_default_transport",
]
cc_library {
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 26ae13d..b00602c 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -479,8 +479,8 @@
// Return true if we stripped any EGL_GL_COLORSPACE_KHR or HDR metadata attributes.
// Protect devices from attributes they don't recognize that are managed by Android
static EGLBoolean stripAttributes(egl_display_ptr dp, const EGLint* attrib_list,
- EGLint format,
- std::vector<EGLint>& stripped_attrib_list) {
+ EGLint format,
+ std::vector<EGLint>& stripped_attrib_list) {
std::vector<EGLint> allowedColorSpaces;
switch (format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
@@ -712,7 +712,8 @@
cta8613 |= s->setCta8613Attribute(attr[0], attr[1]);
}
if (smpte2086) {
- int err = native_window_set_buffers_smpte2086_metadata(window, s->getSmpte2086Metadata());
+ android_smpte2086_metadata metadata = s->getSmpte2086Metadata();
+ int err = native_window_set_buffers_smpte2086_metadata(window, &metadata);
if (err != 0) {
ALOGE("error setting native window smpte2086 metadata: %s (%d)",
strerror(-err), err);
@@ -721,7 +722,8 @@
}
}
if (cta8613) {
- int err = native_window_set_buffers_cta861_3_metadata(window, s->getCta8613Metadata());
+ android_cta861_3_metadata metadata = s->getCta8613Metadata();
+ int err = native_window_set_buffers_cta861_3_metadata(window, &metadata);
if (err != 0) {
ALOGE("error setting native window CTS 861.3 metadata: %s (%d)",
strerror(-err), err);
@@ -1578,7 +1580,11 @@
return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
- if (s->cnx->egl.eglSurfaceAttrib) {
+ if (s->setSmpte2086Attribute(attribute, value)) {
+ return EGL_TRUE;
+ } else if (s->setCta8613Attribute(attribute, value)) {
+ return EGL_TRUE;
+ } else if (s->cnx->egl.eglSurfaceAttrib) {
return s->cnx->egl.eglSurfaceAttrib(
dp->disp.dpy, s->surface, attribute, value);
}
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 13b94b6..b68fd61 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -64,8 +64,8 @@
cnx(cnx),
connected(true),
colorSpace(colorSpace),
- smpte2086_metadata({}),
- cta861_3_metadata({}) {
+ egl_smpte2086_metadata({}),
+ egl_cta861_3_metadata({}) {
if (win) {
win->incStrong(this);
}
@@ -90,36 +90,35 @@
EGLBoolean egl_surface_t::setSmpte2086Attribute(EGLint attribute, EGLint value) {
switch (attribute) {
- break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
- smpte2086_metadata.displayPrimaryRed.x = value;
+ egl_smpte2086_metadata.displayPrimaryRed.x = value;
return EGL_TRUE;
case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
- smpte2086_metadata.displayPrimaryRed.y = value;
+ egl_smpte2086_metadata.displayPrimaryRed.y = value;
return EGL_TRUE;
case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
- smpte2086_metadata.displayPrimaryGreen.x = value;
+ egl_smpte2086_metadata.displayPrimaryGreen.x = value;
return EGL_TRUE;
case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
- smpte2086_metadata.displayPrimaryGreen.y = value;
+ egl_smpte2086_metadata.displayPrimaryGreen.y = value;
return EGL_TRUE;
case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
- smpte2086_metadata.displayPrimaryBlue.x = value;
+ egl_smpte2086_metadata.displayPrimaryBlue.x = value;
return EGL_TRUE;
case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
- smpte2086_metadata.displayPrimaryBlue.y = value;
+ egl_smpte2086_metadata.displayPrimaryBlue.y = value;
return EGL_TRUE;
case EGL_SMPTE2086_WHITE_POINT_X_EXT:
- smpte2086_metadata.whitePoint.x = value;
+ egl_smpte2086_metadata.whitePoint.x = value;
return EGL_TRUE;
case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
- smpte2086_metadata.whitePoint.y = value;
+ egl_smpte2086_metadata.whitePoint.y = value;
return EGL_TRUE;
case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
- smpte2086_metadata.maxLuminance = value;
+ egl_smpte2086_metadata.maxLuminance = value;
return EGL_TRUE;
case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
- smpte2086_metadata.minLuminance = value;
+ egl_smpte2086_metadata.minLuminance = value;
return EGL_TRUE;
}
return EGL_FALSE;
@@ -128,15 +127,39 @@
EGLBoolean egl_surface_t::setCta8613Attribute(EGLint attribute, EGLint value) {
switch (attribute) {
case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
- cta861_3_metadata.maxContentLightLevel = value;
+ egl_cta861_3_metadata.maxContentLightLevel = value;
return EGL_TRUE;
case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
- cta861_3_metadata.maxFrameAverageLightLevel = value;
+ egl_cta861_3_metadata.maxFrameAverageLightLevel = value;
return EGL_TRUE;
}
return EGL_FALSE;
}
+const android_smpte2086_metadata egl_surface_t::getSmpte2086Metadata() {
+ android_smpte2086_metadata metadata;
+ metadata.displayPrimaryRed.x = static_cast<float>(egl_smpte2086_metadata.displayPrimaryRed.x) / EGL_METADATA_SCALING_EXT;
+ metadata.displayPrimaryRed.y = static_cast<float>(egl_smpte2086_metadata.displayPrimaryRed.y) / EGL_METADATA_SCALING_EXT;
+ metadata.displayPrimaryGreen.x = static_cast<float>(egl_smpte2086_metadata.displayPrimaryGreen.x) / EGL_METADATA_SCALING_EXT;
+ metadata.displayPrimaryGreen.y = static_cast<float>(egl_smpte2086_metadata.displayPrimaryGreen.y) / EGL_METADATA_SCALING_EXT;
+ metadata.displayPrimaryBlue.x = static_cast<float>(egl_smpte2086_metadata.displayPrimaryBlue.x) / EGL_METADATA_SCALING_EXT;
+ metadata.displayPrimaryBlue.y = static_cast<float>(egl_smpte2086_metadata.displayPrimaryBlue.y) / EGL_METADATA_SCALING_EXT;
+ metadata.whitePoint.x = static_cast<float>(egl_smpte2086_metadata.whitePoint.x) / EGL_METADATA_SCALING_EXT;
+ metadata.whitePoint.y = static_cast<float>(egl_smpte2086_metadata.whitePoint.y) / EGL_METADATA_SCALING_EXT;
+ metadata.maxLuminance = static_cast<float>(egl_smpte2086_metadata.maxLuminance) / EGL_METADATA_SCALING_EXT;
+ metadata.minLuminance = static_cast<float>(egl_smpte2086_metadata.minLuminance) / EGL_METADATA_SCALING_EXT;
+
+ return metadata;
+}
+
+const android_cta861_3_metadata egl_surface_t::getCta8613Metadata() {
+ android_cta861_3_metadata metadata;
+ metadata.maxContentLightLevel = static_cast<float>(egl_cta861_3_metadata.maxContentLightLevel) / EGL_METADATA_SCALING_EXT;
+ metadata.maxFrameAverageLightLevel = static_cast<float>(egl_cta861_3_metadata.maxFrameAverageLightLevel) / EGL_METADATA_SCALING_EXT;
+ return metadata;
+}
+
+
EGLBoolean egl_surface_t::getColorSpaceAttribute(EGLint attribute, EGLint* value) const {
if (attribute == EGL_GL_COLORSPACE_KHR) {
*value = colorSpace;
@@ -148,43 +171,43 @@
EGLBoolean egl_surface_t::getSmpte2086Attribute(EGLint attribute, EGLint *value) const {
switch (attribute) {
case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
- *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryRed.x);
+ *value = egl_smpte2086_metadata.displayPrimaryRed.x;
return EGL_TRUE;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
- *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryRed.y);
+ *value = egl_smpte2086_metadata.displayPrimaryRed.y;
return EGL_TRUE;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
- *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryGreen.x);
+ *value = egl_smpte2086_metadata.displayPrimaryGreen.x;
return EGL_TRUE;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
- *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryGreen.y);
+ *value = egl_smpte2086_metadata.displayPrimaryGreen.y;
return EGL_TRUE;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
- *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryBlue.x);
+ *value = egl_smpte2086_metadata.displayPrimaryBlue.x;
return EGL_TRUE;
break;
case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
- *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryBlue.y);
+ *value = egl_smpte2086_metadata.displayPrimaryBlue.y;
return EGL_TRUE;
break;
case EGL_SMPTE2086_WHITE_POINT_X_EXT:
- *value = *reinterpret_cast<const int*>(&smpte2086_metadata.whitePoint.x);
+ *value = egl_smpte2086_metadata.whitePoint.x;
return EGL_TRUE;
break;
case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
- *value = *reinterpret_cast<const int*>(&smpte2086_metadata.whitePoint.y);
+ *value = egl_smpte2086_metadata.whitePoint.y;
return EGL_TRUE;
break;
case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
- *value = *reinterpret_cast<const int*>(&smpte2086_metadata.maxLuminance);
+ *value = egl_smpte2086_metadata.maxLuminance;
return EGL_TRUE;
break;
case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
- *value = *reinterpret_cast<const int*>(&smpte2086_metadata.minLuminance);
+ *value = egl_smpte2086_metadata.minLuminance;
return EGL_TRUE;
break;
}
@@ -194,11 +217,11 @@
EGLBoolean egl_surface_t::getCta8613Attribute(EGLint attribute, EGLint *value) const {
switch (attribute) {
case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
- *value = *reinterpret_cast<const int*>(&cta861_3_metadata.maxContentLightLevel);
+ *value = egl_cta861_3_metadata.maxContentLightLevel;
return EGL_TRUE;
break;
case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
- *value = *reinterpret_cast<const int*>(&cta861_3_metadata.maxFrameAverageLightLevel);
+ *value = egl_cta861_3_metadata.maxFrameAverageLightLevel;
return EGL_TRUE;
break;
}
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index a9020a1..bda91bb 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -142,8 +142,8 @@
EGLBoolean getColorSpaceAttribute(EGLint attribute, EGLint* value) const;
EGLBoolean getSmpte2086Attribute(EGLint attribute, EGLint* value) const;
EGLBoolean getCta8613Attribute(EGLint attribute, EGLint* value) const;
- const android_smpte2086_metadata* getSmpte2086Metadata() const { return &smpte2086_metadata; }
- const android_cta861_3_metadata* getCta8613Metadata() const { return &cta861_3_metadata; }
+ const android_smpte2086_metadata getSmpte2086Metadata();
+ const android_cta861_3_metadata getCta8613Metadata();
// Try to keep the order of these fields and size unchanged. It's not public API, but
// it's not hard to imagine native games accessing them.
@@ -157,8 +157,27 @@
bool connected;
void disconnect();
EGLint colorSpace;
- android_smpte2086_metadata smpte2086_metadata;
- android_cta861_3_metadata cta861_3_metadata;
+
+ struct egl_xy_color {
+ EGLint x;
+ EGLint y;
+ };
+
+ struct egl_smpte2086_metadata {
+ struct egl_xy_color displayPrimaryRed;
+ struct egl_xy_color displayPrimaryGreen;
+ struct egl_xy_color displayPrimaryBlue;
+ struct egl_xy_color whitePoint;
+ EGLint maxLuminance;
+ EGLint minLuminance;
+ };
+
+ struct egl_cta861_3_metadata {
+ EGLint maxContentLightLevel;
+ EGLint maxFrameAverageLightLevel;
+ };
+ egl_smpte2086_metadata egl_smpte2086_metadata;
+ egl_cta861_3_metadata egl_cta861_3_metadata;
};
class egl_context_t: public egl_object_t {
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 8bb74a2..9ffe036 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -50,17 +50,14 @@
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
+#define METADATA_SCALE(x) (static_cast<EGLint>(x * EGL_METADATA_SCALING_EXT))
+
static bool hasWideColorDisplay =
getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
static bool hasHdrDisplay =
getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
-union FlexAttribute {
- EGLint uint_value;
- float float_value;
-};
-
class EGLTest : public ::testing::Test {
public:
void get8BitConfig(EGLConfig& config);
@@ -425,108 +422,81 @@
}
void EGLTest::addOptionalWindowMetadata(std::vector<EGLint>& attrs) {
- FlexAttribute data;
if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_SMPTE2086_metadata")) {
attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT);
- data.float_value = 0.640;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(0.640));
attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT);
- data.float_value = 0.330;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(0.330));
attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT);
- data.float_value = 0.290;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(0.290));
attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT);
- data.float_value = 0.600;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(0.600));
attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT);
- data.float_value = 0.150;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(0.150));
attrs.push_back(EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT);
- data.float_value = 0.060;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(0.060));
attrs.push_back(EGL_SMPTE2086_WHITE_POINT_X_EXT);
- data.float_value = 0.3127;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(0.3127));
attrs.push_back(EGL_SMPTE2086_WHITE_POINT_Y_EXT);
- data.float_value = 0.3290;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(0.3290));
attrs.push_back(EGL_SMPTE2086_MAX_LUMINANCE_EXT);
- data.float_value = 300.0;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(300));
attrs.push_back(EGL_SMPTE2086_MIN_LUMINANCE_EXT);
- data.float_value = 0.7;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(0.7));
}
if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_CTA861_3_metadata")) {
attrs.push_back(EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT);
- data.float_value = 300.0;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(300));
attrs.push_back(EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT);
- data.float_value = 75.0;
- attrs.push_back(data.uint_value);
+ attrs.push_back(METADATA_SCALE(75));
}
}
void EGLTest::checkOptionalWindowMetadata(EGLSurface eglSurface) {
EGLBoolean success;
EGLint value;
- FlexAttribute expected;
if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_SMPTE2086_metadata")) {
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 0.640;
- ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(METADATA_SCALE(0.640), value);
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 0.330;
- ASSERT_EQ(expected.uint_value, value);
- ASSERT_EQ(0, value);
+ ASSERT_EQ(METADATA_SCALE(0.330), value);
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 0.290;
- ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(METADATA_SCALE(0.290), value);
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 0.600;
- ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(METADATA_SCALE(0.600), value);
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 0.150;
- ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(METADATA_SCALE(0.150), value);
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 0.060;
- ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(METADATA_SCALE(0.060), value);
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_WHITE_POINT_X_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 0.3127;
- ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(METADATA_SCALE(0.3127), value);
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_WHITE_POINT_Y_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 0.3290;
- ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(METADATA_SCALE(0.3290), value);
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 300.0;
- ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(METADATA_SCALE(300.0), value);
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_MIN_LUMINANCE_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 0.7;
- ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(METADATA_SCALE(0.7), value);
}
if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_CTA861_3_metadata")) {
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 300.0;
- ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(METADATA_SCALE(300.0), value);
success = eglQuerySurface(mEglDisplay, eglSurface, EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT, &value);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
- expected.float_value = 75.0;
- ASSERT_EQ(expected.uint_value, value);
+ ASSERT_EQ(METADATA_SCALE(75.0), value);
}
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 9f3189a..ae34d34 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -4,6 +4,7 @@
"-DLOG_TAG=\"SurfaceFlinger\"",
"-Wall",
"-Werror",
+ "-Wthread-safety",
"-Wunused",
"-Wunreachable-code",
],
@@ -26,6 +27,7 @@
"android.hardware.power@1.0",
"libbase",
"libbinder",
+ "libbufferhubqueue",
"libcutils",
"libdl",
"libEGL",
@@ -39,6 +41,7 @@
"libhwbinder",
"liblayers_proto",
"liblog",
+ "libpdx_default_transport",
"libprotobuf-cpp-lite",
"libsync",
"libui",
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index bef12ea..9e01fd0 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -33,8 +33,8 @@
#include <ui/FenceTime.h>
#include "DispSync.h"
-#include "SurfaceFlinger.h"
#include "EventLog/EventLog.h"
+#include "SurfaceFlinger.h"
using std::max;
using std::min;
@@ -53,15 +53,14 @@
// needed to re-synchronize the software vsync model with the hardware. The
// error metric used is the mean of the squared difference between each
// present time and the nearest software-predicted vsync.
-static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared
+static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared
#undef LOG_TAG
#define LOG_TAG "DispSyncThread"
-class DispSyncThread: public Thread {
+class DispSyncThread : public Thread {
public:
-
- explicit DispSyncThread(const char* name):
- mName(name),
+ explicit DispSyncThread(const char* name)
+ : mName(name),
mStop(false),
mPeriod(0),
mPhase(0),
@@ -78,8 +77,8 @@
mPhase = phase;
mReferenceTime = referenceTime;
ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64
- " mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
- ns2us(mPhase), ns2us(mReferenceTime));
+ " mReferenceTime = %" PRId64,
+ mName, ns2us(mPeriod), ns2us(mPhase), ns2us(mReferenceTime));
mCond.signal();
}
@@ -115,8 +114,7 @@
if (mPeriod == 0) {
err = mCond.wait(mMutex);
if (err != NO_ERROR) {
- ALOGE("error waiting for new events: %s (%d)",
- strerror(-err), err);
+ ALOGE("error waiting for new events: %s (%d)", strerror(-err), err);
return false;
}
continue;
@@ -133,16 +131,14 @@
ALOGV("[%s] Waiting forever", mName);
err = mCond.wait(mMutex);
} else {
- ALOGV("[%s] Waiting until %" PRId64, mName,
- ns2us(targetTime));
+ ALOGV("[%s] Waiting until %" PRId64, mName, ns2us(targetTime));
err = mCond.waitRelative(mMutex, targetTime - now);
}
if (err == TIMED_OUT) {
isWakeup = true;
} else if (err != NO_ERROR) {
- ALOGE("error waiting for next event: %s (%d)",
- strerror(-err), err);
+ ALOGE("error waiting for next event: %s (%d)", strerror(-err), err);
return false;
}
}
@@ -153,8 +149,7 @@
static const nsecs_t kMaxWakeupLatency = us2ns(1500);
if (isWakeup) {
- mWakeupLatency = ((mWakeupLatency * 63) +
- (now - targetTime)) / 64;
+ mWakeupLatency = ((mWakeupLatency * 63) + (now - targetTime)) / 64;
mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency);
if (kTraceDetailedInfo) {
ATRACE_INT64("DispSync:WakeupLat", now - targetTime);
@@ -173,8 +168,7 @@
return false;
}
- status_t addEventListener(const char* name, nsecs_t phase,
- const sp<DispSync::Callback>& callback) {
+ status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback) {
if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
@@ -191,8 +185,7 @@
// We want to allow the firstmost future event to fire without
// allowing any past events to fire
- listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase -
- mWakeupLatency;
+ listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency;
mEventListeners.push(listener);
@@ -201,7 +194,7 @@
return NO_ERROR;
}
- status_t removeEventListener(const sp<DispSync::Callback>& callback) {
+ status_t removeEventListener(DispSync::Callback* callback) {
if (kTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
@@ -225,16 +218,15 @@
}
private:
-
struct EventListener {
const char* mName;
nsecs_t mPhase;
nsecs_t mLastEventTime;
- sp<DispSync::Callback> mCallback;
+ DispSync::Callback* mCallback;
};
struct CallbackInvocation {
- sp<DispSync::Callback> mCallback;
+ DispSync::Callback* mCallback;
nsecs_t mEventTime;
};
@@ -243,8 +235,7 @@
ALOGV("[%s] computeNextEventTimeLocked", mName);
nsecs_t nextEventTime = INT64_MAX;
for (size_t i = 0; i < mEventListeners.size(); i++) {
- nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
- now);
+ nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], now);
if (t < nextEventTime) {
nextEventTime = t;
@@ -257,22 +248,19 @@
Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
if (kTraceDetailedInfo) ATRACE_CALL();
- ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName,
- ns2us(now));
+ ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
Vector<CallbackInvocation> callbackInvocations;
nsecs_t onePeriodAgo = now - mPeriod;
for (size_t i = 0; i < mEventListeners.size(); i++) {
- nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
- onePeriodAgo);
+ nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], onePeriodAgo);
if (t < now) {
CallbackInvocation ci;
ci.mCallback = mEventListeners[i].mCallback;
ci.mEventTime = t;
- ALOGV("[%s] [%s] Preparing to fire", mName,
- mEventListeners[i].mName);
+ ALOGV("[%s] [%s] Preparing to fire", mName, mEventListeners[i].mName);
callbackInvocations.push(ci);
mEventListeners.editItemAt(i).mLastEventTime = t;
}
@@ -281,18 +269,16 @@
return callbackInvocations;
}
- nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener,
- nsecs_t baseTime) {
+ nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener, nsecs_t baseTime) {
if (kTraceDetailedInfo) ATRACE_CALL();
- ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")",
- mName, listener.mName, ns2us(baseTime));
+ ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")", mName, listener.mName,
+ ns2us(baseTime));
nsecs_t lastEventTime = listener.mLastEventTime + mWakeupLatency;
ALOGV("[%s] lastEventTime: %" PRId64, mName, ns2us(lastEventTime));
if (baseTime < lastEventTime) {
baseTime = lastEventTime;
- ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName,
- ns2us(baseTime));
+ ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName, ns2us(baseTime));
}
baseTime -= mReferenceTime;
@@ -374,11 +360,8 @@
bool mParity;
};
-DispSync::DispSync(const char* name) :
- mName(name),
- mRefreshSkipCount(0),
- mThread(new DispSyncThread(name)) {
-}
+DispSync::DispSync(const char* name)
+ : mName(name), mRefreshSkipCount(0), mThread(new DispSyncThread(name)) {}
DispSync::~DispSync() {}
@@ -404,7 +387,8 @@
// not needed because any time there is an event registered we will
// turn on the HW vsync events.
if (!mIgnorePresentFences && kEnableZeroPhaseTracer) {
- addEventListener("ZeroPhaseTracer", 0, new ZeroPhaseTracer());
+ mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
+ addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
}
}
}
@@ -451,8 +435,8 @@
mPhase = 0;
mReferenceTime = timestamp;
ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, "
- "mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
- ns2us(mReferenceTime));
+ "mReferenceTime = %" PRId64,
+ mName, ns2us(mPeriod), ns2us(mReferenceTime));
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
}
@@ -480,16 +464,13 @@
// Check against kErrorThreshold / 2 to add some hysteresis before having to
// resync again
bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2);
- ALOGV("[%s] addResyncSample returning %s", mName,
- modelLocked ? "locked" : "unlocked");
+ ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
return !modelLocked;
}
-void DispSync::endResync() {
-}
+void DispSync::endResync() {}
-status_t DispSync::addEventListener(const char* name, nsecs_t phase,
- const sp<Callback>& callback) {
+status_t DispSync::addEventListener(const char* name, nsecs_t phase, Callback* callback) {
Mutex::Autolock lock(mMutex);
return mThread->addEventListener(name, phase, callback);
}
@@ -501,7 +482,7 @@
updateModelLocked();
}
-status_t DispSync::removeEventListener(const sp<Callback>& callback) {
+status_t DispSync::removeEventListener(Callback* callback) {
Mutex::Autolock lock(mMutex);
return mThread->removeEventListener(callback);
}
@@ -597,8 +578,7 @@
// call getSignalTime() periodically so the cache is updated when the
// fence signals.
nsecs_t time = mPresentFences[i]->getCachedSignalTime();
- if (time == Fence::SIGNAL_TIME_PENDING ||
- time == Fence::SIGNAL_TIME_INVALID) {
+ if (time == Fence::SIGNAL_TIME_PENDING || time == Fence::SIGNAL_TIME_INVALID) {
continue;
}
@@ -622,9 +602,8 @@
mError = 0;
// Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam.
mZeroErrSamplesCount++;
- ALOGE_IF(
- (mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
- "No present times for model error.");
+ ALOGE_IF((mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
+ "No present times for model error.");
}
if (kTraceDetailedInfo) {
@@ -650,17 +629,14 @@
void DispSync::dump(String8& result) const {
Mutex::Autolock lock(mMutex);
- result.appendFormat("present fences are %s\n",
- mIgnorePresentFences ? "ignored" : "used");
- result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n",
- mPeriod, 1000000000.0 / mPeriod, mRefreshSkipCount);
+ result.appendFormat("present fences are %s\n", mIgnorePresentFences ? "ignored" : "used");
+ result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n", mPeriod,
+ 1000000000.0 / mPeriod, mRefreshSkipCount);
result.appendFormat("mPhase: %" PRId64 " ns\n", mPhase);
- result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n",
- mError, sqrt(mError));
+ result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n", mError, sqrt(mError));
result.appendFormat("mNumResyncSamplesSincePresent: %d (limit %d)\n",
- mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
- result.appendFormat("mNumResyncSamples: %zd (max %d)\n",
- mNumResyncSamples, MAX_RESYNC_SAMPLES);
+ mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
+ result.appendFormat("mNumResyncSamples: %zd (max %d)\n", mNumResyncSamples, MAX_RESYNC_SAMPLES);
result.appendFormat("mResyncSamples:\n");
nsecs_t previous = -1;
@@ -670,14 +646,13 @@
if (i == 0) {
result.appendFormat(" %" PRId64 "\n", sampleTime);
} else {
- result.appendFormat(" %" PRId64 " (+%" PRId64 ")\n",
- sampleTime, sampleTime - previous);
+ result.appendFormat(" %" PRId64 " (+%" PRId64 ")\n", sampleTime,
+ sampleTime - previous);
}
previous = sampleTime;
}
- result.appendFormat("mPresentFences [%d]:\n",
- NUM_PRESENT_SAMPLES);
+ result.appendFormat("mPresentFences [%d]:\n", NUM_PRESENT_SAMPLES);
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
previous = Fence::SIGNAL_TIME_INVALID;
for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
@@ -685,17 +660,16 @@
nsecs_t presentTime = mPresentFences[idx]->getSignalTime();
if (presentTime == Fence::SIGNAL_TIME_PENDING) {
result.appendFormat(" [unsignaled fence]\n");
- } else if(presentTime == Fence::SIGNAL_TIME_INVALID) {
+ } else if (presentTime == Fence::SIGNAL_TIME_INVALID) {
result.appendFormat(" [invalid fence]\n");
} else if (previous == Fence::SIGNAL_TIME_PENDING ||
- previous == Fence::SIGNAL_TIME_INVALID) {
+ previous == Fence::SIGNAL_TIME_INVALID) {
result.appendFormat(" %" PRId64 " (%.3f ms ago)\n", presentTime,
- (now - presentTime) / 1000000.0);
+ (now - presentTime) / 1000000.0);
} else {
- result.appendFormat(" %" PRId64 " (+%" PRId64 " / %.3f) (%.3f ms ago)\n",
- presentTime, presentTime - previous,
- (presentTime - previous) / (double) mPeriod,
- (now - presentTime) / 1000000.0);
+ result.appendFormat(" %" PRId64 " (+%" PRId64 " / %.3f) (%.3f ms ago)\n", presentTime,
+ presentTime - previous, (presentTime - previous) / (double)mPeriod,
+ (now - presentTime) / 1000000.0);
}
previous = presentTime;
}
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 880a24d..9336f4d 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -20,8 +20,8 @@
#include <stddef.h>
#include <utils/Mutex.h>
-#include <utils/Timers.h>
#include <utils/RefBase.h>
+#include <utils/Timers.h>
#include <ui/FenceTime.h>
@@ -47,12 +47,10 @@
// false to indicate that a resynchronization (via addResyncSample) is not
// needed.
class DispSync {
-
public:
-
- class Callback: public virtual RefBase {
+ class Callback {
public:
- virtual ~Callback() {};
+ virtual ~Callback(){};
virtual void onDispSyncEvent(nsecs_t when) = 0;
};
@@ -108,13 +106,12 @@
// given phase offset from the hardware vsync events. The callback is
// called from a separate thread and it should return reasonably quickly
// (i.e. within a few hundred microseconds).
- status_t addEventListener(const char* name, nsecs_t phase,
- const sp<Callback>& callback);
+ status_t addEventListener(const char* name, nsecs_t phase, Callback* callback);
// removeEventListener removes an already-registered event callback. Once
// this method returns that callback will no longer be called by the
// DispSync object.
- status_t removeEventListener(const sp<Callback>& callback);
+ status_t removeEventListener(Callback* callback);
// computeNextRefresh computes when the next refresh is expected to begin.
// The periodOffset value can be used to move forward or backward; an
@@ -126,7 +123,6 @@
void dump(String8& result) const;
private:
-
void updateModelLocked();
void updateErrorLocked();
void resetErrorLocked();
@@ -174,8 +170,7 @@
// These member variables store information about the present fences used
// to validate the currently computed model.
- std::shared_ptr<FenceTime>
- mPresentFences[NUM_PRESENT_SAMPLES] {FenceTime::NO_FENCE};
+ std::shared_ptr<FenceTime> mPresentFences[NUM_PRESENT_SAMPLES]{FenceTime::NO_FENCE};
size_t mPresentSampleOffset;
int mRefreshSkipCount;
@@ -193,8 +188,10 @@
// Ignore present (retire) fences if the device doesn't have support for the
// sync framework
bool mIgnorePresentFences;
+
+ std::unique_ptr<Callback> mZeroPhaseTracer;
};
-}
+} // namespace android
#endif // ANDROID_DISPSYNC_H
diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp
index 02eea47..ac54059 100644
--- a/services/surfaceflinger/EventControlThread.cpp
+++ b/services/surfaceflinger/EventControlThread.cpp
@@ -14,50 +14,57 @@
* limitations under the License.
*/
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <cutils/sched_policy.h>
+#include <log/log.h>
+#include <system/thread_defs.h>
+
#include "EventControlThread.h"
-#include "SurfaceFlinger.h"
namespace android {
-EventControlThread::EventControlThread(const sp<SurfaceFlinger>& flinger):
- mFlinger(flinger),
- mVsyncEnabled(false) {
+EventControlThread::EventControlThread(EventControlThread::SetVSyncEnabledFunction function)
+ : mSetVSyncEnabled(function) {
+ pthread_setname_np(mThread.native_handle(), "EventControlThread");
+
+ pid_t tid = pthread_gettid_np(mThread.native_handle());
+ setpriority(PRIO_PROCESS, tid, ANDROID_PRIORITY_URGENT_DISPLAY);
+ set_sched_policy(tid, SP_FOREGROUND);
+}
+
+EventControlThread::~EventControlThread() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mKeepRunning = false;
+ mCondition.notify_all();
+ }
+ mThread.join();
}
void EventControlThread::setVsyncEnabled(bool enabled) {
- Mutex::Autolock lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
mVsyncEnabled = enabled;
- mCond.signal();
+ mCondition.notify_all();
}
-bool EventControlThread::threadLoop() {
- enum class VsyncState {Unset, On, Off};
- auto currentVsyncState = VsyncState::Unset;
+// Unfortunately std::unique_lock gives warnings with -Wthread-safety
+void EventControlThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
+ auto keepRunning = true;
+ auto currentVsyncEnabled = false;
- while (true) {
- auto requestedVsyncState = VsyncState::On;
- {
- Mutex::Autolock lock(mMutex);
- requestedVsyncState =
- mVsyncEnabled ? VsyncState::On : VsyncState::Off;
- while (currentVsyncState == requestedVsyncState) {
- status_t err = mCond.wait(mMutex);
- if (err != NO_ERROR) {
- ALOGE("error waiting for new events: %s (%d)",
- strerror(-err), err);
- return false;
- }
- requestedVsyncState =
- mVsyncEnabled ? VsyncState::On : VsyncState::Off;
- }
- }
+ while (keepRunning) {
+ mSetVSyncEnabled(currentVsyncEnabled);
- bool enable = requestedVsyncState == VsyncState::On;
- mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, enable);
- currentVsyncState = requestedVsyncState;
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this, currentVsyncEnabled, keepRunning]() NO_THREAD_SAFETY_ANALYSIS {
+ return currentVsyncEnabled != mVsyncEnabled || keepRunning != mKeepRunning;
+ });
+ currentVsyncEnabled = mVsyncEnabled;
+ keepRunning = mKeepRunning;
}
-
- return false;
}
} // namespace android
diff --git a/services/surfaceflinger/EventControlThread.h b/services/surfaceflinger/EventControlThread.h
index 1b1ef75..321fb79 100644
--- a/services/surfaceflinger/EventControlThread.h
+++ b/services/surfaceflinger/EventControlThread.h
@@ -14,35 +14,41 @@
* limitations under the License.
*/
-#ifndef ANDROID_EVENTCONTROLTHREAD_H
-#define ANDROID_EVENTCONTROLTHREAD_H
+#pragma once
-#include <stddef.h>
+#include <cstddef>
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <thread>
-#include <utils/Mutex.h>
-#include <utils/Thread.h>
+#include <android-base/thread_annotations.h>
namespace android {
class SurfaceFlinger;
-class EventControlThread: public Thread {
+class EventControlThread {
public:
+ using SetVSyncEnabledFunction = std::function<void(bool)>;
- explicit EventControlThread(const sp<SurfaceFlinger>& flinger);
- virtual ~EventControlThread() {}
+ explicit EventControlThread(SetVSyncEnabledFunction function);
+ ~EventControlThread();
void setVsyncEnabled(bool enabled);
- virtual bool threadLoop();
private:
- sp<SurfaceFlinger> mFlinger;
- bool mVsyncEnabled;
+ void threadMain();
- Mutex mMutex;
- Condition mCond;
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+
+ const SetVSyncEnabledFunction mSetVSyncEnabled;
+ bool mVsyncEnabled GUARDED_BY(mMutex) = false;
+ bool mKeepRunning GUARDED_BY(mMutex) = true;
+
+ // Must be last so that everything is initialized before the thread starts.
+ std::thread mThread{&EventControlThread::threadMain, this};
};
-}
-
-#endif // ANDROID_EVENTCONTROLTHREAD_H
+} // namespace android
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 5c0e3b3..53d95e2 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -16,13 +16,17 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <stdint.h>
+#include <pthread.h>
+#include <sched.h>
#include <sys/types.h>
+#include <chrono>
+#include <cstdint>
#include <cutils/compiler.h>
+#include <cutils/sched_policy.h>
-#include <gui/IDisplayEventConnection.h>
#include <gui/DisplayEventReceiver.h>
+#include <gui/IDisplayEventConnection.h>
#include <utils/Errors.h>
#include <utils/String8.h>
@@ -31,109 +35,126 @@
#include "EventThread.h"
#include "SurfaceFlinger.h"
+using namespace std::chrono_literals;
+
// ---------------------------------------------------------------------------
+
namespace android {
+
// ---------------------------------------------------------------------------
-EventThread::EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bool interceptVSyncs)
- : mVSyncSource(src),
- mFlinger(flinger),
- mUseSoftwareVSync(false),
- mVsyncEnabled(false),
- mDebugVsyncEnabled(false),
- mInterceptVSyncs(interceptVSyncs) {
-
- for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
- mVSyncEvent[i].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
- mVSyncEvent[i].header.id = 0;
- mVSyncEvent[i].header.timestamp = 0;
- mVSyncEvent[i].vsync.count = 0;
+EventThread::EventThread(VSyncSource* src, SurfaceFlinger& flinger, bool interceptVSyncs,
+ const char* threadName)
+ : mVSyncSource(src), mFlinger(flinger), mInterceptVSyncs(interceptVSyncs) {
+ for (auto& event : mVSyncEvent) {
+ event.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+ event.header.id = 0;
+ event.header.timestamp = 0;
+ event.vsync.count = 0;
}
+
+ mThread = std::thread(&EventThread::threadMain, this);
+
+ pthread_setname_np(mThread.native_handle(), threadName);
+
+ pid_t tid = pthread_gettid_np(mThread.native_handle());
+
+ // Use SCHED_FIFO to minimize jitter
+ constexpr int EVENT_THREAD_PRIORITY = 2;
+ struct sched_param param = {0};
+ param.sched_priority = EVENT_THREAD_PRIORITY;
+ if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO for EventThread");
+ }
+
+ set_sched_policy(tid, SP_FOREGROUND);
+}
+
+EventThread::~EventThread() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mKeepRunning = false;
+ mCondition.notify_all();
+ }
+ mThread.join();
}
void EventThread::setPhaseOffset(nsecs_t phaseOffset) {
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
mVSyncSource->setPhaseOffset(phaseOffset);
}
-void EventThread::onFirstRef() {
- run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
-}
-
sp<EventThread::Connection> EventThread::createEventConnection() const {
return new Connection(const_cast<EventThread*>(this));
}
status_t EventThread::registerDisplayEventConnection(
const sp<EventThread::Connection>& connection) {
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
mDisplayEventConnections.add(connection);
- mCondition.broadcast();
+ mCondition.notify_all();
return NO_ERROR;
}
-void EventThread::removeDisplayEventConnection(
- const wp<EventThread::Connection>& connection) {
- Mutex::Autolock _l(mLock);
+void EventThread::removeDisplayEventConnection(const wp<EventThread::Connection>& connection) {
+ std::lock_guard<std::mutex> lock(mMutex);
mDisplayEventConnections.remove(connection);
}
-void EventThread::setVsyncRate(uint32_t count,
- const sp<EventThread::Connection>& connection) {
+void EventThread::setVsyncRate(uint32_t count, const sp<EventThread::Connection>& connection) {
if (int32_t(count) >= 0) { // server must protect against bad params
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
const int32_t new_count = (count == 0) ? -1 : count;
if (connection->count != new_count) {
connection->count = new_count;
- mCondition.broadcast();
+ mCondition.notify_all();
}
}
}
-void EventThread::requestNextVsync(
- const sp<EventThread::Connection>& connection) {
- Mutex::Autolock _l(mLock);
+void EventThread::requestNextVsync(const sp<EventThread::Connection>& connection) {
+ std::lock_guard<std::mutex> lock(mMutex);
mFlinger.resyncWithRateLimit();
if (connection->count < 0) {
connection->count = 0;
- mCondition.broadcast();
+ mCondition.notify_all();
}
}
void EventThread::onScreenReleased() {
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
if (!mUseSoftwareVSync) {
// disable reliance on h/w vsync
mUseSoftwareVSync = true;
- mCondition.broadcast();
+ mCondition.notify_all();
}
}
void EventThread::onScreenAcquired() {
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
if (mUseSoftwareVSync) {
// resume use of h/w vsync
mUseSoftwareVSync = false;
- mCondition.broadcast();
+ mCondition.notify_all();
}
}
void EventThread::onVSyncEvent(nsecs_t timestamp) {
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[0].header.id = 0;
mVSyncEvent[0].header.timestamp = timestamp;
mVSyncEvent[0].vsync.count++;
- mCondition.broadcast();
+ mCondition.notify_all();
}
void EventThread::onHotplugReceived(int type, bool connected) {
ALOGE_IF(type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
- "received hotplug event for an invalid display (id=%d)", type);
+ "received hotplug event for an invalid display (id=%d)", type);
- Mutex::Autolock _l(mLock);
+ std::lock_guard<std::mutex> lock(mMutex);
if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
DisplayEventReceiver::Event event;
event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
@@ -141,54 +162,54 @@
event.header.timestamp = systemTime();
event.hotplug.connected = connected;
mPendingEvents.add(event);
- mCondition.broadcast();
+ mCondition.notify_all();
}
}
-bool EventThread::threadLoop() {
- DisplayEventReceiver::Event event;
- Vector< sp<EventThread::Connection> > signalConnections;
- signalConnections = waitForEvent(&event);
+void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (mKeepRunning) {
+ DisplayEventReceiver::Event event;
+ Vector<sp<EventThread::Connection> > signalConnections;
+ signalConnections = waitForEventLocked(&lock, &event);
- // dispatch events to listeners...
- const size_t count = signalConnections.size();
- for (size_t i=0 ; i<count ; i++) {
- const sp<Connection>& conn(signalConnections[i]);
- // now see if we still need to report this event
- status_t err = conn->postEvent(event);
- if (err == -EAGAIN || err == -EWOULDBLOCK) {
- // The destination doesn't accept events anymore, it's probably
- // full. For now, we just drop the events on the floor.
- // FIXME: Note that some events cannot be dropped and would have
- // to be re-sent later.
- // Right-now we don't have the ability to do this.
- ALOGW("EventThread: dropping event (%08x) for connection %p",
- event.header.type, conn.get());
- } else if (err < 0) {
- // handle any other error on the pipe as fatal. the only
- // reasonable thing to do is to clean-up this connection.
- // The most common error we'll get here is -EPIPE.
- removeDisplayEventConnection(signalConnections[i]);
+ // dispatch events to listeners...
+ const size_t count = signalConnections.size();
+ for (size_t i = 0; i < count; i++) {
+ const sp<Connection>& conn(signalConnections[i]);
+ // now see if we still need to report this event
+ status_t err = conn->postEvent(event);
+ if (err == -EAGAIN || err == -EWOULDBLOCK) {
+ // The destination doesn't accept events anymore, it's probably
+ // full. For now, we just drop the events on the floor.
+ // FIXME: Note that some events cannot be dropped and would have
+ // to be re-sent later.
+ // Right-now we don't have the ability to do this.
+ ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type,
+ conn.get());
+ } else if (err < 0) {
+ // handle any other error on the pipe as fatal. the only
+ // reasonable thing to do is to clean-up this connection.
+ // The most common error we'll get here is -EPIPE.
+ removeDisplayEventConnection(signalConnections[i]);
+ }
}
}
- return true;
}
// This will return when (1) a vsync event has been received, and (2) there was
// at least one connection interested in receiving it when we started waiting.
-Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
- DisplayEventReceiver::Event* event)
-{
- Mutex::Autolock _l(mLock);
- Vector< sp<EventThread::Connection> > signalConnections;
+Vector<sp<EventThread::Connection> > EventThread::waitForEventLocked(
+ std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* event) {
+ Vector<sp<EventThread::Connection> > signalConnections;
- do {
+ while (signalConnections.isEmpty() && mKeepRunning) {
bool eventPending = false;
bool waitForVSync = false;
size_t vsyncCount = 0;
nsecs_t timestamp = 0;
- for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
+ for (int32_t i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; i++) {
timestamp = mVSyncEvent[i].header.timestamp;
if (timestamp) {
// we have a vsync event to dispatch
@@ -214,7 +235,7 @@
// find out connections waiting for events
size_t count = mDisplayEventConnections.size();
- for (size_t i=0 ; i<count ; ) {
+ for (size_t i = 0; i < count;) {
sp<Connection> connection(mDisplayEventConnections[i].promote());
if (connection != nullptr) {
bool added = false;
@@ -231,7 +252,7 @@
signalConnections.add(connection);
added = true;
} else if (connection->count == 1 ||
- (vsyncCount % connection->count) == 0) {
+ (vsyncCount % connection->count) == 0) {
// continuous event, and time to report it
signalConnections.add(connection);
added = true;
@@ -285,8 +306,8 @@
// use a (long) timeout when waiting for h/w vsync, and
// generate fake events when necessary.
bool softwareSync = mUseSoftwareVSync;
- nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
- if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
+ auto timeout = softwareSync ? 16ms : 1000ms;
+ if (mCondition.wait_for(*lock, timeout) == std::cv_status::timeout) {
if (!softwareSync) {
ALOGW("Timed out waiting for hw vsync; faking it");
}
@@ -302,10 +323,10 @@
// h/w vsync should be disabled, so this will wait until we
// get a new connection, or an existing connection becomes
// interested in receiving vsync again.
- mCondition.wait(mLock);
+ mCondition.wait(*lock);
}
}
- } while (signalConnections.isEmpty());
+ }
// here we're guaranteed to have a timestamp and some connections to signal
// (The connections might have dropped out of mDisplayEventConnections
@@ -318,7 +339,7 @@
// never enable h/w VSYNC when screen is off
if (!mVsyncEnabled) {
mVsyncEnabled = true;
- mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this));
+ mVSyncSource->setCallback(this);
mVSyncSource->setVSyncEnabled(true);
}
}
@@ -334,29 +355,23 @@
}
void EventThread::dump(String8& result) const {
- Mutex::Autolock _l(mLock);
- result.appendFormat("VSYNC state: %s\n",
- mDebugVsyncEnabled?"enabled":"disabled");
- result.appendFormat(" soft-vsync: %s\n",
- mUseSoftwareVSync?"enabled":"disabled");
+ std::lock_guard<std::mutex> lock(mMutex);
+ result.appendFormat("VSYNC state: %s\n", mDebugVsyncEnabled ? "enabled" : "disabled");
+ result.appendFormat(" soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
result.appendFormat(" numListeners=%zu,\n events-delivered: %u\n",
- mDisplayEventConnections.size(),
- mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
- for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) {
- sp<Connection> connection =
- mDisplayEventConnections.itemAt(i).promote();
- result.appendFormat(" %p: count=%d\n",
- connection.get(), connection != nullptr ? connection->count : 0);
+ mDisplayEventConnections.size(),
+ mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
+ for (size_t i = 0; i < mDisplayEventConnections.size(); i++) {
+ sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
+ result.appendFormat(" %p: count=%d\n", connection.get(),
+ connection != nullptr ? connection->count : 0);
}
}
// ---------------------------------------------------------------------------
-EventThread::Connection::Connection(
- const sp<EventThread>& eventThread)
- : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize)
-{
-}
+EventThread::Connection::Connection(EventThread* eventThread)
+ : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}
EventThread::Connection::~Connection() {
// do nothing here -- clean-up will happen automatically
@@ -382,12 +397,11 @@
mEventThread->requestNextVsync(this);
}
-status_t EventThread::Connection::postEvent(
- const DisplayEventReceiver::Event& event) {
+status_t EventThread::Connection::postEvent(const DisplayEventReceiver::Event& event) {
ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 0823839..9ae8fb2 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -14,18 +14,21 @@
* limitations under the License.
*/
-#ifndef ANDROID_SURFACE_FLINGER_EVENT_THREAD_H
-#define ANDROID_SURFACE_FLINGER_EVENT_THREAD_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
-#include <private/gui/BitTube.h>
+#include <android-base/thread_annotations.h>
+
#include <gui/DisplayEventReceiver.h>
#include <gui/IDisplayEventConnection.h>
+#include <private/gui/BitTube.h>
#include <utils/Errors.h>
-#include <utils/threads.h>
#include <utils/SortedVector.h>
#include "DisplayDevice.h"
@@ -39,10 +42,9 @@
// ---------------------------------------------------------------------------
-
-class VSyncSource : public virtual RefBase {
+class VSyncSource {
public:
- class Callback: public virtual RefBase {
+ class Callback {
public:
virtual ~Callback() {}
virtual void onVSyncEvent(nsecs_t when) = 0;
@@ -50,14 +52,14 @@
virtual ~VSyncSource() {}
virtual void setVSyncEnabled(bool enable) = 0;
- virtual void setCallback(const sp<Callback>& callback) = 0;
+ virtual void setCallback(Callback* callback) = 0;
virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
};
-class EventThread : public Thread, private VSyncSource::Callback {
+class EventThread : private VSyncSource::Callback {
class Connection : public BnDisplayEventConnection {
public:
- explicit Connection(const sp<EventThread>& eventThread);
+ explicit Connection(EventThread* eventThread);
status_t postEvent(const DisplayEventReceiver::Event& event);
// count >= 1 : continuous event. count is the vsync rate
@@ -70,14 +72,15 @@
virtual void onFirstRef();
status_t stealReceiveChannel(gui::BitTube* outChannel) override;
status_t setVsyncRate(uint32_t count) override;
- void requestNextVsync() override; // asynchronous
- sp<EventThread> const mEventThread;
+ void requestNextVsync() override; // asynchronous
+ EventThread* const mEventThread;
gui::BitTube mChannel;
};
public:
-
- EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bool interceptVSyncs);
+ EventThread(VSyncSource* src, SurfaceFlinger& flinger, bool interceptVSyncs,
+ const char* threadName);
+ ~EventThread();
sp<Connection> createEventConnection() const;
status_t registerDisplayEventConnection(const sp<Connection>& connection);
@@ -94,47 +97,46 @@
// called when receiving a hotplug event
void onHotplugReceived(int type, bool connected);
- Vector< sp<EventThread::Connection> > waitForEvent(
- DisplayEventReceiver::Event* event);
-
void dump(String8& result) const;
void setPhaseOffset(nsecs_t phaseOffset);
private:
- virtual bool threadLoop();
- virtual void onFirstRef();
-
- virtual void onVSyncEvent(nsecs_t timestamp);
+ void threadMain();
+ Vector<sp<EventThread::Connection>> waitForEventLocked(std::unique_lock<std::mutex>* lock,
+ DisplayEventReceiver::Event* event)
+ REQUIRES(mMutex);
void removeDisplayEventConnection(const wp<Connection>& connection);
- void enableVSyncLocked();
- void disableVSyncLocked();
+ void enableVSyncLocked() REQUIRES(mMutex);
+ void disableVSyncLocked() REQUIRES(mMutex);
+
+ // Implements VSyncSource::Callback
+ void onVSyncEvent(nsecs_t timestamp) override;
// constants
- sp<VSyncSource> mVSyncSource;
+ VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
SurfaceFlinger& mFlinger;
- mutable Mutex mLock;
- mutable Condition mCondition;
+ std::thread mThread;
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
// protected by mLock
- SortedVector< wp<Connection> > mDisplayEventConnections;
- Vector< DisplayEventReceiver::Event > mPendingEvents;
- DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
- bool mUseSoftwareVSync;
- bool mVsyncEnabled;
+ SortedVector<wp<Connection>> mDisplayEventConnections GUARDED_BY(mMutex);
+ Vector<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
+ DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES] GUARDED_BY(
+ mMutex);
+ bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
+ bool mVsyncEnabled GUARDED_BY(mMutex) = false;
+ bool mKeepRunning GUARDED_BY(mMutex) = true;
// for debugging
- bool mDebugVsyncEnabled;
+ bool mDebugVsyncEnabled GUARDED_BY(mMutex) = false;
- const bool mInterceptVSyncs;
+ const bool mInterceptVSyncs = false;
};
// ---------------------------------------------------------------------------
}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif /* ANDROID_SURFACE_FLINGER_EVENT_THREAD_H */
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index 0b1199c..5a6ff4d 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -14,32 +14,29 @@
* limitations under the License.
*/
-#include <stdint.h>
#include <errno.h>
+#include <stdint.h>
#include <sys/types.h>
#include <binder/IPCThreadState.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
#include <gui/IDisplayEventConnection.h>
-#include "MessageQueue.h"
#include "EventThread.h"
+#include "MessageQueue.h"
#include "SurfaceFlinger.h"
namespace android {
// ---------------------------------------------------------------------------
-MessageBase::MessageBase()
- : MessageHandler() {
-}
+MessageBase::MessageBase() : MessageHandler() {}
-MessageBase::~MessageBase() {
-}
+MessageBase::~MessageBase() {}
void MessageBase::handleMessage(const Message&) {
this->handler();
@@ -75,22 +72,17 @@
// ---------------------------------------------------------------------------
-MessageQueue::MessageQueue()
-{
-}
+MessageQueue::MessageQueue() {}
-MessageQueue::~MessageQueue() {
-}
+MessageQueue::~MessageQueue() {}
-void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
-{
+void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
mFlinger = flinger;
mLooper = new Looper(true);
mHandler = new Handler(*this);
}
-void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
-{
+void MessageQueue::setEventThread(EventThread* eventThread) {
if (mEventThread == eventThread) {
return;
}
@@ -102,8 +94,8 @@
mEventThread = eventThread;
mEvents = eventThread->createEventConnection();
mEvents->stealReceiveChannel(&mEventTube);
- mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT,
- MessageQueue::cb_eventReceiver, this);
+ mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
+ this);
}
void MessageQueue::waitMessage() {
@@ -128,9 +120,7 @@
} while (true);
}
-status_t MessageQueue::postMessage(
- const sp<MessageBase>& messageHandler, nsecs_t relTime)
-{
+status_t MessageQueue::postMessage(const sp<MessageBase>& messageHandler, nsecs_t relTime) {
const Message dummyMessage;
if (relTime > 0) {
mLooper->sendMessageDelayed(relTime, messageHandler, dummyMessage);
@@ -140,7 +130,6 @@
return NO_ERROR;
}
-
void MessageQueue::invalidate() {
mEvents->requestNextVsync();
}
@@ -150,7 +139,7 @@
}
int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
- MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
+ MessageQueue* queue = reinterpret_cast<MessageQueue*>(data);
return queue->eventReceiver(fd, events);
}
@@ -158,7 +147,7 @@
ssize_t n;
DisplayEventReceiver::Event buffer[8];
while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
- for (int i=0 ; i<n ; i++) {
+ for (int i = 0; i < n; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
mHandler->dispatchInvalidate();
break;
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 14f50bb..dcfc716 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -17,16 +17,16 @@
#ifndef ANDROID_MESSAGE_QUEUE_H
#define ANDROID_MESSAGE_QUEUE_H
-#include <stdint.h>
#include <errno.h>
+#include <stdint.h>
#include <sys/types.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
#include <utils/Looper.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
-#include <private/gui/BitTube.h>
#include <gui/DisplayEventReceiver.h>
+#include <private/gui/BitTube.h>
#include "Barrier.h"
@@ -40,11 +40,10 @@
// ---------------------------------------------------------------------------
-class MessageBase : public MessageHandler
-{
+class MessageBase : public MessageHandler {
public:
MessageBase();
-
+
// return true if message has a handler
virtual bool handler() = 0;
@@ -79,15 +78,12 @@
class MessageQueue {
class Handler : public MessageHandler {
- enum {
- eventMaskInvalidate = 0x1,
- eventMaskRefresh = 0x2,
- eventMaskTransaction = 0x4
- };
+ enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 };
MessageQueue& mQueue;
int32_t mEventMask;
+
public:
- explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
+ explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
virtual void handleMessage(const Message& message);
void dispatchRefresh();
void dispatchInvalidate();
@@ -97,28 +93,27 @@
sp<SurfaceFlinger> mFlinger;
sp<Looper> mLooper;
- sp<EventThread> mEventThread;
+ EventThread* mEventThread;
sp<IDisplayEventConnection> mEvents;
gui::BitTube mEventTube;
sp<Handler> mHandler;
-
static int cb_eventReceiver(int fd, int events, void* data);
int eventReceiver(int fd, int events);
public:
enum {
- INVALIDATE = 0,
- REFRESH = 1,
+ INVALIDATE = 0,
+ REFRESH = 1,
};
MessageQueue();
~MessageQueue();
void init(const sp<SurfaceFlinger>& flinger);
- void setEventThread(const sp<EventThread>& events);
+ void setEventThread(EventThread* events);
void waitMessage();
- status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0);
+ status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0);
// sends INVALIDATE message at next VSYNC
void invalidate();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d8740d9..1054c32 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -424,7 +424,7 @@
postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
}
-class DispSyncSource : public VSyncSource, private DispSync::Callback {
+class DispSyncSource final : public VSyncSource, private DispSync::Callback {
public:
DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
const char* name) :
@@ -435,14 +435,13 @@
mVsyncEventLabel(String8::format("VSYNC-%s", name)),
mDispSync(dispSync),
mCallbackMutex(),
- mCallback(),
mVsyncMutex(),
mPhaseOffset(phaseOffset),
mEnabled(false) {}
- virtual ~DispSyncSource() {}
+ ~DispSyncSource() override = default;
- virtual void setVSyncEnabled(bool enable) {
+ void setVSyncEnabled(bool enable) override {
Mutex::Autolock lock(mVsyncMutex);
if (enable) {
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
@@ -464,12 +463,12 @@
mEnabled = enable;
}
- virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+ void setCallback(VSyncSource::Callback* callback) override{
Mutex::Autolock lock(mCallbackMutex);
mCallback = callback;
}
- virtual void setPhaseOffset(nsecs_t phaseOffset) {
+ void setPhaseOffset(nsecs_t phaseOffset) override {
Mutex::Autolock lock(mVsyncMutex);
// Normalize phaseOffset to [0, period)
@@ -506,7 +505,7 @@
private:
virtual void onDispSyncEvent(nsecs_t when) {
- sp<VSyncSource::Callback> callback;
+ VSyncSource::Callback* callback;
{
Mutex::Autolock lock(mCallbackMutex);
callback = mCallback;
@@ -533,37 +532,36 @@
DispSync* mDispSync;
Mutex mCallbackMutex; // Protects the following
- sp<VSyncSource::Callback> mCallback;
+ VSyncSource::Callback* mCallback = nullptr;
Mutex mVsyncMutex; // Protects the following
nsecs_t mPhaseOffset;
bool mEnabled;
};
-class InjectVSyncSource : public VSyncSource {
+class InjectVSyncSource final : public VSyncSource {
public:
- InjectVSyncSource() {}
+ InjectVSyncSource() = default;
+ ~InjectVSyncSource() override = default;
- virtual ~InjectVSyncSource() {}
-
- virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+ void setCallback(VSyncSource::Callback* callback) override {
std::lock_guard<std::mutex> lock(mCallbackMutex);
mCallback = callback;
}
- virtual void onInjectSyncEvent(nsecs_t when) {
+ void onInjectSyncEvent(nsecs_t when) {
std::lock_guard<std::mutex> lock(mCallbackMutex);
if (mCallback) {
mCallback->onVSyncEvent(when);
}
}
- virtual void setVSyncEnabled(bool) {}
- virtual void setPhaseOffset(nsecs_t) {}
+ void setVSyncEnabled(bool) override {}
+ void setPhaseOffset(nsecs_t) override {}
private:
std::mutex mCallbackMutex; // Protects the following
- sp<VSyncSource::Callback> mCallback;
+ VSyncSource::Callback* mCallback = nullptr;
};
// Do not call property_set on main thread which will be blocked by init
@@ -577,23 +575,16 @@
Mutex::Autolock _l(mStateLock);
// start the EventThread
- sp<VSyncSource> vsyncSrc =
- new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
- mEventThread = new EventThread(vsyncSrc, *this, false);
- sp<VSyncSource> sfVsyncSrc =
- new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
- mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
- mEventQueue.setEventThread(mSFEventThread);
- // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter
- struct sched_param param = {0};
- param.sched_priority = 2;
- if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
- ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
- }
- if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 0) {
- ALOGE("Couldn't set SCHED_FIFO for EventThread");
- }
+ mEventThreadSource = std::make_unique<DispSyncSource>(
+ &mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
+ mEventThread = std::make_unique<EventThread>(
+ mEventThreadSource.get(), *this, false, "sfEventThread");
+ mSfEventThreadSource = std::make_unique<DispSyncSource>(
+ &mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
+ mSFEventThread = std::make_unique<EventThread>(
+ mSfEventThreadSource.get(), *this, true, "appEventThread");
+ mEventQueue.setEventThread(mSFEventThread.get());
// Get a RenderEngine for the given display / config (can't fail)
getBE().mRenderEngine = RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
@@ -636,8 +627,9 @@
}
}
- mEventControlThread = new EventControlThread(this);
- mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
+ mEventControlThread = std::make_unique<EventControlThread>([this](bool enabled) {
+ setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled);
+ });
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -1072,13 +1064,14 @@
if (enable) {
ALOGV("VSync Injections enabled");
if (mVSyncInjector.get() == nullptr) {
- mVSyncInjector = new InjectVSyncSource();
- mInjectorEventThread = new EventThread(mVSyncInjector, *this, false);
+ mVSyncInjector = std::make_unique<InjectVSyncSource>();
+ mInjectorEventThread = std::make_unique<EventThread>(
+ mVSyncInjector.get(), *this, false, "injEvThread");
}
- mEventQueue.setEventThread(mInjectorEventThread);
+ mEventQueue.setEventThread(mInjectorEventThread.get());
} else {
ALOGV("VSync Injections disabled");
- mEventQueue.setEventThread(mSFEventThread);
+ mEventQueue.setEventThread(mSFEventThread.get());
}
mInjectVSyncs = enable;
@@ -1101,7 +1094,8 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const {
+status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
+ NO_THREAD_SAFETY_ANALYSIS {
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
@@ -3567,7 +3561,8 @@
// ---------------------------------------------------------------------------
-status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto) {
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto)
+ NO_THREAD_SAFETY_ANALYSIS {
String8 result;
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bde1a8e..19dd059 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -719,11 +719,13 @@
// constant members (no synchronization needed for access)
nsecs_t mBootTime;
bool mGpuToCpuSupported;
- sp<EventThread> mEventThread;
- sp<EventThread> mSFEventThread;
- sp<EventThread> mInjectorEventThread;
- sp<InjectVSyncSource> mVSyncInjector;
- sp<EventControlThread> mEventControlThread;
+ std::unique_ptr<EventThread> mEventThread;
+ std::unique_ptr<EventThread> mSFEventThread;
+ std::unique_ptr<EventThread> mInjectorEventThread;
+ std::unique_ptr<VSyncSource> mEventThreadSource;
+ std::unique_ptr<VSyncSource> mSfEventThreadSource;
+ std::unique_ptr<InjectVSyncSource> mVSyncInjector;
+ std::unique_ptr<EventControlThread> mEventControlThread;
sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
// Can only accessed from the main thread, these members
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index e1997d7..1a99cf4 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -27,7 +27,6 @@
staticLibraries := \
libperformance \
- libpdx_default_transport \
libbufferhub
sharedLibraries := \
@@ -38,7 +37,8 @@
libsync \
libutils \
libgui \
- libui
+ libui \
+ libpdx_default_transport \
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(sourceFiles)
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 063d83c..caf9049 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -10,9 +10,6 @@
"libbroadcastring",
"libhwcomposer-client",
"libdisplay",
- "libbufferhubqueue",
- "libbufferhub",
- "libpdx_default_transport",
],
shared_libs: [
@@ -20,6 +17,7 @@
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0",
"libbase",
+ "libbufferhubqueue",
"libbinder",
"libcutils",
"libfmq",
@@ -30,6 +28,7 @@
"libsync",
"libui",
"libutils",
+ "libpdx_default_transport",
],
header_libs: [
diff --git a/services/vr/performanced/Android.mk b/services/vr/performanced/Android.mk
index 1470234..a548ef0 100644
--- a/services/vr/performanced/Android.mk
+++ b/services/vr/performanced/Android.mk
@@ -22,7 +22,6 @@
staticLibraries := \
libperformance \
- libpdx_default_transport \
libvr_manager
sharedLibraries := \
@@ -30,7 +29,8 @@
libbase \
libcutils \
liblog \
- libutils
+ libutils \
+ libpdx_default_transport \
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(sourceFiles)
diff --git a/vulkan/libvulkan/stubhal.cpp b/vulkan/libvulkan/stubhal.cpp
index 726e854..7404b94 100644
--- a/vulkan/libvulkan/stubhal.cpp
+++ b/vulkan/libvulkan/stubhal.cpp
@@ -97,6 +97,14 @@
return VK_SUCCESS;
}
+VKAPI_ATTR VkResult
+EnumeratePhysicalDeviceGroups(VkInstance /*instance*/,
+ uint32_t* count,
+ VkPhysicalDeviceGroupProperties* /*properties*/) {
+ *count = 0;
+ return VK_SUCCESS;
+}
+
VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
const char* name) {
if (strcmp(name, "vkCreateInstance") == 0)
@@ -108,6 +116,9 @@
EnumerateInstanceExtensionProperties);
if (strcmp(name, "vkEnumeratePhysicalDevices") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices);
+ if (strcmp(name, "vkEnumeratePhysicalDeviceGroups") == 0)
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ EnumeratePhysicalDeviceGroups);
if (strcmp(name, "vkGetInstanceProcAddr") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr);
// Per the spec, return NULL if instance is NULL.