Merge "Fix WM input limitations on secondary displays (2/4)"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 9216e75..4362019 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1290,6 +1290,8 @@
DumpPacketStats();
+ RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
+
DoKmsg();
DumpIpAddrAndRules();
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 9e32bc6..2470a1d 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -95,15 +95,6 @@
static constexpr size_t kSha256Size = 32;
static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
-// NOTE: keep in sync with Installer
-static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
-static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
-static constexpr int FLAG_USE_QUOTA = 1 << 12;
-static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
-static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
-static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 15;
-static constexpr int FLAG_FORCE = 1 << 16;
-
namespace {
constexpr const char* kDump = "android.permission.DUMP";
@@ -613,6 +604,31 @@
remove_path_xattr(path, kXattrInodeCodeCache);
}
}
+
+ auto extPath = findDataMediaPath(uuid, userId);
+ if (flags & FLAG_CLEAR_CACHE_ONLY) {
+ // Clear only cached data from shared storage
+ path = StringPrintf("%s/Android/data/%s/cache", extPath.c_str(), pkgname);
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+ // No code cache on shared storage
+ } else {
+ // Clear everything on shared storage
+ path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents(path, true) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ }
}
if (flags & FLAG_STORAGE_DE) {
std::string suffix = "";
@@ -681,6 +697,20 @@
if (delete_dir_contents_and_dir(path) != 0) {
res = error("Failed to delete " + path);
}
+
+ auto extPath = findDataMediaPath(uuid, userId);
+ path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
+ path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
+ path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
}
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
new file mode 100644
index 0000000..3de5c79
--- /dev/null
+++ b/cmds/installd/TEST_MAPPING
@@ -0,0 +1,19 @@
+{
+ "presubmit": [
+ {
+ "name": "installd_cache_test"
+ },
+ {
+ "name": "installd_dexopt_test"
+ },
+ {
+ "name": "installd_otapreopt_test"
+ },
+ {
+ "name": "installd_service_test"
+ },
+ {
+ "name": "installd_utils_test"
+ }
+ ]
+}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 91e20b7..89b08e5 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -102,4 +102,17 @@
boolean prepareAppProfile(@utf8InCpp String packageName,
int userId, int appId, @utf8InCpp String profileName, @utf8InCpp String codePath,
@nullable @utf8InCpp String dexMetadata);
+
+ const int FLAG_STORAGE_DE = 0x1;
+ const int FLAG_STORAGE_CE = 0x2;
+
+ const int FLAG_CLEAR_CACHE_ONLY = 0x10;
+ const int FLAG_CLEAR_CODE_CACHE_ONLY = 0x20;
+
+ const int FLAG_FREE_CACHE_V2 = 0x100;
+ const int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 0x200;
+ const int FLAG_FREE_CACHE_NOOP = 0x400;
+
+ const int FLAG_USE_QUOTA = 0x1000;
+ const int FLAG_FORCE = 0x2000;
}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 0e78e3a..66dece7 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1692,15 +1692,12 @@
*dexopt_needed_out = NO_DEXOPT_NEEDED; return true;
case 1: // dexoptanalyzer: dex2oat_from_scratch
*dexopt_needed_out = DEX2OAT_FROM_SCRATCH; return true;
- case 5: // dexoptanalyzer: dex2oat_for_bootimage_odex
+ case 4: // dexoptanalyzer: dex2oat_for_bootimage_odex
*dexopt_needed_out = -DEX2OAT_FOR_BOOT_IMAGE; return true;
- case 6: // dexoptanalyzer: dex2oat_for_filter_odex
+ case 5: // dexoptanalyzer: dex2oat_for_filter_odex
*dexopt_needed_out = -DEX2OAT_FOR_FILTER; return true;
- case 7: // dexoptanalyzer: dex2oat_for_relocation_odex
- *dexopt_needed_out = -DEX2OAT_FOR_RELOCATION; return true;
case 2: // dexoptanalyzer: dex2oat_for_bootimage_oat
case 3: // dexoptanalyzer: dex2oat_for_filter_oat
- case 4: // dexoptanalyzer: dex2oat_for_relocation_oat
*error_msg = StringPrintf("Dexoptanalyzer return the status of an oat file."
" Expected odex file status for secondary dex %s"
" : dexoptanalyzer result=%d",
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index bb6fab3..0db11e1 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -31,7 +31,6 @@
static constexpr int DEX2OAT_FROM_SCRATCH = 1;
static constexpr int DEX2OAT_FOR_BOOT_IMAGE = 2;
static constexpr int DEX2OAT_FOR_FILTER = 3;
-static constexpr int DEX2OAT_FOR_RELOCATION = 4;
// Clear the reference profile identified by the given profile name.
bool clear_primary_reference_profile(const std::string& pkgname, const std::string& profile_name);
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 2d58515..db09070 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -40,8 +40,8 @@
constexpr int64_t kGbInBytes = 1024 * kMbInBytes;
constexpr int64_t kTbInBytes = 1024 * kGbInBytes;
-static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
-static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
+#define FLAG_FREE_CACHE_V2 InstalldNativeService::FLAG_FREE_CACHE_V2
+#define FLAG_FREE_CACHE_V2_DEFY_QUOTA InstalldNativeService::FLAG_FREE_CACHE_V2_DEFY_QUOTA
int get_property(const char *key, char *value, const char *default_value) {
return property_get(key, value, default_value);
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 279bce8..f216c53 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -84,10 +84,16 @@
system(cmd.c_str());
}
-static void mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
- ::mkdir(path.c_str(), mode);
- ::chown(path.c_str(), owner, group);
- ::chmod(path.c_str(), mode);
+static int mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
+ int ret = ::mkdir(path.c_str(), mode);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = ::chown(path.c_str(), owner, group);
+ if (ret != 0) {
+ return ret;
+ }
+ return ::chmod(path.c_str(), mode);
}
static int log_callback(int type, const char *fmt, ...) { // NOLINT
@@ -184,7 +190,7 @@
se_info_ = "default";
app_apk_dir_ = android_app_dir + package_name_;
- create_mock_app();
+ ASSERT_TRUE(create_mock_app());
}
virtual void TearDown() {
@@ -198,33 +204,56 @@
delete service_;
}
- void create_mock_app() {
+ ::testing::AssertionResult create_mock_app() {
// Create the oat dir.
app_oat_dir_ = app_apk_dir_ + "/oat";
- mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755);
- service_->createOatDir(app_oat_dir_, kRuntimeIsa);
+ if (mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755) != 0) {
+ return ::testing::AssertionFailure() << "Could not create app dir " << app_apk_dir_
+ << " : " << strerror(errno);
+ }
+ binder::Status status = service_->createOatDir(app_oat_dir_, kRuntimeIsa);
+ if (!status.isOk()) {
+ return ::testing::AssertionFailure() << "Could not create oat dir: "
+ << status.toString8().c_str();
+ }
// Copy the primary apk.
apk_path_ = app_apk_dir_ + "/base.jar";
- ASSERT_TRUE(WriteBase64ToFile(kDexFile, apk_path_, kSystemUid, kSystemGid, 0644));
+ std::string error_msg;
+ if (!WriteBase64ToFile(kDexFile, apk_path_, kSystemUid, kSystemGid, 0644, &error_msg)) {
+ return ::testing::AssertionFailure() << "Could not write base64 file to " << apk_path_
+ << " : " << error_msg;
+ }
// Create the app user data.
- ASSERT_TRUE(service_->createAppData(
- volume_uuid_,
- package_name_,
- kTestUserId,
- kAppDataFlags,
- kTestAppUid,
- se_info_,
- kOSdkVersion,
- &ce_data_inode_).isOk());
+ status = service_->createAppData(
+ volume_uuid_,
+ package_name_,
+ kTestUserId,
+ kAppDataFlags,
+ kTestAppUid,
+ se_info_,
+ kOSdkVersion,
+ &ce_data_inode_);
+ if (!status.isOk()) {
+ return ::testing::AssertionFailure() << "Could not create app data: "
+ << status.toString8().c_str();
+ }
// Create a secondary dex file on CE storage
const char* volume_uuid_cstr = volume_uuid_ == nullptr ? nullptr : volume_uuid_->c_str();
app_private_dir_ce_ = create_data_user_ce_package_path(
volume_uuid_cstr, kTestUserId, package_name_.c_str());
secondary_dex_ce_ = app_private_dir_ce_ + "/secondary_ce.jar";
- ASSERT_TRUE(WriteBase64ToFile(kDexFile, secondary_dex_ce_, kTestAppUid, kTestAppGid, 0600));
+ if (!WriteBase64ToFile(kDexFile,
+ secondary_dex_ce_,
+ kTestAppUid,
+ kTestAppGid,
+ 0600,
+ &error_msg)) {
+ return ::testing::AssertionFailure() << "Could not write base64 file to "
+ << secondary_dex_ce_ << " : " << error_msg;
+ }
std::string app_private_dir_ce_link = create_data_user_ce_package_path_as_user_link(
volume_uuid_cstr, kTestUserId, package_name_.c_str());
secondary_dex_ce_link_ = app_private_dir_ce_link + "/secondary_ce.jar";
@@ -233,10 +262,24 @@
app_private_dir_de_ = create_data_user_de_package_path(
volume_uuid_cstr, kTestUserId, package_name_.c_str());
secondary_dex_de_ = app_private_dir_de_ + "/secondary_de.jar";
- ASSERT_TRUE(WriteBase64ToFile(kDexFile, secondary_dex_de_, kTestAppUid, kTestAppGid, 0600));
+ if (!WriteBase64ToFile(kDexFile,
+ secondary_dex_de_,
+ kTestAppUid,
+ kTestAppGid,
+ 0600,
+ &error_msg)) {
+ return ::testing::AssertionFailure() << "Could not write base64 file to "
+ << secondary_dex_de_ << " : " << error_msg;
+ }
// Fix app data uid.
- ASSERT_TRUE(service_->fixupAppData(volume_uuid_, kTestUserId).isOk());
+ status = service_->fixupAppData(volume_uuid_, kTestUserId);
+ if (!status.isOk()) {
+ return ::testing::AssertionFailure() << "Could not fixup app data: "
+ << status.toString8().c_str();
+ }
+
+ return ::testing::AssertionSuccess();
}
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index a5af5d7..9dad995 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -37,7 +37,7 @@
constexpr const char* kTestUuid = "TEST";
-static constexpr int FLAG_FORCE = 1 << 16;
+#define FLAG_FORCE InstalldNativeService::FLAG_FORCE
int get_property(const char *key, char *value, const char *default_value) {
return property_get(key, value, default_value);
diff --git a/cmds/installd/tests/test_utils.h b/cmds/installd/tests/test_utils.h
index b8785c6..a7ef674 100644
--- a/cmds/installd/tests/test_utils.h
+++ b/cmds/installd/tests/test_utils.h
@@ -3,6 +3,7 @@
#include <sys/capability.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <selinux/android.h>
uint8_t kBase64Map[256] = {
@@ -74,7 +75,7 @@
}
bool WriteBase64ToFile(const char* base64, const std::string& file,
- uid_t uid, gid_t gid, int mode) {
+ uid_t uid, gid_t gid, int mode, std::string* error_msg) {
CHECK(base64 != nullptr);
size_t length;
std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length));
@@ -83,8 +84,10 @@
int fd = open(file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+ using android::base::StringPrintf;
+
if (fd < 0) {
- PLOG(ERROR) << "Could not open file " << file;
+ *error_msg = StringPrintf("Could not open file %s: %s", file.c_str(), strerror(errno));
return false;
}
@@ -92,18 +95,18 @@
while (wrote < length) {
ssize_t cur = write(fd, bytes.get() + wrote, length - wrote);
if (cur == -1) {
- PLOG(ERROR) << "Could not write file " << file;
+ *error_msg = StringPrintf("Could not write file %s: %s", file.c_str(), strerror(errno));
return false;
}
wrote += cur;
}
if (::chown(file.c_str(), uid, gid) != 0) {
- PLOG(ERROR) << "Could not chown file " << file;
+ *error_msg = StringPrintf("Could not chown file %s: %s", file.c_str(), strerror(errno));
return false;
}
if (::chmod(file.c_str(), mode) != 0) {
- PLOG(ERROR) << "Could not chmod file " << file;
+ *error_msg = StringPrintf("Could not chmod file %s: %s", file.c_str(), strerror(errno));
return false;
}
return true;
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 0bc08a9..68ddeb0 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -30,14 +30,13 @@
message SurfaceChange {
required int32 id = 1;
-
+ reserved 7;
oneof SurfaceChange {
PositionChange position = 2;
SizeChange size = 3;
AlphaChange alpha = 4;
LayerChange layer = 5;
CropChange crop = 6;
- FinalCropChange final_crop = 7;
MatrixChange matrix = 8;
OverrideScalingModeChange override_scaling_mode = 9;
TransparentRegionHintChange transparent_region_hint = 10;
@@ -71,10 +70,6 @@
required Rectangle rectangle = 1;
}
-message FinalCropChange {
- required Rectangle rectangle = 1;
-}
-
message MatrixChange {
required float dsdx = 1;
required float dtdx = 2;
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index d9ff4ba..6602546 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -388,9 +388,6 @@
case SurfaceChange::SurfaceChangeCase::kMatrix:
setMatrix(transaction, change.id(), change.matrix());
break;
- case SurfaceChange::SurfaceChangeCase::kFinalCrop:
- setFinalCrop(transaction, change.id(), change.final_crop());
- break;
case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode:
setOverrideScalingMode(transaction, change.id(),
change.override_scaling_mode());
@@ -492,16 +489,6 @@
t.setCrop_legacy(mLayers[id], r);
}
-void Replayer::setFinalCrop(SurfaceComposerClient::Transaction& t,
- layer_id id, const FinalCropChange& fcc) {
- ALOGV("Layer %d: Setting Final Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
- fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
- fcc.rectangle().bottom());
- Rect r = Rect(fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
- fcc.rectangle().bottom());
- t.setFinalCrop_legacy(mLayers[id], r);
-}
-
void Replayer::setMatrix(SurfaceComposerClient::Transaction& t,
layer_id id, const MatrixChange& mc) {
ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(),
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index 295403e..68390d3 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -92,8 +92,6 @@
layer_id id, const LayerChange& lc);
void setCrop(SurfaceComposerClient::Transaction& t,
layer_id id, const CropChange& cc);
- void setFinalCrop(SurfaceComposerClient::Transaction& t,
- layer_id id, const FinalCropChange& fcc);
void setMatrix(SurfaceComposerClient::Transaction& t,
layer_id id, const MatrixChange& mc);
void setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index 86da4d3..0f336dd 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -39,13 +39,13 @@
int32_t physicalBottom;
int32_t deviceWidth;
int32_t deviceHeight;
- String8 uniqueId;
+ std::string uniqueId;
DisplayViewport() :
displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0),
logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0),
- deviceWidth(0), deviceHeight(0) {
+ deviceWidth(0), deviceHeight(0), uniqueId() {
}
bool operator==(const DisplayViewport& other) const {
diff --git a/include/input/Input.h b/include/input/Input.h
index 7c4379e..819a89f 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -25,7 +25,6 @@
#include <utils/BitSet.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
-#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Vector.h>
#include <stdint.h>
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 1ea69d3..34d164c 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -31,9 +31,9 @@
}
// Information provided by the kernel.
- String8 name;
- String8 location;
- String8 uniqueId;
+ std::string name;
+ std::string location;
+ std::string uniqueId;
uint16_t bus;
uint16_t vendor;
uint16_t product;
@@ -45,7 +45,7 @@
// It is hashed from whatever kernel provided information is available.
// Ideally, the way this value is computed should not change between Android releases
// because that would invalidate persistent settings that rely on it.
- String8 descriptor;
+ std::string descriptor;
// A value added to uniquely identify a device in the absence of a unique id. This
// is intended to be a minimum way to distinguish from other active devices and may
@@ -73,16 +73,16 @@
};
void initialize(int32_t id, int32_t generation, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+ const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
bool hasMic);
inline int32_t getId() const { return mId; }
inline int32_t getControllerNumber() const { return mControllerNumber; }
inline int32_t getGeneration() const { return mGeneration; }
inline const InputDeviceIdentifier& getIdentifier() const { return mIdentifier; }
- inline const String8& getAlias() const { return mAlias; }
- inline const String8& getDisplayName() const {
- return mAlias.isEmpty() ? mIdentifier.name : mAlias;
+ inline const std::string& getAlias() const { return mAlias; }
+ inline const std::string& getDisplayName() const {
+ return mAlias.empty() ? mIdentifier.name : mAlias;
}
inline bool isExternal() const { return mIsExternal; }
inline bool hasMic() const { return mHasMic; }
@@ -121,7 +121,7 @@
int32_t mGeneration;
int32_t mControllerNumber;
InputDeviceIdentifier mIdentifier;
- String8 mAlias;
+ std::string mAlias;
bool mIsExternal;
bool mHasMic;
uint32_t mSources;
@@ -149,7 +149,7 @@
*
* Returns an empty string if not found.
*/
-extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+extern std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
const InputDeviceIdentifier& deviceIdentifier,
InputDeviceConfigurationFileType type);
@@ -162,8 +162,8 @@
*
* Returns an empty string if not found.
*/
-extern String8 getInputDeviceConfigurationFilePathByName(
- const String8& name, InputDeviceConfigurationFileType type);
+extern std::string getInputDeviceConfigurationFilePathByName(
+ const std::string& name, InputDeviceConfigurationFileType type);
} // namespace android
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index e8d1345..5fd86b4 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -27,6 +27,8 @@
* The InputConsumer is used by the application to receive events from the input dispatcher.
*/
+#include <string>
+
#include <input/Input.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 33d2757..9f4559f 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -27,7 +27,6 @@
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
-#include <utils/String8.h>
#include <utils/Unicode.h>
#include <utils/RefBase.h>
@@ -75,10 +74,10 @@
};
/* Loads a key character map from a file. */
- static status_t load(const String8& filename, Format format, sp<KeyCharacterMap>* outMap);
+ static status_t load(const std::string& filename, Format format, sp<KeyCharacterMap>* outMap);
/* Loads a key character map from its string contents. */
- static status_t loadContents(const String8& filename,
+ static status_t loadContents(const std::string& filename,
const char* contents, Format format, sp<KeyCharacterMap>* outMap);
/* Combines a base key character map and an overlay. */
@@ -221,7 +220,7 @@
status_t parseKey();
status_t parseKeyProperty();
status_t finishKey(Key* key);
- status_t parseModifier(const String8& token, int32_t* outMetaState);
+ status_t parseModifier(const std::string& token, int32_t* outMetaState);
status_t parseCharacterLiteral(char16_t* outCharacter);
};
diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h
index 1e8de71..73815fe 100644
--- a/include/input/KeyLayoutMap.h
+++ b/include/input/KeyLayoutMap.h
@@ -62,7 +62,7 @@
*/
class KeyLayoutMap : public RefBase {
public:
- static status_t load(const String8& filename, sp<KeyLayoutMap>* outMap);
+ static status_t load(const std::string& filename, sp<KeyLayoutMap>* outMap);
status_t mapKey(int32_t scanCode, int32_t usageCode,
int32_t* outKeyCode, uint32_t* outFlags) const;
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index d4903e9..8b66f69 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -21,7 +21,6 @@
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
#include <utils/Errors.h>
-#include <utils/String8.h>
#include <utils/PropertyMap.h>
namespace android {
@@ -43,10 +42,10 @@
*/
class KeyMap {
public:
- String8 keyLayoutFile;
+ std::string keyLayoutFile;
sp<KeyLayoutMap> keyLayoutMap;
- String8 keyCharacterMapFile;
+ std::string keyCharacterMapFile;
sp<KeyCharacterMap> keyCharacterMap;
KeyMap();
@@ -56,11 +55,11 @@
const PropertyMap* deviceConfiguration);
inline bool haveKeyLayout() const {
- return !keyLayoutFile.isEmpty();
+ return !keyLayoutFile.empty();
}
inline bool haveKeyCharacterMap() const {
- return !keyCharacterMapFile.isEmpty();
+ return !keyCharacterMapFile.empty();
}
inline bool isComplete() const {
@@ -68,12 +67,12 @@
}
private:
- bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
- status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
+ bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
+ status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name);
- String8 getPath(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name, InputDeviceConfigurationFileType type);
+ const std::string& name);
+ std::string getPath(const InputDeviceIdentifier& deviceIdentifier,
+ const std::string& name, InputDeviceConfigurationFileType type);
};
/**
diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h
index e245ead..24e0e0e 100644
--- a/include/input/VirtualKeyMap.h
+++ b/include/input/VirtualKeyMap.h
@@ -23,7 +23,6 @@
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
-#include <utils/String8.h>
#include <utils/Unicode.h>
namespace android {
@@ -50,7 +49,7 @@
public:
~VirtualKeyMap();
- static status_t load(const String8& filename, VirtualKeyMap** outMap);
+ static status_t load(const std::string& filename, VirtualKeyMap** outMap);
inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
return mVirtualKeys;
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index d516eb1..857bbf9 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -189,7 +189,7 @@
// them out without going through the buffer.
// Slurp up all of the lines.
- const char* lastLine = txt+1;
+ const char* lastLine = txt;
while (txt < end) {
if (*txt++ == '\n') lastLine = txt;
}
diff --git a/libs/binder/ndk/ABinderProcess.cpp b/libs/binder/ndk/ABinderProcess.cpp
new file mode 100644
index 0000000..c89caaf
--- /dev/null
+++ b/libs/binder/ndk/ABinderProcess.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_process.h>
+
+#include <mutex>
+
+#include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
+
+using ::android::IPCThreadState;
+using ::android::ProcessState;
+
+void ABinderProcess_startThreadPool() {
+ ProcessState::self()->startThreadPool();
+ ProcessState::self()->giveThreadPoolName();
+}
+bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads) {
+ return ProcessState::self()->setThreadPoolMaxThreadCount(numThreads) == 0;
+}
+void ABinderProcess_joinThreadPool() {
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/libs/binder/ndk/AIBinder.cpp b/libs/binder/ndk/AIBinder.cpp
new file mode 100644
index 0000000..83972f7
--- /dev/null
+++ b/libs/binder/ndk/AIBinder.cpp
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_ibinder.h>
+#include "AIBinder_internal.h"
+
+#include <android/binder_status.h>
+#include "AParcel_internal.h"
+
+#include <android-base/logging.h>
+
+using ::android::IBinder;
+using ::android::Parcel;
+using ::android::sp;
+using ::android::String16;
+using ::android::wp;
+
+namespace ABBinderTag {
+
+static const void* kId = "ABBinder";
+static void* kValue = static_cast<void*>(new bool{true});
+void cleanId(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */};
+
+static void attach(const sp<IBinder>& binder) {
+ binder->attachObject(kId, kValue, nullptr /*cookie*/, cleanId);
+}
+static bool has(const sp<IBinder>& binder) {
+ return binder != nullptr && binder->findObject(kId) == kValue;
+}
+
+} // namespace ABBinderTag
+
+AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
+AIBinder::~AIBinder() {}
+
+bool AIBinder::associateClass(const AIBinder_Class* clazz) {
+ using ::android::String8;
+
+ if (clazz == nullptr) return false;
+ if (mClazz == clazz) return true;
+
+ String8 newDescriptor(clazz->getInterfaceDescriptor());
+
+ if (mClazz != nullptr) {
+ String8 currentDescriptor(mClazz->getInterfaceDescriptor());
+ if (newDescriptor == currentDescriptor) {
+ LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor
+ << "' match during associateClass, but they are different class objects. "
+ "Class descriptor collision?";
+ } else {
+ LOG(ERROR) << __func__
+ << ": Class cannot be associated on object which already has a class. "
+ "Trying to associate to '"
+ << newDescriptor.c_str() << "' but already set to '"
+ << currentDescriptor.c_str() << "'.";
+ }
+
+ // always a failure because we know mClazz != clazz
+ return false;
+ }
+
+ CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor
+
+ String8 descriptor(getBinder()->getInterfaceDescriptor());
+ if (descriptor != newDescriptor) {
+ LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor.c_str()
+ << "' but descriptor is actually '" << descriptor.c_str() << "'.";
+ return false;
+ }
+
+ // if this is a local object, it's not one known to libbinder_ndk
+ mClazz = clazz;
+
+ return true;
+}
+
+ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
+ : AIBinder(clazz), BBinder(), mUserData(userData) {
+ CHECK(clazz != nullptr);
+}
+ABBinder::~ABBinder() {
+ getClass()->onDestroy(mUserData);
+}
+
+const String16& ABBinder::getInterfaceDescriptor() const {
+ return getClass()->getInterfaceDescriptor();
+}
+
+binder_status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
+ binder_flags_t flags) {
+ if (isUserCommand(code)) {
+ if (!data.checkInterface(this)) {
+ return EX_ILLEGAL_STATE;
+ }
+
+ const AParcel in = AParcel::readOnly(this, &data);
+ AParcel out = AParcel(this, reply, false /*owns*/);
+
+ return getClass()->onTransact(this, code, &in, &out);
+ } else {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
+ : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
+ CHECK(binder != nullptr);
+}
+ABpBinder::~ABpBinder() {}
+
+sp<AIBinder> ABpBinder::fromBinder(const ::android::sp<::android::IBinder>& binder) {
+ if (binder == nullptr) {
+ return nullptr;
+ }
+ if (ABBinderTag::has(binder)) {
+ return static_cast<ABBinder*>(binder.get());
+ }
+ return new ABpBinder(binder);
+}
+
+struct AIBinder_Weak {
+ wp<AIBinder> binder;
+};
+AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder) {
+ if (binder == nullptr) {
+ return nullptr;
+ }
+
+ return new AIBinder_Weak{wp<AIBinder>(binder)};
+}
+void AIBinder_Weak_delete(AIBinder_Weak** weakBinder) {
+ if (weakBinder == nullptr) {
+ return;
+ }
+
+ delete *weakBinder;
+ *weakBinder = nullptr;
+}
+AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder) {
+ if (weakBinder == nullptr) {
+ return nullptr;
+ }
+
+ sp<AIBinder> binder = weakBinder->binder.promote();
+ AIBinder_incStrong(binder.get());
+ return binder.get();
+}
+
+AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
+ AIBinder_Class_onDestroy onDestroy,
+ AIBinder_Class_onTransact onTransact)
+ : onCreate(onCreate),
+ onDestroy(onDestroy),
+ onTransact(onTransact),
+ mInterfaceDescriptor(interfaceDescriptor) {}
+
+AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
+ AIBinder_Class_onCreate onCreate,
+ AIBinder_Class_onDestroy onDestroy,
+ AIBinder_Class_onTransact onTransact) {
+ if (interfaceDescriptor == nullptr || onCreate == nullptr || onDestroy == nullptr ||
+ onTransact == nullptr) {
+ return nullptr;
+ }
+
+ return new AIBinder_Class(interfaceDescriptor, onCreate, onDestroy, onTransact);
+}
+
+AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) {
+ if (clazz == nullptr) {
+ LOG(ERROR) << __func__ << ": Must provide class to construct local binder.";
+ return nullptr;
+ }
+
+ void* userData = clazz->onCreate(args);
+
+ sp<AIBinder> ret = new ABBinder(clazz, userData);
+ ABBinderTag::attach(ret->getBinder());
+
+ AIBinder_incStrong(ret.get());
+ return ret.get();
+}
+
+bool AIBinder_isRemote(const AIBinder* binder) {
+ if (binder == nullptr) {
+ return true;
+ }
+
+ return binder->isRemote();
+}
+
+bool AIBinder_isAlive(const AIBinder* binder) {
+ if (binder == nullptr) {
+ return false;
+ }
+
+ return const_cast<AIBinder*>(binder)->getBinder()->isBinderAlive();
+}
+
+binder_status_t AIBinder_ping(AIBinder* binder) {
+ if (binder == nullptr) {
+ return EX_NULL_POINTER;
+ }
+
+ return binder->getBinder()->pingBinder();
+}
+
+void AIBinder_incStrong(AIBinder* binder) {
+ if (binder == nullptr) {
+ LOG(ERROR) << __func__ << ": on null binder";
+ return;
+ }
+
+ binder->incStrong(nullptr);
+}
+void AIBinder_decStrong(AIBinder* binder) {
+ if (binder == nullptr) {
+ LOG(ERROR) << __func__ << ": on null binder";
+ return;
+ }
+
+ binder->decStrong(nullptr);
+}
+int32_t AIBinder_debugGetRefCount(AIBinder* binder) {
+ if (binder == nullptr) {
+ LOG(ERROR) << __func__ << ": on null binder";
+ return -1;
+ }
+
+ return binder->getStrongCount();
+}
+
+bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) {
+ if (binder == nullptr) {
+ return false;
+ }
+
+ return binder->associateClass(clazz);
+}
+
+const AIBinder_Class* AIBinder_getClass(AIBinder* binder) {
+ if (binder == nullptr) {
+ return nullptr;
+ }
+
+ return binder->getClass();
+}
+
+void* AIBinder_getUserData(AIBinder* binder) {
+ if (binder == nullptr) {
+ return nullptr;
+ }
+
+ ABBinder* bBinder = binder->asABBinder();
+ if (bBinder == nullptr) {
+ return nullptr;
+ }
+
+ return bBinder->getUserData();
+}
+
+binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) {
+ if (binder == nullptr || in == nullptr) {
+ LOG(ERROR) << __func__ << ": requires non-null parameters.";
+ return EX_NULL_POINTER;
+ }
+ const AIBinder_Class* clazz = binder->getClass();
+ if (clazz == nullptr) {
+ LOG(ERROR) << __func__
+ << ": Class must be defined for a remote binder transaction. See "
+ "AIBinder_associateClass.";
+ return EX_ILLEGAL_STATE;
+ }
+
+ *in = new AParcel(binder);
+ binder_status_t status = (**in)->writeInterfaceToken(clazz->getInterfaceDescriptor());
+ if (status != EX_NONE) {
+ delete *in;
+ *in = nullptr;
+ }
+
+ return status;
+}
+
+binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
+ AParcel** out, binder_flags_t flags) {
+ if (in == nullptr) {
+ LOG(ERROR) << __func__ << ": requires non-null in parameter";
+ return EX_NULL_POINTER;
+ }
+
+ using AutoParcelDestroyer = std::unique_ptr<AParcel*, void (*)(AParcel**)>;
+ // This object is the input to the transaction. This function takes ownership of it and deletes
+ // it.
+ AutoParcelDestroyer forIn(in, AParcel_delete);
+
+ if (!isUserCommand(code)) {
+ LOG(ERROR) << __func__ << ": Only user-defined transactions can be made from the NDK.";
+ return EX_UNSUPPORTED_OPERATION;
+ }
+
+ if ((flags & ~FLAG_ONEWAY) != 0) {
+ LOG(ERROR) << __func__ << ": Unrecognized flags sent: " << flags;
+ return EX_ILLEGAL_ARGUMENT;
+ }
+
+ if (binder == nullptr || *in == nullptr || out == nullptr) {
+ LOG(ERROR) << __func__ << ": requires non-null parameters.";
+ return EX_NULL_POINTER;
+ }
+
+ if ((*in)->getBinder() != binder) {
+ LOG(ERROR) << __func__ << ": parcel is associated with binder object " << binder
+ << " but called with " << (*in)->getBinder();
+ return EX_ILLEGAL_STATE;
+ }
+
+ *out = new AParcel(binder);
+
+ binder_status_t parcelStatus =
+ binder->getBinder()->transact(code, *(*in)->operator->(), (*out)->operator->(), flags);
+
+ if (parcelStatus != EX_NONE) {
+ delete *out;
+ *out = nullptr;
+ }
+
+ return parcelStatus;
+}
diff --git a/libs/binder/ndk/AIBinder_internal.h b/libs/binder/ndk/AIBinder_internal.h
new file mode 100644
index 0000000..23949bb
--- /dev/null
+++ b/libs/binder/ndk/AIBinder_internal.h
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+#include "AIBinder_internal.h"
+
+#include <atomic>
+
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+
+inline bool isUserCommand(transaction_code_t code) {
+ return code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION;
+}
+
+struct ABBinder;
+struct ABpBinder;
+
+struct AIBinder : public virtual ::android::RefBase {
+ AIBinder(const AIBinder_Class* clazz);
+ virtual ~AIBinder();
+
+ bool associateClass(const AIBinder_Class* clazz);
+ const AIBinder_Class* getClass() const { return mClazz; }
+
+ virtual ::android::sp<::android::IBinder> getBinder() = 0;
+ virtual ABBinder* asABBinder() { return nullptr; }
+ virtual ABpBinder* asABpBinder() { return nullptr; }
+
+ bool isRemote() const {
+ ::android::sp<::android::IBinder> binder = const_cast<AIBinder*>(this)->getBinder();
+ return binder->remoteBinder() != nullptr;
+ }
+
+private:
+ // AIBinder instance is instance of this class for a local object. In order to transact on a
+ // remote object, this also must be set for simplicity (although right now, only the
+ // interfaceDescriptor from it is used).
+ const AIBinder_Class* mClazz;
+};
+
+// This is a local AIBinder object with a known class.
+struct ABBinder : public AIBinder, public ::android::BBinder {
+ virtual ~ABBinder();
+
+ void* getUserData() { return mUserData; }
+
+ ::android::sp<::android::IBinder> getBinder() override { return this; }
+ ABBinder* asABBinder() override { return this; }
+
+ const ::android::String16& getInterfaceDescriptor() const override;
+ binder_status_t onTransact(uint32_t code, const ::android::Parcel& data,
+ ::android::Parcel* reply, binder_flags_t flags) override;
+
+private:
+ ABBinder(const AIBinder_Class* clazz, void* userData);
+
+ // only thing that should create an ABBinder
+ friend AIBinder* AIBinder_new(const AIBinder_Class*, void*);
+
+ // Can contain implementation if this is a local binder. This can still be nullptr for a local
+ // binder. If it is nullptr, the implication is the implementation state is entirely external to
+ // this object and the functionality provided in the AIBinder_Class is sufficient.
+ void* mUserData;
+};
+
+// This binder object may be remote or local (even though it is 'Bp'). It is not yet associated with
+// a class.
+struct ABpBinder : public AIBinder, public ::android::BpRefBase {
+ static ::android::sp<AIBinder> fromBinder(const ::android::sp<::android::IBinder>& binder);
+
+ virtual ~ABpBinder();
+
+ ::android::sp<::android::IBinder> getBinder() override { return remote(); }
+ ABpBinder* asABpBinder() override { return this; }
+
+private:
+ ABpBinder(const ::android::sp<::android::IBinder>& binder);
+};
+
+struct AIBinder_Class {
+ AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
+ AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact);
+
+ const ::android::String16& getInterfaceDescriptor() const { return mInterfaceDescriptor; }
+
+ const AIBinder_Class_onCreate onCreate;
+ const AIBinder_Class_onDestroy onDestroy;
+ const AIBinder_Class_onTransact onTransact;
+
+private:
+ // This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
+ // one.
+ const ::android::String16 mInterfaceDescriptor;
+};
diff --git a/libs/binder/ndk/AParcel.cpp b/libs/binder/ndk/AParcel.cpp
new file mode 100644
index 0000000..93384d6
--- /dev/null
+++ b/libs/binder/ndk/AParcel.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_parcel.h>
+#include "AParcel_internal.h"
+
+#include "AIBinder_internal.h"
+
+#include <binder/Parcel.h>
+
+using ::android::IBinder;
+using ::android::Parcel;
+using ::android::sp;
+
+void AParcel_delete(AParcel** parcel) {
+ if (parcel == nullptr) {
+ return;
+ }
+
+ delete *parcel;
+ *parcel = nullptr;
+}
+
+binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) {
+ return (*parcel)->writeStrongBinder(binder->getBinder());
+}
+binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder) {
+ sp<IBinder> readBinder = nullptr;
+ binder_status_t status = (*parcel)->readStrongBinder(&readBinder);
+ if (status != EX_NONE) {
+ return status;
+ }
+ sp<AIBinder> ret = ABpBinder::fromBinder(readBinder);
+ AIBinder_incStrong(ret.get());
+ *binder = ret.get();
+ return status;
+}
+binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder) {
+ sp<IBinder> readBinder = nullptr;
+ binder_status_t status = (*parcel)->readNullableStrongBinder(&readBinder);
+ if (status != EX_NONE) {
+ return status;
+ }
+ sp<AIBinder> ret = ABpBinder::fromBinder(readBinder);
+ AIBinder_incStrong(ret.get());
+ *binder = ret.get();
+ return status;
+}
+
+// See gen_parcel_helper.py. These auto-generated read/write methods use the same types for
+// libbinder and this library.
+// @START
+binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) {
+ return (*parcel)->writeInt32(value);
+}
+
+binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) {
+ return (*parcel)->writeUint32(value);
+}
+
+binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) {
+ return (*parcel)->writeInt64(value);
+}
+
+binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) {
+ return (*parcel)->writeUint64(value);
+}
+
+binder_status_t AParcel_writeFloat(AParcel* parcel, float value) {
+ return (*parcel)->writeFloat(value);
+}
+
+binder_status_t AParcel_writeDouble(AParcel* parcel, double value) {
+ return (*parcel)->writeDouble(value);
+}
+
+binder_status_t AParcel_writeBool(AParcel* parcel, bool value) {
+ return (*parcel)->writeBool(value);
+}
+
+binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) {
+ return (*parcel)->writeChar(value);
+}
+
+binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) {
+ return (*parcel)->writeByte(value);
+}
+
+binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) {
+ return (*parcel)->readInt32(value);
+}
+
+binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) {
+ return (*parcel)->readUint32(value);
+}
+
+binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) {
+ return (*parcel)->readInt64(value);
+}
+
+binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) {
+ return (*parcel)->readUint64(value);
+}
+
+binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) {
+ return (*parcel)->readFloat(value);
+}
+
+binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) {
+ return (*parcel)->readDouble(value);
+}
+
+binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) {
+ return (*parcel)->readBool(value);
+}
+
+binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) {
+ return (*parcel)->readChar(value);
+}
+
+binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) {
+ return (*parcel)->readByte(value);
+}
+
+// @END
diff --git a/libs/binder/ndk/AParcel_internal.h b/libs/binder/ndk/AParcel_internal.h
new file mode 100644
index 0000000..9f30a2f
--- /dev/null
+++ b/libs/binder/ndk/AParcel_internal.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.
+ */
+
+#pragma once
+
+#include <android/binder_parcel.h>
+
+#include <sys/cdefs.h>
+
+#include <binder/Parcel.h>
+#include "AIBinder_internal.h"
+
+struct AParcel {
+ const ::android::Parcel* operator->() const { return mParcel; }
+ ::android::Parcel* operator->() { return mParcel; }
+
+ AParcel(const AIBinder* binder) : AParcel(binder, new ::android::Parcel, true /*owns*/) {}
+ AParcel(const AIBinder* binder, ::android::Parcel* parcel, bool owns)
+ : mBinder(binder), mParcel(parcel), mOwns(owns) {}
+
+ ~AParcel() {
+ if (mOwns) {
+ delete mParcel;
+ }
+ }
+
+ static const AParcel readOnly(const AIBinder* binder, const ::android::Parcel* parcel) {
+ return AParcel(binder, const_cast<::android::Parcel*>(parcel), false);
+ }
+
+ const AIBinder* getBinder() { return mBinder; }
+
+private:
+ // This object is associated with a calls to a specific AIBinder object. This is used for sanity
+ // checking to make sure that a parcel is one that is expected.
+ const AIBinder* mBinder;
+
+ ::android::Parcel* mParcel;
+ bool mOwns;
+};
diff --git a/libs/binder/ndk/AServiceManager.cpp b/libs/binder/ndk/AServiceManager.cpp
new file mode 100644
index 0000000..3979945
--- /dev/null
+++ b/libs/binder/ndk/AServiceManager.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_manager.h>
+#include "AIBinder_internal.h"
+
+#include <binder/IServiceManager.h>
+
+using ::android::defaultServiceManager;
+using ::android::IBinder;
+using ::android::IServiceManager;
+using ::android::sp;
+using ::android::String16;
+
+binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance) {
+ if (binder == nullptr || instance == nullptr) {
+ return EX_NULL_POINTER;
+ }
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ return sm->addService(String16(instance), binder->getBinder());
+}
+AIBinder* AServiceManager_getService(const char* instance) {
+ if (instance == nullptr) {
+ return nullptr;
+ }
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16(instance));
+
+ sp<AIBinder> ret = ABpBinder::fromBinder(binder);
+ AIBinder_incStrong(ret.get());
+ return ret.get();
+}
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
new file mode 100644
index 0000000..76d5a73
--- /dev/null
+++ b/libs/binder/ndk/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+cc_library {
+ name: "libbinder_ndk",
+ vendor_available: false,
+
+ export_include_dirs: [
+ "include_ndk",
+ "include_apex",
+ ],
+
+ srcs: [
+ "ABinderProcess.cpp",
+ "AIBinder.cpp",
+ "AParcel.cpp",
+ "AServiceManager.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libutils",
+ ],
+}
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h
new file mode 100644
index 0000000..b8f38ba
--- /dev/null
+++ b/libs/binder/ndk/include_apex/android/binder_manager.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+
+__BEGIN_DECLS
+
+/**
+ * This registers the service with the default service manager under this instance name.
+ */
+binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance);
+
+/**
+ * Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
+ * it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
+ * for calling AIBinder_decStrong).
+ */
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
+
+__END_DECLS
diff --git a/libs/binder/ndk/include_apex/android/binder_process.h b/libs/binder/ndk/include_apex/android/binder_process.h
new file mode 100644
index 0000000..69e6387
--- /dev/null
+++ b/libs/binder/ndk/include_apex/android/binder_process.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * This creates a threadpool for incoming binder transactions if it has not already been created.
+ */
+void ABinderProcess_startThreadPool();
+/**
+ * This sets the maximum number of threads that can be started in the threadpool. By default, after
+ * startThreadPool is called, this is one. If it is called additional times, it will only prevent
+ * the kernel from starting new threads and will not delete already existing threads.
+ */
+bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads);
+/**
+ * This adds the current thread to the threadpool. This may cause the threadpool to exceed the
+ * maximum size.
+ */
+void ABinderProcess_joinThreadPool();
+
+__END_DECLS
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
new file mode 100644
index 0000000..aa29437
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -0,0 +1,257 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+#include <android/binder_parcel.h>
+#include <android/binder_status.h>
+
+__BEGIN_DECLS
+
+// Also see TF_* in kernel's binder.h
+typedef uint32_t binder_flags_t;
+enum {
+ /**
+ * The transaction will be dispatched and then returned to the caller. The outgoing process
+ * cannot block a call made by this, and execution of the call will not be waited on. An error
+ * can still be returned if the call is unable to be processed by the binder driver. All oneway
+ * calls are guaranteed to be ordered if they are sent on the same AIBinder object.
+ */
+ FLAG_ONEWAY = 0x01,
+};
+
+// Also see IBinder.h in libbinder
+typedef uint32_t transaction_code_t;
+enum {
+ /**
+ * The first transaction code available for user commands (inclusive).
+ */
+ FIRST_CALL_TRANSACTION = 0x00000001,
+ /**
+ * The last transaction code available for user commands (inclusive).
+ */
+ LAST_CALL_TRANSACTION = 0x00ffffff,
+};
+
+/**
+ * Represents a type of AIBinder object which can be sent out.
+ */
+struct AIBinder_Class;
+typedef struct AIBinder_Class AIBinder_Class;
+
+/**
+ * Represents a local or remote object which can be used for IPC or which can itself be sent.
+ *
+ * This object has a refcount associated with it and will be deleted when its refcount reaches zero.
+ * How methods interactive with this refcount is described below. When using this API, it is
+ * intended for a client of a service to hold a strong reference to that service. This also means
+ * that user data typically should hold a strong reference to a local AIBinder object. A remote
+ * AIBinder object automatically holds a strong reference to the AIBinder object in the server's
+ * process. A typically memory layout looks like this:
+ *
+ * Key:
+ * ---> Ownership/a strong reference
+ * ...> A weak reference
+ *
+ * (process boundary)
+ * |
+ * MyInterface ---> AIBinder_Weak | ProxyForMyInterface
+ * ^ . | |
+ * | . | |
+ * | v | v
+ * UserData <--- AIBinder <-|- AIBinder
+ * |
+ *
+ * In this way, you'll notice that a proxy for the interface holds a strong reference to the
+ * implementation and that in the server process, the AIBinder object which was sent can be resent
+ * so that the same AIBinder object always represents the same object. This allows, for instance, an
+ * implementation (usually a callback) to transfer all ownership to a remote process and
+ * automatically be deleted when the remote process is done with it or dies. Other memory models are
+ * possible, but this is the standard one.
+ */
+struct AIBinder;
+typedef struct AIBinder AIBinder;
+
+/**
+ * The AIBinder object associated with this can be retrieved if it is still alive so that it can be
+ * re-used. The intention of this is to enable the same AIBinder object to always represent the same
+ * object.
+ */
+struct AIBinder_Weak;
+typedef struct AIBinder_Weak AIBinder_Weak;
+
+/**
+ * This is called whenever a new AIBinder object is needed of a specific class.
+ *
+ * These arguments are passed from AIBinder_new. The return value is stored and can be retrieved
+ * using AIBinder_getUserData.
+ */
+typedef void* (*AIBinder_Class_onCreate)(void* args);
+
+/**
+ * This is called whenever an AIBinder object is no longer referenced and needs destroyed.
+ *
+ * Typically, this just deletes whatever the implementation is.
+ */
+typedef void (*AIBinder_Class_onDestroy)(void* userData);
+
+/**
+ * This is called whenever a transaction needs to be processed by a local implementation.
+ */
+typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transaction_code_t code,
+ const AParcel* in, AParcel* out);
+
+/**
+ * An interfaceDescriptor uniquely identifies the type of object that is being created. This is used
+ * internally for sanity checks on transactions.
+ *
+ * None of these parameters can be nullptr.
+ *
+ * This is created one time during library initialization and cleaned up when the process exits or
+ * execs.
+ */
+__attribute__((warn_unused_result)) AIBinder_Class* AIBinder_Class_define(
+ const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
+ AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact);
+
+/**
+ * Creates a new binder object of the appropriate class.
+ *
+ * Ownership of args is passed to this object. The lifecycle is implemented with AIBinder_incStrong
+ * and AIBinder_decStrong. When the reference count reaches zero, onDestroy is called.
+ *
+ * When this is called, the refcount is implicitly 1. So, calling decStrong exactly one time is
+ * required to delete this object.
+ */
+__attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args);
+
+/**
+ * If this is hosted in a process other than the current one.
+ */
+bool AIBinder_isRemote(const AIBinder* binder);
+
+/**
+ * If this binder is known to be alive. This will not send a transaction to a remote process and
+ * returns a result based on the last known information. That is, whenever a transaction is made,
+ * this is automatically updated to reflect the current alive status of this binder. This will be
+ * updated as the result of a transaction made using AIBinder_transact, but it will also be updated
+ * based on the results of bookkeeping or other transactions made internally.
+ */
+bool AIBinder_isAlive(const AIBinder* binder);
+
+/**
+ * Built-in transaction for all binder objects. This sends a transaction which will immediately
+ * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
+ * sanity check.
+ */
+binder_status_t AIBinder_ping(AIBinder* binder);
+
+/**
+ * This can only be called if a strong reference to this object already exists in process.
+ */
+void AIBinder_incStrong(AIBinder* binder);
+
+/**
+ * This will delete the object and call onDestroy once the refcount reaches zero.
+ */
+void AIBinder_decStrong(AIBinder* binder);
+
+/**
+ * For debugging only!
+ */
+int32_t AIBinder_debugGetRefCount(AIBinder* binder);
+
+/**
+ * This sets the class of an AIBinder object. This checks to make sure the remote object is of
+ * the expected class. A class must be set in order to use transactions on an AIBinder object.
+ * However, if an object is just intended to be passed through to another process or used as a
+ * handle this need not be called.
+ *
+ * This returns true if the class association succeeds. If it fails, no change is made to the
+ * binder object.
+ */
+bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz);
+
+/**
+ * Returns the class that this binder was constructed with or associated with.
+ */
+const AIBinder_Class* AIBinder_getClass(AIBinder* binder);
+
+/**
+ * Value returned by onCreate for a local binder. For stateless classes (if onCreate returns
+ * nullptr), this also returns nullptr. For a remote binder, this will always return nullptr.
+ */
+void* AIBinder_getUserData(AIBinder* binder);
+
+/**
+ * A transaction is a series of calls to these functions which looks this
+ * - call AIBinder_prepareTransaction
+ * - fill out the in parcel with parameters (lifetime of the 'in' variable)
+ * - call AIBinder_transact
+ * - read results from the out parcel (lifetime of the 'out' variable)
+ */
+
+/**
+ * Creates a parcel to start filling out for a transaction. This may add data to the parcel for
+ * security, debugging, or other purposes. This parcel is to be sent via AIBinder_transact and it
+ * represents the input data to the transaction. It is recommended to check if the object is local
+ * and call directly into its user data before calling this as the parceling and unparceling cost
+ * can be avoided. This AIBinder must be either built with a class or associated with a class before
+ * using this API.
+ *
+ * This does not affect the ownership of binder. When this function succeeds, the in parcel's
+ * ownership is passed to the caller. At this point, the parcel can be filled out and passed to
+ * AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be
+ * deleted with AParcel_delete.
+ */
+binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in);
+
+/**
+ * Transact using a parcel created from AIBinder_prepareTransaction. This actually communicates with
+ * the object representing this binder object. This also passes out a parcel to be used for the
+ * return transaction. This takes ownership of the in parcel and automatically deletes it after it
+ * is sent to the remote process. The output parcel is the result of the transaction. If the
+ * transaction has FLAG_ONEWAY, the out parcel will be empty. Otherwise, this will block until the
+ * remote process has processed the transaction, and the out parcel will contain the output data
+ * from transaction.
+ *
+ * This does not affect the ownership of binder. The out parcel's ownership is passed to the caller
+ * and must be released with AParcel_delete when finished reading.
+ */
+binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
+ AParcel** out, binder_flags_t flags);
+
+/**
+ * This does not take any ownership of the input binder, but it can be used to retrieve it if
+ * something else in some process still holds a reference to it.
+ */
+__attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder);
+
+/**
+ * Deletes the weak reference. This will have no impact on the lifetime of the binder.
+ */
+void AIBinder_Weak_delete(AIBinder_Weak** weakBinder);
+
+/**
+ * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns
+ * nullptr.
+ */
+__attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder);
+
+__END_DECLS
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
new file mode 100644
index 0000000..19925f7
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+#include <android/binder_status.h>
+
+struct AIBinder;
+typedef struct AIBinder AIBinder;
+
+__BEGIN_DECLS
+
+/**
+ * This object represents a package of data that can be sent between processes. When transacting, an
+ * instance of it is automatically created to be used for the transaction. When two processes use
+ * binder to communicate, they must agree on a format of this parcel to be used in order to transfer
+ * data. This is usually done in an IDL (see AIDL, specificially).
+ */
+struct AParcel;
+typedef struct AParcel AParcel;
+
+/**
+ * Cleans up a parcel and sets it to nullptr.
+ */
+void AParcel_delete(AParcel** parcel);
+
+/**
+ * Writes an AIBinder to the next location in a non-null parcel. Can be null.
+ */
+binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder);
+
+/**
+ * Reads an AIBinder from the next location in a non-null parcel. This will fail if the binder is
+ * non-null. One strong ref-count of ownership is passed to the caller of this function.
+ */
+binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder);
+
+/**
+ * Reads an AIBinder from the next location in a non-null parcel. This may read a null. One strong
+ * ref-count of ownership is passed to the caller of this function.
+ */
+binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder);
+
+// @START
+/**
+ * Writes int32_t value to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value);
+
+/**
+ * Writes uint32_t value to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value);
+
+/**
+ * Writes int64_t value to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value);
+
+/**
+ * Writes uint64_t value to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value);
+
+/**
+ * Writes float value to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeFloat(AParcel* parcel, float value);
+
+/**
+ * Writes double value to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeDouble(AParcel* parcel, double value);
+
+/**
+ * Writes bool value to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeBool(AParcel* parcel, bool value);
+
+/**
+ * Writes char16_t value to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value);
+
+/**
+ * Writes int8_t value to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value);
+
+/**
+ * Reads into int32_t value from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value);
+
+/**
+ * Reads into uint32_t value from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value);
+
+/**
+ * Reads into int64_t value from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value);
+
+/**
+ * Reads into uint64_t value from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value);
+
+/**
+ * Reads into float value from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readFloat(const AParcel* parcel, float* value);
+
+/**
+ * Reads into double value from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readDouble(const AParcel* parcel, double* value);
+
+/**
+ * Reads into bool value from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readBool(const AParcel* parcel, bool* value);
+
+/**
+ * Reads into char16_t value from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value);
+
+/**
+ * Reads into int8_t value from the next location in a non-null parcel.
+ */
+binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value);
+
+// @END
+
+__END_DECLS
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
new file mode 100644
index 0000000..d414c99
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+// Keep the exception codes in sync with android/os/Parcel.java.
+enum {
+ EX_NONE = 0,
+ EX_SECURITY = -1,
+ EX_BAD_PARCELABLE = -2,
+ EX_ILLEGAL_ARGUMENT = -3,
+ EX_NULL_POINTER = -4,
+ EX_ILLEGAL_STATE = -5,
+ EX_NETWORK_MAIN_THREAD = -6,
+ EX_UNSUPPORTED_OPERATION = -7,
+ EX_SERVICE_SPECIFIC = -8,
+ EX_PARCELABLE = -9,
+
+ /**
+ * This is special and Java specific; see Parcel.java.
+ * This should be considered a success, and the next readInt32 bytes can be ignored.
+ */
+ EX_HAS_REPLY_HEADER = -128,
+
+ /**
+ * This is special, and indicates to native binder proxies that the
+ * transaction has failed at a low level.
+ */
+ EX_TRANSACTION_FAILED = -129,
+};
+
+/**
+ * One of the above values or -errno.
+ * By convention, positive values are considered to mean service-specific exceptions.
+ */
+typedef int32_t binder_status_t;
+
+__END_DECLS
diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh
new file mode 100755
index 0000000..6c8527d
--- /dev/null
+++ b/libs/binder/ndk/runtests.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+ echo "You need to source and lunch before you can use this script"
+ exit 1
+fi
+
+set -ex
+
+function run_libbinder_ndk_test() {
+ adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
+ local pid=$!
+ trap "kill $pid" ERR
+ adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client
+ trap '' ERR
+ kill $pid
+}
+
+[ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
+ MODULES-IN-frameworks-native-libs-binder-ndk
+
+adb root
+adb wait-for-device
+adb sync data
+
+run_libbinder_ndk_test
diff --git a/libs/binder/ndk/scripts/format.sh b/libs/binder/ndk/scripts/format.sh
new file mode 100755
index 0000000..698d291
--- /dev/null
+++ b/libs/binder/ndk/scripts/format.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+echo "Formatting code"
+
+bpfmt -w $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -name "Android.bp")
+clang-format -i $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -\( -name "*.cpp" -o -name "*.h" -\))
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
new file mode 100755
index 0000000..5c0b936
--- /dev/null
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python3
+
+# 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.
+
+import os
+import sys
+
+# list (pretty, cpp)
+data_types = [
+ ("Int32", "int32_t"),
+ ("Uint32", "uint32_t"),
+ ("Int64", "int64_t"),
+ ("Uint64", "uint64_t"),
+ ("Float", "float"),
+ ("Double", "double"),
+ ("Bool", "bool"),
+ ("Char", "char16_t"),
+ ("Byte", "int8_t"),
+]
+
+def replaceFileTags(path, content):
+ print("Updating", path)
+ with open(path, "r+") as f:
+ lines = f.readlines()
+
+ start = lines.index("// @START\n")
+ end = lines.index("// @END\n")
+
+ if end <= start or start < 0 or end < 0:
+ print("Failed to find tags in", path)
+ exit(1)
+
+ f.seek(0)
+ f.write("".join(lines[:start+1]) + content + "".join(lines[end:]))
+ f.truncate()
+
+def main():
+ if len(sys.argv) != 1:
+ print("No arguments.")
+ exit(1)
+
+ ABT = os.environ.get('ANDROID_BUILD_TOP', None)
+ if ABT is None:
+ print("Can't get ANDROID_BUILD_TOP. Lunch?")
+ exit(1)
+ ROOT = ABT + "/frameworks/native/libs/binder/ndk/"
+
+ print("Updating auto-generated code")
+
+ header = ""
+ source = ""
+
+ for pretty, cpp in data_types:
+ header += "/**\n"
+ header += " * Writes " + cpp + " value to the next location in a non-null parcel.\n"
+ header += " */\n"
+ header += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value);\n\n"
+ source += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) {\n"
+ source += " return (*parcel)->write" + pretty + "(value);\n"
+ source += "}\n\n"
+
+ for pretty, cpp in data_types:
+ header += "/**\n"
+ header += " * Reads into " + cpp + " value from the next location in a non-null parcel.\n"
+ header += " */\n"
+ header += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value);\n\n"
+ source += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) {\n"
+ source += " return (*parcel)->read" + pretty + "(value);\n"
+ source += "}\n\n"
+
+ replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header)
+ replaceFileTags(ROOT + "AParcel.cpp", source)
+
+ print("Updating DONE.")
+
+if __name__ == "__main__":
+ main()
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
new file mode 100644
index 0000000..d242138
--- /dev/null
+++ b/libs/binder/ndk/test/Android.bp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+// This test is a unit test of the low-level API that is presented here.
+// Actual users should use AIDL to generate these complicated stubs.
+
+cc_defaults {
+ name: "test_libbinder_ndk_defaults",
+ shared_libs: [
+ "libbase",
+ ],
+ strip: {
+ none: true,
+ },
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
+
+cc_library_static {
+ name: "test_libbinder_ndk_library",
+ defaults: ["test_libbinder_ndk_defaults"],
+ export_include_dirs: ["include"],
+ shared_libs: ["libbinder_ndk"],
+ export_shared_lib_headers: ["libbinder_ndk"],
+ srcs: ["iface.cpp"],
+}
+
+cc_defaults {
+ name: "test_libbinder_ndk_test_defaults",
+ defaults: ["test_libbinder_ndk_defaults"],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libutils",
+ ],
+ static_libs: [
+ "libbinder_ndk",
+ "test_libbinder_ndk_library",
+ ],
+}
+
+cc_test {
+ name: "libbinder_ndk_test_client",
+ defaults: ["test_libbinder_ndk_test_defaults"],
+ srcs: ["main_client.cpp"],
+}
+
+cc_test {
+ name: "libbinder_ndk_test_server",
+ defaults: ["test_libbinder_ndk_test_defaults"],
+ srcs: ["main_server.cpp"],
+ gtest: false,
+}
diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp
new file mode 100644
index 0000000..a1aa0fa
--- /dev/null
+++ b/libs/binder/ndk/test/iface.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <iface/iface.h>
+
+using ::android::sp;
+using ::android::wp;
+
+const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo";
+const char* kIFooDescriptor = "my-special-IFoo-class";
+
+struct IFoo_Class_Data {
+ sp<IFoo> foo;
+};
+
+void* IFoo_Class_onCreate(void* args) {
+ IFoo_Class_Data* foo = static_cast<IFoo_Class_Data*>(args);
+ // This is a foo, but we're currently not verifying that. So, the method newLocalBinder is
+ // coupled with this.
+ return static_cast<void*>(foo);
+}
+
+void IFoo_Class_onDestroy(void* userData) {
+ delete static_cast<IFoo_Class_Data*>(userData);
+}
+
+binder_status_t IFoo_Class_onTransact(AIBinder* binder, transaction_code_t code, const AParcel* in,
+ AParcel* out) {
+ binder_status_t stat = EX_UNSUPPORTED_OPERATION;
+
+ sp<IFoo> foo = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder))->foo;
+ CHECK(foo != nullptr) << "Transaction made on already deleted object";
+
+ switch (code) {
+ case IFoo::DOFOO: {
+ int32_t valueIn;
+ stat = AParcel_readInt32(in, &valueIn);
+ if (stat != EX_NONE) break;
+ int32_t valueOut = foo->doubleNumber(valueIn);
+ stat = AParcel_writeInt32(out, valueOut);
+ break;
+ }
+ }
+
+ return stat;
+}
+
+AIBinder_Class* IFoo::kClass = AIBinder_Class_define(kIFooDescriptor, IFoo_Class_onCreate,
+ IFoo_Class_onDestroy, IFoo_Class_onTransact);
+
+class BpFoo : public IFoo {
+public:
+ BpFoo(AIBinder* binder) : mBinder(binder) {}
+ virtual ~BpFoo() { AIBinder_decStrong(mBinder); }
+
+ virtual int32_t doubleNumber(int32_t in) {
+ AParcel* parcelIn;
+ CHECK(EX_NONE == AIBinder_prepareTransaction(mBinder, &parcelIn));
+
+ CHECK(EX_NONE == AParcel_writeInt32(parcelIn, in));
+
+ AParcel* parcelOut;
+ CHECK(EX_NONE ==
+ AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, &parcelOut, 0 /*flags*/));
+
+ int32_t out;
+ CHECK(EX_NONE == AParcel_readInt32(parcelOut, &out));
+
+ AParcel_delete(&parcelOut);
+
+ return out;
+ }
+
+private:
+ // Always assumes one refcount
+ AIBinder* mBinder;
+};
+
+IFoo::~IFoo() {
+ AIBinder_Weak_delete(&mWeakBinder);
+}
+
+binder_status_t IFoo::addService(const char* instance) {
+ AIBinder* binder = nullptr;
+
+ if (mWeakBinder != nullptr) {
+ // one strong ref count of binder
+ binder = AIBinder_Weak_promote(mWeakBinder);
+ }
+ if (binder == nullptr) {
+ // or one strong refcount here
+ binder = AIBinder_new(IFoo::kClass, static_cast<void*>(new IFoo_Class_Data{this}));
+ if (mWeakBinder != nullptr) {
+ AIBinder_Weak_delete(&mWeakBinder);
+ }
+ mWeakBinder = AIBinder_Weak_new(binder);
+ }
+
+ binder_status_t status = AServiceManager_addService(binder, instance);
+ // Strong references we care about kept by remote process
+ AIBinder_decStrong(binder);
+ return status;
+}
+
+sp<IFoo> IFoo::getService(const char* instance) {
+ AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr
+ if (binder == nullptr) {
+ return nullptr;
+ }
+
+ if (!AIBinder_associateClass(binder, IFoo::kClass)) {
+ AIBinder_decStrong(binder);
+ return nullptr;
+ }
+
+ if (AIBinder_isRemote(binder)) {
+ sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder
+ return ret;
+ }
+
+ IFoo_Class_Data* data = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder));
+
+ CHECK(data != nullptr); // always created with non-null data
+
+ sp<IFoo> ret = data->foo;
+
+ AIBinder* held = AIBinder_Weak_promote(ret->mWeakBinder);
+ CHECK(held == binder);
+ AIBinder_decStrong(held);
+
+ // IFoo only keeps a weak reference to AIBinder, so we can drop this
+ AIBinder_decStrong(binder);
+ return ret;
+}
diff --git a/libs/binder/ndk/test/include/iface/iface.h b/libs/binder/ndk/test/include/iface/iface.h
new file mode 100644
index 0000000..4c61e9d
--- /dev/null
+++ b/libs/binder/ndk/test/include/iface/iface.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+#include <utils/RefBase.h>
+
+class IFoo : public virtual ::android::RefBase {
+public:
+ static const char* kSomeInstanceName;
+ static AIBinder_Class* kClass;
+
+ // Takes ownership of IFoo
+ binder_status_t addService(const char* instance);
+ static ::android::sp<IFoo> getService(const char* instance);
+
+ enum Call {
+ DOFOO = FIRST_CALL_TRANSACTION + 0,
+ };
+
+ virtual ~IFoo();
+ virtual int32_t doubleNumber(int32_t in) = 0;
+
+private:
+ AIBinder_Weak* mWeakBinder = nullptr; // maybe owns AIBinder
+};
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
new file mode 100644
index 0000000..967789f
--- /dev/null
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <gtest/gtest.h>
+#include <iface/iface.h>
+
+using ::android::sp;
+
+constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
+
+// This is too slow
+// TEST(NdkBinder, GetServiceThatDoesntExist) {
+// sp<IFoo> foo = IFoo::getService("asdfghkl;");
+// EXPECT_EQ(nullptr, foo.get());
+// }
+
+TEST(NdkBinder, DoubleNumber) {
+ sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
+ ASSERT_NE(foo, nullptr);
+ EXPECT_EQ(2, foo->doubleNumber(1));
+}
+
+TEST(NdkBinder, RetrieveNonNdkService) {
+ AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
+ ASSERT_NE(nullptr, binder);
+ EXPECT_TRUE(AIBinder_isRemote(binder));
+ EXPECT_TRUE(AIBinder_isAlive(binder));
+ EXPECT_EQ(EX_NONE, AIBinder_ping(binder));
+
+ AIBinder_decStrong(binder);
+}
+
+class MyTestFoo : public IFoo {
+ int32_t doubleNumber(int32_t in) override {
+ LOG(INFO) << "doubleNumber " << in;
+ return 2 * in;
+ }
+};
+
+TEST(NdkBinder, GetServiceInProcess) {
+ static const char* kInstanceName = "test-get-service-in-process";
+
+ sp<IFoo> foo = new MyTestFoo;
+ EXPECT_EQ(EX_NONE, foo->addService(kInstanceName));
+
+ sp<IFoo> getFoo = IFoo::getService(kInstanceName);
+ EXPECT_EQ(foo.get(), getFoo.get());
+
+ EXPECT_EQ(2, getFoo->doubleNumber(1));
+}
+
+TEST(NdkBinder, AddServiceMultipleTimes) {
+ static const char* kInstanceName1 = "test-multi-1";
+ static const char* kInstanceName2 = "test-multi-2";
+ sp<IFoo> foo = new MyTestFoo;
+ EXPECT_EQ(EX_NONE, foo->addService(kInstanceName1));
+ EXPECT_EQ(EX_NONE, foo->addService(kInstanceName2));
+ EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
+}
diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp
new file mode 100644
index 0000000..f3da7da
--- /dev/null
+++ b/libs/binder/ndk/test/main_server.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_process.h>
+#include <iface/iface.h>
+
+using ::android::sp;
+
+class MyFoo : public IFoo {
+ int32_t doubleNumber(int32_t in) override {
+ LOG(INFO) << "doubling " << in;
+ return 2 * in;
+ }
+};
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ // Strong reference to MyFoo kept by service manager.
+ binder_status_t status = (new MyFoo)->addService(IFoo::kSomeInstanceName);
+
+ if (status != EX_NONE) {
+ LOG(FATAL) << "Could not register: " << status;
+ }
+
+ ABinderProcess_joinThreadPool();
+
+ return 1;
+}
diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh
new file mode 100755
index 0000000..1eba892
--- /dev/null
+++ b/libs/binder/ndk/update.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+set -ex
+
+# This script makes sure that the source code is in sync with the various scripts
+./scripts/gen_parcel_helper.py
+./scripts/format.sh
diff --git a/libs/binder/tests/binderTextOutputTest.cpp b/libs/binder/tests/binderTextOutputTest.cpp
index f6dd22d..ce99f59 100644
--- a/libs/binder/tests/binderTextOutputTest.cpp
+++ b/libs/binder/tests/binderTextOutputTest.cpp
@@ -28,15 +28,14 @@
#include <binder/TextOutput.h>
#include <binder/Debug.h>
-static void CheckMessage(const CapturedStderr& cap,
+static void CheckMessage(CapturedStderr& cap,
const char* expected,
bool singleline) {
- std::string output;
- ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
- android::base::ReadFdToString(cap.fd(), &output);
+ cap.Stop();
+ std::string output = cap.str();
if (singleline)
output.erase(std::remove(output.begin(), output.end(), '\n'));
- ASSERT_STREQ(output.c_str(), expected);
+ ASSERT_EQ(output, expected);
}
#define CHECK_LOG_(input, expect, singleline) \
@@ -60,28 +59,22 @@
TEST(TextOutput, HandlesStdEndl) {
CapturedStderr cap;
android::aerr << "foobar" << std::endl;
- std::string output;
- ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
- android::base::ReadFdToString(cap.fd(), &output);
- ASSERT_STREQ(output.c_str(), "foobar\n");
+ cap.Stop();
+ ASSERT_EQ(cap.str(), "foobar\n");
}
TEST(TextOutput, HandlesCEndl) {
CapturedStderr cap;
android::aerr << "foobar" << "\n";
- std::string output;
- ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
- android::base::ReadFdToString(cap.fd(), &output);
- ASSERT_STREQ(output.c_str(), "foobar\n");
+ cap.Stop();
+ ASSERT_EQ(cap.str(), "foobar\n");
}
TEST(TextOutput, HandlesAndroidEndl) {
CapturedStderr cap;
android::aerr << "foobar" << android::endl;
- std::string output;
- ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
- android::base::ReadFdToString(cap.fd(), &output);
- ASSERT_STREQ(output.c_str(), "foobar\n");
+ cap.Stop();
+ ASSERT_EQ(cap.str(), "foobar\n");
}
TEST(TextOutput, HandleEmptyString) {
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 5532db4..faf02f3 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -834,10 +834,10 @@
xform = crop * xform;
}
- // SurfaceFlinger expects the top of its window textures to be at a Y
- // coordinate of 0, so GLConsumer must behave the same way. We don't
- // want to expose this to applications, however, so we must add an
- // additional vertical flip to the transform after all the other transforms.
+ // GLConsumer uses the GL convention where (0, 0) is the bottom-left
+ // corner and (1, 1) is the top-right corner. Add an additional vertical
+ // flip after all other transforms to map from GL convention to buffer
+ // queue memory layout, where (0, 0) is the top-left corner.
xform = mtxFlipV * xform;
memcpy(outTransform, xform.asArray(), sizeof(xform));
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 81f692d..7f9668f 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -331,34 +331,6 @@
return result;
}
- virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_VIEWPORT, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to transact: %d", result);
- return result;
- }
- result = reply.readInt32();
- if (result == NO_ERROR) {
- result = reply.read(*outViewport);
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to read: %d", result);
- return result;
- }
- }
- return result;
- }
-
virtual int getActiveConfig(const sp<IBinder>& display)
{
Parcel data, reply;
@@ -775,26 +747,6 @@
}
return NO_ERROR;
}
- case GET_DISPLAY_VIEWPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- Rect outViewport;
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to readStrongBinder: %d", result);
- return result;
- }
- result = getDisplayViewport(display, &outViewport);
- result = reply->writeInt32(result);
- if (result == NO_ERROR) {
- result = reply->write(outViewport);
- if (result != NO_ERROR) {
- ALOGE("getDisplayViewport failed to write: %d", result);
- return result;
- }
- }
- return NO_ERROR;
- }
case GET_ACTIVE_CONFIG: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = data.readStrongBinder();
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index d3dc16d..ccde9e0 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -42,7 +42,6 @@
RETURN_ON_ERROR(parcel->writeInt32(mWidth));
RETURN_ON_ERROR(parcel->writeInt32(mHeight));
RETURN_ON_ERROR(parcel->write(mCrop));
- RETURN_ON_ERROR(parcel->write(mFinalCrop));
RETURN_ON_ERROR(parcel->writeFloat(mColor.r));
RETURN_ON_ERROR(parcel->writeFloat(mColor.g));
RETURN_ON_ERROR(parcel->writeFloat(mColor.b));
@@ -81,7 +80,6 @@
RETURN_ON_ERROR(parcel->readInt32(&mWidth));
RETURN_ON_ERROR(parcel->readInt32(&mHeight));
RETURN_ON_ERROR(parcel->read(mCrop));
- RETURN_ON_ERROR(parcel->read(mFinalCrop));
mColor.r = parcel->readFloat();
RETURN_ON_ERROR(parcel->errorCheck());
mColor.g = parcel->readFloat();
@@ -121,8 +119,7 @@
info.mLayerStack, info.mZ, static_cast<double>(info.mX), static_cast<double>(info.mY),
info.mWidth, info.mHeight);
- result.appendFormat("crop=%s, finalCrop=%s, ",
- to_string(info.mCrop).c_str(), to_string(info.mFinalCrop).c_str());
+ result.appendFormat("crop=%s, ", to_string(info.mCrop).c_str());
result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty);
result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str());
result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str());
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 931c446..deb8ea8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -38,7 +38,6 @@
*reinterpret_cast<layer_state_t::matrix22_t *>(
output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix;
output.write(crop_legacy);
- output.write(finalCrop_legacy);
output.writeStrongBinder(barrierHandle_legacy);
output.writeStrongBinder(reparentHandle);
output.writeUint64(frameNumber_legacy);
@@ -99,7 +98,6 @@
return BAD_VALUE;
}
input.read(crop_legacy);
- input.read(finalCrop_legacy);
barrierHandle_legacy = input.readStrongBinder();
reparentHandle = input.readStrongBinder();
frameNumber_legacy = input.readUint64();
@@ -248,10 +246,6 @@
barrierGbp_legacy = other.barrierGbp_legacy;
frameNumber_legacy = other.frameNumber_legacy;
}
- if (other.what & eFinalCropChanged_legacy) {
- what |= eFinalCropChanged_legacy;
- finalCrop_legacy = other.finalCrop_legacy;
- }
if (other.what & eOverrideScalingModeChanged) {
what |= eOverrideScalingModeChanged;
overrideScalingMode = other.overrideScalingMode;
@@ -318,6 +312,10 @@
what |= eSidebandStreamChanged;
sidebandStream = other.sidebandStream;
}
+
+ if (other.what != what) {
+ ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating?");
+ }
}
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b8465e3..7168de4 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -353,18 +353,6 @@
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop_legacy(
- const sp<SurfaceControl>& sc, const Rect& crop) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
- s->what |= layer_state_t::eFinalCropChanged_legacy;
- s->finalCrop_legacy = crop;
- return *this;
-}
-
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
const sp<IBinder>& handle,
@@ -839,10 +827,6 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
- return ComposerService::getComposerService()->getDisplayViewport(display, outViewport);
-}
-
int SurfaceComposerClient::getActiveConfig(const sp<IBinder>& display) {
return ComposerService::getComposerService()->getActiveConfig(display);
}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index b9158f1..98ec338 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -157,9 +157,6 @@
virtual status_t getDisplayStats(const sp<IBinder>& display,
DisplayStatInfo* stats) = 0;
- /* returns display viewport information of the given display */
- virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) = 0;
-
/* indicates which of the configurations returned by getDisplayInfo is
* currently active */
virtual int getActiveConfig(const sp<IBinder>& display) = 0;
@@ -253,8 +250,7 @@
ENABLE_VSYNC_INJECTIONS,
INJECT_VSYNC,
GET_LAYER_DEBUG_INFO,
- CREATE_SCOPED_CONNECTION,
- GET_DISPLAY_VIEWPORT
+ CREATE_SCOPED_CONNECTION
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 11261c3..82b01b8 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -43,6 +43,7 @@
eFXSurfaceBufferQueue = 0x00000000,
eFXSurfaceColor = 0x00020000,
eFXSurfaceBufferState = 0x00040000,
+ eFXSurfaceContainer = 0x00080000,
eFXSurfaceMask = 0x000F0000,
};
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
index 92bd8c5..66a7b4d 100644
--- a/libs/gui/include/gui/LayerDebugInfo.h
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -52,7 +52,6 @@
int32_t mWidth = -1;
int32_t mHeight = -1;
Rect mCrop = Rect::INVALID_RECT;
- Rect mFinalCrop = Rect::INVALID_RECT;
half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf);
uint32_t mFlags = 0;
PixelFormat mPixelFormat = PIXEL_FORMAT_NONE;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 0981798..0859aff 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -54,25 +54,24 @@
eLayerStackChanged = 0x00000080,
eCropChanged_legacy = 0x00000100,
eDeferTransaction_legacy = 0x00000200,
- eFinalCropChanged_legacy = 0x00000400,
- eOverrideScalingModeChanged = 0x00000800,
- eGeometryAppliesWithResize = 0x00001000,
- eReparentChildren = 0x00002000,
- eDetachChildren = 0x00004000,
- eRelativeLayerChanged = 0x00008000,
- eReparent = 0x00010000,
- eColorChanged = 0x00020000,
- eDestroySurface = 0x00040000,
- eTransformChanged = 0x00100000,
- eTransformToDisplayInverseChanged = 0x00200000,
- eCropChanged = 0x00400000,
- eBufferChanged = 0x00800000,
- eAcquireFenceChanged = 0x01000000,
- eDataspaceChanged = 0x02000000,
- eHdrMetadataChanged = 0x04000000,
- eSurfaceDamageRegionChanged = 0x08000000,
- eApiChanged = 0x10000000,
- eSidebandStreamChanged = 0x20000000,
+ eOverrideScalingModeChanged = 0x00000400,
+ eGeometryAppliesWithResize = 0x00000800,
+ eReparentChildren = 0x00001000,
+ eDetachChildren = 0x00002000,
+ eRelativeLayerChanged = 0x00004000,
+ eReparent = 0x00008000,
+ eColorChanged = 0x00010000,
+ eDestroySurface = 0x00020000,
+ eTransformChanged = 0x00040000,
+ eTransformToDisplayInverseChanged = 0x00080000,
+ eCropChanged = 0x00100000,
+ eBufferChanged = 0x00200000,
+ eAcquireFenceChanged = 0x00400000,
+ eDataspaceChanged = 0x00800000,
+ eHdrMetadataChanged = 0x01000000,
+ eSurfaceDamageRegionChanged = 0x02000000,
+ eApiChanged = 0x04000000,
+ eSidebandStreamChanged = 0x08000000,
};
layer_state_t()
@@ -88,7 +87,6 @@
mask(0),
reserved(0),
crop_legacy(Rect::INVALID_RECT),
- finalCrop_legacy(Rect::INVALID_RECT),
frameNumber_legacy(0),
overrideScalingMode(-1),
transform(0),
@@ -126,7 +124,6 @@
uint8_t reserved;
matrix22_t matrix;
Rect crop_legacy;
- Rect finalCrop_legacy;
sp<IBinder> barrierHandle_legacy;
sp<IBinder> reparentHandle;
uint64_t frameNumber_legacy;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 9bd1131..d83ba84 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -79,9 +79,6 @@
static status_t getDisplayInfo(const sp<IBinder>& display,
DisplayInfo* info);
- // Get the display viewport for the given display
- static status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport);
-
// Get the index of the current active configuration (relative to the list
// returned by getDisplayInfo)
static int getActiveConfig(const sp<IBinder>& display);
@@ -204,7 +201,6 @@
Transaction& setMatrix(const sp<SurfaceControl>& sc,
float dsdx, float dtdx, float dtdy, float dsdy);
Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
- Transaction& setFinalCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
// Defers applying any changes made in this transaction until the Layer
// identified by handle reaches the given frameNumber. If the Layer identified
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index f22e702..3542aba 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -581,9 +581,6 @@
Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
status_t getDisplayStats(const sp<IBinder>& /*display*/,
DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
- status_t getDisplayViewport(const sp<IBinder>& /*display*/, Rect* /*outViewport*/) override {
- return NO_ERROR;
- }
int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
status_t setActiveConfig(const sp<IBinder>& /*display*/, int /*id*/)
override {
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 5d27bf6..778c453 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -20,9 +20,12 @@
#include <unistd.h>
#include <ctype.h>
+#include <android-base/stringprintf.h>
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
+using android::base::StringPrintf;
+
namespace android {
static const char* CONFIGURATION_FILE_DIR[] = {
@@ -41,8 +44,8 @@
return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
}
-static void appendInputDeviceConfigurationFileRelativePath(String8& path,
- const String8& name, InputDeviceConfigurationFileType type) {
+static void appendInputDeviceConfigurationFileRelativePath(std::string& path,
+ const std::string& name, InputDeviceConfigurationFileType type) {
path.append(CONFIGURATION_FILE_DIR[type]);
for (size_t i = 0; i < name.length(); i++) {
char ch = name[i];
@@ -54,28 +57,28 @@
path.append(CONFIGURATION_FILE_EXTENSION[type]);
}
-String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
const InputDeviceIdentifier& deviceIdentifier,
InputDeviceConfigurationFileType type) {
if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
if (deviceIdentifier.version != 0) {
// Try vendor product version.
- String8 versionPath(getInputDeviceConfigurationFilePathByName(
- String8::format("Vendor_%04x_Product_%04x_Version_%04x",
+ std::string versionPath = getInputDeviceConfigurationFilePathByName(
+ StringPrintf("Vendor_%04x_Product_%04x_Version_%04x",
deviceIdentifier.vendor, deviceIdentifier.product,
deviceIdentifier.version),
- type));
- if (!versionPath.isEmpty()) {
+ type);
+ if (!versionPath.empty()) {
return versionPath;
}
}
// Try vendor product.
- String8 productPath(getInputDeviceConfigurationFilePathByName(
- String8::format("Vendor_%04x_Product_%04x",
+ std::string productPath = getInputDeviceConfigurationFilePathByName(
+ StringPrintf("Vendor_%04x_Product_%04x",
deviceIdentifier.vendor, deviceIdentifier.product),
- type));
- if (!productPath.isEmpty()) {
+ type);
+ if (!productPath.empty()) {
return productPath;
}
}
@@ -84,22 +87,25 @@
return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
}
-String8 getInputDeviceConfigurationFilePathByName(
- const String8& name, InputDeviceConfigurationFileType type) {
+std::string getInputDeviceConfigurationFilePathByName(
+ const std::string& name, InputDeviceConfigurationFileType type) {
// Search system repository.
- String8 path;
+ std::string path;
// Treblized input device config files will be located /odm/usr or /vendor/usr.
const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
for (size_t i = 0; i < size(rootsForPartition); i++) {
- path.setTo(rootsForPartition[i]);
- path.append("/usr/");
+ if (rootsForPartition[i] == nullptr) {
+ continue;
+ }
+ path = rootsForPartition[i];
+ path += "/usr/";
appendInputDeviceConfigurationFileRelativePath(path, name, type);
#if DEBUG_PROBE
ALOGD("Probing for system provided input device configuration file: path='%s'",
- path.string());
+ path.c_str());
#endif
- if (!access(path.string(), R_OK)) {
+ if (!access(path.c_str(), R_OK)) {
#if DEBUG_PROBE
ALOGD("Found");
#endif
@@ -109,13 +115,17 @@
// Search user repository.
// TODO Should only look here if not in safe mode.
- path.setTo(getenv("ANDROID_DATA"));
- path.append("/system/devices/");
+ path = "";
+ char *androidData = getenv("ANDROID_DATA");
+ if (androidData != nullptr) {
+ path += androidData;
+ }
+ path += "/system/devices/";
appendInputDeviceConfigurationFileRelativePath(path, name, type);
#if DEBUG_PROBE
- ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
+ ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str());
#endif
- if (!access(path.string(), R_OK)) {
+ if (!access(path.c_str(), R_OK)) {
#if DEBUG_PROBE
ALOGD("Found");
#endif
@@ -125,16 +135,16 @@
// Not found.
#if DEBUG_PROBE
ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
- name.string(), type);
+ name.c_str(), type);
#endif
- return String8();
+ return "";
}
// --- InputDeviceInfo ---
InputDeviceInfo::InputDeviceInfo() {
- initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false);
+ initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false);
}
InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
@@ -150,7 +160,7 @@
}
void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+ const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
bool hasMic) {
mId = id;
mGeneration = generation;
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 26747bd..e189d20 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -106,14 +106,14 @@
}
}
-status_t KeyCharacterMap::load(const String8& filename,
+status_t KeyCharacterMap::load(const std::string& filename,
Format format, sp<KeyCharacterMap>* outMap) {
outMap->clear();
Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
+ status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
if (status) {
- ALOGE("Error %d opening key character map file %s.", status, filename.string());
+ ALOGE("Error %d opening key character map file %s.", status, filename.c_str());
} else {
status = load(tokenizer, format, outMap);
delete tokenizer;
@@ -121,12 +121,12 @@
return status;
}
-status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents,
+status_t KeyCharacterMap::loadContents(const std::string& filename, const char* contents,
Format format, sp<KeyCharacterMap>* outMap) {
outMap->clear();
Tokenizer* tokenizer;
- status_t status = Tokenizer::fromContents(filename, contents, &tokenizer);
+ status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
if (status) {
ALOGE("Error %d opening key character map.", status);
} else {
@@ -944,7 +944,7 @@
properties.add(Property(PROPERTY_NUMBER));
} else {
int32_t metaState;
- status_t status = parseModifier(token, &metaState);
+ status_t status = parseModifier(token.string(), &metaState);
if (status) {
ALOGE("%s: Expected a property name or modifier, got '%s'.",
mTokenizer->getLocation().string(), token.string());
@@ -1137,7 +1137,7 @@
return NO_ERROR;
}
-status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
+status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
if (token == "base") {
*outMetaState = 0;
return NO_ERROR;
@@ -1145,7 +1145,7 @@
int32_t combinedMeta = 0;
- const char* str = token.string();
+ const char* str = token.c_str();
const char* start = str;
for (const char* cur = str; ; cur++) {
char ch = *cur;
@@ -1164,7 +1164,7 @@
}
if (combinedMeta & metaState) {
ALOGE("%s: Duplicate modifier combination '%s'.",
- mTokenizer->getLocation().string(), token.string());
+ mTokenizer->getLocation().string(), token.c_str());
return BAD_VALUE;
}
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index c440078..88cb0db 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -49,13 +49,13 @@
KeyLayoutMap::~KeyLayoutMap() {
}
-status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) {
+status_t KeyLayoutMap::load(const std::string& filename, sp<KeyLayoutMap>* outMap) {
outMap->clear();
Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
+ status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
if (status) {
- ALOGE("Error %d opening key layout map file %s.", status, filename.string());
+ ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
} else {
sp<KeyLayoutMap> map = new KeyLayoutMap();
if (!map.get()) {
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 11842ee..0c22bfe 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -45,22 +45,22 @@
String8 keyLayoutName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
keyLayoutName)) {
- status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
+ status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
"it was not found.",
- deviceIdenfifier.name.string(), keyLayoutName.string());
+ deviceIdenfifier.name.c_str(), keyLayoutName.string());
}
}
String8 keyCharacterMapName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
keyCharacterMapName)) {
- status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
+ status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard character "
"map '%s' but it was not found.",
- deviceIdenfifier.name.string(), keyLayoutName.string());
+ deviceIdenfifier.name.c_str(), keyLayoutName.string());
}
}
@@ -70,30 +70,30 @@
}
// Try searching by device identifier.
- if (probeKeyMap(deviceIdenfifier, String8::empty())) {
+ if (probeKeyMap(deviceIdenfifier, "")) {
return OK;
}
// Fall back on the Generic key map.
// TODO Apply some additional heuristics here to figure out what kind of
// generic key map to use (US English, etc.) for typical external keyboards.
- if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
+ if (probeKeyMap(deviceIdenfifier, "Generic")) {
return OK;
}
// Try the Virtual key map as a last resort.
- if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
+ if (probeKeyMap(deviceIdenfifier, "Virtual")) {
return OK;
}
// Give up!
ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
- deviceIdenfifier.name.string());
+ deviceIdenfifier.name.c_str());
return NAME_NOT_FOUND;
}
bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
- const String8& keyMapName) {
+ const std::string& keyMapName) {
if (!haveKeyLayout()) {
loadKeyLayout(deviceIdentifier, keyMapName);
}
@@ -104,10 +104,10 @@
}
status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name) {
- String8 path(getPath(deviceIdentifier, name,
+ const std::string& name) {
+ std::string path(getPath(deviceIdentifier, name,
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
- if (path.isEmpty()) {
+ if (path.empty()) {
return NAME_NOT_FOUND;
}
@@ -116,15 +116,15 @@
return status;
}
- keyLayoutFile.setTo(path);
+ keyLayoutFile = path;
return OK;
}
status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name) {
- String8 path(getPath(deviceIdentifier, name,
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
- if (path.isEmpty()) {
+ const std::string& name) {
+ std::string path = getPath(deviceIdentifier, name,
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP);
+ if (path.empty()) {
return NAME_NOT_FOUND;
}
@@ -134,13 +134,13 @@
return status;
}
- keyCharacterMapFile.setTo(path);
+ keyCharacterMapFile = path;
return OK;
}
-String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name, InputDeviceConfigurationFileType type) {
- return name.isEmpty()
+std::string KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
+ const std::string& name, InputDeviceConfigurationFileType type) {
+ return name.empty()
? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
: getInputDeviceConfigurationFilePathByName(name, type);
}
@@ -174,7 +174,7 @@
}
}
- return strstr(deviceIdentifier.name.string(), "-keypad");
+ return strstr(deviceIdentifier.name.c_str(), "-keypad");
}
static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp
index 9932973..3ec53bf 100644
--- a/libs/input/VirtualKeyMap.cpp
+++ b/libs/input/VirtualKeyMap.cpp
@@ -46,13 +46,13 @@
VirtualKeyMap::~VirtualKeyMap() {
}
-status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
+status_t VirtualKeyMap::load(const std::string& filename, VirtualKeyMap** outMap) {
*outMap = nullptr;
Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
+ status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
if (status) {
- ALOGE("Error %d opening virtual key map file %s.", status, filename.string());
+ ALOGE("Error %d opening virtual key map file %s.", status, filename.c_str());
} else {
VirtualKeyMap* map = new VirtualKeyMap();
if (!map) {
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 94caf6b..8976d2d 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -35,6 +35,8 @@
bool secure{false};
nsecs_t appVsyncOffset{0};
nsecs_t presentationDeadline{0};
+ uint32_t viewportW{0};
+ uint32_t viewportH{0};
};
/* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 7788452..68b60fc 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -25,6 +25,8 @@
#include <ui/Rect.h>
#include <utils/Flattenable.h>
+#include <android-base/macros.h>
+
namespace android {
// ---------------------------------------------------------------------------
@@ -93,11 +95,11 @@
Region& subtractSelf(const Region& rhs, int dx, int dy);
// these translate rhs first
- const Region translate(int dx, int dy) const;
- const Region merge(const Region& rhs, int dx, int dy) const;
- const Region mergeExclusive(const Region& rhs, int dx, int dy) const;
- const Region intersect(const Region& rhs, int dx, int dy) const;
- const Region subtract(const Region& rhs, int dx, int dy) const;
+ const Region translate(int dx, int dy) const WARN_UNUSED;
+ const Region merge(const Region& rhs, int dx, int dy) const WARN_UNUSED;
+ const Region mergeExclusive(const Region& rhs, int dx, int dy) const WARN_UNUSED;
+ const Region intersect(const Region& rhs, int dx, int dy) const WARN_UNUSED;
+ const Region subtract(const Region& rhs, int dx, int dy) const WARN_UNUSED;
// convenience operators overloads
inline const Region operator | (const Region& rhs) const;
diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h
index 1f5d535..e5c5e5b 100644
--- a/opengl/libs/EGL/BlobCache.h
+++ b/opengl/libs/EGL/BlobCache.h
@@ -97,6 +97,10 @@
//
int unflatten(void const* buffer, size_t size);
+ // clear flushes out all contents of the cache then the BlobCache, leaving
+ // it in an empty state.
+ void clear() { mCacheEntries.clear(); }
+
protected:
// mMaxTotalSize is the maximum size that all cache entries can occupy. This
// includes space for both keys and values. When a call to BlobCache::set
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 77a474f..a964d29 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -76,16 +76,16 @@
return value ? "true" : "false";
}
-static String8 sha1(const String8& in) {
+static std::string sha1(const std::string& in) {
SHA_CTX ctx;
SHA1_Init(&ctx);
- SHA1_Update(&ctx, reinterpret_cast<const u_char*>(in.string()), in.size());
+ SHA1_Update(&ctx, reinterpret_cast<const u_char*>(in.c_str()), in.size());
u_char digest[SHA_DIGEST_LENGTH];
SHA1_Final(digest, &ctx);
- String8 out;
+ std::string out;
for (size_t i = 0; i < SHA_DIGEST_LENGTH; i++) {
- out.appendFormat("%02x", digest[i]);
+ out += StringPrintf("%02x", digest[i]);
}
return out;
}
@@ -141,7 +141,7 @@
// --- EventHub::Device ---
-EventHub::Device::Device(int fd, int32_t id, const String8& path,
+EventHub::Device::Device(int fd, int32_t id, const std::string& path,
const InputDeviceIdentifier& identifier) :
next(nullptr),
fd(fd), id(id), path(path), identifier(identifier),
@@ -172,9 +172,9 @@
}
status_t EventHub::Device::enable() {
- fd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+ fd = open(path.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
if(fd < 0) {
- ALOGE("could not open %s, %s\n", path.string(), strerror(errno));
+ ALOGE("could not open %s, %s\n", path.c_str(), strerror(errno));
return -errno;
}
enabled = true;
@@ -307,7 +307,7 @@
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
- axis, device->identifier.name.string(), device->fd, errno);
+ axis, device->identifier.name.c_str(), device->fd, errno);
return -errno;
}
@@ -416,7 +416,7 @@
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
- axis, device->identifier.name.string(), device->fd, errno);
+ axis, device->identifier.name.c_str(), device->fd, errno);
return -errno;
}
@@ -512,7 +512,7 @@
return NAME_NOT_FOUND;
}
-void EventHub::setExcludedDevices(const Vector<String8>& devices) {
+void EventHub::setExcludedDevices(const std::vector<std::string>& devices) {
AutoMutex _l(mLock);
mExcludedDevices = devices;
@@ -599,16 +599,16 @@
return false;
}
-static String8 generateDescriptor(InputDeviceIdentifier& identifier) {
- String8 rawDescriptor;
- rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor,
+static std::string generateDescriptor(InputDeviceIdentifier& identifier) {
+ std::string rawDescriptor;
+ rawDescriptor += StringPrintf(":%04x:%04x:", identifier.vendor,
identifier.product);
// TODO add handling for USB devices to not uniqueify kbs that show up twice
- if (!identifier.uniqueId.isEmpty()) {
- rawDescriptor.append("uniqueId:");
- rawDescriptor.append(identifier.uniqueId);
+ if (!identifier.uniqueId.empty()) {
+ rawDescriptor += "uniqueId:";
+ rawDescriptor += identifier.uniqueId;
} else if (identifier.nonce != 0) {
- rawDescriptor.appendFormat("nonce:%04x", identifier.nonce);
+ rawDescriptor += StringPrintf("nonce:%04x", identifier.nonce);
}
if (identifier.vendor == 0 && identifier.product == 0) {
@@ -616,12 +616,12 @@
// built-in so we need to rely on other information to uniquely identify
// the input device. Usually we try to avoid relying on the device name or
// location but for built-in input device, they are unlikely to ever change.
- if (!identifier.name.isEmpty()) {
- rawDescriptor.append("name:");
- rawDescriptor.append(identifier.name);
- } else if (!identifier.location.isEmpty()) {
- rawDescriptor.append("location:");
- rawDescriptor.append(identifier.location);
+ if (!identifier.name.empty()) {
+ rawDescriptor += "name:";
+ rawDescriptor += identifier.name;
+ } else if (!identifier.location.empty()) {
+ rawDescriptor += "location:";
+ rawDescriptor += identifier.location;
}
}
identifier.descriptor = sha1(rawDescriptor);
@@ -637,8 +637,8 @@
// Ideally, we also want the descriptor to be short and relatively opaque.
identifier.nonce = 0;
- String8 rawDescriptor = generateDescriptor(identifier);
- if (identifier.uniqueId.isEmpty()) {
+ std::string rawDescriptor = generateDescriptor(identifier);
+ if (identifier.uniqueId.empty()) {
// If it didn't have a unique id check for conflicts and enforce
// uniqueness if necessary.
while(getDeviceByDescriptorLocked(identifier.descriptor) != nullptr) {
@@ -646,8 +646,8 @@
rawDescriptor = generateDescriptor(identifier);
}
}
- ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.string(),
- identifier.descriptor.string());
+ ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.c_str(),
+ identifier.descriptor.c_str());
}
void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
@@ -664,7 +664,7 @@
effect.replay.delay = 0;
if (ioctl(device->fd, EVIOCSFF, &effect)) {
ALOGW("Could not upload force feedback effect to device %s due to error %d.",
- device->identifier.name.string(), errno);
+ device->identifier.name.c_str(), errno);
return;
}
device->ffEffectId = effect.id;
@@ -677,7 +677,7 @@
ev.value = 1;
if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
ALOGW("Could not start force feedback effect on device %s due to error %d.",
- device->identifier.name.string(), errno);
+ device->identifier.name.c_str(), errno);
return;
}
device->ffEffectPlaying = true;
@@ -699,18 +699,18 @@
ev.value = 0;
if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
ALOGW("Could not stop force feedback effect on device %s due to error %d.",
- device->identifier.name.string(), errno);
+ device->identifier.name.c_str(), errno);
return;
}
}
}
}
-EventHub::Device* EventHub::getDeviceByDescriptorLocked(String8& descriptor) const {
+EventHub::Device* EventHub::getDeviceByDescriptorLocked(const std::string& descriptor) const {
size_t size = mDevices.size();
for (size_t i = 0; i < size; i++) {
Device* device = mDevices.valueAt(i);
- if (descriptor.compare(device->identifier.descriptor) == 0) {
+ if (descriptor == device->identifier.descriptor) {
return device;
}
}
@@ -763,7 +763,7 @@
while (mClosingDevices) {
Device* device = mClosingDevices;
ALOGV("Reporting device closed: id=%d, name=%s\n",
- device->id, device->path.string());
+ device->id, device->path.c_str());
mClosingDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
@@ -785,7 +785,7 @@
while (mOpeningDevices != nullptr) {
Device* device = mOpeningDevices;
ALOGV("Reporting device opened: id=%d, name=%s\n",
- device->id, device->path.string());
+ device->id, device->path.c_str());
mOpeningDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
@@ -867,7 +867,7 @@
for (size_t i = 0; i < count; i++) {
struct input_event& iev = readBuffer[i];
ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d",
- device->path.string(),
+ device->path.c_str(),
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
@@ -936,7 +936,7 @@
"event time %" PRId64 ", current time %" PRId64
", call time %" PRId64 ". "
"Using current time instead.",
- device->path.string(), event->when, time, now);
+ device->path.c_str(), event->when, time, now);
event->when = time;
} else {
ALOGV("Event time is ok but failed the fast path and required "
@@ -962,12 +962,12 @@
}
} else if (eventItem.events & EPOLLHUP) {
ALOGI("Removing device %s due to epoll hang-up event.",
- device->identifier.name.string());
+ device->identifier.name.c_str());
deviceChanged = true;
closeDeviceLocked(device);
} else {
ALOGW("Received unexpected epoll event 0x%08x for device %s.",
- eventItem.events, device->identifier.name.string());
+ eventItem.events, device->identifier.name.c_str());
}
}
@@ -1125,14 +1125,14 @@
//fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
- identifier.name.setTo(buffer);
+ identifier.name = buffer;
}
// Check to see if the device is on our excluded list
for (size_t i = 0; i < mExcludedDevices.size(); i++) {
- const String8& item = mExcludedDevices.itemAt(i);
+ const std::string& item = mExcludedDevices[i];
if (identifier.name == item) {
- ALOGI("ignoring event id %s driver %s\n", devicePath, item.string());
+ ALOGI("ignoring event id %s driver %s\n", devicePath, item.c_str());
close(fd);
return -1;
}
@@ -1163,7 +1163,7 @@
//fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
- identifier.location.setTo(buffer);
+ identifier.location = buffer;
}
// Get device unique id.
@@ -1171,7 +1171,7 @@
//fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
- identifier.uniqueId.setTo(buffer);
+ identifier.uniqueId = buffer;
}
// Fill in the descriptor.
@@ -1179,7 +1179,7 @@
// Allocate device. (The device object takes ownership of the fd at this point.)
int32_t deviceId = mNextDeviceId++;
- Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
+ Device* device = new Device(fd, deviceId, devicePath, identifier);
ALOGV("add device %d: %s\n", deviceId, devicePath);
ALOGV(" bus: %04x\n"
@@ -1187,10 +1187,10 @@
" product %04x\n"
" version %04x\n",
identifier.bus, identifier.vendor, identifier.product, identifier.version);
- ALOGV(" name: \"%s\"\n", identifier.name.string());
- ALOGV(" location: \"%s\"\n", identifier.location.string());
- ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.string());
- ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.string());
+ ALOGV(" name: \"%s\"\n", identifier.name.c_str());
+ ALOGV(" location: \"%s\"\n", identifier.location.c_str());
+ ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.c_str());
+ ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.c_str());
ALOGV(" driver: v%d.%d.%d\n",
driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
@@ -1343,7 +1343,7 @@
// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == 0) {
ALOGV("Dropping device: id=%d, path='%s', name='%s'",
- deviceId, devicePath, device->identifier.name.string());
+ deviceId, devicePath, device->identifier.name.c_str());
delete device;
return -1;
}
@@ -1374,11 +1374,11 @@
ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
"configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
- deviceId, fd, devicePath, device->identifier.name.string(),
+ deviceId, fd, devicePath, device->identifier.name.c_str(),
device->classes,
- device->configurationFile.string(),
- device->keyMap.keyLayoutFile.string(),
- device->keyMap.keyCharacterMapFile.string(),
+ device->configurationFile.c_str(),
+ device->keyMap.keyLayoutFile.c_str(),
+ device->keyMap.keyCharacterMapFile.c_str(),
toString(mBuiltInKeyboardId == deviceId));
addDeviceLocked(device);
@@ -1392,11 +1392,11 @@
unsigned int repeatRate[] = {0, 0};
if (ioctl(device->fd, EVIOCSREP, repeatRate)) {
ALOGW("Unable to disable kernel key repeat for %s: %s",
- device->path.string(), strerror(errno));
+ device->path.c_str(), strerror(errno));
}
}
- String8 wakeMechanism("EPOLLWAKEUP");
+ std::string wakeMechanism = "EPOLLWAKEUP";
if (!mUsingEpollWakeup) {
#ifndef EVIOCSSUSPENDBLOCK
// uapi headers don't include EVIOCSSUSPENDBLOCK, and future kernels
@@ -1416,7 +1416,7 @@
// clock.
int clockId = CLOCK_MONOTONIC;
bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId);
- ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.string(),
+ ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.c_str(),
toString(usingClockIoctl));
}
@@ -1473,7 +1473,7 @@
identifier.uniqueId = "<virtual>";
assignDescriptorLocked(identifier);
- Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, String8("<virtual>"), identifier);
+ Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, "<virtual>", identifier);
device->classes = INPUT_DEVICE_CLASS_KEYBOARD
| INPUT_DEVICE_CLASS_ALPHAKEY
| INPUT_DEVICE_CLASS_DPAD
@@ -1491,26 +1491,26 @@
void EventHub::loadConfigurationLocked(Device* device) {
device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
- if (device->configurationFile.isEmpty()) {
+ if (device->configurationFile.empty()) {
ALOGD("No input device configuration file found for device '%s'.",
- device->identifier.name.string());
+ device->identifier.name.c_str());
} else {
- status_t status = PropertyMap::load(device->configurationFile,
+ status_t status = PropertyMap::load(String8(device->configurationFile.c_str()),
&device->configuration);
if (status) {
ALOGE("Error loading input device configuration file for device '%s'. "
"Using default configuration.",
- device->identifier.name.string());
+ device->identifier.name.c_str());
}
}
}
status_t EventHub::loadVirtualKeyMapLocked(Device* device) {
// The virtual key map is supplied by the kernel as a system board property file.
- String8 path;
- path.append("/sys/board_properties/virtualkeys.");
- path.append(device->identifier.name);
- if (access(path.string(), R_OK)) {
+ std::string path;
+ path += "/sys/board_properties/virtualkeys.";
+ path += device->identifier.name;
+ if (access(path.c_str(), R_OK)) {
return NAME_NOT_FOUND;
}
return VirtualKeyMap::load(path, &device->virtualKeyMap);
@@ -1543,7 +1543,7 @@
int32_t EventHub::getNextControllerNumberLocked(Device* device) {
if (mControllerNumbers.isFull()) {
ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s",
- device->identifier.name.string());
+ device->identifier.name.c_str());
return 0;
}
// Since the controller number 0 is reserved for non-controllers, translate all numbers up by
@@ -1617,12 +1617,12 @@
void EventHub::closeDeviceLocked(Device* device) {
ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n",
- device->path.string(), device->identifier.name.string(), device->id,
+ device->path.c_str(), device->identifier.name.c_str(), device->id,
device->fd, device->classes);
if (device->id == mBuiltInKeyboardId) {
ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
- device->path.string(), mBuiltInKeyboardId);
+ device->path.c_str(), mBuiltInKeyboardId);
mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
}
@@ -1648,7 +1648,7 @@
// Unlink the device from the opening devices list then delete it.
// We don't need to tell the client that the device was closed because
// it does not even know it was opened in the first place.
- ALOGI("Device %s was immediately closed after opening.", device->path.string());
+ ALOGI("Device %s was immediately closed after opening.", device->path.c_str());
if (pred) {
pred->next = device->next;
} else {
@@ -1750,28 +1750,28 @@
const Device* device = mDevices.valueAt(i);
if (mBuiltInKeyboardId == device->id) {
dump += StringPrintf(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
- device->id, device->identifier.name.string());
+ device->id, device->identifier.name.c_str());
} else {
dump += StringPrintf(INDENT2 "%d: %s\n", device->id,
- device->identifier.name.string());
+ device->identifier.name.c_str());
}
dump += StringPrintf(INDENT3 "Classes: 0x%08x\n", device->classes);
- dump += StringPrintf(INDENT3 "Path: %s\n", device->path.string());
+ dump += StringPrintf(INDENT3 "Path: %s\n", device->path.c_str());
dump += StringPrintf(INDENT3 "Enabled: %s\n", toString(device->enabled));
- dump += StringPrintf(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
- dump += StringPrintf(INDENT3 "Location: %s\n", device->identifier.location.string());
+ dump += StringPrintf(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.c_str());
+ dump += StringPrintf(INDENT3 "Location: %s\n", device->identifier.location.c_str());
dump += StringPrintf(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
- dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
+ dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.c_str());
dump += StringPrintf(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
"product=0x%04x, version=0x%04x\n",
device->identifier.bus, device->identifier.vendor,
device->identifier.product, device->identifier.version);
dump += StringPrintf(INDENT3 "KeyLayoutFile: %s\n",
- device->keyMap.keyLayoutFile.string());
+ device->keyMap.keyLayoutFile.c_str());
dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n",
- device->keyMap.keyCharacterMapFile.string());
+ device->keyMap.keyCharacterMapFile.c_str());
dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n",
- device->configurationFile.string());
+ device->configurationFile.c_str());
dump += StringPrintf(INDENT3 "HaveKeyboardLayoutOverlay: %s\n",
toString(device->overlayKeyMap != nullptr));
}
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index dfe3def..ea663b7 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -18,6 +18,8 @@
#ifndef _RUNTIME_EVENT_HUB_H
#define _RUNTIME_EVENT_HUB_H
+#include <vector>
+
#include <input/Input.h>
#include <input/InputDevice.h>
#include <input/Keyboard.h>
@@ -29,7 +31,6 @@
#include <utils/List.h>
#include <utils/Errors.h>
#include <utils/PropertyMap.h>
-#include <utils/Vector.h>
#include <utils/KeyedVector.h>
#include <utils/BitSet.h>
@@ -207,7 +208,7 @@
// Sets devices that are excluded from opening.
// This can be used to ignore input devices for sensors.
- virtual void setExcludedDevices(const Vector<String8>& devices) = 0;
+ virtual void setExcludedDevices(const std::vector<std::string>& devices) = 0;
/*
* Wait for events to become available and returns them.
@@ -303,7 +304,7 @@
virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
AxisInfo* outAxisInfo) const;
- virtual void setExcludedDevices(const Vector<String8>& devices);
+ virtual void setExcludedDevices(const std::vector<std::string>& devices);
virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const;
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const;
@@ -344,7 +345,7 @@
int fd; // may be -1 if device is closed
const int32_t id;
- const String8 path;
+ const std::string path;
const InputDeviceIdentifier identifier;
uint32_t classes;
@@ -357,7 +358,7 @@
uint8_t ffBitmask[(FF_MAX + 1) / 8];
uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];
- String8 configurationFile;
+ std::string configurationFile;
PropertyMap* configuration;
VirtualKeyMap* virtualKeyMap;
KeyMap keyMap;
@@ -373,7 +374,8 @@
int32_t timestampOverrideSec;
int32_t timestampOverrideUsec;
- Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier);
+ Device(int fd, int32_t id, const std::string& path,
+ const InputDeviceIdentifier& identifier);
~Device();
void close();
@@ -413,7 +415,7 @@
void scanDevicesLocked();
status_t readNotifyLocked();
- Device* getDeviceByDescriptorLocked(String8& descriptor) const;
+ Device* getDeviceByDescriptorLocked(const std::string& descriptor) const;
Device* getDeviceLocked(int32_t deviceId) const;
Device* getDeviceByPathLocked(const char* devicePath) const;
@@ -457,7 +459,7 @@
bool mNeedToSendFinishedDeviceScan;
bool mNeedToReopenDevices;
bool mNeedToScanDevices;
- Vector<String8> mExcludedDevices;
+ std::vector<std::string> mExcludedDevices;
int mEpollFd;
int mINotifyFd;
diff --git a/services/inputflinger/InputApplication.h b/services/inputflinger/InputApplication.h
index 724fc2c..9b365b9 100644
--- a/services/inputflinger/InputApplication.h
+++ b/services/inputflinger/InputApplication.h
@@ -17,6 +17,8 @@
#ifndef _UI_INPUT_APPLICATION_H
#define _UI_INPUT_APPLICATION_H
+#include <string>
+
#include <input/Input.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index a213b2d..92e0af2 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -31,7 +31,6 @@
#include <utils/Vector.h>
#include <utils/Timers.h>
#include <utils/RefBase.h>
-#include <utils/String8.h>
namespace android {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index a4f83b7..8f12129 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -257,11 +257,12 @@
// --- InputReaderConfiguration ---
bool InputReaderConfiguration::getDisplayViewport(ViewportType viewportType,
- const String8* uniqueDisplayId, DisplayViewport* outViewport) const {
+ const std::string& uniqueDisplayId, DisplayViewport* outViewport) const {
const DisplayViewport* viewport = nullptr;
- if (viewportType == ViewportType::VIEWPORT_VIRTUAL && uniqueDisplayId != nullptr) {
+ if (viewportType == ViewportType::VIEWPORT_VIRTUAL && !uniqueDisplayId.empty()) {
+
for (const DisplayViewport& currentViewport : mVirtualDisplays) {
- if (currentViewport.uniqueId == *uniqueDisplayId) {
+ if (currentViewport.uniqueId == uniqueDisplayId) {
viewport = ¤tViewport;
break;
}
@@ -473,10 +474,10 @@
if (device->isIgnored()) {
ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
- identifier.name.string());
+ identifier.name.c_str());
} else {
ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
- identifier.name.string(), device->getSources());
+ identifier.name.c_str(), device->getSources());
}
mDevices.add(deviceId, device);
@@ -501,10 +502,10 @@
if (device->isIgnored()) {
ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)",
- device->getId(), device->getName().string());
+ device->getId(), device->getName().c_str());
} else {
ALOGI("Device removed: id=%d, name='%s', sources=0x%08x",
- device->getId(), device->getName().string(), device->getSources());
+ device->getId(), device->getName().c_str(), device->getSources());
}
if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
@@ -687,7 +688,7 @@
if (now < mDisableVirtualKeysTimeout) {
ALOGI("Dropping virtual key from device %s because virtual keys are "
"temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d",
- device->getName().string(),
+ device->getName().c_str(),
(mDisableVirtualKeysTimeout - now) * 0.000001,
keyCode, scanCode);
return true;
@@ -894,7 +895,7 @@
if (i != 0) {
dump += ", ";
}
- dump += mConfig.excludedDeviceNames.itemAt(i).string();
+ dump += mConfig.excludedDeviceNames[i];
}
dump += "]\n";
dump += StringPrintf(INDENT2 "VirtualKeyQuietTime: %0.1fms\n",
@@ -1077,7 +1078,7 @@
getDeviceInfo(& deviceInfo);
dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(),
- deviceInfo.getDisplayName().string());
+ deviceInfo.getDisplayName().c_str());
dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration);
dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic));
@@ -1135,7 +1136,7 @@
if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) {
if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
- String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
+ std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
if (mAlias != alias) {
mAlias = alias;
bumpGeneration();
@@ -1196,7 +1197,7 @@
#endif
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
- ALOGI("Detected input event buffer overrun for device %s.", getName().string());
+ ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
@@ -2294,7 +2295,7 @@
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
if (mParameters.orientationAware) {
DisplayViewport dvp;
- config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, nullptr, &dvp);
+ config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &dvp);
mViewport = dvp;
}
}
@@ -2464,7 +2465,7 @@
// key was not actually down
ALOGI("Dropping key up from device %s because the key was not down. "
"keyCode=%d, scanCode=%d",
- getDeviceName().string(), keyCode, scanCode);
+ getDeviceName().c_str(), keyCode, scanCode);
return;
}
}
@@ -2705,7 +2706,7 @@
mOrientation = DISPLAY_ORIENTATION_0;
if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
DisplayViewport v;
- if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, nullptr, &v)) {
+ if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &v)) {
mOrientation = v.orientation;
}
}
@@ -3020,7 +3021,7 @@
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
DisplayViewport v;
- if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, nullptr, &v)) {
+ if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &v)) {
mOrientation = v.orientation;
} else {
mOrientation = DISPLAY_ORIENTATION_0;
@@ -3394,8 +3395,10 @@
mParameters.hasAssociatedDisplay = true;
if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
mParameters.associatedDisplayIsExternal = getDevice()->isExternal();
+ String8 uniqueDisplayId;
getDevice()->getConfiguration().tryGetProperty(String8("touch.displayId"),
- mParameters.uniqueDisplayId);
+ uniqueDisplayId);
+ mParameters.uniqueDisplayId = uniqueDisplayId.c_str();
}
}
@@ -3506,7 +3509,7 @@
// Ensure we have valid X and Y axes.
if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis! "
- "The device will be inoperable.", getDeviceName().string());
+ "The device will be inoperable.", getDeviceName().c_str());
mDeviceMode = DEVICE_MODE_DISABLED;
return;
}
@@ -3518,15 +3521,15 @@
// Get associated display dimensions.
DisplayViewport newViewport;
if (mParameters.hasAssociatedDisplay) {
- const String8* uniqueDisplayId = nullptr;
+ std::string uniqueDisplayId;
ViewportType viewportTypeToUse;
if (mParameters.associatedDisplayIsExternal) {
viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL;
- } else if (!mParameters.uniqueDisplayId.isEmpty()) {
+ } else if (!mParameters.uniqueDisplayId.empty()) {
// If the IDC file specified a unique display Id, then it expects to be linked to a
// virtual display with the same unique ID.
- uniqueDisplayId = &mParameters.uniqueDisplayId;
+ uniqueDisplayId = mParameters.uniqueDisplayId;
viewportTypeToUse = ViewportType::VIEWPORT_VIRTUAL;
} else {
viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;
@@ -3536,7 +3539,7 @@
ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
"display. The device will be inoperable until the display size "
"becomes available.",
- getDeviceName().string());
+ getDeviceName().c_str());
mDeviceMode = DEVICE_MODE_DISABLED;
return;
}
@@ -3642,7 +3645,7 @@
if (viewportChanged || deviceModeChanged) {
ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
"display id %d",
- getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight,
+ getDeviceId(), getDeviceName().c_str(), mSurfaceWidth, mSurfaceHeight,
mSurfaceOrientation, mDeviceMode, mViewport.displayId);
// Configure X and Y factors.
@@ -6925,7 +6928,7 @@
#if DEBUG_POINTERS
ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
"ignoring the rest.",
- getDeviceName().string(), MAX_POINTERS);
+ getDeviceName().c_str(), MAX_POINTERS);
#endif
break; // too many fingers!
}
@@ -7016,7 +7019,7 @@
if (slotCount > MAX_SLOTS) {
ALOGW("MultiTouch Device %s reported %zu slots but the framework "
"only supports a maximum of %zu slots at this time.",
- getDeviceName().string(), slotCount, MAX_SLOTS);
+ getDeviceName().c_str(), slotCount, MAX_SLOTS);
slotCount = MAX_SLOTS;
}
mMultiTouchMotionAccumulator.configure(getDevice(),
@@ -7259,7 +7262,7 @@
// Prefer to keep explicitly mapped axes.
if (mAxes.size() > PointerCoords::MAX_AXES) {
ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.",
- getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES);
+ getDeviceName().c_str(), mAxes.size(), PointerCoords::MAX_AXES);
pruneAxes(true);
pruneAxes(false);
}
@@ -7281,7 +7284,7 @@
} else {
ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids "
"have already been assigned to other axes.",
- getDeviceName().string(), mAxes.keyAt(i));
+ getDeviceName().c_str(), mAxes.keyAt(i));
mAxes.removeItemsAt(i--);
numAxes -= 1;
}
@@ -7310,7 +7313,7 @@
continue;
}
ALOGI("Discarding joystick '%s' axis %d because there are too many axes.",
- getDeviceName().string(), mAxes.keyAt(i));
+ getDeviceName().c_str(), mAxes.keyAt(i));
mAxes.removeItemsAt(i);
}
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index af26b4f..c06168d 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -101,7 +101,7 @@
// The excluded device names for the platform.
// Devices with these names will be ignored.
- Vector<String8> excludedDeviceNames;
+ std::vector<std::string> excludedDeviceNames;
// Velocity control parameters for mouse pointer movements.
VelocityControlParameters pointerVelocityControlParameters;
@@ -201,7 +201,7 @@
pointerGestureZoomSpeedRatio(0.3f),
showTouches(false) { }
- bool getDisplayViewport(ViewportType viewportType, const String8* displayId,
+ bool getDisplayViewport(ViewportType viewportType, const std::string& uniqueDisplayId,
DisplayViewport* outViewport) const;
void setPhysicalDisplayViewport(ViewportType viewportType, const DisplayViewport& viewport);
void setVirtualDisplayViewports(const Vector<DisplayViewport>& viewports);
@@ -274,11 +274,11 @@
const InputDeviceIdentifier& identifier) = 0;
/* Gets a user-supplied alias for a particular input device, or an empty string if none. */
- virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) = 0;
+ virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier) = 0;
/* Gets the affine calibration associated with the specified device. */
virtual TouchAffineTransformation getTouchAffineTransformation(
- const String8& inputDeviceDescriptor, int32_t surfaceRotation) = 0;
+ const std::string& inputDeviceDescriptor, int32_t surfaceRotation) = 0;
};
@@ -553,8 +553,8 @@
inline int32_t getId() const { return mId; }
inline int32_t getControllerNumber() const { return mControllerNumber; }
inline int32_t getGeneration() const { return mGeneration; }
- inline const String8& getName() const { return mIdentifier.name; }
- inline const String8& getDescriptor() { return mIdentifier.descriptor; }
+ inline const std::string getName() const { return mIdentifier.name; }
+ inline const std::string getDescriptor() { return mIdentifier.descriptor; }
inline uint32_t getClasses() const { return mClasses; }
inline uint32_t getSources() const { return mSources; }
@@ -625,7 +625,7 @@
int32_t mGeneration;
int32_t mControllerNumber;
InputDeviceIdentifier mIdentifier;
- String8 mAlias;
+ std::string mAlias;
uint32_t mClasses;
Vector<InputMapper*> mMappers;
@@ -981,7 +981,7 @@
inline InputDevice* getDevice() { return mDevice; }
inline int32_t getDeviceId() { return mDevice->getId(); }
- inline const String8 getDeviceName() { return mDevice->getName(); }
+ inline const std::string getDeviceName() { return mDevice->getName(); }
inline InputReaderContext* getContext() { return mContext; }
inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); }
inline InputListenerInterface* getListener() { return mContext->getListener(); }
@@ -1309,7 +1309,7 @@
bool associatedDisplayIsExternal;
bool orientationAware;
bool hasButtonUnderPad;
- String8 uniqueDisplayId;
+ std::string uniqueDisplayId;
enum GestureMode {
GESTURE_MODE_SINGLE_TOUCH,
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index bd11d56..2f046c3 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -217,18 +217,18 @@
idi.product = id->productId;
idi.version = id->version;
- String8 configFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
+ std::string configFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
idi, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
- if (configFile.isEmpty()) {
+ if (configFile.empty()) {
ALOGD("No input device configuration file found for device '%s'.",
- idi.name.string());
+ idi.name.c_str());
} else {
auto propMap = new input_property_map_t();
- status_t status = PropertyMap::load(configFile, &propMap->propertyMap);
+ status_t status = PropertyMap::load(String8(configFile.c_str()), &propMap->propertyMap);
if (status) {
ALOGE("Error loading input device configuration file for device '%s'. "
"Using default configuration.",
- idi.name.string());
+ idi.name.c_str());
delete propMap;
return nullptr;
}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 286cf88..9b985dc 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -142,7 +142,7 @@
}
void setDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
- const String8& uniqueId) {
+ const std::string& uniqueId) {
DisplayViewport v = createDisplayViewport(displayId, width, height, orientation, uniqueId);
// Set the size of both the internal and external display at the same time.
mConfig.setPhysicalDisplayViewport(ViewportType::VIEWPORT_INTERNAL, v);
@@ -150,14 +150,14 @@
}
void setVirtualDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
- const String8& uniqueId) {
+ const std::string& uniqueId) {
Vector<DisplayViewport> viewports;
viewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId));
mConfig.setVirtualDisplayViewports(viewports);
}
- void addExcludedDeviceName(const String8& deviceName) {
- mConfig.excludedDeviceNames.push(deviceName);
+ void addExcludedDeviceName(const std::string& deviceName) {
+ mConfig.excludedDeviceNames.push_back(deviceName);
}
void addDisabledDevice(int32_t deviceId) {
@@ -188,7 +188,7 @@
return mInputDevices;
}
- TouchAffineTransformation getTouchAffineTransformation(const String8& inputDeviceDescriptor,
+ TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
int32_t surfaceRotation) {
return transform;
}
@@ -203,7 +203,7 @@
private:
DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
- int32_t orientation, const String8& uniqueId) {
+ int32_t orientation, const std::string& uniqueId) {
bool isRotated = (orientation == DISPLAY_ORIENTATION_90
|| orientation == DISPLAY_ORIENTATION_270);
DisplayViewport v;
@@ -239,8 +239,8 @@
return nullptr;
}
- virtual String8 getDeviceAlias(const InputDeviceIdentifier&) {
- return String8::empty();
+ virtual std::string getDeviceAlias(const InputDeviceIdentifier&) {
+ return "";
}
};
@@ -392,7 +392,7 @@
};
KeyedVector<int32_t, Device*> mDevices;
- Vector<String8> mExcludedDevices;
+ std::vector<std::string> mExcludedDevices;
List<RawEvent> mEvents;
protected:
@@ -405,7 +405,7 @@
public:
FakeEventHub() { }
- void addDevice(int32_t deviceId, const String8& name, uint32_t classes) {
+ void addDevice(int32_t deviceId, const std::string& name, uint32_t classes) {
Device* device = new Device(classes);
device->identifier.name = name;
mDevices.add(deviceId, device);
@@ -534,7 +534,7 @@
return device->leds.valueFor(led);
}
- Vector<String8>& getExcludedDevices() {
+ std::vector<std::string>& getExcludedDevices() {
return mExcludedDevices;
}
@@ -566,7 +566,7 @@
private:
Device* getDevice(int32_t deviceId) const {
ssize_t index = mDevices.indexOfKey(deviceId);
- return index >= 0 ? mDevices.valueAt(index) : NULL;
+ return index >= 0 ? mDevices.valueAt(index) : nullptr;
}
virtual uint32_t getDeviceClasses(int32_t deviceId) const {
@@ -658,7 +658,7 @@
return NAME_NOT_FOUND;
}
- virtual void setExcludedDevices(const Vector<String8>& devices) {
+ virtual void setExcludedDevices(const std::vector<std::string>& devices) {
mExcludedDevices = devices;
}
@@ -1052,7 +1052,7 @@
mNextDevice = device;
}
- InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const String8& name,
+ InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const std::string& name,
uint32_t classes) {
InputDeviceIdentifier identifier;
identifier.name = name;
@@ -1101,7 +1101,7 @@
mFakeEventHub.clear();
}
- void addDevice(int32_t deviceId, const String8& name, uint32_t classes,
+ void addDevice(int32_t deviceId, const std::string& name, uint32_t classes,
const PropertyMap* configuration) {
mFakeEventHub->addDevice(deviceId, name, classes);
@@ -1129,7 +1129,7 @@
}
FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber,
- const String8& name, uint32_t classes, uint32_t sources,
+ const std::string& name, uint32_t classes, uint32_t sources,
const PropertyMap* configuration) {
InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes);
FakeInputMapper* mapper = new FakeInputMapper(device, sources);
@@ -1141,17 +1141,18 @@
};
TEST_F(InputReaderTest, GetInputDevices) {
- ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"),
+ ASSERT_NO_FATAL_FAILURE(addDevice(1, "keyboard",
INPUT_DEVICE_CLASS_KEYBOARD, nullptr));
- ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("ignored"),
+ ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored",
0, nullptr)); // no classes so device will be ignored
+
Vector<InputDeviceInfo> inputDevices;
mReader->getInputDevices(inputDevices);
ASSERT_EQ(1U, inputDevices.size());
ASSERT_EQ(1, inputDevices[0].getId());
- ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string());
+ ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str());
ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType());
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources());
ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size());
@@ -1160,7 +1161,7 @@
inputDevices = mFakePolicy->getInputDevices();
ASSERT_EQ(1U, inputDevices.size());
ASSERT_EQ(1, inputDevices[0].getId());
- ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string());
+ ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str());
ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType());
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources());
ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size());
@@ -1169,12 +1170,12 @@
TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
constexpr int32_t deviceId = 1;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0, String8("fake"), deviceClass);
+ InputDevice* device = mReader->newDevice(deviceId, 0, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
device->addMapper(mapper);
mReader->setNextDevice(device);
- addDevice(deviceId, String8("fake"), deviceClass, nullptr);
+ addDevice(deviceId, "fake", deviceClass, nullptr);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(nullptr));
@@ -1208,7 +1209,7 @@
TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
FakeInputMapper* mapper = nullptr;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
+ ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
@@ -1235,7 +1236,7 @@
TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) {
FakeInputMapper* mapper = nullptr;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
+ ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN);
@@ -1262,7 +1263,7 @@
TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) {
FakeInputMapper* mapper = nullptr;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
+ ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN);
@@ -1289,8 +1290,9 @@
TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) {
FakeInputMapper* mapper = nullptr;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
+ ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
+
mapper->addSupportedKeyCode(AKEYCODE_A);
mapper->addSupportedKeyCode(AKEYCODE_B);
@@ -1323,7 +1325,7 @@
}
TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) {
- addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD, nullptr);
+ addDevice(1, "ignored", INPUT_DEVICE_CLASS_KEYBOARD, nullptr);
NotifyConfigurationChangedArgs args;
@@ -1333,7 +1335,7 @@
TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) {
FakeInputMapper* mapper = nullptr;
- ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
+ ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake",
INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1);
@@ -1373,7 +1375,7 @@
mFakeListener = new FakeInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
- mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
+ mFakeEventHub->addDevice(DEVICE_ID, DEVICE_NAME, 0);
InputDeviceIdentifier identifier;
identifier.name = DEVICE_NAME;
mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
@@ -1399,7 +1401,7 @@
TEST_F(InputDeviceTest, ImmutableProperties) {
ASSERT_EQ(DEVICE_ID, mDevice->getId());
- ASSERT_STREQ(DEVICE_NAME, mDevice->getName());
+ ASSERT_STREQ(DEVICE_NAME, mDevice->getName().c_str());
ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses());
}
@@ -1427,7 +1429,7 @@
InputDeviceInfo info;
mDevice->getDeviceInfo(&info);
ASSERT_EQ(DEVICE_ID, info.getId());
- ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string());
+ ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.c_str());
ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NONE, info.getKeyboardType());
ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, info.getSources());
@@ -1497,7 +1499,7 @@
InputDeviceInfo info;
mDevice->getDeviceInfo(&info);
ASSERT_EQ(DEVICE_ID, info.getId());
- ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string());
+ ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.c_str());
ASSERT_EQ(AINPUT_KEYBOARD_TYPE_ALPHABETIC, info.getKeyboardType());
ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), info.getSources());
@@ -1570,7 +1572,7 @@
mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
- mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
+ mFakeEventHub->addDevice(DEVICE_ID, DEVICE_NAME, 0);
}
virtual void TearDown() {
@@ -1597,12 +1599,12 @@
void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
int32_t orientation) {
- mFakePolicy->setDisplayViewport(displayId, width, height, orientation, String8::empty());
+ mFakePolicy->setDisplayViewport(displayId, width, height, orientation, "");
configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
}
void setVirtualDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
- int32_t orientation, const String8& uniqueId) {
+ int32_t orientation, const std::string& uniqueId) {
mFakePolicy->setVirtualDisplayViewport(displayId, width, height, orientation, uniqueId);
configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
}
@@ -3048,7 +3050,7 @@
void TouchInputMapperTest::prepareVirtualDisplay(int32_t orientation) {
setVirtualDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH,
- VIRTUAL_DISPLAY_HEIGHT, orientation, String8(VIRTUAL_DISPLAY_UNIQUE_ID));
+ VIRTUAL_DISPLAY_HEIGHT, orientation, VIRTUAL_DISPLAY_UNIQUE_ID);
}
void TouchInputMapperTest::prepareVirtualKeys() {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 05535a5..da57511 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -125,6 +125,7 @@
"Scheduler/EventControlThread.cpp",
"Scheduler/EventThread.cpp",
"Scheduler/MessageQueue.cpp",
+ "Scheduler/Scheduler.cpp",
"StartPropertySetThread.cpp",
"SurfaceFlinger.cpp",
"SurfaceInterceptor.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 1bb7a85..89394cd 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -58,7 +58,7 @@
mRefreshPending(false) {
ALOGV("Creating Layer %s", name.string());
- mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
+ mTexture.init(renderengine::Texture::TEXTURE_EXTERNAL, mTextureName);
mPremultipliedAlpha = !(flags & ISurfaceComposerClient::eNonPremultiplied);
@@ -180,7 +180,7 @@
if (!blackOutLayer) {
// TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = getFiltering() || needsFiltering(renderArea) || isFixedSize();
+ const bool useFiltering = needsFiltering(renderArea) || isFixedSize();
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
@@ -589,17 +589,6 @@
ui::Transform t = getTransform();
Rect win = bounds;
- Rect finalCrop = getFinalCrop(s);
- if (!finalCrop.isEmpty()) {
- win = t.transform(win);
- if (!win.intersect(finalCrop, &win)) {
- win.clear();
- }
- win = t.inverse().transform(win);
- if (!win.intersect(bounds, &win)) {
- win.clear();
- }
- }
float left = float(win.left) / float(getActiveWidth(s));
float top = float(win.top) / float(getActiveHeight(s));
@@ -608,7 +597,8 @@
// TODO: we probably want to generate the texture coords with the mesh
// here we assume that we only have 4 vertices
- Mesh::VertexArray<vec2> texCoords(getBE().mMesh.getTexCoordArray<vec2>());
+ renderengine::Mesh::VertexArray<vec2> texCoords(getBE().mMesh.getTexCoordArray<vec2>());
+ // flip texcoords vertically because BufferLayerConsumer expects them to be in GL convention
texCoords[0] = vec2(left, 1.0f - top);
texCoords[1] = vec2(left, 1.0f - bottom);
texCoords[2] = vec2(right, 1.0f - bottom);
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 3d06ded..45906ff 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -178,7 +178,7 @@
bool mBufferLatched; // TODO: Use mActiveBuffer?
// The texture used to draw the layer in GLES composition mode
- mutable Texture mTexture;
+ mutable renderengine::Texture mTexture;
bool mRefreshPending;
};
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index aa8f4e1..fa181ad 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -54,7 +54,8 @@
static const mat4 mtxIdentity;
BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq,
- RE::RenderEngine& engine, uint32_t tex, Layer* layer)
+ renderengine::RenderEngine& engine, uint32_t tex,
+ Layer* layer)
: ConsumerBase(bq, false),
mCurrentCrop(Rect::EMPTY_RECT),
mCurrentTransform(0),
@@ -592,7 +593,8 @@
ConsumerBase::dumpLocked(result, prefix);
}
-BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer, RE::RenderEngine& engine)
+BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer,
+ renderengine::RenderEngine& engine)
: mGraphicBuffer(graphicBuffer),
mImage{engine.createImage()},
mCreated(false),
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 943b8a8..257a4e5 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -37,10 +37,10 @@
class Layer;
class String8;
-namespace RE {
+namespace renderengine {
class RenderEngine;
class Image;
-} // namespace RE
+} // namespace renderengine
/*
* BufferLayerConsumer consumes buffers of graphics data from a BufferQueue,
@@ -73,7 +73,7 @@
// BufferLayerConsumer constructs a new BufferLayerConsumer object. The
// tex parameter indicates the name of the RenderEngine texture to which
// images are to be streamed.
- BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, RE::RenderEngine& engine,
+ BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, renderengine::RenderEngine& engine,
uint32_t tex, Layer* layer);
// Sets the contents changed listener. This should be used instead of
@@ -216,19 +216,19 @@
status_t bindTextureImageLocked();
private:
- // Image is a utility class for tracking and creating RE::Images. There
+ // Image is a utility class for tracking and creating renderengine::Images. There
// is primarily just one image per slot, but there is also special cases:
// - After freeBuffer, we must still keep the current image/buffer
- // Reference counting RE::Images lets us handle all these cases easily while
- // also only creating new RE::Images from buffers when required.
+ // Reference counting renderengine::Images lets us handle all these cases easily while
+ // also only creating new renderengine::Images from buffers when required.
class Image : public LightRefBase<Image> {
public:
- Image(sp<GraphicBuffer> graphicBuffer, RE::RenderEngine& engine);
+ Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine);
Image(const Image& rhs) = delete;
Image& operator=(const Image& rhs) = delete;
- // createIfNeeded creates an RE::Image if we haven't created one yet.
+ // createIfNeeded creates an renderengine::Image if we haven't created one yet.
status_t createIfNeeded();
const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
@@ -236,7 +236,7 @@
return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
}
- const RE::Image& image() const { return *mImage; }
+ const renderengine::Image& image() const { return *mImage; }
private:
// Only allow instantiation using ref counting.
@@ -247,7 +247,7 @@
sp<GraphicBuffer> mGraphicBuffer;
// mImage is the image created from mGraphicBuffer.
- std::unique_ptr<RE::Image> mImage;
+ std::unique_ptr<renderengine::Image> mImage;
bool mCreated;
int32_t mCropWidth;
int32_t mCropHeight;
@@ -255,7 +255,7 @@
// freeBufferLocked frees up the given buffer slot. If the slot has been
// initialized this will release the reference to the GraphicBuffer in
- // that slot and destroy the RE::Image in that slot. Otherwise it has no
+ // that slot and destroy the renderengine::Image in that slot. Otherwise it has no
// effect.
//
// This method must be called with mMutex locked.
@@ -351,7 +351,7 @@
// setFilteringEnabled().
bool mFilteringEnabled;
- RE::RenderEngine& mRE;
+ renderengine::RenderEngine& mRE;
// mTexName is the name of the RenderEngine texture to which streamed
// images will be bound when bindTexImage is called. It is set at
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 038eb01..ac3aad1 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -58,7 +58,6 @@
return s.transparentRegionHint;
}
Rect getCrop(const Layer::State& s) const;
- Rect getFinalCrop(const Layer::State& /*s*/) const { return Rect::EMPTY_RECT; }
bool setTransform(uint32_t transform) override;
bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
@@ -79,7 +78,6 @@
// Override to ignore legacy layer state properties that are not used by BufferStateLayer
bool setCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; };
- bool setFinalCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; };
void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/,
uint64_t /*frameNumber*/) override {}
void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/,
@@ -127,7 +125,7 @@
private:
void onFirstRef() override;
- std::unique_ptr<RE::Image> mTextureImage;
+ std::unique_ptr<renderengine::Image> mTextureImage;
std::array<float, 16> mTransformMatrix;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index acadfa0..9bf75e8 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -45,7 +45,7 @@
bool useIdentityTransform) {
half4 color = getColor();
if (color.a > 0) {
- Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
+ renderengine::Mesh mesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2);
computeGeometry(renderArea, mesh, useIdentityTransform);
auto& engine(mFlinger->getRenderEngine());
engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */,
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index aab6c22..3eb0a92 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -215,9 +215,10 @@
const wp<IBinder>& displayToken,
const sp<ANativeWindow>& nativeWindow,
const sp<DisplaySurface>& displaySurface,
- std::unique_ptr<RE::Surface> renderSurface,
+ std::unique_ptr<renderengine::Surface> renderSurface,
int displayWidth,
int displayHeight,
+ int displayInstallOrientation,
bool hasWideColorGamut,
const HdrCapabilities& hdrCapabilities,
const int32_t supportedPerFrameMetadata,
@@ -233,6 +234,7 @@
mSurface{std::move(renderSurface)},
mDisplayWidth(displayWidth),
mDisplayHeight(displayHeight),
+ mDisplayInstallOrientation(displayInstallOrientation),
mPageFlipCount(0),
mIsSecure(isSecure),
mLayerStack(NO_LAYER_STACK),
@@ -384,8 +386,7 @@
size_t w = mDisplayWidth;
size_t h = mDisplayHeight;
Rect sourceCrop(0, 0, w, h);
- mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, h,
- false, ui::Transform::ROT_0);
+ mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, ui::Transform::ROT_0);
}
const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
@@ -604,9 +605,8 @@
// need to take care of primary display rotation for mGlobalTransform
// for case if the panel is not installed aligned with device orientation
if (mType == DisplayType::DISPLAY_PRIMARY) {
- int primaryDisplayOrientation = mFlinger->getPrimaryDisplayOrientation();
DisplayDevice::orientationToTransfrom(
- (orientation + primaryDisplayOrientation) % (DisplayState::eOrientation270 + 1),
+ (orientation + mDisplayInstallOrientation) % (DisplayState::eOrientation270 + 1),
w, h, &R);
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index ddb09c5..ed73671 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -24,6 +24,7 @@
#include <unordered_map>
#include <binder/IBinder.h>
+#include <gui/LayerState.h>
#include <hardware/hwcomposer_defs.h>
#include <math/mat4.h>
#include <renderengine/Surface.h>
@@ -84,9 +85,10 @@
const wp<IBinder>& displayToken,
const sp<ANativeWindow>& nativeWindow,
const sp<DisplaySurface>& displaySurface,
- std::unique_ptr<RE::Surface> renderSurface,
+ std::unique_ptr<renderengine::Surface> renderSurface,
int displayWidth,
int displayHeight,
+ int displayInstallOrientation,
bool hasWideColorGamut,
const HdrCapabilities& hdrCapabilities,
const int32_t supportedPerFrameMetadata,
@@ -110,6 +112,7 @@
int getWidth() const;
int getHeight() const;
+ int getInstallOrientation() const { return mDisplayInstallOrientation; }
void setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
@@ -231,9 +234,10 @@
sp<ANativeWindow> mNativeWindow;
sp<DisplaySurface> mDisplaySurface;
- std::unique_ptr<RE::Surface> mSurface;
+ std::unique_ptr<renderengine::Surface> mSurface;
int mDisplayWidth;
int mDisplayHeight;
+ const int mDisplayInstallOrientation;
mutable uint32_t mPageFlipCount;
std::string mDisplayName;
bool mIsSecure;
@@ -339,18 +343,103 @@
rotation) {}
DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqWidth,
uint32_t reqHeight, ui::Transform::orientation_flags rotation)
- : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, rotation), mDevice(device),
- mSourceCrop(sourceCrop) {}
+ : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE,
+ getDisplayRotation(rotation, device->getInstallOrientation())),
+ mDevice(device),
+ mSourceCrop(sourceCrop) {}
const ui::Transform& getTransform() const override { return mDevice->getTransform(); }
Rect getBounds() const override { return mDevice->getBounds(); }
int getHeight() const override { return mDevice->getHeight(); }
int getWidth() const override { return mDevice->getWidth(); }
bool isSecure() const override { return mDevice->isSecure(); }
- bool needsFiltering() const override { return mDevice->needsFiltering(); }
- Rect getSourceCrop() const override { return mSourceCrop; }
+
+ bool needsFiltering() const override {
+ // check if the projection from the logical display to the physical
+ // display needs filtering
+ if (mDevice->needsFiltering()) {
+ return true;
+ }
+
+ // check if the projection from the logical render area (i.e., the
+ // physical display) to the physical render area requires filtering
+ const Rect sourceCrop = getSourceCrop();
+ int width = sourceCrop.width();
+ int height = sourceCrop.height();
+ if (getRotationFlags() & ui::Transform::ROT_90) {
+ std::swap(width, height);
+ }
+ return width != getReqWidth() || height != getReqHeight();
+ }
+
+ Rect getSourceCrop() const override {
+ // use the (projected) logical display viewport by default
+ if (mSourceCrop.isEmpty()) {
+ return mDevice->getScissor();
+ }
+
+ const int orientation = mDevice->getInstallOrientation();
+ if (orientation == DisplayState::eOrientationDefault) {
+ return mSourceCrop;
+ }
+
+ // Install orientation is transparent to the callers. Apply it now.
+ uint32_t flags = 0x00;
+ switch (orientation) {
+ case DisplayState::eOrientation90:
+ flags = ui::Transform::ROT_90;
+ break;
+ case DisplayState::eOrientation180:
+ flags = ui::Transform::ROT_180;
+ break;
+ case DisplayState::eOrientation270:
+ flags = ui::Transform::ROT_270;
+ break;
+ }
+ ui::Transform tr;
+ tr.set(flags, getWidth(), getHeight());
+ return tr.transform(mSourceCrop);
+ }
private:
+ // Install orientation is transparent to the callers. We need to cancel
+ // it out by modifying rotation flags.
+ static ui::Transform::orientation_flags getDisplayRotation(
+ ui::Transform::orientation_flags rotation, int orientation) {
+ if (orientation == DisplayState::eOrientationDefault) {
+ return rotation;
+ }
+
+ // convert hw orientation into flag presentation
+ // here inverse transform needed
+ uint8_t hw_rot_90 = 0x00;
+ uint8_t hw_flip_hv = 0x00;
+ switch (orientation) {
+ case DisplayState::eOrientation90:
+ hw_rot_90 = ui::Transform::ROT_90;
+ hw_flip_hv = ui::Transform::ROT_180;
+ break;
+ case DisplayState::eOrientation180:
+ hw_flip_hv = ui::Transform::ROT_180;
+ break;
+ case DisplayState::eOrientation270:
+ hw_rot_90 = ui::Transform::ROT_90;
+ break;
+ }
+
+ // transform flags operation
+ // 1) flip H V if both have ROT_90 flag
+ // 2) XOR these flags
+ uint8_t rotation_rot_90 = rotation & ui::Transform::ROT_90;
+ uint8_t rotation_flip_hv = rotation & ui::Transform::ROT_180;
+ if (rotation_rot_90 & hw_rot_90) {
+ rotation_flip_hv = (~rotation_flip_hv) & ui::Transform::ROT_180;
+ }
+
+ return static_cast<ui::Transform::orientation_flags>(
+ (rotation_rot_90 ^ hw_rot_90) | (rotation_flip_hv ^ hw_flip_hv));
+ }
+
const sp<const DisplayDevice> mDevice;
const Rect mSourceCrop;
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c7d67e2..29de50c 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -78,7 +78,6 @@
mOverrideScalingMode(-1),
mCurrentFrameNumber(0),
mFrameLatencyNeeded(false),
- mFiltering(false),
mNeedsFiltering(false),
mProtectedByApp(false),
mClientRef(client),
@@ -103,8 +102,6 @@
mCurrentState.flags = layerFlags;
mCurrentState.active_legacy.transform.set(0, 0);
mCurrentState.crop_legacy.makeInvalid();
- mCurrentState.finalCrop_legacy.makeInvalid();
- mCurrentState.requestedFinalCrop_legacy = mCurrentState.finalCrop_legacy;
mCurrentState.requestedCrop_legacy = mCurrentState.crop_legacy;
mCurrentState.z = 0;
mCurrentState.color.a = 1.0f;
@@ -298,11 +295,6 @@
ui::Transform t = getTransform();
win = t.transform(win);
- Rect finalCrop = getFinalCrop(s);
- if (!finalCrop.isEmpty()) {
- win.intersect(finalCrop, &win);
- }
-
const sp<Layer>& p = mDrawingParent.promote();
// Now we need to calculate the parent bounds, so we can clip ourselves to those.
// When calculating the parent bounds for purposes of clipping,
@@ -351,13 +343,9 @@
ui::Transform t = s.active_legacy.transform;
- if (p != nullptr || !s.finalCrop_legacy.isEmpty()) {
+ if (p != nullptr) {
floatWin = t.transform(floatWin);
floatWin = floatWin.intersect(parentBounds);
-
- if (!s.finalCrop_legacy.isEmpty()) {
- floatWin = floatWin.intersect(s.finalCrop_legacy.toFloatRect());
- }
floatWin = t.inverse().transform(floatWin);
}
@@ -388,12 +376,6 @@
if (!activeCrop.intersect(display->getViewport(), &activeCrop)) {
activeCrop.clear();
}
- Rect finalCrop = getFinalCrop(s);
- if (!finalCrop.isEmpty()) {
- if (!activeCrop.intersect(finalCrop, &activeCrop)) {
- activeCrop.clear();
- }
- }
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
@@ -554,12 +536,6 @@
// computeBounds returns a FloatRect to provide more accuracy during the
// transformation. We then round upon constructing 'frame'.
Rect frame{t.transform(computeBounds(activeTransparentRegion))};
- Rect finalCrop = getFinalCrop(s);
- if (!finalCrop.isEmpty()) {
- if (!frame.intersect(finalCrop, &frame)) {
- frame.clear();
- }
- }
if (!frame.intersect(display->getViewport(), &frame)) {
frame.clear();
}
@@ -671,10 +647,6 @@
Rect bounds = reduce(win, getActiveTransparentRegion(s));
Rect frame(getTransform().transform(bounds));
frame.intersect(display->getViewport(), &frame);
- Rect finalCrop = getFinalCrop(s);
- if (!finalCrop.isEmpty()) {
- frame.intersect(finalCrop, &frame);
- }
auto& displayTransform = display->getTransform();
auto position = displayTransform.transform(frame);
@@ -700,10 +672,6 @@
onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform);
}
-void Layer::draw(const RenderArea& renderArea) {
- onDraw(renderArea, Region(renderArea.getBounds()), false);
-}
-
void Layer::clearWithOpenGL(const RenderArea& renderArea, float red, float green, float blue,
float alpha) const {
auto& engine(mFlinger->getRenderEngine());
@@ -712,11 +680,6 @@
engine.drawMesh(getBE().mMesh);
}
-void Layer::clearWithOpenGL(const RenderArea& renderArea) const {
- getBE().compositionInfo.firstClear = true;
- computeGeometry(renderArea, getBE().mMesh, false);
-}
-
void Layer::setCompositionType(int32_t displayId, HWC2::Composition type, bool /*callIntoHwc*/) {
if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("setCompositionType called without a valid HWC layer");
@@ -768,38 +731,14 @@
return true;
}
-void Layer::setFiltering(bool filtering) {
- mFiltering = filtering;
-}
-
-bool Layer::getFiltering() const {
- return mFiltering;
-}
-
// ----------------------------------------------------------------------------
// local state
// ----------------------------------------------------------------------------
-static void boundPoint(vec2* point, const Rect& crop) {
- if (point->x < crop.left) {
- point->x = crop.left;
- }
- if (point->x > crop.right) {
- point->x = crop.right;
- }
- if (point->y < crop.top) {
- point->y = crop.top;
- }
- if (point->y > crop.bottom) {
- point->y = crop.bottom;
- }
-}
-
-void Layer::computeGeometry(const RenderArea& renderArea, Mesh& mesh,
+void Layer::computeGeometry(const RenderArea& renderArea,
+ renderengine::Mesh& mesh,
bool useIdentityTransform) const {
- const Layer::State& s(getDrawingState());
const ui::Transform renderAreaTransform(renderArea.getTransform());
- const uint32_t height = renderArea.getHeight();
FloatRect win = computeBounds();
vec2 lt = vec2(win.left, win.top);
@@ -815,22 +754,11 @@
rt = layerTransform.transform(rt);
}
- Rect finalCrop = getFinalCrop(s);
- if (!finalCrop.isEmpty()) {
- boundPoint(<, finalCrop);
- boundPoint(&lb, finalCrop);
- boundPoint(&rb, finalCrop);
- boundPoint(&rt, finalCrop);
- }
-
- Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+ renderengine::Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
position[0] = renderAreaTransform.transform(lt);
position[1] = renderAreaTransform.transform(lb);
position[2] = renderAreaTransform.transform(rb);
position[3] = renderAreaTransform.transform(rt);
- for (size_t i = 0; i < 4; i++) {
- position[i].y = height - position[i].y;
- }
}
bool Layer::isSecure() const {
@@ -1291,20 +1219,6 @@
return true;
}
-bool Layer::setFinalCrop_legacy(const Rect& crop, bool immediate) {
- if (mCurrentState.requestedFinalCrop_legacy == crop) return false;
- mCurrentState.sequence++;
- mCurrentState.requestedFinalCrop_legacy = crop;
- if (immediate && !mFreezeGeometryUpdates) {
- mCurrentState.finalCrop_legacy = crop;
- }
- mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate;
-
- mCurrentState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
bool Layer::setOverrideScalingMode(int32_t scalingMode) {
if (scalingMode == mOverrideScalingMode) return false;
mOverrideScalingMode = scalingMode;
@@ -1416,7 +1330,6 @@
info.mWidth = ds.active_legacy.w;
info.mHeight = ds.active_legacy.h;
info.mCrop = ds.crop_legacy;
- info.mFinalCrop = ds.finalCrop_legacy;
info.mColor = ds.color;
info.mFlags = ds.flags;
info.mPixelFormat = getPixelFormat();
@@ -1954,7 +1867,6 @@
size->set_h(state.active_legacy.h);
LayerProtoHelper::writeToProto(state.crop_legacy, layerInfo->mutable_crop());
- LayerProtoHelper::writeToProto(state.finalCrop_legacy, layerInfo->mutable_final_crop());
layerInfo->set_is_opaque(isOpaque(state));
layerInfo->set_invalidate(contentDirty);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 604ec65..9bd28b8 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -129,10 +129,6 @@
Rect crop_legacy;
Rect requestedCrop_legacy;
- // finalCrop is expressed in display space coordinate.
- Rect finalCrop_legacy;
- Rect requestedFinalCrop_legacy;
-
// If set, defers this state update until the identified Layer
// receives a frame with the given frameNumber
wp<Layer> barrierLayer_legacy;
@@ -225,8 +221,6 @@
virtual bool setPosition(float x, float y, bool immediate);
// Buffer space
virtual bool setCrop_legacy(const Rect& crop, bool immediate);
- // Parent buffer space/display space
- virtual bool setFinalCrop_legacy(const Rect& crop, bool immediate);
// TODO(b/38182121): Could we eliminate the various latching modes by
// using the layer hierarchy?
@@ -284,7 +278,8 @@
return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
}
- void computeGeometry(const RenderArea& renderArea, Mesh& mesh, bool useIdentityTransform) const;
+ void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh,
+ bool useIdentityTransform) const;
FloatRect computeBounds(const Region& activeTransparentRegion) const;
FloatRect computeBounds() const;
@@ -350,7 +345,6 @@
return s.activeTransparentRegion_legacy;
}
virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
- virtual Rect getFinalCrop(const Layer::State& s) const { return s.finalCrop_legacy; }
protected:
/*
@@ -413,7 +407,6 @@
*/
void draw(const RenderArea& renderArea, const Region& clip);
void draw(const RenderArea& renderArea, bool useIdentityTransform);
- void draw(const RenderArea& renderArea);
/*
* doTransaction - process the transaction. This is a good place to figure
@@ -511,11 +504,6 @@
// -----------------------------------------------------------------------
- void clearWithOpenGL(const RenderArea& renderArea) const;
- void setFiltering(bool filtering);
- bool getFiltering() const;
-
-
inline const State& getDrawingState() const { return mDrawingState; }
inline const State& getCurrentState() const { return mCurrentState; }
inline State& getCurrentState() { return mCurrentState; }
@@ -731,8 +719,6 @@
int32_t mOverrideScalingMode;
std::atomic<uint64_t> mCurrentFrameNumber;
bool mFrameLatencyNeeded;
- // Whether filtering is forced on or not
- bool mFiltering;
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering;
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
index f389b57..da98bf5 100644
--- a/services/surfaceflinger/LayerBE.cpp
+++ b/services/surfaceflinger/LayerBE.cpp
@@ -30,14 +30,14 @@
LayerBE::LayerBE(Layer* layer, std::string layerName)
: mLayer(layer),
- mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
+ mMesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2, 2) {
compositionInfo.layer = std::make_shared<LayerBE>(*this);
compositionInfo.layerName = layerName;
}
LayerBE::LayerBE(const LayerBE& layer)
: mLayer(layer.mLayer),
- mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
+ mMesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2, 2) {
compositionInfo.layer = layer.compositionInfo.layer;
compositionInfo.layerName = layer.mLayer->getName().string();
}
@@ -48,7 +48,7 @@
}
}
-void LayerBE::clear(RE::RenderEngine& engine) {
+void LayerBE::clear(renderengine::RenderEngine& engine) {
engine.setupFillWithColor(0, 0, 0, 0);
engine.drawMesh(mMesh);
}
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 531cdcd..f5150a7 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -91,13 +91,13 @@
explicit LayerBE(const LayerBE& layer);
void onLayerDisplayed(const sp<Fence>& releaseFence);
- void clear(RE::RenderEngine& renderEngine);
- Mesh& getMesh() { return mMesh; }
+ void clear(renderengine::RenderEngine& renderEngine);
+ renderengine::Mesh& getMesh() { return mMesh; }
private:
Layer*const mLayer;
// The mesh used to draw the layer in GLES composition mode
- Mesh mMesh;
+ renderengine::Mesh mMesh;
// HWC items, accessed from the main thread
struct HWCInfo {
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 136cdc0..72abea8 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -90,11 +90,6 @@
mCurrent.crop_legacy = mFront.requestedCrop_legacy;
mRecomputeVisibleRegions = true;
}
- if (mFront.finalCrop_legacy != mFront.requestedFinalCrop_legacy) {
- mFront.finalCrop_legacy = mFront.requestedFinalCrop_legacy;
- mCurrent.finalCrop_legacy = mFront.requestedFinalCrop_legacy;
- mRecomputeVisibleRegions = true;
- }
}
ALOGD_IF(DEBUG_RESIZE,
diff --git a/services/surfaceflinger/RenderEngine/Android.bp b/services/surfaceflinger/RenderEngine/Android.bp
index 13752f2..064eb17 100644
--- a/services/surfaceflinger/RenderEngine/Android.bp
+++ b/services/surfaceflinger/RenderEngine/Android.bp
@@ -41,18 +41,25 @@
name: "librenderengine_sources",
srcs: [
"Description.cpp",
- "GLES20RenderEngine.cpp",
- "GLExtensions.cpp",
- "Image.cpp",
"Mesh.cpp",
- "Program.cpp",
- "ProgramCache.cpp",
"RenderEngine.cpp",
- "Surface.cpp",
"Texture.cpp",
],
}
+filegroup {
+ name: "librenderengine_gl_sources",
+ srcs: [
+ "gl/GLES20RenderEngine.cpp",
+ "gl/GLExtensions.cpp",
+ "gl/GLFramebuffer.cpp",
+ "gl/GLImage.cpp",
+ "gl/GLSurface.cpp",
+ "gl/Program.cpp",
+ "gl/ProgramCache.cpp",
+ ],
+}
+
cc_library_static {
name: "librenderengine",
defaults: ["librenderengine_defaults"],
@@ -68,6 +75,7 @@
],
srcs: [
":librenderengine_sources",
+ ":librenderengine_gl_sources",
],
lto: {
thin: true,
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index d5f2103..b7522da 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include <renderengine/Description.h>
+#include <renderengine/private/Description.h>
#include <stdint.h>
-#include <string.h>
#include <utils/TypeHelpers.h>
namespace android {
+namespace renderengine {
void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
mPremultipliedAlpha = premultipliedAlpha;
@@ -95,4 +95,5 @@
mDisplayMaxLuminance = maxLuminance;
}
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
index 43852eb..5a3c2c8 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
namespace android {
+namespace renderengine {
Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize)
: mVertexCount(vertexCount),
@@ -94,4 +95,5 @@
return mStride;
}
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 594b1ed..e94200e 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -16,29 +16,30 @@
#include <renderengine/RenderEngine.h>
+#include <vector>
+
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
#include <log/log.h>
#include <private/gui/SyncFeatures.h>
-#include <renderengine/GLES20RenderEngine.h>
-#include <renderengine/GLExtensions.h>
#include <renderengine/Image.h>
#include <renderengine/Mesh.h>
#include <renderengine/Surface.h>
#include <ui/Rect.h>
#include <ui/Region.h>
-
-#include <vector>
+#include <utils/KeyedVector.h>
+#include "gl/GLES20RenderEngine.h"
+#include "gl/GLExtensions.h"
+#include "gl/ProgramCache.h"
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
+using namespace android::renderengine::gl;
extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-// ---------------------------------------------------------------------------
namespace android {
-namespace RE {
-// ---------------------------------------------------------------------------
+namespace renderengine {
RenderEngine::~RenderEngine() = default;
@@ -183,133 +184,6 @@
return SyncFeatures::getInstance().useWaitSync();
}
-bool RenderEngine::isCurrent() const {
- return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
-}
-
-std::unique_ptr<RE::Surface> RenderEngine::createSurface() {
- return std::make_unique<Surface>(*this);
-}
-
-std::unique_ptr<RE::Image> RenderEngine::createImage() {
- return std::make_unique<Image>(*this);
-}
-
-bool RenderEngine::setCurrentSurface(const android::RE::Surface& surface) {
- // Note: RE::Surface is an abstract interface. This implementation only ever
- // creates RE::impl::Surface's, so it is safe to just cast to the actual
- // type.
- return setCurrentSurface(static_cast<const android::RE::impl::Surface&>(surface));
-}
-
-bool RenderEngine::setCurrentSurface(const android::RE::impl::Surface& surface) {
- bool success = true;
- EGLSurface eglSurface = surface.getEGLSurface();
- if (eglSurface != eglGetCurrentSurface(EGL_DRAW)) {
- success = eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext) == EGL_TRUE;
- if (success && surface.getAsync()) {
- eglSwapInterval(mEGLDisplay, 0);
- }
- }
-
- return success;
-}
-
-void RenderEngine::resetCurrentSurface() {
- eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-}
-
-base::unique_fd RenderEngine::flush() {
- if (!GLExtensions::getInstance().hasNativeFenceSync()) {
- return base::unique_fd();
- }
-
- EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
- if (sync == EGL_NO_SYNC_KHR) {
- ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
- return base::unique_fd();
- }
-
- // native fence fd will not be populated until flush() is done.
- glFlush();
-
- // get the fence fd
- base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
- eglDestroySyncKHR(mEGLDisplay, sync);
- if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
- ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
- }
-
- return fenceFd;
-}
-
-bool RenderEngine::finish() {
- if (!GLExtensions::getInstance().hasFenceSync()) {
- ALOGW("no synchronization support");
- return false;
- }
-
- EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr);
- if (sync == EGL_NO_SYNC_KHR) {
- ALOGW("failed to create EGL fence sync: %#x", eglGetError());
- return false;
- }
-
- EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
- 2000000000 /*2 sec*/);
- EGLint error = eglGetError();
- eglDestroySyncKHR(mEGLDisplay, sync);
- if (result != EGL_CONDITION_SATISFIED_KHR) {
- if (result == EGL_TIMEOUT_EXPIRED_KHR) {
- ALOGW("fence wait timed out");
- } else {
- ALOGW("error waiting on EGL fence: %#x", error);
- }
- return false;
- }
-
- return true;
-}
-
-bool RenderEngine::waitFence(base::unique_fd fenceFd) {
- if (!GLExtensions::getInstance().hasNativeFenceSync() ||
- !GLExtensions::getInstance().hasWaitSync()) {
- return false;
- }
-
- EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
- EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
- if (sync == EGL_NO_SYNC_KHR) {
- ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
- return false;
- }
-
- // fenceFd is now owned by EGLSync
- (void)fenceFd.release();
-
- // XXX: The spec draft is inconsistent as to whether this should return an
- // EGLint or void. Ignore the return value for now, as it's not strictly
- // needed.
- eglWaitSyncKHR(mEGLDisplay, sync, 0);
- EGLint error = eglGetError();
- eglDestroySyncKHR(mEGLDisplay, sync);
- if (error != EGL_SUCCESS) {
- ALOGE("failed to wait for EGL native fence sync: %#x", error);
- return false;
- }
-
- return true;
-}
-
-void RenderEngine::checkErrors() const {
- do {
- // there could be more than one error flag
- GLenum error = glGetError();
- if (error == GL_NO_ERROR) break;
- ALOGE("GL error 0x%04x", int(error));
- } while (true);
-}
-
RenderEngine::GlesVersion RenderEngine::parseGlesVersion(const char* str) {
int major, minor;
if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) {
@@ -328,72 +202,6 @@
return GLES_VERSION_1_0;
}
-void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, float red,
- float green, float blue, float alpha) {
- size_t c;
- Rect const* r = region.getArray(&c);
- Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
- Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
- for (size_t i = 0; i < c; i++, r++) {
- position[i * 6 + 0].x = r->left;
- position[i * 6 + 0].y = height - r->top;
- position[i * 6 + 1].x = r->left;
- position[i * 6 + 1].y = height - r->bottom;
- position[i * 6 + 2].x = r->right;
- position[i * 6 + 2].y = height - r->bottom;
- position[i * 6 + 3].x = r->left;
- position[i * 6 + 3].y = height - r->top;
- position[i * 6 + 4].x = r->right;
- position[i * 6 + 4].y = height - r->bottom;
- position[i * 6 + 5].x = r->right;
- position[i * 6 + 5].y = height - r->top;
- }
- setupFillWithColor(red, green, blue, alpha);
- drawMesh(mesh);
-}
-
-void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
- glClearColor(red, green, blue, alpha);
- glClear(GL_COLOR_BUFFER_BIT);
-}
-
-void RenderEngine::setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
- glScissor(left, bottom, right, top);
- glEnable(GL_SCISSOR_TEST);
-}
-
-void RenderEngine::disableScissor() {
- glDisable(GL_SCISSOR_TEST);
-}
-
-void RenderEngine::genTextures(size_t count, uint32_t* names) {
- glGenTextures(count, names);
-}
-
-void RenderEngine::deleteTextures(size_t count, uint32_t const* names) {
- glDeleteTextures(count, names);
-}
-
-void RenderEngine::bindExternalTextureImage(uint32_t texName, const android::RE::Image& image) {
- // Note: RE::Image is an abstract interface. This implementation only ever
- // creates RE::impl::Image's, so it is safe to just cast to the actual type.
- return bindExternalTextureImage(texName, static_cast<const android::RE::impl::Image&>(image));
-}
-
-void RenderEngine::bindExternalTextureImage(uint32_t texName,
- const android::RE::impl::Image& image) {
- const GLenum target = GL_TEXTURE_EXTERNAL_OES;
-
- glBindTexture(target, texName);
- if (image.getEGLImage() != EGL_NO_IMAGE_KHR) {
- glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(image.getEGLImage()));
- }
-}
-
-void RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) {
- glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
-}
-
void RenderEngine::dump(String8& result) {
const GLExtensions& extensions = GLExtensions::getInstance();
@@ -405,45 +213,6 @@
result.appendFormat("%s\n", extensions.getExtensions());
}
-// ---------------------------------------------------------------------------
-
-void RenderEngine::bindNativeBufferAsFrameBuffer(ANativeWindowBuffer* buffer,
- RE::BindNativeBufferAsFramebuffer* bindHelper) {
- bindHelper->mImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
- buffer, nullptr);
- if (bindHelper->mImage == EGL_NO_IMAGE_KHR) {
- bindHelper->mStatus = NO_MEMORY;
- return;
- }
-
- uint32_t glStatus;
- bindImageAsFramebuffer(bindHelper->mImage, &bindHelper->mTexName, &bindHelper->mFbName,
- &glStatus);
-
- ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
- glStatus);
-
- bindHelper->mStatus = glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
-}
-
-void RenderEngine::unbindNativeBufferAsFrameBuffer(RE::BindNativeBufferAsFramebuffer* bindHelper) {
- if (bindHelper->mImage == EGL_NO_IMAGE_KHR) {
- return;
- }
-
- // back to main framebuffer
- unbindFramebuffer(bindHelper->mTexName, bindHelper->mFbName);
- eglDestroyImageKHR(mEGLDisplay, bindHelper->mImage);
-
- // Workaround for b/77935566 to force the EGL driver to release the
- // screenshot buffer
- setScissor(0, 0, 0, 0);
- clearWithColor(0.0, 0.0, 0.0, 0.0);
- disableScissor();
-}
-
-// ---------------------------------------------------------------------------
-
static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
EGLint wanted, EGLConfig* outConfig) {
EGLint numConfigs = -1, n = 0;
@@ -594,12 +363,6 @@
return config;
}
-void RenderEngine::primeCache() const {
- ProgramCache::getInstance().primeCache(mFeatureFlags & USE_COLOR_MANAGEMENT);
-}
-
-// ---------------------------------------------------------------------------
-
-} // namespace impl
-} // namespace RE
-} // namespace android
+} // namespace impl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Texture.cpp b/services/surfaceflinger/RenderEngine/Texture.cpp
index c07ba08..5eabbcf 100644
--- a/services/surfaceflinger/RenderEngine/Texture.cpp
+++ b/services/surfaceflinger/RenderEngine/Texture.cpp
@@ -16,9 +16,8 @@
#include <renderengine/Texture.h>
-#include <string.h>
-
namespace android {
+namespace renderengine {
Texture::Texture()
: mTextureName(0), mTextureTarget(TEXTURE_2D), mWidth(0), mHeight(0), mFiltering(false) {}
@@ -74,4 +73,5 @@
return mHeight;
}
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
similarity index 66%
rename from services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
rename to services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
index 617ba76..61df675 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
@@ -19,28 +19,31 @@
#define LOG_TAG "RenderEngine"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <renderengine/GLES20RenderEngine.h>
+#include "GLES20RenderEngine.h"
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <renderengine/Description.h>
-#include <renderengine/Mesh.h>
-#include <renderengine/Program.h>
-#include <renderengine/ProgramCache.h>
-#include <renderengine/Texture.h>
-#include <ui/ColorSpace.h>
-#include <ui/DebugUtils.h>
-#include <ui/Rect.h>
-#include <utils/String8.h>
-#include <utils/Trace.h>
-
-#include <cutils/compiler.h>
#include <math.h>
-
#include <fstream>
#include <sstream>
-// ---------------------------------------------------------------------------
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <cutils/compiler.h>
+#include <renderengine/Mesh.h>
+#include <renderengine/Texture.h>
+#include <renderengine/private/Description.h>
+#include <ui/ColorSpace.h>
+#include <ui/DebugUtils.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+#include "GLExtensions.h"
+#include "GLFramebuffer.h"
+#include "GLImage.h"
+#include "GLSurface.h"
+#include "Program.h"
+#include "ProgramCache.h"
+
bool checkGlError(const char* op, int lineNumber) {
bool errorFound = false;
GLint error = glGetError();
@@ -100,11 +103,9 @@
file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size());
}
-// ---------------------------------------------------------------------------
namespace android {
-namespace RE {
-namespace impl {
-// ---------------------------------------------------------------------------
+namespace renderengine {
+namespace gl {
using ui::Dataspace;
@@ -155,30 +156,247 @@
GLES20RenderEngine::~GLES20RenderEngine() {}
-size_t GLES20RenderEngine::getMaxTextureSize() const {
- return mMaxTextureSize;
+std::unique_ptr<Framebuffer> GLES20RenderEngine::createFramebuffer() {
+ return std::make_unique<GLFramebuffer>(*this);
}
-size_t GLES20RenderEngine::getMaxViewportDims() const {
- return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1];
+std::unique_ptr<Surface> GLES20RenderEngine::createSurface() {
+ return std::make_unique<GLSurface>(*this);
+}
+
+std::unique_ptr<Image> GLES20RenderEngine::createImage() {
+ return std::make_unique<GLImage>(*this);
+}
+
+void GLES20RenderEngine::primeCache() const {
+ ProgramCache::getInstance().primeCache(mFeatureFlags & USE_COLOR_MANAGEMENT);
+}
+
+bool GLES20RenderEngine::isCurrent() const {
+ return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
+}
+
+bool GLES20RenderEngine::setCurrentSurface(const Surface& surface) {
+ // Surface is an abstract interface. GLES20RenderEngine only ever
+ // creates GLSurface's, so it is safe to just cast to the actual
+ // type.
+ bool success = true;
+ const GLSurface& glSurface = static_cast<const GLSurface&>(surface);
+ EGLSurface eglSurface = glSurface.getEGLSurface();
+ if (eglSurface != eglGetCurrentSurface(EGL_DRAW)) {
+ success = eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext) == EGL_TRUE;
+ if (success && glSurface.getAsync()) {
+ eglSwapInterval(mEGLDisplay, 0);
+ }
+ }
+ return success;
+}
+
+void GLES20RenderEngine::resetCurrentSurface() {
+ eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
+
+base::unique_fd GLES20RenderEngine::flush() {
+ if (!GLExtensions::getInstance().hasNativeFenceSync()) {
+ return base::unique_fd();
+ }
+
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
+ return base::unique_fd();
+ }
+
+ // native fence fd will not be populated until flush() is done.
+ glFlush();
+
+ // get the fence fd
+ base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
+ }
+
+ return fenceFd;
+}
+
+bool GLES20RenderEngine::finish() {
+ if (!GLExtensions::getInstance().hasFenceSync()) {
+ ALOGW("no synchronization support");
+ return false;
+ }
+
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGW("failed to create EGL fence sync: %#x", eglGetError());
+ return false;
+ }
+
+ EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+ 2000000000 /*2 sec*/);
+ EGLint error = eglGetError();
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (result != EGL_CONDITION_SATISFIED_KHR) {
+ if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ALOGW("fence wait timed out");
+ } else {
+ ALOGW("error waiting on EGL fence: %#x", error);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool GLES20RenderEngine::waitFence(base::unique_fd fenceFd) {
+ if (!GLExtensions::getInstance().hasNativeFenceSync() ||
+ !GLExtensions::getInstance().hasWaitSync()) {
+ return false;
+ }
+
+ EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
+ return false;
+ }
+
+ // fenceFd is now owned by EGLSync
+ (void)fenceFd.release();
+
+ // XXX: The spec draft is inconsistent as to whether this should return an
+ // EGLint or void. Ignore the return value for now, as it's not strictly
+ // needed.
+ eglWaitSyncKHR(mEGLDisplay, sync, 0);
+ EGLint error = eglGetError();
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (error != EGL_SUCCESS) {
+ ALOGE("failed to wait for EGL native fence sync: %#x", error);
+ return false;
+ }
+
+ return true;
+}
+
+void GLES20RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, float red,
+ float green, float blue, float alpha) {
+ size_t c;
+ Rect const* r = region.getArray(&c);
+ Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
+ Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+ for (size_t i = 0; i < c; i++, r++) {
+ position[i * 6 + 0].x = r->left;
+ position[i * 6 + 0].y = height - r->top;
+ position[i * 6 + 1].x = r->left;
+ position[i * 6 + 1].y = height - r->bottom;
+ position[i * 6 + 2].x = r->right;
+ position[i * 6 + 2].y = height - r->bottom;
+ position[i * 6 + 3].x = r->left;
+ position[i * 6 + 3].y = height - r->top;
+ position[i * 6 + 4].x = r->right;
+ position[i * 6 + 4].y = height - r->bottom;
+ position[i * 6 + 5].x = r->right;
+ position[i * 6 + 5].y = height - r->top;
+ }
+ setupFillWithColor(red, green, blue, alpha);
+ drawMesh(mesh);
+}
+
+void GLES20RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
+ glClearColor(red, green, blue, alpha);
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+void GLES20RenderEngine::setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
+ glScissor(left, bottom, right, top);
+ glEnable(GL_SCISSOR_TEST);
+}
+
+void GLES20RenderEngine::disableScissor() {
+ glDisable(GL_SCISSOR_TEST);
+}
+
+void GLES20RenderEngine::genTextures(size_t count, uint32_t* names) {
+ glGenTextures(count, names);
+}
+
+void GLES20RenderEngine::deleteTextures(size_t count, uint32_t const* names) {
+ glDeleteTextures(count, names);
+}
+
+void GLES20RenderEngine::bindExternalTextureImage(uint32_t texName,
+ const Image& image) {
+ const GLImage& glImage = static_cast<const GLImage&>(image);
+ const GLenum target = GL_TEXTURE_EXTERNAL_OES;
+
+ glBindTexture(target, texName);
+ if (glImage.getEGLImage() != EGL_NO_IMAGE_KHR) {
+ glEGLImageTargetTexture2DOES(target,
+ static_cast<GLeglImageOES>(glImage.getEGLImage()));
+ }
+}
+
+void GLES20RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) {
+ glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+}
+
+status_t GLES20RenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
+ GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
+ EGLImageKHR eglImage = glFramebuffer->getEGLImage();
+ uint32_t textureName = glFramebuffer->getTextureName();
+ uint32_t framebufferName = glFramebuffer->getFramebufferName();
+
+ // Bind the texture and turn our EGLImage into a texture
+ glBindTexture(GL_TEXTURE_2D, textureName);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)eglImage);
+
+ // Bind the Framebuffer to render into
+ glBindFramebuffer(GL_FRAMEBUFFER, framebufferName);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, textureName, 0);
+
+ mRenderToFbo = true;
+
+ uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES,
+ "glCheckFramebufferStatusOES error %d", glStatus);
+
+ return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
+}
+
+void GLES20RenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
+ mRenderToFbo = false;
+
+ // back to main framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // Workaround for b/77935566 to force the EGL driver to release the
+ // screenshot buffer
+ setScissor(0, 0, 0, 0);
+ clearWithColor(0.0, 0.0, 0.0, 0.0);
+ disableScissor();
+}
+
+void GLES20RenderEngine::checkErrors() const {
+ do {
+ // there could be more than one error flag
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) break;
+ ALOGE("GL error 0x%04x", int(error));
+ } while (true);
}
void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
- size_t hwh, bool yswap,
ui::Transform::orientation_flags rotation) {
int32_t l = sourceCrop.left;
int32_t r = sourceCrop.right;
-
- // In GL, (0, 0) is the bottom-left corner, so flip y coordinates
- int32_t t = hwh - sourceCrop.top;
- int32_t b = hwh - sourceCrop.bottom;
-
- mat4 m;
- if (yswap) {
- m = mat4::ortho(l, r, t, b, 0, 1);
- } else {
- m = mat4::ortho(l, r, b, t, 0, 1);
+ int32_t b = sourceCrop.bottom;
+ int32_t t = sourceCrop.top;
+ if (mRenderToFbo) {
+ std::swap(t, b);
}
+ mat4 m = mat4::ortho(l, r, b, t, 0, 1);
// Apply custom rotation to the projection.
float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
@@ -272,30 +490,6 @@
glDisable(GL_BLEND);
}
-void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName,
- uint32_t* fbName, uint32_t* status) {
- GLuint tname, name;
- // turn our EGLImage into a texture
- glGenTextures(1, &tname);
- glBindTexture(GL_TEXTURE_2D, tname);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
-
- // create a Framebuffer Object to render into
- glGenFramebuffers(1, &name);
- glBindFramebuffer(GL_FRAMEBUFFER, name);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0);
-
- *status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- *texName = tname;
- *fbName = name;
-}
-
-void GLES20RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) {
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- glDeleteFramebuffers(1, &fbName);
- glDeleteTextures(1, &texName);
-}
-
void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
mState.setPremultipliedAlpha(true);
mState.setOpaque(false);
@@ -429,6 +623,14 @@
}
}
+size_t GLES20RenderEngine::getMaxTextureSize() const {
+ return mMaxTextureSize;
+}
+
+size_t GLES20RenderEngine::getMaxViewportDims() const {
+ return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1];
+}
+
void GLES20RenderEngine::dump(String8& result) {
RenderEngine::dump(result);
result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
@@ -463,12 +665,6 @@
return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
}
-// ---------------------------------------------------------------------------
-} // namespace impl
-} // namespace RE
-} // namespace android
-// ---------------------------------------------------------------------------
-
-#if defined(__gl_h_)
-#error "don't include gl/gl.h in this file"
-#endif
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
new file mode 100644
index 0000000..04dc1b1
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2013 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 SF_GLES20RENDERENGINE_H_
+#define SF_GLES20RENDERENGINE_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <GLES2/gl2.h>
+#include <renderengine/RenderEngine.h>
+#include <renderengine/private/Description.h>
+
+namespace android {
+
+class String8;
+
+namespace renderengine {
+
+class Mesh;
+class Texture;
+
+namespace gl {
+
+class GLImage;
+class GLSurface;
+
+class GLES20RenderEngine : public impl::RenderEngine {
+public:
+ GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
+ ~GLES20RenderEngine() override;
+
+ std::unique_ptr<Framebuffer> createFramebuffer() override;
+ std::unique_ptr<Surface> createSurface() override;
+ std::unique_ptr<Image> createImage() override;
+
+ void primeCache() const override;
+ bool isCurrent() const override;
+ bool setCurrentSurface(const Surface& surface) override;
+ void resetCurrentSurface() override;
+ base::unique_fd flush() override;
+ bool finish() override;
+ bool waitFence(base::unique_fd fenceFd) override;
+ void clearWithColor(float red, float green, float blue, float alpha) override;
+ void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
+ float blue, float alpha) override;
+ void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) override;
+ void disableScissor() override;
+ void genTextures(size_t count, uint32_t* names) override;
+ void deleteTextures(size_t count, uint32_t const* names) override;
+ void bindExternalTextureImage(uint32_t texName, const Image& image) override;
+ void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) override;
+ status_t bindFrameBuffer(Framebuffer* framebuffer) override;
+ void unbindFrameBuffer(Framebuffer* framebuffer) override;
+ void checkErrors() const override;
+
+protected:
+ void dump(String8& result) override;
+ void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+ ui::Transform::orientation_flags rotation) override;
+ void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+ const half4& color) override;
+
+ // Color management related functions and state
+ void setSourceY410BT2020(bool enable) override;
+ void setSourceDataSpace(ui::Dataspace source) override;
+ void setOutputDataSpace(ui::Dataspace dataspace) override;
+ void setDisplayMaxLuminance(const float maxLuminance) override;
+
+ void setupLayerTexturing(const Texture& texture) override;
+ void setupLayerBlackedOut() override;
+ void setupFillWithColor(float r, float g, float b, float a) override;
+ void setupColorTransform(const mat4& colorTransform) override;
+ void disableTexturing() override;
+ void disableBlending() override;
+
+ void drawMesh(const Mesh& mesh) override;
+
+ size_t getMaxTextureSize() const override;
+ size_t getMaxViewportDims() const override;
+
+private:
+ // A data space is considered HDR data space if it has BT2020 color space
+ // with PQ or HLG transfer function.
+ bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
+ bool needsXYZTransformMatrix() const;
+
+ GLuint mProtectedTexName;
+ GLint mMaxViewportDims[2];
+ GLint mMaxTextureSize;
+ GLuint mVpWidth;
+ GLuint mVpHeight;
+ Description mState;
+
+ mat4 mSrgbToDisplayP3;
+ mat4 mDisplayP3ToSrgb;
+ mat3 mSrgbToXyz;
+ mat3 mBt2020ToXyz;
+ mat3 mDisplayP3ToXyz;
+ mat4 mXyzToSrgb;
+ mat4 mXyzToDisplayP3;
+ mat4 mXyzToBt2020;
+
+ bool mRenderToFbo = false;
+
+ // Current dataspace of layer being rendered
+ ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
+
+ // Current output dataspace of the render engine
+ ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN;
+
+ // Whether device supports color management, currently color management
+ // supports sRGB, DisplayP3 color spaces.
+ const bool mUseColorManagement = false;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
+
+#endif /* SF_GLES20RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
similarity index 92%
rename from services/surfaceflinger/RenderEngine/GLExtensions.cpp
rename to services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
index b4fb2a1..6f50ea7 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
@@ -14,16 +14,17 @@
* limitations under the License.
*/
-#include <renderengine/GLExtensions.h>
+#include "GLExtensions.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-namespace android {
-// ---------------------------------------------------------------------------
+ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::gl::GLExtensions)
-ANDROID_SINGLETON_STATIC_INSTANCE(GLExtensions)
+namespace android {
+namespace renderengine {
+namespace gl {
SortedVector<String8> GLExtensions::parseExtensionString(char const* extensions) {
SortedVector<String8> list;
@@ -120,5 +121,6 @@
return mEGLExtensionList.indexOf(s) >= 0;
}
-// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/GLExtensions.h b/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
similarity index 93%
rename from services/surfaceflinger/RenderEngine/include/renderengine/GLExtensions.h
rename to services/surfaceflinger/RenderEngine/gl/GLExtensions.h
index 1ff0d24..efdd8b7 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
@@ -24,13 +24,13 @@
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
-
#include <utils/Singleton.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
namespace android {
-// ---------------------------------------------------------------------------
+namespace renderengine {
+namespace gl {
class GLExtensions : public Singleton<GLExtensions> {
friend class Singleton<GLExtensions>;
@@ -82,7 +82,8 @@
bool hasEGLExtension(char const* extension) const;
};
-// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
#endif // ANDROID_SF_GLEXTENSION_H
diff --git a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp b/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp
new file mode 100644
index 0000000..6aca1c8
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include "GLFramebuffer.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include "GLES20RenderEngine.h"
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+GLFramebuffer::GLFramebuffer(const GLES20RenderEngine& engine)
+ : mEGLDisplay(engine.getEGLDisplay()),
+ mEGLImage(EGL_NO_IMAGE_KHR) {
+ glGenTextures(1, &mTextureName);
+ glGenFramebuffers(1, &mFramebufferName);
+}
+
+GLFramebuffer::~GLFramebuffer() {
+ glDeleteFramebuffers(1, &mFramebufferName);
+ glDeleteTextures(1, &mTextureName);
+ eglDestroyImageKHR(mEGLDisplay, mEGLImage);
+}
+
+bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) {
+ if (mEGLImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mEGLDisplay, mEGLImage);
+ mEGLImage = EGL_NO_IMAGE_KHR;
+ }
+
+ if (nativeBuffer) {
+ mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID,
+ nativeBuffer, nullptr);
+ if (mEGLImage == EGL_NO_IMAGE_KHR) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h b/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h
new file mode 100644
index 0000000..90b2248
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <renderengine/Framebuffer.h>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLES20RenderEngine;
+
+class GLFramebuffer : public renderengine::Framebuffer {
+public:
+ explicit GLFramebuffer(const GLES20RenderEngine& engine);
+ ~GLFramebuffer() override;
+
+ bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) override;
+ EGLImageKHR getEGLImage() const { return mEGLImage; }
+ uint32_t getTextureName() const { return mTextureName; }
+ uint32_t getFramebufferName() const { return mFramebufferName; }
+
+private:
+ EGLDisplay mEGLDisplay;
+ EGLImageKHR mEGLImage;
+ uint32_t mTextureName, mFramebufferName;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Image.cpp b/services/surfaceflinger/RenderEngine/gl/GLImage.cpp
similarity index 78%
rename from services/surfaceflinger/RenderEngine/Image.cpp
rename to services/surfaceflinger/RenderEngine/gl/GLImage.cpp
index ee140eb..746f3e7 100644
--- a/services/surfaceflinger/RenderEngine/Image.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLImage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -14,27 +14,17 @@
* limitations under the License.
*/
-#include <renderengine/Image.h>
+#include "GLImage.h"
#include <vector>
#include <log/log.h>
-
-#include <renderengine/GLExtensions.h>
-#include <renderengine/RenderEngine.h>
+#include "GLExtensions.h"
+#include "GLES20RenderEngine.h"
namespace android {
-namespace RE {
-
-Image::~Image() = default;
-
-namespace impl {
-
-Image::Image(const RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
-
-Image::~Image() {
- setNativeWindowBuffer(nullptr, false);
-}
+namespace renderengine {
+namespace gl {
static std::vector<EGLint> buildAttributeList(bool isProtected) {
std::vector<EGLint> attrs;
@@ -53,7 +43,13 @@
return attrs;
}
-bool Image::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) {
+GLImage::GLImage(const GLES20RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
+
+GLImage::~GLImage() {
+ setNativeWindowBuffer(nullptr, false);
+}
+
+bool GLImage::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) {
if (mEGLImage != EGL_NO_IMAGE_KHR) {
if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
ALOGE("failed to destroy image: %#x", eglGetError());
@@ -74,6 +70,6 @@
return true;
}
-} // namespace impl
-} // namespace RE
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLImage.h b/services/surfaceflinger/RenderEngine/gl/GLImage.h
new file mode 100644
index 0000000..f670783
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/gl/GLImage.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <android-base/macros.h>
+#include <renderengine/Image.h>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLES20RenderEngine;
+
+class GLImage : public renderengine::Image {
+public:
+ explicit GLImage(const GLES20RenderEngine& engine);
+ ~GLImage() override;
+
+ bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) override;
+
+ EGLImageKHR getEGLImage() const { return mEGLImage; }
+
+private:
+ EGLDisplay mEGLDisplay;
+ EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR;
+
+ DISALLOW_COPY_AND_ASSIGN(GLImage);
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Surface.cpp b/services/surfaceflinger/RenderEngine/gl/GLSurface.cpp
similarity index 69%
rename from services/surfaceflinger/RenderEngine/Surface.cpp
rename to services/surfaceflinger/RenderEngine/gl/GLSurface.cpp
index 3e98ab4..ff9a252 100644
--- a/services/surfaceflinger/RenderEngine/Surface.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLSurface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -14,32 +14,30 @@
* limitations under the License.
*/
-#include <renderengine/Surface.h>
+#include "GLSurface.h"
#include <log/log.h>
-#include <renderengine/RenderEngine.h>
#include <ui/PixelFormat.h>
+#include "GLES20RenderEngine.h"
namespace android {
-namespace RE {
+namespace renderengine {
+namespace gl {
-Surface::~Surface() = default;
-
-namespace impl {
-
-Surface::Surface(const RenderEngine& engine)
+GLSurface::GLSurface(const GLES20RenderEngine& engine)
: mEGLDisplay(engine.getEGLDisplay()), mEGLConfig(engine.getEGLConfig()) {
// RE does not assume any config when EGL_KHR_no_config_context is supported
if (mEGLConfig == EGL_NO_CONFIG_KHR) {
- mEGLConfig = RenderEngine::chooseEglConfig(mEGLDisplay, PIXEL_FORMAT_RGBA_8888, false);
+ mEGLConfig = GLES20RenderEngine::chooseEglConfig(mEGLDisplay,
+ PIXEL_FORMAT_RGBA_8888, false);
}
}
-Surface::~Surface() {
+GLSurface::~GLSurface() {
setNativeWindow(nullptr);
}
-void Surface::setNativeWindow(ANativeWindow* window) {
+void GLSurface::setNativeWindow(ANativeWindow* window) {
if (mEGLSurface != EGL_NO_SURFACE) {
eglDestroySurface(mEGLDisplay, mEGLSurface);
mEGLSurface = EGL_NO_SURFACE;
@@ -51,7 +49,7 @@
}
}
-void Surface::swapBuffers() const {
+void GLSurface::swapBuffers() const {
if (!eglSwapBuffers(mEGLDisplay, mEGLSurface)) {
EGLint error = eglGetError();
@@ -64,7 +62,7 @@
}
}
-EGLint Surface::queryConfig(EGLint attrib) const {
+EGLint GLSurface::queryConfig(EGLint attrib) const {
EGLint value;
if (!eglGetConfigAttrib(mEGLDisplay, mEGLConfig, attrib, &value)) {
value = 0;
@@ -73,7 +71,7 @@
return value;
}
-EGLint Surface::querySurface(EGLint attrib) const {
+EGLint GLSurface::querySurface(EGLint attrib) const {
EGLint value;
if (!eglQuerySurface(mEGLDisplay, mEGLSurface, attrib, &value)) {
value = 0;
@@ -82,30 +80,30 @@
return value;
}
-int32_t Surface::queryRedSize() const {
+int32_t GLSurface::queryRedSize() const {
return queryConfig(EGL_RED_SIZE);
}
-int32_t Surface::queryGreenSize() const {
+int32_t GLSurface::queryGreenSize() const {
return queryConfig(EGL_GREEN_SIZE);
}
-int32_t Surface::queryBlueSize() const {
+int32_t GLSurface::queryBlueSize() const {
return queryConfig(EGL_BLUE_SIZE);
}
-int32_t Surface::queryAlphaSize() const {
+int32_t GLSurface::queryAlphaSize() const {
return queryConfig(EGL_ALPHA_SIZE);
}
-int32_t Surface::queryWidth() const {
+int32_t GLSurface::queryWidth() const {
return querySurface(EGL_WIDTH);
}
-int32_t Surface::queryHeight() const {
+int32_t GLSurface::queryHeight() const {
return querySurface(EGL_HEIGHT);
}
-} // namespace impl
-} // namespace RE
-} // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLSurface.h b/services/surfaceflinger/RenderEngine/gl/GLSurface.h
new file mode 100644
index 0000000..0b89c70
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/gl/GLSurface.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <EGL/egl.h>
+#include <android-base/macros.h>
+#include <renderengine/Surface.h>
+
+struct ANativeWindow;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLES20RenderEngine;
+
+class GLSurface final : public renderengine::Surface {
+public:
+ GLSurface(const GLES20RenderEngine& engine);
+ ~GLSurface() override;
+
+ // renderengine::Surface implementation
+ void setCritical(bool enable) override { mCritical = enable; }
+ void setAsync(bool enable) override { mAsync = enable; }
+
+ void setNativeWindow(ANativeWindow* window) override;
+ void swapBuffers() const override;
+
+ int32_t queryRedSize() const override;
+ int32_t queryGreenSize() const override;
+ int32_t queryBlueSize() const override;
+ int32_t queryAlphaSize() const override;
+
+ int32_t queryWidth() const override;
+ int32_t queryHeight() const override;
+
+ bool getAsync() const { return mAsync; }
+ EGLSurface getEGLSurface() const { return mEGLSurface; }
+
+private:
+ EGLint queryConfig(EGLint attrib) const;
+ EGLint querySurface(EGLint attrib) const;
+
+ EGLDisplay mEGLDisplay;
+ EGLConfig mEGLConfig;
+
+ bool mCritical = false;
+ bool mAsync = false;
+
+ ANativeWindow* mWindow = nullptr;
+ EGLSurface mEGLSurface = EGL_NO_SURFACE;
+
+ DISALLOW_COPY_AND_ASSIGN(GLSurface);
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/gl/Program.cpp
similarity index 96%
rename from services/surfaceflinger/RenderEngine/Program.cpp
rename to services/surfaceflinger/RenderEngine/gl/Program.cpp
index 87371dc..c8d6cf9 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/Program.cpp
@@ -14,17 +14,18 @@
* limitations under the License.
*/
-#include <renderengine/Program.h>
+#include "Program.h"
#include <stdint.h>
#include <log/log.h>
#include <math/mat4.h>
-#include <renderengine/Description.h>
-#include <renderengine/ProgramCache.h>
#include <utils/String8.h>
+#include "ProgramCache.h"
namespace android {
+namespace renderengine {
+namespace gl {
Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment)
: mInitialized(false) {
@@ -152,4 +153,6 @@
glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.mProjectionMatrix.asArray());
}
-} /* namespace android */
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Program.h b/services/surfaceflinger/RenderEngine/gl/Program.h
similarity index 92%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Program.h
rename to services/surfaceflinger/RenderEngine/gl/Program.h
index 5e621cb..bb429ef 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Program.h
+++ b/services/surfaceflinger/RenderEngine/gl/Program.h
@@ -20,13 +20,16 @@
#include <stdint.h>
#include <GLES2/gl2.h>
-#include <renderengine/Description.h>
-#include <renderengine/ProgramCache.h>
+#include <renderengine/private/Description.h>
+#include "ProgramCache.h"
namespace android {
class String8;
+namespace renderengine {
+namespace gl {
+
/*
* Abstracts a GLSL program comprising a vertex and fragment shader
*/
@@ -85,6 +88,8 @@
GLint mOutputTransformMatrixLoc;
};
-} /* namespace android */
+} // namespace gl
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_PROGRAM_H */
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
similarity index 98%
rename from services/surfaceflinger/RenderEngine/ProgramCache.cpp
rename to services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
index b7101e0..a19c1f1 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
@@ -16,17 +16,20 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <renderengine/ProgramCache.h>
+#include "ProgramCache.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
-#include <renderengine/Description.h>
-#include <renderengine/Program.h>
+#include <renderengine/private/Description.h>
#include <utils/String8.h>
#include <utils/Trace.h>
+#include "Program.h"
+
+ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::gl::ProgramCache)
namespace android {
-// -----------------------------------------------------------------------------------------------
+namespace renderengine {
+namespace gl {
/*
* A simple formatter class to automatically add the endl and
@@ -73,10 +76,6 @@
return f;
}
-// -----------------------------------------------------------------------------------------------
-
-ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache)
-
ProgramCache::ProgramCache() {}
ProgramCache::~ProgramCache() {}
@@ -685,4 +684,6 @@
}
}
-} /* namespace android */
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/ProgramCache.h b/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
similarity index 96%
rename from services/surfaceflinger/RenderEngine/include/renderengine/ProgramCache.h
rename to services/surfaceflinger/RenderEngine/gl/ProgramCache.h
index a5bee45..ea77a2d 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
@@ -18,17 +18,23 @@
#define SF_RENDER_ENGINE_PROGRAMCACHE_H
#include <GLES2/gl2.h>
-#include <renderengine/Description.h>
+#include <renderengine/private/Description.h>
#include <utils/KeyedVector.h>
#include <utils/Singleton.h>
#include <utils/TypeHelpers.h>
namespace android {
+class String8;
+
+namespace renderengine {
+
class Description;
+
+namespace gl {
+
class Formatter;
class Program;
-class String8;
/*
* This class generates GLSL programs suitable to handle a given
@@ -188,8 +194,11 @@
DefaultKeyedVector<Key, Program*> mCache;
};
-ANDROID_BASIC_TYPES_TRAITS(ProgramCache::Key)
+} // namespace gl
+} // namespace renderengine
-} /* namespace android */
+ANDROID_BASIC_TYPES_TRAITS(renderengine::gl::ProgramCache::Key)
+
+} // namespace android
#endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h b/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
new file mode 100644
index 0000000..6595466
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace renderengine {
+
+class Framebuffer {
+public:
+ virtual ~Framebuffer() = default;
+
+ virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) = 0;
+};
+
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/include/renderengine/GLES20RenderEngine.h
deleted file mode 100644
index 0e9efdb..0000000
--- a/services/surfaceflinger/RenderEngine/include/renderengine/GLES20RenderEngine.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2013 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 SF_GLES20RENDERENGINE_H_
-#define SF_GLES20RENDERENGINE_H_
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <GLES2/gl2.h>
-#include <renderengine/Description.h>
-#include <renderengine/ProgramCache.h>
-#include <renderengine/RenderEngine.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-// ---------------------------------------------------------------------------
-
-class String8;
-class Mesh;
-class Texture;
-
-namespace RE {
-namespace impl {
-
-class GLES20RenderEngine : public RenderEngine {
- GLuint mProtectedTexName;
- GLint mMaxViewportDims[2];
- GLint mMaxTextureSize;
- GLuint mVpWidth;
- GLuint mVpHeight;
-
- struct Group {
- GLuint texture;
- GLuint fbo;
- GLuint width;
- GLuint height;
- mat4 colorTransform;
- };
-
- Description mState;
- Vector<Group> mGroupStack;
-
- virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName,
- uint32_t* status);
- virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName);
-
-public:
- GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
- virtual ~GLES20RenderEngine();
-
-protected:
- virtual void dump(String8& result);
- virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
- bool yswap, ui::Transform::orientation_flags rotation);
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
- const half4& color) override;
-
- // Color management related functions and state
- void setSourceY410BT2020(bool enable) override;
- void setSourceDataSpace(ui::Dataspace source) override;
- void setOutputDataSpace(ui::Dataspace dataspace) override;
- void setDisplayMaxLuminance(const float maxLuminance) override;
-
- virtual void setupLayerTexturing(const Texture& texture);
- virtual void setupLayerBlackedOut();
- virtual void setupFillWithColor(float r, float g, float b, float a);
- virtual void setupColorTransform(const mat4& colorTransform);
- virtual void disableTexturing();
- virtual void disableBlending();
-
- virtual void drawMesh(const Mesh& mesh);
-
- virtual size_t getMaxTextureSize() const;
- virtual size_t getMaxViewportDims() const;
-
- // Current dataspace of layer being rendered
- ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
-
- // Current output dataspace of the render engine
- ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN;
-
- // Whether device supports color management, currently color management
- // supports sRGB, DisplayP3 color spaces.
- const bool mUseColorManagement = false;
- mat4 mSrgbToDisplayP3;
- mat4 mDisplayP3ToSrgb;
- mat3 mSrgbToXyz;
- mat3 mBt2020ToXyz;
- mat3 mDisplayP3ToXyz;
- mat4 mXyzToSrgb;
- mat4 mXyzToDisplayP3;
- mat4 mXyzToBt2020;
-
-private:
- // A data space is considered HDR data space if it has BT2020 color space
- // with PQ or HLG transfer function.
- bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
- bool needsXYZTransformMatrix() const;
-};
-
-// ---------------------------------------------------------------------------
-} // namespace impl
-} // namespace RE
-} // namespace android
-// ---------------------------------------------------------------------------
-
-#endif /* SF_GLES20RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Image.h b/services/surfaceflinger/RenderEngine/include/renderengine/Image.h
index c38fe0a..85ec91a 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Image.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Image.h
@@ -16,45 +16,17 @@
#pragma once
-#include <cstdint>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
struct ANativeWindowBuffer;
namespace android {
-namespace RE {
+namespace renderengine {
class Image {
public:
- virtual ~Image() = 0;
+ virtual ~Image() = default;
virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) = 0;
};
-namespace impl {
+} // namespace renderengine
+} // namespace android
-class RenderEngine;
-
-class Image : public RE::Image {
-public:
- explicit Image(const RenderEngine& engine);
- ~Image() override;
-
- Image(const Image&) = delete;
- Image& operator=(const Image&) = delete;
-
- bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) override;
-
-private:
- // methods internal to RenderEngine
- friend class RenderEngine;
- EGLSurface getEGLImage() const { return mEGLImage; }
-
- EGLDisplay mEGLDisplay;
- EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR;
-};
-
-} // namespace impl
-} // namespace RE
-} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h b/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
index d0a9ac0..39ca2f7 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
@@ -20,6 +20,7 @@
#include <stdint.h>
namespace android {
+namespace renderengine {
class Mesh {
public:
@@ -97,5 +98,6 @@
Primitive mPrimitive;
};
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_MESH_H */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
index 6213784..86a1264 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
@@ -17,15 +17,16 @@
#ifndef SF_RENDERENGINE_H_
#define SF_RENDERENGINE_H_
-#include <memory>
-
#include <stdint.h>
#include <sys/types.h>
+#include <memory>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <android-base/unique_fd.h>
#include <math/mat4.h>
+#include <renderengine/Framebuffer.h>
+#include <renderengine/Image.h>
#include <ui/GraphicTypes.h>
#include <ui/Transform.h>
@@ -33,21 +34,19 @@
struct ANativeWindowBuffer;
-// ---------------------------------------------------------------------------
namespace android {
-// ---------------------------------------------------------------------------
class String8;
class Rect;
class Region;
-class Mesh;
-class Texture;
-namespace RE {
+namespace renderengine {
-class Image;
-class Surface;
class BindNativeBufferAsFramebuffer;
+class Image;
+class Mesh;
+class Surface;
+class Texture;
namespace impl {
class RenderEngine;
@@ -61,8 +60,9 @@
virtual ~RenderEngine() = 0;
- virtual std::unique_ptr<RE::Surface> createSurface() = 0;
- virtual std::unique_ptr<RE::Image> createImage() = 0;
+ virtual std::unique_ptr<Framebuffer> createFramebuffer() = 0;
+ virtual std::unique_ptr<Surface> createSurface() = 0;
+ virtual std::unique_ptr<Image> createImage() = 0;
virtual void primeCache() const = 0;
@@ -73,7 +73,7 @@
virtual bool useWaitSync() const = 0;
virtual bool isCurrent() const = 0;
- virtual bool setCurrentSurface(const RE::Surface& surface) = 0;
+ virtual bool setCurrentSurface(const Surface& surface) = 0;
virtual void resetCurrentSurface() = 0;
// helpers
@@ -97,28 +97,27 @@
virtual void disableScissor() = 0;
virtual void genTextures(size_t count, uint32_t* names) = 0;
virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
- virtual void bindExternalTextureImage(uint32_t texName, const RE::Image& image) = 0;
+ virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
virtual void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) = 0;
- virtual void bindNativeBufferAsFrameBuffer(ANativeWindowBuffer* buffer,
- RE::BindNativeBufferAsFramebuffer* bindHelper) = 0;
- virtual void unbindNativeBufferAsFrameBuffer(RE::BindNativeBufferAsFramebuffer* bindHelper) = 0;
+ // When binding a native buffer, it must be done before setViewportAndProjection
+ // Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
+ virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
+ virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0;
// set-up
- virtual void checkErrors() const;
- virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
- bool yswap, ui::Transform::orientation_flags rotation) = 0;
+ virtual void checkErrors() const = 0;
+ virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+ ui::Transform::orientation_flags rotation) = 0;
virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
const half4& color) = 0;
virtual void setupLayerTexturing(const Texture& texture) = 0;
virtual void setupLayerBlackedOut() = 0;
virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
-
virtual void setupColorTransform(const mat4& /* colorTransform */) = 0;
-
virtual void disableTexturing() = 0;
virtual void disableBlending() = 0;
- // HDR and wide color gamut support
+ // HDR and color management support
virtual void setSourceY410BT2020(bool enable) = 0;
virtual void setSourceDataSpace(ui::Dataspace source) = 0;
virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0;
@@ -135,27 +134,28 @@
class BindNativeBufferAsFramebuffer {
public:
BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer)
- : mEngine(engine) {
- mEngine.bindNativeBufferAsFrameBuffer(buffer, this);
+ : mEngine(engine),
+ mFramebuffer(mEngine.createFramebuffer()),
+ mStatus(NO_ERROR) {
+ mStatus = mFramebuffer->setNativeWindowBuffer(buffer) ?
+ mEngine.bindFrameBuffer(mFramebuffer.get()) : NO_MEMORY;
}
- ~BindNativeBufferAsFramebuffer() { mEngine.unbindNativeBufferAsFrameBuffer(this); }
+ ~BindNativeBufferAsFramebuffer() {
+ mFramebuffer->setNativeWindowBuffer(nullptr);
+ mEngine.unbindFrameBuffer(mFramebuffer.get());
+ }
status_t getStatus() const { return mStatus; }
-protected:
- friend impl::RenderEngine;
-
+private:
RenderEngine& mEngine;
- EGLImageKHR mImage;
- uint32_t mTexName, mFbName;
+ std::unique_ptr<Framebuffer> mFramebuffer;
status_t mStatus;
};
namespace impl {
-class Image;
-class Surface;
-
-class RenderEngine : public RE::RenderEngine {
+class RenderEngine : public renderengine::RenderEngine {
+protected:
enum GlesVersion {
GLES_VERSION_1_0 = 0x10000,
GLES_VERSION_1_1 = 0x10001,
@@ -171,7 +171,6 @@
static bool overrideUseContextPriorityFromConfig(bool useContextPriority);
-protected:
RenderEngine(uint32_t featureFlags);
const uint32_t mFeatureFlags;
@@ -183,73 +182,21 @@
static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
- // RenderEngine interface implementation
-
- std::unique_ptr<RE::Surface> createSurface() override;
- std::unique_ptr<RE::Image> createImage() override;
-
- void primeCache() const override;
-
// dump the extension strings. always call the base class.
void dump(String8& result) override;
bool useNativeFenceSync() const override;
bool useWaitSync() const override;
- bool isCurrent() const;
- bool setCurrentSurface(const RE::Surface& surface) override;
- void resetCurrentSurface() override;
-
- // synchronization
-
- // flush submits RenderEngine command stream for execution and returns a
- // native fence fd that is signaled when the execution has completed. It
- // returns -1 on errors.
- base::unique_fd flush() override;
- // finish waits until RenderEngine command stream has been executed. It
- // returns false on errors.
- bool finish() override;
- // waitFence inserts a wait on an external fence fd to RenderEngine
- // command stream. It returns false on errors.
- bool waitFence(base::unique_fd fenceFd) override;
-
- // helpers
- void clearWithColor(float red, float green, float blue, float alpha) override;
- void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
- float blue, float alpha) override;
-
- // common to all GL versions
- void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) override;
- void disableScissor() override;
- void genTextures(size_t count, uint32_t* names) override;
- void deleteTextures(size_t count, uint32_t const* names) override;
- void bindExternalTextureImage(uint32_t texName, const RE::Image& image) override;
- void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) override;
-
- void checkErrors() const override;
-
void setupColorTransform(const mat4& /* colorTransform */) override {}
// internal to RenderEngine
EGLDisplay getEGLDisplay() const;
EGLConfig getEGLConfig() const;
-
- // Common implementation
- bool setCurrentSurface(const RE::impl::Surface& surface);
- void bindExternalTextureImage(uint32_t texName, const RE::impl::Image& image);
-
- void bindNativeBufferAsFrameBuffer(ANativeWindowBuffer* buffer,
- RE::BindNativeBufferAsFramebuffer* bindHelper) override;
- void unbindNativeBufferAsFrameBuffer(RE::BindNativeBufferAsFramebuffer* bindHelper) override;
-
- // Overriden by each specialization
- virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName,
- uint32_t* status) = 0;
- virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0;
};
-} // namespace impl
-} // namespace RE
-} // namespace android
+} // namespace impl
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Surface.h b/services/surfaceflinger/RenderEngine/include/renderengine/Surface.h
index d4d3d8c..3343e1f 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Surface.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Surface.h
@@ -18,16 +18,14 @@
#include <cstdint>
-#include <EGL/egl.h>
-
struct ANativeWindow;
namespace android {
-namespace RE {
+namespace renderengine {
class Surface {
public:
- virtual ~Surface() = 0;
+ virtual ~Surface() = default;
virtual void setCritical(bool enable) = 0;
virtual void setAsync(bool enable) = 0;
@@ -44,52 +42,5 @@
virtual int32_t queryHeight() const = 0;
};
-namespace impl {
-
-class RenderEngine;
-
-class Surface final : public RE::Surface {
-public:
- Surface(const RenderEngine& engine);
- ~Surface();
-
- Surface(const Surface&) = delete;
- Surface& operator=(const Surface&) = delete;
-
- // RE::Surface implementation
- void setCritical(bool enable) override { mCritical = enable; }
- void setAsync(bool enable) override { mAsync = enable; }
-
- void setNativeWindow(ANativeWindow* window) override;
- void swapBuffers() const override;
-
- int32_t queryRedSize() const override;
- int32_t queryGreenSize() const override;
- int32_t queryBlueSize() const override;
- int32_t queryAlphaSize() const override;
-
- int32_t queryWidth() const override;
- int32_t queryHeight() const override;
-
-private:
- EGLint queryConfig(EGLint attrib) const;
- EGLint querySurface(EGLint attrib) const;
-
- // methods internal to RenderEngine
- friend class RenderEngine;
- bool getAsync() const { return mAsync; }
- EGLSurface getEGLSurface() const { return mEGLSurface; }
-
- EGLDisplay mEGLDisplay;
- EGLConfig mEGLConfig;
-
- bool mCritical = false;
- bool mAsync = false;
-
- ANativeWindow* mWindow = nullptr;
- EGLSurface mEGLSurface = EGL_NO_SURFACE;
-};
-
-} // namespace impl
-} // namespace RE
-} // namespace android
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Texture.h b/services/surfaceflinger/RenderEngine/include/renderengine/Texture.h
index 56b6b31..fb3e0cc 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Texture.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Texture.h
@@ -14,22 +14,17 @@
* limitations under the License.
*/
-#include <math/mat4.h>
-#include <stdint.h>
-
#ifndef SF_RENDER_ENGINE_TEXTURE_H
#define SF_RENDER_ENGINE_TEXTURE_H
+#include <stdint.h>
+
+#include <math/mat4.h>
+
namespace android {
+namespace renderengine {
class Texture {
- uint32_t mTextureName;
- uint32_t mTextureTarget;
- size_t mWidth;
- size_t mHeight;
- bool mFiltering;
- mat4 mTextureMatrix;
-
public:
enum Target { TEXTURE_2D = 0x0DE1, TEXTURE_EXTERNAL = 0x8D65 };
@@ -50,7 +45,16 @@
bool getFiltering() const;
size_t getWidth() const;
size_t getHeight() const;
+
+private:
+ uint32_t mTextureName;
+ uint32_t mTextureTarget;
+ size_t mWidth;
+ size_t mHeight;
+ bool mFiltering;
+ mat4 mTextureMatrix;
};
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_TEXTURE_H */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Description.h b/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
similarity index 93%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Description.h
rename to services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
index 9bc7e1c..a6301ae 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Description.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-#include <GLES2/gl2.h>
-#include <renderengine/Texture.h>
-
#ifndef SF_RENDER_ENGINE_DESCRIPTION_H_
#define SF_RENDER_ENGINE_DESCRIPTION_H_
-namespace android {
+#include <renderengine/Texture.h>
+namespace android {
+namespace renderengine {
+
+namespace gl {
class Program;
+class ProgramCache;
+}
/*
* This holds the state of the rendering engine. This class is used
@@ -63,8 +66,8 @@
void setDisplayMaxLuminance(const float maxLuminance);
private:
- friend class Program;
- friend class ProgramCache;
+ friend class gl::Program;
+ friend class gl::ProgramCache;
// whether textures are premultiplied
bool mPremultipliedAlpha = false;
@@ -94,6 +97,7 @@
mat4 mOutputTransformMatrix;
};
-} /* namespace android */
+} // namespace renderengine
+} // namespace android
#endif /* SF_RENDER_ENGINE_DESCRIPTION_H_ */
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index b84177c..fa2b0a6 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -45,11 +45,27 @@
namespace impl {
+EventThread::EventThread(std::unique_ptr<VSyncSource> src,
+ ResyncWithRateLimitCallback resyncWithRateLimitCallback,
+ InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
+ : EventThread(nullptr, std::move(src), resyncWithRateLimitCallback, interceptVSyncsCallback,
+ threadName) {}
+
EventThread::EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
+ : EventThread(src, nullptr, resyncWithRateLimitCallback, interceptVSyncsCallback,
+ threadName) {}
+
+EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
+ ResyncWithRateLimitCallback resyncWithRateLimitCallback,
+ InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
: mVSyncSource(src),
+ mVSyncSourceUnique(std::move(uniqueSrc)),
mResyncWithRateLimitCallback(resyncWithRateLimitCallback),
mInterceptVSyncsCallback(interceptVSyncsCallback) {
+ if (src == nullptr) {
+ mVSyncSource = mVSyncSourceUnique.get();
+ }
for (auto& event : mVSyncEvent) {
event.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
event.header.id = 0;
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index a0262b2..127891e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -108,8 +108,12 @@
using ResyncWithRateLimitCallback = std::function<void()>;
using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
+ // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
+ EventThread(std::unique_ptr<VSyncSource> src,
+ ResyncWithRateLimitCallback resyncWithRateLimitCallback,
+ InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
~EventThread();
sp<BnDisplayEventConnection> createEventConnection() const override;
@@ -134,6 +138,11 @@
private:
friend EventThreadTest;
+ // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
+ EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
+ ResyncWithRateLimitCallback resyncWithRateLimitCallback,
+ InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
+
void threadMain();
Vector<sp<EventThread::Connection>> waitForEventLocked(std::unique_lock<std::mutex>* lock,
DisplayEventReceiver::Event* event)
@@ -146,8 +155,10 @@
// Implements VSyncSource::Callback
void onVSyncEvent(nsecs_t timestamp) override;
+ // TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete.
+ VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
+ std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
// constants
- VSyncSource* const mVSyncSource GUARDED_BY(mMutex) = nullptr;
const ResyncWithRateLimitCallback mResyncWithRateLimitCallback;
const InterceptVSyncsCallback mInterceptVSyncsCallback;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 056d381..58355ae 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -101,6 +101,17 @@
this);
}
+void MessageQueue::setEventConnection(const sp<BnDisplayEventConnection>& connection) {
+ if (mEventTube.getFd() >= 0) {
+ mLooper->removeFd(mEventTube.getFd());
+ }
+
+ mEvents = connection;
+ mEvents->stealReceiveChannel(&mEventTube);
+ mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
+ this);
+}
+
void MessageQueue::waitMessage() {
do {
IPCThreadState::self()->flushCommands();
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 90d1c72..2ec697e 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -85,7 +85,9 @@
virtual ~MessageQueue();
virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
+ // TODO(akrulec): Remove this function once everything is migrated to Scheduler.
virtual void setEventThread(EventThread* events) = 0;
+ virtual void setEventConnection(const sp<BnDisplayEventConnection>& connection) = 0;
virtual void waitMessage() = 0;
virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
virtual void invalidate() = 0;
@@ -125,6 +127,7 @@
~MessageQueue() override = default;
void init(const sp<SurfaceFlinger>& flinger) override;
void setEventThread(android::EventThread* events) override;
+ void setEventConnection(const sp<BnDisplayEventConnection>& connection) override;
void waitMessage() override;
status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) override;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
new file mode 100644
index 0000000..bb85f4c
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#include "Scheduler.h"
+
+#include <cinttypes>
+#include <cstdint>
+#include <memory>
+
+#include <gui/ISurfaceComposer.h>
+
+#include "DispSync.h"
+#include "DispSyncSource.h"
+#include "EventThread.h"
+#include "InjectVSyncSource.h"
+
+namespace android {
+
+#define RETURN_VALUE_IF_INVALID(value) \
+ if (handle == nullptr || mConnections.count(handle->id) == 0) return value
+#define RETURN_IF_INVALID() \
+ if (handle == nullptr || mConnections.count(handle->id) == 0) return
+
+std::atomic<int64_t> Scheduler::sNextId = 0;
+
+Scheduler::~Scheduler() = default;
+
+sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
+ const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ impl::EventThread::InterceptVSyncsCallback interceptCallback) {
+ const int64_t id = sNextId++;
+ ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
+
+ std::unique_ptr<EventThread> eventThread =
+ makeEventThread(connectionName, dispSync, phaseOffsetNs, resyncCallback,
+ interceptCallback);
+ auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
+ eventThread->createEventConnection(),
+ std::move(eventThread));
+ mConnections.insert(std::make_pair(id, std::move(connection)));
+ return mConnections[id]->handle;
+}
+
+std::unique_ptr<EventThread> Scheduler::makeEventThread(
+ const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ impl::EventThread::InterceptVSyncsCallback interceptCallback) {
+ std::unique_ptr<VSyncSource> eventThreadSource =
+ std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
+ return std::make_unique<impl::EventThread>(std::move(eventThreadSource), resyncCallback,
+ interceptCallback, connectionName);
+}
+
+sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
+ const sp<Scheduler::ConnectionHandle>& handle) {
+ RETURN_VALUE_IF_INVALID(nullptr);
+ return mConnections[handle->id]->thread->createEventConnection();
+}
+
+EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
+ RETURN_VALUE_IF_INVALID(nullptr);
+ return mConnections[handle->id]->thread.get();
+}
+
+sp<BnDisplayEventConnection> Scheduler::getEventConnection(const sp<ConnectionHandle>& handle) {
+ RETURN_VALUE_IF_INVALID(nullptr);
+ return mConnections[handle->id]->eventConnection;
+}
+
+void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle,
+ EventThread::DisplayType displayType, bool connected) {
+ RETURN_IF_INVALID();
+ mConnections[handle->id]->thread->onHotplugReceived(displayType, connected);
+}
+
+void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) {
+ RETURN_IF_INVALID();
+ mConnections[handle->id]->thread->onScreenAcquired();
+}
+
+void Scheduler::onScreenReleased(const sp<Scheduler::ConnectionHandle>& handle) {
+ RETURN_IF_INVALID();
+ mConnections[handle->id]->thread->onScreenReleased();
+}
+
+void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, String8& result) const {
+ RETURN_IF_INVALID();
+ mConnections.at(handle->id)->thread->dump(result);
+}
+
+void Scheduler::setPhaseOffset(const sp<Scheduler::ConnectionHandle>& handle, nsecs_t phaseOffset) {
+ RETURN_IF_INVALID();
+ mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
+}
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
new file mode 100644
index 0000000..8efbff4
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <memory>
+
+#include <gui/ISurfaceComposer.h>
+
+#include "DispSync.h"
+#include "EventThread.h"
+#include "InjectVSyncSource.h"
+
+namespace android {
+
+class Scheduler {
+public:
+ /* The scheduler handle is a BBinder object passed to the client from which we can extract
+ * an ID for subsequent operations.
+ */
+ class ConnectionHandle : public BBinder {
+ public:
+ ConnectionHandle(int64_t id) : id(id) {}
+ ~ConnectionHandle() = default;
+ const int64_t id;
+ };
+
+ class Connection {
+ public:
+ Connection(sp<ConnectionHandle> handle, sp<BnDisplayEventConnection> eventConnection,
+ std::unique_ptr<EventThread> eventThread)
+ : handle(handle), eventConnection(eventConnection), thread(std::move(eventThread)) {}
+ ~Connection() = default;
+
+ sp<ConnectionHandle> handle;
+ sp<BnDisplayEventConnection> eventConnection;
+ const std::unique_ptr<EventThread> thread;
+ };
+
+ Scheduler() = default;
+ virtual ~Scheduler();
+
+ /** Creates an EventThread connection. */
+ sp<ConnectionHandle> createConnection(
+ const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ impl::EventThread::InterceptVSyncsCallback interceptCallback);
+ sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle);
+
+ // Getter methods.
+ EventThread* getEventThread(const sp<ConnectionHandle>& handle);
+ sp<BnDisplayEventConnection> getEventConnection(const sp<ConnectionHandle>& handle);
+
+ // Should be called when receiving a hotplug event.
+ void hotplugReceived(const sp<ConnectionHandle>& handle, EventThread::DisplayType displayType,
+ bool connected);
+ // Should be called after the screen is turned on.
+ void onScreenAcquired(const sp<ConnectionHandle>& handle);
+ // Should be called before the screen is turned off.
+ void onScreenReleased(const sp<ConnectionHandle>& handle);
+ // Should be called when dumpsys command is received.
+ void dump(const sp<ConnectionHandle>& handle, String8& result) const;
+ // Offers ability to modify phase offset in the event thread.
+ void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
+
+protected:
+ virtual std::unique_ptr<EventThread> makeEventThread(
+ const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ impl::EventThread::InterceptVSyncsCallback interceptCallback);
+
+private:
+ static std::atomic<int64_t> sNextId;
+ std::unordered_map<int64_t, std::unique_ptr<Connection>> mConnections;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 888dd38..8c46e8a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -87,6 +87,7 @@
#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/InjectVSyncSource.h"
+#include "Scheduler/Scheduler.h"
#include <cutils/compiler.h>
@@ -193,9 +194,9 @@
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
// TODO(courtneygo): Rename hasWideColorDisplay to clarify its actual meaning.
bool SurfaceFlinger::hasWideColorDisplay;
+int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
bool SurfaceFlinger::useColorManagement;
-
std::string getHwcServiceName() {
char value[PROPERTY_VALUE_MAX] = {};
property_get("debug.sf.hwc_service_name", value, "default");
@@ -329,19 +330,19 @@
switch (primaryDisplayOrientation) {
case V1_1::DisplayOrientation::ORIENTATION_90:
- mPrimaryDisplayOrientation = DisplayState::eOrientation90;
+ SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation90;
break;
case V1_1::DisplayOrientation::ORIENTATION_180:
- mPrimaryDisplayOrientation = DisplayState::eOrientation180;
+ SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation180;
break;
case V1_1::DisplayOrientation::ORIENTATION_270:
- mPrimaryDisplayOrientation = DisplayState::eOrientation270;
+ SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation270;
break;
default:
- mPrimaryDisplayOrientation = DisplayState::eOrientationDefault;
+ SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
break;
}
- ALOGV("Primary Display Orientation is set to %2d.", mPrimaryDisplayOrientation);
+ ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
// Note: We create a local temporary with the real DispSync implementation
// type temporarily so we can initialize it with the configured values,
@@ -399,6 +400,9 @@
property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
const int earlyGlAppOffsetNs = atoi(value);
+ property_get("debug.sf.use_scheduler", value, "0");
+ mUseScheduler = atoi(value);
+
const VSyncModulator::Offsets earlyOffsets =
{earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
@@ -595,32 +599,54 @@
Mutex::Autolock _l(mStateLock);
// start the EventThread
- mEventThreadSource =
- std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
- SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
- mEventThread = std::make_unique<impl::EventThread>(mEventThreadSource.get(),
- [this] { resyncWithRateLimit(); },
- impl::EventThread::InterceptVSyncsCallback(),
- "appEventThread");
- mSfEventThreadSource =
- std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
- SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
+ if (mUseScheduler) {
+ mScheduler = std::make_unique<Scheduler>();
+ mAppConnectionHandle =
+ mScheduler->createConnection("appConnection", mPrimaryDispSync.get(),
+ SurfaceFlinger::vsyncPhaseOffsetNs,
+ [this] { resyncWithRateLimit(); },
+ impl::EventThread::InterceptVSyncsCallback());
+ mSfConnectionHandle =
+ mScheduler->createConnection("sfConnection", mPrimaryDispSync.get(),
+ SurfaceFlinger::sfVsyncPhaseOffsetNs,
+ [this] { resyncWithRateLimit(); },
+ [this](nsecs_t timestamp) {
+ mInterceptor->saveVSyncEvent(timestamp);
+ });
- mSFEventThread =
- std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
- [this] { resyncWithRateLimit(); },
- [this](nsecs_t timestamp) {
- mInterceptor->saveVSyncEvent(timestamp);
- },
- "sfEventThread");
- mEventQueue->setEventThread(mSFEventThread.get());
- mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
+ mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
+ mVsyncModulator.setEventThreads(mScheduler->getEventThread(mSfConnectionHandle),
+ mScheduler->getEventThread(mAppConnectionHandle));
+ } else {
+ mEventThreadSource =
+ std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
+ SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
+ mEventThread =
+ std::make_unique<impl::EventThread>(mEventThreadSource.get(),
+ [this] { resyncWithRateLimit(); },
+ impl::EventThread::InterceptVSyncsCallback(),
+ "appEventThread");
+ mSfEventThreadSource =
+ std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
+ SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
+
+ mSFEventThread =
+ std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
+ [this] { resyncWithRateLimit(); },
+ [this](nsecs_t timestamp) {
+ mInterceptor->saveVSyncEvent(timestamp);
+ },
+ "sfEventThread");
+ mEventQueue->setEventThread(mSFEventThread.get());
+ mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
+ }
// Get a RenderEngine for the given display / config (can't fail)
int32_t renderEngineFeature = 0;
- renderEngineFeature |= (useColorManagement ? RE::RenderEngine::USE_COLOR_MANAGEMENT : 0);
- getBE().mRenderEngine =
- RE::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888, renderEngineFeature);
+ renderEngineFeature |= (useColorManagement ?
+ renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0);
+ getBE().mRenderEngine = renderengine::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
+ renderEngineFeature);
LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
@@ -819,6 +845,12 @@
float xdpi = hwConfig->getDpiX();
float ydpi = hwConfig->getDpiY();
+ info.w = hwConfig->getWidth();
+ info.h = hwConfig->getHeight();
+ // Default display viewport to display width and height
+ info.viewportW = info.w;
+ info.viewportH = info.h;
+
if (type == DisplayDevice::DISPLAY_PRIMARY) {
// The density of the device is provided by a build property
float density = Density::getBuildDensity() / 160.0f;
@@ -838,6 +870,13 @@
// TODO: this needs to go away (currently needed only by webkit)
const auto display = getDefaultDisplayDeviceLocked();
info.orientation = display ? display->getOrientation() : 0;
+
+ // This is for screenrecord
+ const Rect viewport = display->getViewport();
+ if (viewport.isValid()) {
+ info.viewportW = uint32_t(viewport.getWidth());
+ info.viewportH = uint32_t(viewport.getHeight());
+ }
} else {
// TODO: where should this value come from?
static const int TV_DENSITY = 213;
@@ -845,8 +884,6 @@
info.orientation = 0;
}
- info.w = hwConfig->getWidth();
- info.h = hwConfig->getHeight();
info.xdpi = xdpi;
info.ydpi = ydpi;
info.fps = 1e9 / hwConfig->getVsyncPeriod();
@@ -871,7 +908,7 @@
info.secure = true;
if (type == DisplayDevice::DISPLAY_PRIMARY &&
- mPrimaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
+ primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
std::swap(info.w, info.h);
}
@@ -893,21 +930,6 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
- if (outViewport == nullptr || display.get() == nullptr) {
- return BAD_VALUE;
- }
-
- sp<const DisplayDevice> device(getDisplayDevice(display));
- if (device == nullptr) {
- return BAD_VALUE;
- }
-
- *outViewport = device->getViewport();
-
- return NO_ERROR;
-}
-
int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) {
const auto display = getDisplayDevice(displayToken);
if (!display) {
@@ -1086,6 +1108,8 @@
return;
}
+ // TODO(akrulec): Part of the Injector should be refactored, so that it
+ // can be passed to Scheduler.
if (enable) {
ALOGV("VSync Injections enabled");
if (mVSyncInjector.get() == nullptr) {
@@ -1144,10 +1168,18 @@
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource) {
- if (vsyncSource == eVsyncSourceSurfaceFlinger) {
- return mSFEventThread->createEventConnection();
+ if (mUseScheduler) {
+ if (vsyncSource == eVsyncSourceSurfaceFlinger) {
+ return mScheduler->createDisplayEventConnection(mSfConnectionHandle);
+ } else {
+ return mScheduler->createDisplayEventConnection(mAppConnectionHandle);
+ }
} else {
- return mEventThread->createEventConnection();
+ if (vsyncSource == eVsyncSourceSurfaceFlinger) {
+ return mSFEventThread->createEventConnection();
+ } else {
+ return mEventThread->createEventConnection();
+ }
}
}
@@ -2181,7 +2213,16 @@
switch (compositionInfo.compositionType)
{
case HWC2::Composition::Invalid:
+ break;
+
case HWC2::Composition::Client:
+ if (compositionInfo.hwc.hwcLayer) {
+ auto error = (compositionInfo.hwc.hwcLayer)->
+ setCompositionType(compositionInfo.compositionType);
+ ALOGE_IF(error != HWC2::Error::None,
+ "[SF] Failed to set composition type: %s (%d)",
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
break;
case HWC2::Composition::Sideband:
@@ -2420,7 +2461,7 @@
/*
* Create our display's surface
*/
- std::unique_ptr<RE::Surface> renderSurface = getRenderEngine().createSurface();
+ std::unique_ptr<renderengine::Surface> renderSurface = getRenderEngine().createSurface();
renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY);
renderSurface->setAsync(state.isVirtual());
renderSurface->setNativeWindow(nativeWindow.get());
@@ -2438,14 +2479,18 @@
nativeWindow->setSwapInterval(nativeWindow.get(), 0);
}
+ const int displayInstallOrientation = state.type == DisplayDevice::DISPLAY_PRIMARY ?
+ primaryDisplayOrientation : DisplayState::eOrientationDefault;
+
// virtual displays are always considered enabled
auto initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
sp<DisplayDevice> display =
new DisplayDevice(this, state.type, displayId, state.isSecure, displayToken,
nativeWindow, dispSurface, std::move(renderSurface), displayWidth,
- displayHeight, hasWideColorGamut, hdrCapabilities,
- supportedPerFrameMetadata, hwcColorModes, initialPowerMode);
+ displayHeight, displayInstallOrientation, hasWideColorGamut,
+ hdrCapabilities, supportedPerFrameMetadata, hwcColorModes,
+ initialPowerMode);
if (maxFrameBufferAcquiredBuffers >= 3) {
nativeWindowSurface->preallocateBuffers();
@@ -2498,9 +2543,19 @@
display->disconnect(getHwComposer());
}
if (draw[i].type == DisplayDevice::DISPLAY_PRIMARY) {
- mEventThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
+ if (mUseScheduler) {
+ mScheduler->hotplugReceived(mAppConnectionHandle,
+ EventThread::DisplayType::Primary, false);
+ } else {
+ mEventThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
+ }
} else if (draw[i].type == DisplayDevice::DISPLAY_EXTERNAL) {
- mEventThread->onHotplugReceived(EventThread::DisplayType::External, false);
+ if (mUseScheduler) {
+ mScheduler->hotplugReceived(mAppConnectionHandle,
+ EventThread::DisplayType::External, false);
+ } else {
+ mEventThread->onHotplugReceived(EventThread::DisplayType::External, false);
+ }
}
mDisplays.erase(draw.keyAt(i));
} else {
@@ -2603,11 +2658,23 @@
dispSurface, producer));
if (!state.isVirtual()) {
if (state.type == DisplayDevice::DISPLAY_PRIMARY) {
- mEventThread->onHotplugReceived(EventThread::DisplayType::Primary,
+ if (mUseScheduler) {
+ mScheduler->hotplugReceived(mAppConnectionHandle,
+ EventThread::DisplayType::Primary,
true);
+ } else {
+ mEventThread->onHotplugReceived(EventThread::DisplayType::Primary,
+ true);
+ }
} else if (state.type == DisplayDevice::DISPLAY_EXTERNAL) {
- mEventThread->onHotplugReceived(EventThread::DisplayType::External,
+ if (mUseScheduler) {
+ mScheduler->hotplugReceived(mAppConnectionHandle,
+ EventThread::DisplayType::External,
true);
+ } else {
+ mEventThread->onHotplugReceived(EventThread::DisplayType::External,
+ true);
+ }
}
}
}
@@ -3569,10 +3636,6 @@
if (layer->setCrop_legacy(s.crop_legacy, !geometryAppliesWithResize))
flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eFinalCropChanged_legacy) {
- if (layer->setFinalCrop_legacy(s.finalCrop_legacy, !geometryAppliesWithResize))
- flags |= eTraversalNeeded;
- }
if (what & layer_state_t::eLayerStackChanged) {
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
// We only allow setting layer stacks for top level layers,
@@ -3717,6 +3780,11 @@
uniqueName, w, h, flags,
handle, &layer);
break;
+ case ISurfaceComposerClient::eFXSurfaceContainer:
+ result = createContainerLayer(client,
+ uniqueName, w, h, flags,
+ handle, &layer);
+ break;
default:
result = BAD_VALUE;
break;
@@ -3820,6 +3888,16 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::createContainerLayer(const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags,
+ sp<IBinder>* handle, sp<Layer>* outLayer)
+{
+ *outLayer = new ContainerLayer(this, client, name, w, h, flags);
+ *handle = (*outLayer)->getHandle();
+ return NO_ERROR;
+}
+
+
status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle)
{
// called by a client when it wants to remove a Layer
@@ -3921,7 +3999,11 @@
getHwComposer().setPowerMode(type, mode);
if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
// FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenAcquired();
+ if (mUseScheduler) {
+ mScheduler->onScreenAcquired(mAppConnectionHandle);
+ } else {
+ mEventThread->onScreenAcquired();
+ }
resyncToHardwareVsync(true);
}
@@ -3945,7 +4027,11 @@
disableHardwareVsync(true); // also cancels any in-progress resync
// FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenReleased();
+ if (mUseScheduler) {
+ mScheduler->onScreenReleased(mAppConnectionHandle);
+ } else {
+ mEventThread->onScreenReleased();
+ }
}
getHwComposer().setPowerMode(type, mode);
@@ -3957,7 +4043,11 @@
getHwComposer().setPowerMode(type, mode);
if (display->isPrimary() && currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
// FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenAcquired();
+ if (mUseScheduler) {
+ mScheduler->onScreenAcquired(mAppConnectionHandle);
+ } else {
+ mEventThread->onScreenAcquired();
+ }
resyncToHardwareVsync(true);
}
} else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
@@ -3965,7 +4055,11 @@
if (display->isPrimary()) {
disableHardwareVsync(true); // also cancels any in-progress resync
// FIXME: eventthread only knows about the main display right now
- mEventThread->onScreenReleased();
+ if (mUseScheduler) {
+ mScheduler->onScreenReleased(mAppConnectionHandle);
+ } else {
+ mEventThread->onScreenReleased();
+ }
}
getHwComposer().setPowerMode(type, mode);
} else {
@@ -4563,10 +4657,15 @@
result.appendFormat(" transaction time: %f us\n",
inTransactionDuration/1000.0);
+ result.appendFormat(" use Scheduler: %s\n", mUseScheduler ? "true" : "false");
/*
* VSYNC state
*/
- mEventThread->dump(result);
+ if (mUseScheduler) {
+ mScheduler->dump(mAppConnectionHandle, result);
+ } else {
+ mEventThread->dump(result);
+ }
result.append("\n");
/*
@@ -4714,7 +4813,6 @@
case GET_DISPLAY_COLOR_MODES:
case GET_DISPLAY_CONFIGS:
case GET_DISPLAY_STATS:
- case GET_DISPLAY_VIEWPORT:
case GET_SUPPORTED_FRAME_TIMESTAMPS:
// Calling setTransactionState is safe, because you need to have been
// granted a reference to Client* and Handle* to do anything with it.
@@ -4903,12 +5001,20 @@
}
case 1018: { // Modify Choreographer's phase offset
n = data.readInt32();
- mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ if (mUseScheduler) {
+ mScheduler->setPhaseOffset(mAppConnectionHandle, static_cast<nsecs_t>(n));
+ } else {
+ mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ }
return NO_ERROR;
}
case 1019: { // Modify SurfaceFlinger's phase offset
n = data.readInt32();
- mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ if (mUseScheduler) {
+ mScheduler->setPhaseOffset(mSfConnectionHandle, static_cast<nsecs_t>(n));
+ } else {
+ mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ }
return NO_ERROR;
}
case 1020: { // Layer updates interceptor
@@ -5082,37 +5188,15 @@
display = getDisplayDeviceLocked(displayToken);
if (!display) return BAD_VALUE;
- const Rect& dispScissor = display->getScissor();
- if (!dispScissor.isEmpty()) {
- sourceCrop.set(dispScissor);
- // adb shell screencap will default reqWidth and reqHeight to zeros.
- if (reqWidth == 0 || reqHeight == 0) {
- reqWidth = uint32_t(display->getViewport().width());
- reqHeight = uint32_t(display->getViewport().height());
- }
- }
+ // ignore sourceCrop (i.e., use the projected logical display
+ // viewport) until the framework is fixed
+ sourceCrop.clear();
- // get screen geometry
- uint32_t width = display->getWidth();
- uint32_t height = display->getHeight();
-
- if (renderAreaRotation & ui::Transform::ROT_90) {
- std::swap(width, height);
- }
-
- if (mPrimaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
- std::swap(width, height);
- }
-
- if ((reqWidth > width) || (reqHeight > height)) {
- ALOGE("size mismatch (%d, %d) > (%d, %d)", reqWidth, reqHeight, width, height);
- } else {
- if (reqWidth == 0) {
- reqWidth = width;
- }
- if (reqHeight == 0) {
- reqHeight = height;
- }
+ // set the requested width/height to the logical display viewport size
+ // by default
+ if (reqWidth == 0 || reqHeight == 0) {
+ reqWidth = uint32_t(display->getViewport().width());
+ reqHeight = uint32_t(display->getViewport().height());
}
}
@@ -5135,6 +5219,7 @@
: RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR),
mLayer(layer),
mCrop(crop),
+ mNeedsFiltering(false),
mFlinger(flinger),
mChildrenOnly(childrenOnly) {}
const ui::Transform& getTransform() const override { return mTransform; }
@@ -5147,7 +5232,7 @@
}
int getWidth() const override { return mLayer->getActiveWidth(mLayer->getDrawingState()); }
bool isSecure() const override { return false; }
- bool needsFiltering() const override { return false; }
+ bool needsFiltering() const override { return mNeedsFiltering; }
Rect getSourceCrop() const override {
if (mCrop.isEmpty()) {
return getBounds();
@@ -5168,6 +5253,11 @@
};
void render(std::function<void()> drawLayers) override {
+ const Rect sourceCrop = getSourceCrop();
+ // no need to check rotation because there is none
+ mNeedsFiltering = sourceCrop.width() != getReqWidth() ||
+ sourceCrop.height() != getReqHeight();
+
if (!mChildrenOnly) {
mTransform = mLayer->getTransform().inverse();
drawLayers();
@@ -5190,6 +5280,7 @@
// layer which has no properties set and which does not draw.
sp<ContainerLayer> screenshotParentLayer;
ui::Transform mTransform;
+ bool mNeedsFiltering;
SurfaceFlinger* mFlinger;
const bool mChildrenOnly;
@@ -5321,64 +5412,16 @@
}
void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
- TraverseLayersFunction traverseLayers, bool yswap,
+ TraverseLayersFunction traverseLayers,
bool useIdentityTransform) {
ATRACE_CALL();
auto& engine(getRenderEngine());
- // get screen geometry
- const auto raWidth = renderArea.getWidth();
- const auto raHeight = renderArea.getHeight();
-
const auto reqWidth = renderArea.getReqWidth();
const auto reqHeight = renderArea.getReqHeight();
- Rect sourceCrop = renderArea.getSourceCrop();
-
- bool filtering = false;
- if (mPrimaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
- filtering = static_cast<int32_t>(reqWidth) != raHeight ||
- static_cast<int32_t>(reqHeight) != raWidth;
- } else {
- filtering = static_cast<int32_t>(reqWidth) != raWidth ||
- static_cast<int32_t>(reqHeight) != raHeight;
- }
-
- // if a default or invalid sourceCrop is passed in, set reasonable values
- if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || !sourceCrop.isValid()) {
- sourceCrop.setLeftTop(Point(0, 0));
- sourceCrop.setRightBottom(Point(raWidth, raHeight));
- } else if (mPrimaryDisplayOrientation != DisplayState::eOrientationDefault) {
- ui::Transform tr;
- uint32_t flags = 0x00;
- switch (mPrimaryDisplayOrientation) {
- case DisplayState::eOrientation90:
- flags = ui::Transform::ROT_90;
- break;
- case DisplayState::eOrientation180:
- flags = ui::Transform::ROT_180;
- break;
- case DisplayState::eOrientation270:
- flags = ui::Transform::ROT_270;
- break;
- }
- tr.set(flags, raWidth, raHeight);
- sourceCrop = tr.transform(sourceCrop);
- }
-
- // ensure that sourceCrop is inside screen
- if (sourceCrop.left < 0) {
- ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
- }
- if (sourceCrop.right > raWidth) {
- ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, raWidth);
- }
- if (sourceCrop.top < 0) {
- ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
- }
- if (sourceCrop.bottom > raHeight) {
- ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
- }
+ const auto sourceCrop = renderArea.getSourceCrop();
+ const auto rotation = renderArea.getRotationFlags();
// assume ColorMode::SRGB / RenderIntent::COLORIMETRIC
engine.setOutputDataSpace(Dataspace::SRGB);
@@ -5387,40 +5430,8 @@
// make sure to clear all GL error flags
engine.checkErrors();
- ui::Transform::orientation_flags rotation = renderArea.getRotationFlags();
- if (mPrimaryDisplayOrientation != DisplayState::eOrientationDefault) {
- // convert hw orientation into flag presentation
- // here inverse transform needed
- uint8_t hw_rot_90 = 0x00;
- uint8_t hw_flip_hv = 0x00;
- switch (mPrimaryDisplayOrientation) {
- case DisplayState::eOrientation90:
- hw_rot_90 = ui::Transform::ROT_90;
- hw_flip_hv = ui::Transform::ROT_180;
- break;
- case DisplayState::eOrientation180:
- hw_flip_hv = ui::Transform::ROT_180;
- break;
- case DisplayState::eOrientation270:
- hw_rot_90 = ui::Transform::ROT_90;
- break;
- }
-
- // transform flags operation
- // 1) flip H V if both have ROT_90 flag
- // 2) XOR these flags
- uint8_t rotation_rot_90 = rotation & ui::Transform::ROT_90;
- uint8_t rotation_flip_hv = rotation & ui::Transform::ROT_180;
- if (rotation_rot_90 & hw_rot_90) {
- rotation_flip_hv = (~rotation_flip_hv) & ui::Transform::ROT_180;
- }
- rotation = static_cast<ui::Transform::orientation_flags>
- ((rotation_rot_90 ^ hw_rot_90) | (rotation_flip_hv ^ hw_flip_hv));
- }
-
// set-up our viewport
- engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, raHeight, yswap,
- rotation);
+ engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, rotation);
engine.disableTexturing();
const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
@@ -5428,9 +5439,7 @@
engine.clearWithColor(0, 0, 0, alpha);
traverseLayers([&](Layer* layer) {
- if (filtering) layer->setFiltering(true);
layer->draw(renderArea, useIdentityTransform);
- if (filtering) layer->setFiltering(false);
});
}
@@ -5458,7 +5467,7 @@
// this binds the given EGLImage as a framebuffer for the
// duration of this scope.
- RE::BindNativeBufferAsFramebuffer bufferBond(getRenderEngine(), buffer);
+ renderengine::BindNativeBufferAsFramebuffer bufferBond(getRenderEngine(), buffer);
if (bufferBond.getStatus() != NO_ERROR) {
ALOGE("got ANWB binding error while taking screenshot");
return INVALID_OPERATION;
@@ -5468,7 +5477,7 @@
// via an FBO, which means we didn't have to create
// an EGLSurface and therefore we're not
// dependent on the context's EGLConfig.
- renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform);
+ renderScreenImplLocked(renderArea, traverseLayers, useIdentityTransform);
if (DEBUG_SCREENSHOTS) {
getRenderEngine().finish();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3dbceae..3e76904 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -69,6 +69,7 @@
#include "Scheduler/DispSync.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/MessageQueue.h"
+#include "Scheduler/Scheduler.h"
#include "Scheduler/VSyncModulator.h"
#include "TimeStats/TimeStats.h"
@@ -106,7 +107,7 @@
class EventThread;
} // namespace impl
-namespace RE {
+namespace renderengine {
class RenderEngine;
}
@@ -175,7 +176,7 @@
const std::string mHwcServiceName; // "default" for real use, something else for testing.
// constant members (no synchronization needed for access)
- std::unique_ptr<RE::RenderEngine> mRenderEngine;
+ std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
EGLContext mEGLContext;
EGLDisplay mEGLDisplay;
@@ -288,6 +289,8 @@
// found on devices with wide color gamut (e.g. Display-P3) display.
static bool hasWideColorDisplay;
+ static int primaryDisplayOrientation;
+
// Indicate if device wants color management on its display.
static bool useColorManagement;
@@ -345,13 +348,11 @@
// TODO: this should be made accessible only to HWComposer
const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int id);
- RE::RenderEngine& getRenderEngine() const { return *getBE().mRenderEngine; }
+ renderengine::RenderEngine& getRenderEngine() const { return *getBE().mRenderEngine; }
bool authenticateSurfaceTextureLocked(
const sp<IGraphicBufferProducer>& bufferProducer) const;
- int getPrimaryDisplayOrientation() const { return mPrimaryDisplayOrientation; }
-
private:
friend class Client;
friend class DisplayEventConnection;
@@ -435,7 +436,6 @@
virtual status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
const Rect& sourceCrop, float frameScale, bool childrenOnly);
virtual status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
- virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport);
virtual status_t getDisplayConfigs(const sp<IBinder>& displayToken,
Vector<DisplayInfo>* configs);
virtual int getActiveConfig(const sp<IBinder>& displayToken);
@@ -548,6 +548,10 @@
uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
sp<Layer>* outLayer);
+ status_t createContainerLayer(const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
+ sp<Layer>* outLayer);
+
String8 getUniqueLayerName(const String8& name);
// called in response to the window-manager calling
@@ -577,7 +581,7 @@
void startBootAnim();
void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
- bool yswap, bool useIdentityTransform);
+ bool useIdentityTransform);
status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
sp<GraphicBuffer>* outBuffer,
bool useIdentityTransform);
@@ -877,7 +881,6 @@
mutable std::unique_ptr<MessageQueue> mEventQueue{std::make_unique<impl::MessageQueue>()};
FrameTracker mAnimFrameTracker;
std::unique_ptr<DispSync> mPrimaryDispSync;
- int mPrimaryDisplayOrientation = DisplayState::eOrientationDefault;
// protected by mDestroyedLayerLock;
mutable Mutex mDestroyedLayerLock;
@@ -933,6 +936,11 @@
CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface;
SurfaceFlingerBE mBE;
+
+ bool mUseScheduler = false;
+ std::unique_ptr<Scheduler> mScheduler;
+ sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
+ sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index f504c13..0b4c6fc 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -113,7 +113,6 @@
layer->mCurrentState.barrierLayer_legacy.promote(),
layer->mCurrentState.frameNumber_legacy);
}
- addFinalCropLocked(transaction, layerId, layer->mCurrentState.finalCrop_legacy);
addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode());
addFlagsLocked(transaction, layerId, layer->mCurrentState.flags);
}
@@ -289,15 +288,6 @@
setProtoRectLocked(protoRect, rect);
}
-void SurfaceInterceptor::addFinalCropLocked(Transaction* transaction, int32_t layerId,
- const Rect& rect)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- FinalCropChange* finalCropChange(change->mutable_final_crop());
- Rectangle* protoRect(finalCropChange->mutable_rectangle());
- setProtoRectLocked(protoRect, rect);
-}
-
void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber)
{
@@ -374,9 +364,6 @@
}
addDeferTransactionLocked(transaction, layerId, otherLayer, state.frameNumber_legacy);
}
- if (state.what & layer_state_t::eFinalCropChanged_legacy) {
- addFinalCropLocked(transaction, layerId, state.finalCrop_legacy);
- }
if (state.what & layer_state_t::eOverrideScalingModeChanged) {
addOverrideScalingModeLocked(transaction, layerId, state.overrideScalingMode);
}
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 218a1d2..394b99b 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -146,7 +146,6 @@
void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
void addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber);
- void addFinalCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
void addOverrideScalingModeLocked(Transaction* transaction, int32_t layerId,
int32_t overrideScalingMode);
void addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state);
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index e1c0fd3..a5bf9c1 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -101,7 +101,6 @@
layerProto.requested_position().y()};
layer->size = {layerProto.size().w(), layerProto.size().h()};
layer->crop = generateRect(layerProto.crop());
- layer->finalCrop = generateRect(layerProto.final_crop());
layer->isOpaque = layerProto.is_opaque();
layer->invalidate = layerProto.invalidate();
layer->dataspace = layerProto.dataspace();
@@ -299,8 +298,7 @@
z, static_cast<double>(position.x), static_cast<double>(position.y), size.x,
size.y);
- StringAppendF(&result, "crop=%s, finalCrop=%s, ", crop.to_string().c_str(),
- finalCrop.to_string().c_str());
+ StringAppendF(&result, "crop=%s, ", crop.to_string().c_str());
StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate);
StringAppendF(&result, "dataspace=%s, ", dataspace.c_str());
StringAppendF(&result, "defaultPixelFormat=%s, ", pixelFormat.c_str());
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 360e599..b1610cf 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -92,7 +92,6 @@
float2 requestedPosition;
int2 size;
LayerProtoParser::Rect crop;
- LayerProtoParser::Rect finalCrop;
bool isOpaque;
bool invalidate;
std::string dataspace;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 7f882da..2a09634 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -41,7 +41,7 @@
// The layer's crop in it's own bounds.
optional RectProto crop = 14;
// The layer's crop in it's parent's bounds.
- optional RectProto final_crop = 15;
+ optional RectProto final_crop = 15 [deprecated=true];
optional bool is_opaque = 16;
optional bool invalidate = 17;
optional string dataspace = 18;
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 1319e12..34d0fd7 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "CredentialsTest.*:LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*:-CropLatchingTest.FinalCropLatchingBufferOldSize"
+ "filter": "CredentialsTest.*:LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*"
}
}
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 8ac2c87..740d2fa 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -167,7 +167,6 @@
bool alphaUpdateFound(const SurfaceChange& change, bool foundAlpha);
bool layerUpdateFound(const SurfaceChange& change, bool foundLayer);
bool cropUpdateFound(const SurfaceChange& change, bool foundCrop);
- bool finalCropUpdateFound(const SurfaceChange& change, bool foundFinalCrop);
bool matrixUpdateFound(const SurfaceChange& change, bool foundMatrix);
bool scalingModeUpdateFound(const SurfaceChange& change, bool foundScalingMode);
bool transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion);
@@ -199,7 +198,6 @@
void alphaUpdate(Transaction&);
void layerUpdate(Transaction&);
void cropUpdate(Transaction&);
- void finalCropUpdate(Transaction&);
void matrixUpdate(Transaction&);
void overrideScalingModeUpdate(Transaction&);
void transparentRegionHintUpdate(Transaction&);
@@ -323,10 +321,6 @@
t.setCrop_legacy(mBGSurfaceControl, CROP_UPDATE);
}
-void SurfaceInterceptorTest::finalCropUpdate(Transaction& t) {
- t.setFinalCrop_legacy(mBGSurfaceControl, CROP_UPDATE);
-}
-
void SurfaceInterceptorTest::matrixUpdate(Transaction& t) {
t.setMatrix(mBGSurfaceControl, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2);
}
@@ -377,7 +371,6 @@
runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
runInTransaction(&SurfaceInterceptorTest::layerUpdate);
runInTransaction(&SurfaceInterceptorTest::cropUpdate);
- runInTransaction(&SurfaceInterceptorTest::finalCropUpdate);
runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
runInTransaction(&SurfaceInterceptorTest::overrideScalingModeUpdate);
runInTransaction(&SurfaceInterceptorTest::transparentRegionHintUpdate);
@@ -460,20 +453,6 @@
return foundCrop;
}
-bool SurfaceInterceptorTest::finalCropUpdateFound(const SurfaceChange& change,
- bool foundFinalCrop) {
- bool hasLeft(change.final_crop().rectangle().left() == CROP_UPDATE.left);
- bool hasTop(change.final_crop().rectangle().top() == CROP_UPDATE.top);
- bool hasRight(change.final_crop().rectangle().right() == CROP_UPDATE.right);
- bool hasBottom(change.final_crop().rectangle().bottom() == CROP_UPDATE.bottom);
- if (hasLeft && hasRight && hasTop && hasBottom && !foundFinalCrop) {
- foundFinalCrop = true;
- } else if (hasLeft && hasRight && hasTop && hasBottom && foundFinalCrop) {
- [] () { FAIL(); }();
- }
- return foundFinalCrop;
-}
-
bool SurfaceInterceptorTest::matrixUpdateFound(const SurfaceChange& change, bool foundMatrix) {
bool hasSx((float)change.matrix().dsdx() == (float)M_SQRT1_2);
bool hasTx((float)change.matrix().dtdx() == (float)M_SQRT1_2);
@@ -593,9 +572,6 @@
case SurfaceChange::SurfaceChangeCase::kCrop:
foundUpdate = cropUpdateFound(change, foundUpdate);
break;
- case SurfaceChange::SurfaceChangeCase::kFinalCrop:
- foundUpdate = finalCropUpdateFound(change, foundUpdate);
- break;
case SurfaceChange::SurfaceChangeCase::kMatrix:
foundUpdate = matrixUpdateFound(change, foundUpdate);
break;
@@ -636,7 +612,6 @@
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kAlpha));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kLayer));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kCrop));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kFinalCrop));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kMatrix));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOverrideScalingMode));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kTransparentRegionHint));
@@ -755,11 +730,6 @@
captureTest(&SurfaceInterceptorTest::cropUpdate, SurfaceChange::SurfaceChangeCase::kCrop);
}
-TEST_F(SurfaceInterceptorTest, InterceptFinalCropUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::finalCropUpdate,
- SurfaceChange::SurfaceChangeCase::kFinalCrop);
-}
-
TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4ab4fec..ed1529b 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -1759,168 +1759,6 @@
}
}
-TEST_F(LayerTransactionTest, SetFinalCropBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- const Rect crop(8, 8, 24, 24);
-
- // same as in SetCropBasic
- Transaction().setFinalCrop_legacy(layer, crop).apply();
- auto shot = screenshot();
- shot->expectColor(crop, Color::RED);
- shot->expectBorder(crop, Color::BLACK);
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropEmpty_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // same as in SetCropEmpty
- {
- SCOPED_TRACE("empty rect");
- Transaction().setFinalCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- {
- SCOPED_TRACE("negative rect");
- Transaction().setFinalCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropOutOfBounds_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // same as in SetCropOutOfBounds
- Transaction().setFinalCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropWithTranslation_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // final crop is applied post-translation
- Transaction().setPosition(layer, 16, 16).setFinalCrop_legacy(layer, Rect(8, 8, 24, 24)).apply();
- auto shot = screenshot();
- shot->expectColor(Rect(16, 16, 24, 24), Color::RED);
- shot->expectBorder(Rect(16, 16, 24, 24), Color::BLACK);
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropWithScale_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // final crop is not affected by matrix
- Transaction()
- .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
- .setFinalCrop_legacy(layer, Rect(8, 8, 24, 24))
- .apply();
- auto shot = screenshot();
- shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
- shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropWithResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // same as in SetCropWithResize
- Transaction().setFinalCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = screenshot();
- shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
- shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
- {
- SCOPED_TRACE("resize applied");
- auto shot = screenshot();
- shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
- shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
- }
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropWithNextResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // same as in SetCropWithNextResize
- Transaction()
- .setFinalCrop_legacy(layer, Rect(8, 8, 24, 24))
- .setGeometryAppliesWithResize(layer)
- .apply();
- {
- SCOPED_TRACE("waiting for next resize");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setFinalCrop_legacy(layer, Rect(4, 4, 12, 12)).apply();
- {
- SCOPED_TRACE("pending final crop modified");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setSize(layer, 16, 16).apply();
- {
- SCOPED_TRACE("resize pending");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- // finally resize
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
- {
- SCOPED_TRACE("new final crop applied");
- auto shot = screenshot();
- shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
- shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
- }
-}
-
-TEST_F(LayerTransactionTest, SetFinalCropWithNextResizeScaleToWindow_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // same as in SetCropWithNextResizeScaleToWindow
- Transaction()
- .setFinalCrop_legacy(layer, Rect(4, 4, 12, 12))
- .setSize(layer, 16, 16)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .setGeometryAppliesWithResize(layer)
- .apply();
- {
- SCOPED_TRACE("new final crop pending");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
- shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK);
- }
-
- // XXX final crop is never latched without other geometry change (b/69315677)
- Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
- Transaction().setPosition(layer, 0, 0).apply();
- {
- SCOPED_TRACE("new final crop applied");
- auto shot = screenshot();
- shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
- shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
- }
-}
-
TEST_F(LayerTransactionTest, SetBufferBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
@@ -2346,7 +2184,6 @@
t.setSize(mFGSurfaceControl, 64, 64);
t.setPosition(mFGSurfaceControl, 64, 64);
t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
- t.setFinalCrop_legacy(mFGSurfaceControl, Rect(0, 0, -1, -1));
});
EXPECT_INITIAL_STATE("After restoring initial state");
@@ -2375,43 +2212,6 @@
}
};
-// In this test we ensure that setGeometryAppliesWithResize actually demands
-// a buffer of the new size, and not just any size.
-TEST_F(CropLatchingTest, FinalCropLatchingBufferOldSize) {
- EXPECT_INITIAL_STATE("before anything");
- // Normally the crop applies immediately even while a resize is pending.
- asTransaction([&](Transaction& t) {
- t.setSize(mFGSurfaceControl, 128, 128);
- t.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
- });
-
- EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
-
- restoreInitialState();
-
- // In order to prepare to submit a buffer at the wrong size, we acquire it prior to
- // initiating the resize.
- lockAndFillFGBuffer();
-
- asTransaction([&](Transaction& t) {
- t.setSize(mFGSurfaceControl, 128, 128);
- t.setGeometryAppliesWithResize(mFGSurfaceControl);
- t.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
- });
-
- EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
-
- // We now submit our old buffer, at the old size, and ensure it doesn't
- // trigger geometry latching.
- unlockFGBuffer();
-
- EXPECT_INITIAL_STATE("after unlocking FG buffer (with geometryAppliesWithResize)");
-
- completeFGResize();
-
- EXPECT_CROPPED_STATE("after the resize finishes");
-}
-
TEST_F(LayerUpdateTest, DeferredTransactionTest) {
sp<ScreenCapture> sc;
{
@@ -2588,22 +2388,6 @@
}
}
-TEST_F(ChildLayerTest, ChildLayerFinalCropping) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setFinalCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
- });
-
- {
- ScreenCapture::captureScreen(&mCapture);
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(4, 4);
- mCapture->expectBGColor(5, 5);
- }
-}
-
TEST_F(ChildLayerTest, ChildLayerConstraints) {
asTransaction([&](Transaction& t) {
t.show(mChild);
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 7fafab9..356a880 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -634,40 +634,6 @@
EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
}
-TEST_F(TransactionTest, LayerFinalCrop) {
- // TODO: Add scaling to confirm that crop happens in display space?
- {
- TransactionScope ts(*sFakeComposer);
- Rect cropRect(32, 32, 32 + 64, 32 + 64);
- ts.setFinalCrop_legacy(mFGSurfaceControl, cropRect);
- }
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
- // In display space we are cropping with [32, 32, 96, 96] against display rect
- // [64, 64, 128, 128]. Should yield display rect [64, 64, 96, 96]
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 32, 64 + 32};
-
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-
-TEST_F(TransactionTest, LayerFinalCropEmpty) {
- // TODO: Add scaling to confirm that crop happens in display space?
- {
- TransactionScope ts(*sFakeComposer);
- Rect cropRect(16, 16, 32, 32);
- ts.setFinalCrop_legacy(mFGSurfaceControl, cropRect);
- }
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
- // In display space we are cropping with [16, 16, 32, 32] against display rect
- // [64, 64, 128, 128]. The intersection is empty and only the background layer is composited.
- std::vector<RenderState> referenceFrame(1);
- referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-
TEST_F(TransactionTest, LayerSetLayer) {
{
TransactionScope ts(*sFakeComposer);
@@ -992,22 +958,6 @@
EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
}
-TEST_F(ChildLayerTest, FinalCropping) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
- }
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
- referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
- referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-
TEST_F(ChildLayerTest, Constraints) {
{
TransactionScope ts(*sFakeComposer);
@@ -1354,7 +1304,6 @@
ts.setSize(mFGSurfaceControl, 64, 64);
ts.setPosition(mFGSurfaceControl, 64, 64);
ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
- ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(0, 0, -1, -1));
}
};
@@ -1425,111 +1374,6 @@
EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
}
-TEST_F(LatchingTest, FinalCropLatching) {
- // Normally the crop applies immediately even while a resize is pending.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
- }
-
- auto referenceFrame1 = mBaseFrame;
- referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
- referenceFrame1[FG_LAYER].mSourceCrop =
- hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
- EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
-
- restoreInitialState();
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setGeometryAppliesWithResize(mFGSurfaceControl);
- ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
- }
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
- completeFGResize();
-
- auto referenceFrame2 = mBaseFrame;
- referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
- referenceFrame2[FG_LAYER].mSourceCrop =
- hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
- referenceFrame2[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
-}
-
-// In this test we ensure that setGeometryAppliesWithResize actually demands
-// a buffer of the new size, and not just any size.
-TEST_F(LatchingTest, FinalCropLatchingBufferOldSize) {
- // Normally the crop applies immediately even while a resize is pending.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
- }
-
- auto referenceFrame1 = mBaseFrame;
- referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
- referenceFrame1[FG_LAYER].mSourceCrop =
- hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
- EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
-
- restoreInitialState();
-
- // In order to prepare to submit a buffer at the wrong size, we acquire it prior to
- // initiating the resize.
- lockAndFillFGBuffer();
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setGeometryAppliesWithResize(mFGSurfaceControl);
- ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
- }
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
- // We now submit our old buffer, at the old size, and ensure it doesn't
- // trigger geometry latching.
- unlockFGBuffer();
-
- auto referenceFrame2 = mBaseFrame;
- referenceFrame2[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
-
- completeFGResize();
- auto referenceFrame3 = referenceFrame2;
- referenceFrame3[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
- referenceFrame3[FG_LAYER].mSourceCrop =
- hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
- referenceFrame3[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame3, sFakeComposer->getLatestFrame()));
-}
-
-TEST_F(LatchingTest, FinalCropLatchingRegressionForb37531386) {
- // In this scenario, we attempt to set the final crop a second time while the resize
- // is still pending, and ensure we are successful. Success meaning the second crop
- // is the one which eventually latches and not the first.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setGeometryAppliesWithResize(mFGSurfaceControl);
- ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
- }
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(0, 0, -1, -1));
- }
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
- completeFGResize();
-
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-
} // namespace
int main(int argc, char** argv) {
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 8f1f5e5..f1f0fbf 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -22,6 +22,7 @@
"DisplayTransactionTest.cpp",
"EventControlThreadTest.cpp",
"EventThreadTest.cpp",
+ "SchedulerTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockDisplaySurface.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 1f57b8e..32712c7 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -116,7 +116,7 @@
// These mocks are created by the test, but are destroyed by SurfaceFlinger
// by virtue of being stored into a std::unique_ptr. However we still need
// to keep a reference to them for use in setting up call expectations.
- RE::mock::RenderEngine* mRenderEngine = new RE::mock::RenderEngine();
+ renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
Hwc2::mock::Composer* mComposer = nullptr;
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
@@ -127,7 +127,7 @@
sp<mock::GraphicBufferProducer> mProducer;
mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
sp<mock::NativeWindow> mNativeWindow;
- RE::mock::Surface* mRenderSurface = nullptr;
+ renderengine::mock::Surface* mRenderSurface = nullptr;
};
DisplayTransactionTest::DisplayTransactionTest() {
@@ -155,7 +155,7 @@
mFlinger.mutableEventControlThread().reset(mEventControlThread);
mFlinger.mutableEventThread().reset(mEventThread);
mFlinger.mutableEventQueue().reset(mMessageQueue);
- mFlinger.setupRenderEngine(std::unique_ptr<RE::RenderEngine>(mRenderEngine));
+ mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
@@ -277,9 +277,10 @@
// For simplicity, we only expect to create a single render surface for
// each test.
ASSERT_TRUE(test->mRenderSurface == nullptr);
- test->mRenderSurface = new RE::mock::Surface();
+ test->mRenderSurface = new renderengine::mock::Surface();
EXPECT_CALL(*test->mRenderEngine, createSurface())
- .WillOnce(Return(ByMove(std::unique_ptr<RE::Surface>(test->mRenderSurface))));
+ .WillOnce(Return(ByMove(
+ std::unique_ptr<renderengine::Surface>(test->mRenderSurface))));
EXPECT_CALL(*test->mRenderSurface, setAsync(static_cast<bool>(ASYNC))).Times(1);
EXPECT_CALL(*test->mRenderSurface, setCritical(static_cast<bool>(CRITICAL))).Times(1);
EXPECT_CALL(*test->mRenderSurface, setNativeWindow(test->mNativeWindow.get())).Times(1);
@@ -1735,11 +1736,11 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new mock::DisplaySurface();
- auto renderSurface = new RE::mock::Surface();
+ auto renderSurface = new renderengine::mock::Surface();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
- display.setRenderSurface(std::unique_ptr<RE::Surface>(renderSurface));
+ display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
display.inject();
// There is a change to the viewport state
@@ -1776,11 +1777,11 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new mock::DisplaySurface();
- auto renderSurface = new RE::mock::Surface();
+ auto renderSurface = new renderengine::mock::Surface();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
- display.setRenderSurface(std::unique_ptr<RE::Surface>(renderSurface));
+ display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
display.inject();
// There is a change to the viewport state
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
new file mode 100644
index 0000000..c809e82
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -0,0 +1,186 @@
+#undef LOG_TAG
+#define LOG_TAG "SchedulerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <log/log.h>
+
+#include "AsyncCallRecorder.h"
+#include "Scheduler/DispSync.h"
+#include "Scheduler/EventThread.h"
+#include "Scheduler/Scheduler.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventThread.h"
+
+using testing::_;
+using testing::Return;
+
+namespace android {
+
+class SchedulerTest : public testing::Test {
+protected:
+ class MockEventThreadConnection : public BnDisplayEventConnection {
+ public:
+ MockEventThreadConnection() = default;
+ ~MockEventThreadConnection() = default;
+
+ MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
+ MOCK_METHOD1(setVsyncRate, status_t(uint32_t count));
+ MOCK_METHOD0(requestNextVsync, void());
+ };
+
+ /**
+ * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else
+ * the same.
+ */
+ class MockScheduler : public android::Scheduler {
+ public:
+ MockScheduler(std::unique_ptr<EventThread> eventThread)
+ : mEventThread(std::move(eventThread)) {}
+
+ std::unique_ptr<EventThread> makeEventThread(
+ const char* /* connectionName */, DispSync* /* dispSync */,
+ nsecs_t /* phaseOffsetNs */,
+ impl::EventThread::ResyncWithRateLimitCallback /* resyncCallback */,
+ impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
+ return std::move(mEventThread);
+ }
+
+ MockScheduler() = default;
+ ~MockScheduler() override = default;
+
+ std::unique_ptr<EventThread> mEventThread;
+ };
+
+ SchedulerTest();
+ ~SchedulerTest() override;
+
+ sp<Scheduler::ConnectionHandle> mConnectionHandle;
+ mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+ mock::EventThread* mEventThread;
+ std::unique_ptr<MockScheduler> mScheduler;
+ sp<MockEventThreadConnection> mEventThreadConnection;
+
+ AsyncCallRecorder<void (*)()> mResyncCallRecorder;
+ AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
+};
+
+SchedulerTest::SchedulerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>();
+ mEventThread = eventThread.get();
+ mScheduler = std::make_unique<MockScheduler>(std::move(eventThread));
+ mEventThreadConnection = new MockEventThreadConnection();
+
+ // createConnection call to scheduler makes a createEventConnection call to EventThread. Make
+ // sure that call gets executed and returns an EventThread::Connection object.
+ EXPECT_CALL(*mEventThread, createEventConnection())
+ .WillRepeatedly(Return(mEventThreadConnection));
+
+ mConnectionHandle = mScheduler->createConnection("appConnection", mPrimaryDispSync, 16,
+ mResyncCallRecorder.getInvocable(),
+ mInterceptVSyncCallRecorder.getInvocable());
+}
+
+SchedulerTest::~SchedulerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(SchedulerTest, canCreateAndDestroyTest) {
+ EXPECT_FALSE(mResyncCallRecorder.waitForCall().has_value());
+ EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall().has_value());
+ EXPECT_EQ(0, mConnectionHandle->id);
+}
+
+TEST_F(SchedulerTest, testNullPtr) {
+ // Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any
+ // exceptions, just gracefully continues.
+ sp<IDisplayEventConnection> returnedValue;
+ ASSERT_NO_FATAL_FAILURE(returnedValue = mScheduler->createDisplayEventConnection(nullptr));
+ EXPECT_TRUE(returnedValue == nullptr);
+ EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
+ EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
+ ASSERT_NO_FATAL_FAILURE(
+ mScheduler->hotplugReceived(nullptr, EventThread::DisplayType::Primary, false));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr));
+ String8 testString;
+ ASSERT_NO_FATAL_FAILURE(mScheduler->dump(nullptr, testString));
+ EXPECT_TRUE(testString == "");
+ ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(nullptr, 10));
+}
+
+TEST_F(SchedulerTest, invalidConnectionHandle) {
+ // Passing an invalid ConnectionHandle is a valid argument. The code doesn't throw any
+ // exceptions, just gracefully continues.
+ sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20);
+
+ sp<IDisplayEventConnection> returnedValue;
+ ASSERT_NO_FATAL_FAILURE(returnedValue =
+ mScheduler->createDisplayEventConnection(connectionHandle));
+ EXPECT_TRUE(returnedValue == nullptr);
+ EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
+ EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
+
+ // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads.
+ EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(connectionHandle,
+ EventThread::DisplayType::Primary, false));
+
+ EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle));
+
+ EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(connectionHandle));
+
+ String8 testString;
+ EXPECT_CALL(*mEventThread, dump(_)).Times(0);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->dump(connectionHandle, testString));
+ EXPECT_TRUE(testString == "");
+
+ EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(connectionHandle, 10));
+}
+
+TEST_F(SchedulerTest, validConnectionHandle) {
+ sp<IDisplayEventConnection> returnedValue;
+ ASSERT_NO_FATAL_FAILURE(returnedValue =
+ mScheduler->createDisplayEventConnection(mConnectionHandle));
+ EXPECT_TRUE(returnedValue != nullptr);
+ ASSERT_EQ(returnedValue, mEventThreadConnection);
+
+ EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr);
+ EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr);
+
+ EXPECT_CALL(*mEventThread, onHotplugReceived(EventThread::DisplayType::Primary, false))
+ .Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(mConnectionHandle,
+ EventThread::DisplayType::Primary, false));
+
+ EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle));
+
+ EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(mConnectionHandle));
+
+ String8 testString("dump");
+ EXPECT_CALL(*mEventThread, dump(testString)).Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, testString));
+ EXPECT_TRUE(testString != "");
+
+ EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10));
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d8e7581..1bba480 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -23,7 +23,7 @@
class EventThread;
-namespace RE {
+namespace renderengine {
class RenderEngine;
}
@@ -36,7 +36,7 @@
// Extend this as needed for accessing SurfaceFlinger private (and public)
// functions.
- void setupRenderEngine(std::unique_ptr<RE::RenderEngine> renderEngine) {
+ void setupRenderEngine(std::unique_ptr<renderengine::RenderEngine> renderEngine) {
mFlinger->getBE().mRenderEngine = std::move(renderEngine);
}
@@ -113,6 +113,7 @@
*/
auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
+ auto& mutablePrimaryDisplayOrientation() { return SurfaceFlinger::primaryDisplayOrientation; }
auto& mutableUseColorManagement() { return SurfaceFlinger::useColorManagement; }
auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
@@ -313,7 +314,7 @@
return *this;
}
- auto& setRenderSurface(std::unique_ptr<RE::Surface> renderSurface) {
+ auto& setRenderSurface(std::unique_ptr<renderengine::Surface> renderSurface) {
mRenderSurface = std::move(renderSurface);
return *this;
}
@@ -328,8 +329,9 @@
sp<DisplayDevice> device =
new DisplayDevice(mFlinger.mFlinger.get(), mType, mDisplayId, mSecure,
mDisplayToken, mNativeWindow, mDisplaySurface,
- std::move(mRenderSurface), 0, 0, false, HdrCapabilities(), 0,
- hdrAndRenderIntents, HWC_POWER_MODE_NORMAL);
+ std::move(mRenderSurface), 0, 0,
+ DisplayState::eOrientationDefault, false, HdrCapabilities(),
+ 0, hdrAndRenderIntents, HWC_POWER_MODE_NORMAL);
mFlinger.mutableDisplays().emplace(mDisplayToken, device);
DisplayDeviceState state;
@@ -352,7 +354,7 @@
const int32_t mDisplayId;
sp<ANativeWindow> mNativeWindow;
sp<DisplaySurface> mDisplaySurface;
- std::unique_ptr<RE::Surface> mRenderSurface;
+ std::unique_ptr<renderengine::Surface> mRenderSurface;
bool mSecure = false;
};
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index 8d503f4..f2f3675 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -30,6 +30,7 @@
MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
MOCK_METHOD1(setEventThread, void(android::EventThread*));
+ MOCK_METHOD1(setEventConnection, void(const sp<BnDisplayEventConnection>& connection));
MOCK_METHOD0(waitMessage, void());
MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
MOCK_METHOD0(invalidate, void());
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
index 200f214..06ef0b2 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
@@ -19,7 +19,7 @@
#include <ui/Region.h>
namespace android {
-namespace RE {
+namespace renderengine {
namespace mock {
// Explicit default instantiation is recommended.
@@ -33,5 +33,5 @@
Image::~Image() = default;
} // namespace mock
-} // namespace RE
+} // namespace renderengine
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index b907c49..1c5135b 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -25,22 +25,23 @@
#include <renderengine/Texture.h>
namespace android {
-namespace RE {
+namespace renderengine {
namespace mock {
-class RenderEngine : public RE::RenderEngine {
+class RenderEngine : public renderengine::RenderEngine {
public:
RenderEngine();
~RenderEngine() override;
- MOCK_METHOD0(createSurface, std::unique_ptr<RE::Surface>());
- MOCK_METHOD0(createImage, std::unique_ptr<RE::Image>());
+ MOCK_METHOD0(createFramebuffer, std::unique_ptr<Framebuffer>());
+ MOCK_METHOD0(createSurface, std::unique_ptr<renderengine::Surface>());
+ MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>());
MOCK_CONST_METHOD0(primeCache, void());
MOCK_METHOD1(dump, void(String8&));
MOCK_CONST_METHOD0(useNativeFenceSync, bool());
MOCK_CONST_METHOD0(useWaitSync, bool());
MOCK_CONST_METHOD0(isCurrent, bool());
- MOCK_METHOD1(setCurrentSurface, bool(const RE::Surface&));
+ MOCK_METHOD1(setCurrentSurface, bool(const renderengine::Surface&));
MOCK_METHOD0(resetCurrentSurface, void());
MOCK_METHOD0(flush, base::unique_fd());
MOCK_METHOD0(finish, bool());
@@ -52,11 +53,11 @@
MOCK_METHOD0(disableScissor, void());
MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
- MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const RE::Image&));
+ MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
MOCK_METHOD5(readPixels, void(size_t, size_t, size_t, size_t, uint32_t*));
MOCK_CONST_METHOD0(checkErrors, void());
- MOCK_METHOD6(setViewportAndProjection,
- void(size_t, size_t, Rect, size_t, bool, ui::Transform::orientation_flags));
+ MOCK_METHOD4(setViewportAndProjection,
+ void(size_t, size_t, Rect, ui::Transform::orientation_flags));
MOCK_METHOD4(setupLayerBlending, void(bool, bool, bool, const half4&));
MOCK_METHOD1(setupLayerTexturing, void(const Texture&));
MOCK_METHOD0(setupLayerBlackedOut, void());
@@ -69,15 +70,14 @@
MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace));
MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace));
MOCK_METHOD1(setDisplayMaxLuminance, void(const float));
- MOCK_METHOD2(bindNativeBufferAsFrameBuffer,
- void(ANativeWindowBuffer*, RE::BindNativeBufferAsFramebuffer*));
- MOCK_METHOD1(unbindNativeBufferAsFrameBuffer, void(RE::BindNativeBufferAsFramebuffer*));
+ MOCK_METHOD1(bindFrameBuffer, status_t(Framebuffer*));
+ MOCK_METHOD1(unbindFrameBuffer, void(Framebuffer*));
MOCK_METHOD1(drawMesh, void(const Mesh&));
MOCK_CONST_METHOD0(getMaxTextureSize, size_t());
MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
};
-class Surface : public RE::Surface {
+class Surface : public renderengine::Surface {
public:
Surface();
~Surface() override;
@@ -94,7 +94,7 @@
MOCK_CONST_METHOD0(queryHeight, int32_t());
};
-class Image : public RE::Image {
+class Image : public renderengine::Image {
public:
Image();
~Image() override;
@@ -104,5 +104,5 @@
};
} // namespace mock
-} // namespace RE
+} // namespace renderengine
} // namespace android
diff --git a/services/vr/performanced/cpu_set.cpp b/services/vr/performanced/cpu_set.cpp
index 1a7264c..d940b79 100644
--- a/services/vr/performanced/cpu_set.cpp
+++ b/services/vr/performanced/cpu_set.cpp
@@ -106,7 +106,7 @@
return sets;
}
-std::string CpuSetManager::DumpState() const {
+void CpuSetManager::DumpState(std::ostringstream& stream) const {
size_t max_path = 0;
std::vector<CpuSet*> sets;
@@ -119,8 +119,6 @@
return a->path() < b->path();
});
- std::ostringstream stream;
-
stream << std::left;
stream << std::setw(max_path) << "Path";
stream << " ";
@@ -146,8 +144,6 @@
stream << std::setw(6) << set->GetTasks().size();
stream << std::endl;
}
-
- return stream.str();
}
void CpuSetManager::MoveUnboundTasks(const std::string& target_set) {
diff --git a/services/vr/performanced/cpu_set.h b/services/vr/performanced/cpu_set.h
index 6879272..4c25e9e 100644
--- a/services/vr/performanced/cpu_set.h
+++ b/services/vr/performanced/cpu_set.h
@@ -5,6 +5,7 @@
#include <memory>
#include <mutex>
+#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
@@ -83,7 +84,7 @@
// to shield the system from interference from unbound kernel threads.
void MoveUnboundTasks(const std::string& target_set);
- std::string DumpState() const;
+ void DumpState(std::ostringstream& stream) const;
operator bool() const { return root_set_ != nullptr; }
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index d304bac..73dcf76 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -1,5 +1,7 @@
#include "performance_service.h"
+#include <sstream>
+
#include <sched.h>
#include <sys/prctl.h>
#include <unistd.h>
@@ -31,6 +33,10 @@
const char kRootCpuSet[] = "/";
+const char kVrAppRenderPolicy[] = "vr:app:render";
+
+const bool kAllowAppsToRequestVrAppRenderPolicy = false;
+
constexpr unsigned long kTimerSlackForegroundNs = 50000;
constexpr unsigned long kTimerSlackBackgroundNs = 40000000;
@@ -133,6 +139,17 @@
using AllowRootSystemTrusted =
CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>;
+ auto vr_app_render_permission_check = [](
+ const pdx::Message& sender, const Task& task) {
+ // For vr:app:render, in addition to system/root apps and VrCore, we
+ // also allow apps to request vr:app:render if
+ // kAllowAppsToRequestVrAppRenderPolicy == true, but not for other
+ // apps, only for themselves.
+ return (task && task.thread_group_id() == sender.GetProcessId() &&
+ kAllowAppsToRequestVrAppRenderPolicy)
+ || AllowRootSystemTrusted::Check(sender, task);
+ };
+
partition_permission_check_ = AllowRootSystemTrusted::Check;
// Setup the scheduler classes.
@@ -184,11 +201,11 @@
.priority = fifo_medium + 2,
.permission_check = AllowRootSystemTrusted::Check,
"/system/performance"}},
- {"vr:app:render",
+ {kVrAppRenderPolicy,
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
.priority = fifo_medium + 1,
- .permission_check = AllowRootSystemTrusted::Check,
+ .permission_check = vr_app_render_permission_check,
"/application/performance"}},
{"normal",
{.timer_slack = kTimerSlackForegroundNs,
@@ -215,7 +232,10 @@
}
std::string PerformanceService::DumpState(size_t /*max_length*/) {
- return cpuset_.DumpState();
+ std::ostringstream stream;
+ stream << "vr_app_render_thread: " << vr_app_render_thread_ << std::endl;
+ cpuset_.DumpState(stream);
+ return stream.str();
}
Status<void> PerformanceService::OnSetSchedulerPolicy(
@@ -241,7 +261,12 @@
// Make sure the sending process is allowed to make the requested change to
// this task.
if (!config.IsAllowed(message, task))
- return ErrorStatus(EINVAL);
+ return ErrorStatus(EPERM);
+
+ if (scheduler_policy == kVrAppRenderPolicy) {
+ // We only allow one vr:app:render thread at a time
+ SetVrAppRenderThread(task_id);
+ }
// Get the thread group's cpu set. Policies that do not specify a cpuset
// should default to this cpuset.
@@ -299,14 +324,16 @@
Status<void> PerformanceService::OnSetCpuPartition(
Message& message, pid_t task_id, const std::string& partition) {
Task task(task_id);
- if (!task || task.thread_group_id() != message.GetProcessId())
+ if (!task)
return ErrorStatus(EINVAL);
+ if (task.thread_group_id() != message.GetProcessId())
+ return ErrorStatus(EPERM);
// Temporary permission check.
// TODO(eieio): Replace this with a configuration file.
if (partition_permission_check_ &&
!partition_permission_check_(message, task)) {
- return ErrorStatus(EINVAL);
+ return ErrorStatus(EPERM);
}
auto target_set = cpuset_.Lookup(partition);
@@ -333,7 +360,12 @@
// Make sure the sending process is allowed to make the requested change to
// this task.
if (!config.IsAllowed(message, task))
- return ErrorStatus(EINVAL);
+ return ErrorStatus(EPERM);
+
+ if (scheduler_class == kVrAppRenderPolicy) {
+ // We only allow one vr:app:render thread at a time
+ SetVrAppRenderThread(task_id);
+ }
struct sched_param param;
param.sched_priority = config.priority;
@@ -356,8 +388,10 @@
pid_t task_id) {
// Make sure the task id is valid and belongs to the sending process.
Task task(task_id);
- if (!task || task.thread_group_id() != message.GetProcessId())
+ if (!task)
return ErrorStatus(EINVAL);
+ if (task.thread_group_id() != message.GetProcessId())
+ return ErrorStatus(EPERM);
return task.GetCpuSetPath();
}
@@ -390,5 +424,38 @@
}
}
+void PerformanceService::SetVrAppRenderThread(pid_t new_vr_app_render_thread) {
+ ALOGI("SetVrAppRenderThread old=%d new=%d",
+ vr_app_render_thread_, new_vr_app_render_thread);
+
+ if (vr_app_render_thread_ >= 0 &&
+ vr_app_render_thread_ != new_vr_app_render_thread) {
+ // Restore the default scheduler policy and priority on the previous
+ // vr:app:render thread.
+ struct sched_param param;
+ param.sched_priority = 0;
+ if (sched_setscheduler(vr_app_render_thread_, SCHED_NORMAL, ¶m) < 0) {
+ if (errno == ESRCH) {
+ ALOGI("Failed to revert %s scheduler policy. Couldn't find thread %d."
+ " Was the app killed?", kVrAppRenderPolicy, vr_app_render_thread_);
+ } else {
+ ALOGE("Failed to revert %s scheduler policy: %s",
+ kVrAppRenderPolicy, strerror(errno));
+ }
+ }
+
+ // Restore the default timer slack on the previous vr:app:render thread.
+ prctl(PR_SET_TIMERSLACK_PID, kTimerSlackForegroundNs,
+ vr_app_render_thread_);
+ }
+
+ // We could also reset the thread's cpuset here, but the cpuset is already
+ // managed by Android. Better to let Android adjust the cpuset as the app
+ // moves to the background, rather than adjust it ourselves here, and risk
+ // stomping on the value set by Android.
+
+ vr_app_render_thread_ = new_vr_app_render_thread;
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index 6b519ab..fe63756 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -39,6 +39,14 @@
pdx::Status<std::string> OnGetCpuPartition(pdx::Message& message,
pid_t task_id);
+ // Set which thread gets the vr:app:render policy. Only one thread at a time
+ // is allowed to have vr:app:render. If multiple threads are allowed
+ // vr:app:render, and those threads busy loop, the system can freeze. When
+ // SetVrAppRenderThread() is called, the thread which we had previously
+ // assigned vr:app:render will have its scheduling policy reset to default
+ // values.
+ void SetVrAppRenderThread(pid_t new_vr_app_render_thread);
+
CpuSetManager cpuset_;
int sched_fifo_min_priority_;
@@ -70,6 +78,8 @@
std::function<bool(const pdx::Message& message, const Task& task)>
partition_permission_check_;
+ pid_t vr_app_render_thread_ = -1;
+
PerformanceService(const PerformanceService&) = delete;
void operator=(const PerformanceService&) = delete;
};