Merge "Expose shared timeline counters into telemetry:"
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 994375b..d95d04a 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -131,6 +131,34 @@
chmod 0666 /sys/kernel/tracing/events/task/task_newtask/enable
chmod 0666 /sys/kernel/debug/tracing/events/gpu_mem/gpu_mem_total/enable
chmod 0666 /sys/kernel/tracing/events/gpu_mem/gpu_mem_total/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/irq/enable
+ chmod 0666 /sys/kernel/tracing/events/irq/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/irq/irq_handler_entry/enable
+ chmod 0666 /sys/kernel/tracing/events/irq/irq_handler_entry/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/irq/irq_handler_exit/enable
+ chmod 0666 /sys/kernel/tracing/events/irq/irq_handler_exit/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/irq/softirq_entry/enable
+ chmod 0666 /sys/kernel/tracing/events/irq/softirq_entry/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/irq/softirq_exit/enable
+ chmod 0666 /sys/kernel/tracing/events/irq/softirq_exit/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/irq/softirq_raise/enable
+ chmod 0666 /sys/kernel/tracing/events/irq/softirq_raise/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_entry/enable
+ chmod 0666 /sys/kernel/tracing/events/irq/tasklet_entry/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_exit/enable
+ chmod 0666 /sys/kernel/tracing/events/irq/tasklet_exit/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_hi_entry/enable
+ chmod 0666 /sys/kernel/tracing/events/irq/tasklet_hi_entry/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_hi_exit/enable
+ chmod 0666 /sys/kernel/tracing/events/irq/tasklet_hi_exit/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/ipi/enable
+ chmod 0666 /sys/kernel/tracing/events/ipi/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/ipi/ipi_entry/enable
+ chmod 0666 /sys/kernel/tracing/events/ipi/ipi_entry/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/ipi/ipi_exit/enable
+ chmod 0666 /sys/kernel/tracing/events/ipi/ipi_exit/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/ipi/ipi_raise/enable
+ chmod 0666 /sys/kernel/tracing/events/ipi/ipi_raise/enable
# disk
chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index bbc724c..3091f6b 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -69,7 +69,7 @@
static const std::vector<std::string> group_names{
"log", "sdcard_r", "sdcard_rw", "mount", "inet", "net_bw_stats",
- "readproc", "bluetooth", "wakelock"};
+ "readproc", "bluetooth", "wakelock", "nfc"};
std::vector<gid_t> groups(group_names.size(), 0);
for (size_t i = 0; i < group_names.size(); ++i) {
grp = getgrnam(group_names[i].c_str());
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 91d5524..a81cdaf 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1636,6 +1636,8 @@
/* Dump Bluetooth HCI logs */
ds.AddDir("/data/misc/bluetooth/logs", true);
+ /* Dump Nfc NCI logs */
+ ds.AddDir("/data/misc/nfc/logs", true);
if (ds.options_->do_screenshot && !ds.do_early_screenshot_) {
MYLOGI("taking late screenshot\n");
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index bb0e5ad..1c6583e 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -239,10 +239,10 @@
EXPECT_EQ(access(getZipFilePath().c_str(), F_OK), 0);
}
-TEST_F(ZippedBugreportGenerationTest, Is3MBMBinSize) {
+TEST_F(ZippedBugreportGenerationTest, Is1MBMBinSize) {
struct stat st;
EXPECT_EQ(stat(getZipFilePath().c_str(), &st), 0);
- EXPECT_GE(st.st_size, 3000000 /* 3MB */);
+ EXPECT_GE(st.st_size, 1000000 /* 1MB */);
}
TEST_F(ZippedBugreportGenerationTest, TakesBetween30And300Seconds) {
@@ -401,7 +401,7 @@
SectionExists("batterystats", /* bytes= */ 1000);
}
-TEST_F(BugreportSectionTest, WifiSectionGenerated) {
+TEST_F(BugreportSectionTest, DISABLED_WifiSectionGenerated) {
SectionExists("wifi", /* bytes= */ 100000);
}
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index bd45005..7c9e3b2 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -41,6 +41,21 @@
"liblogwrap",
],
test_config: "installd_cache_test.xml",
+
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
}
cc_test {
@@ -66,6 +81,21 @@
"liblogwrap",
],
test_config: "installd_service_test.xml",
+
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
}
cc_test {
@@ -93,6 +123,21 @@
"libz",
],
test_config: "installd_dexopt_test.xml",
+
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
}
cc_test {
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 9964888..ba6cdf1 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -479,8 +479,7 @@
}
TEST_F(ListTest, DumpVintf) {
- const std::string expected = "<manifest version=\"2.0\" type=\"device\">\n"
- " <hal format=\"hidl\">\n"
+ const std::string expected = " <hal format=\"hidl\">\n"
" <name>a.h.foo1</name>\n"
" <transport>hwbinder</transport>\n"
" <fqname>@1.0::IFoo/1</fqname>\n"
@@ -499,8 +498,7 @@
" <name>a.h.foo4</name>\n"
" <transport arch=\"32\">passthrough</transport>\n"
" <fqname>@4.0::IFoo/4</fqname>\n"
- " </hal>\n"
- "</manifest>";
+ " </hal>\n";
optind = 1; // mimic Lshal::parseArg()
EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 6c3b79b..c6f656b 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -41,7 +41,6 @@
LayerChange layer = 5;
CropChange crop = 6;
MatrixChange matrix = 8;
- OverrideScalingModeChange override_scaling_mode = 9;
TransparentRegionHintChange transparent_region_hint = 10;
LayerStackChange layer_stack = 11;
HiddenFlagChange hidden_flag = 12;
@@ -55,6 +54,7 @@
ReparentChildrenChange reparent_children = 20;
BackgroundBlurRadiusChange background_blur_radius = 21;
ShadowRadiusChange shadow_radius = 22;
+ BlurRegionsChange blur_regions = 23;
}
}
@@ -95,10 +95,6 @@
required float dtdy = 4;
}
-message OverrideScalingModeChange {
- required int32 override_scaling_mode = 1;
-}
-
message TransparentRegionHintChange {
repeated Rectangle region = 1;
}
@@ -212,6 +208,23 @@
required float radius = 1;
}
+message BlurRegionsChange {
+ repeated BlurRegionChange blur_regions = 1;
+}
+
+message BlurRegionChange {
+ required uint32 blur_radius = 1;
+ required float corner_radius_tl = 2;
+ required float corner_radius_tr = 3;
+ required float corner_radius_bl = 4;
+ required float corner_radius_br = 5;
+ required float alpha = 6;
+ required int32 left = 7;
+ required int32 top = 8;
+ required int32 right = 9;
+ required int32 bottom = 10;
+}
+
message Origin {
required int32 pid = 1;
required int32 uid = 2;
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 86e4f5d..5849212 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -387,10 +387,6 @@
case SurfaceChange::SurfaceChangeCase::kMatrix:
setMatrix(transaction, change.id(), change.matrix());
break;
- case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode:
- setOverrideScalingMode(transaction, change.id(),
- change.override_scaling_mode());
- break;
case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint:
setTransparentRegionHint(transaction, change.id(),
change.transparent_region_hint());
@@ -427,6 +423,9 @@
case SurfaceChange::SurfaceChangeCase::kShadowRadius:
setShadowRadiusChange(transaction, change.id(), change.shadow_radius());
break;
+ case SurfaceChange::SurfaceChangeCase::kBlurRegions:
+ setBlurRegionsChange(transaction, change.id(), change.blur_regions());
+ break;
default:
status = 1;
break;
@@ -525,12 +524,6 @@
t.setMatrix(mLayers[id], mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy());
}
-void Replayer::setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
- layer_id id, const OverrideScalingModeChange& osmc) {
- ALOGV("Layer %d: Setting Override Scaling Mode -- mode=%d", id, osmc.override_scaling_mode());
- t.setOverrideScalingMode(mLayers[id], osmc.override_scaling_mode());
-}
-
void Replayer::setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
layer_id id, const TransparentRegionHintChange& trhc) {
ALOGV("Setting Transparent Region Hint");
@@ -738,3 +731,24 @@
layer_id id, const ShadowRadiusChange& c) {
t.setShadowRadius(mLayers[id], c.radius());
}
+
+void Replayer::setBlurRegionsChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const BlurRegionsChange& c) {
+ std::vector<BlurRegion> regions;
+ for(size_t i=0; i < c.blur_regions_size(); i++) {
+ auto protoRegion = c.blur_regions(i);
+ regions.push_back(BlurRegion{
+ .blurRadius = protoRegion.blur_radius(),
+ .alpha = protoRegion.alpha(),
+ .cornerRadiusTL = protoRegion.corner_radius_tl(),
+ .cornerRadiusTR = protoRegion.corner_radius_tr(),
+ .cornerRadiusBL = protoRegion.corner_radius_bl(),
+ .cornerRadiusBR = protoRegion.corner_radius_br(),
+ .left = protoRegion.left(),
+ .top = protoRegion.top(),
+ .right = protoRegion.right(),
+ .bottom = protoRegion.bottom()
+ });
+ }
+ t.setBlurRegions(mLayers[id], regions);
+}
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index 95857e1..a22262a 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -96,10 +96,10 @@
layer_id id, const CornerRadiusChange& cc);
void setBackgroundBlurRadius(SurfaceComposerClient::Transaction& t,
layer_id id, const BackgroundBlurRadiusChange& cc);
+ void setBlurRegions(SurfaceComposerClient::Transaction& t,
+ layer_id id, const BlurRegionsChange& cc);
void setMatrix(SurfaceComposerClient::Transaction& t,
layer_id id, const MatrixChange& mc);
- void setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
- layer_id id, const OverrideScalingModeChange& osmc);
void setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
layer_id id, const TransparentRegionHintChange& trgc);
void setLayerStack(SurfaceComposerClient::Transaction& t,
@@ -122,6 +122,8 @@
layer_id id, const ReparentChildrenChange& c);
void setShadowRadiusChange(SurfaceComposerClient::Transaction& t,
layer_id id, const ShadowRadiusChange& c);
+ void setBlurRegionsChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const BlurRegionsChange& c);
void setDisplaySurface(SurfaceComposerClient::Transaction& t,
display_id id, const DispSurfaceChange& dsc);
diff --git a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
index d63d97f..58bfbf3 100644
--- a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
+++ b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
@@ -69,7 +69,6 @@
print ("5. Crop Change")
print ("6. Final Crop Change")
print ("7. Matrix Change")
- print ("8. Override Scaling Mode Change")
print ("9. Transparent Region Hint Change")
print ("10. Layer Stack Change")
print ("11. Hidden Flag Change")
@@ -128,9 +127,6 @@
change.matrix.dtdx,\
change.matrix.dsdy,\
change.matrix.dtdy = layer()
- elif option == 8:
- change.override_scaling_mode.override_scaling_mode \
- = override_scaling_mode()
elif option == 9:
for rect in transparent_region_hint():
new = increment.transparent_region_hint.region.add()
@@ -227,11 +223,6 @@
return float(dsdx)
-def override_scaling_mode():
- mode = input("Enter override scaling mode: ")
-
- return int(mode)
-
def transparent_region_hint():
num = input("Enter number of rectangles in region: ")
diff --git a/data/etc/cec_config.xml b/data/etc/cec_config.xml
new file mode 100644
index 0000000..42a45e4
--- /dev/null
+++ b/data/etc/cec_config.xml
@@ -0,0 +1,36 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<cec-settings>
+ <setting name="hdmi_cec_enabled"
+ user-configurable="true">
+ <allowed-values>
+ <value string-value="0" />
+ <value string-value="1" />
+ </allowed-values>
+ <default-value string-value="1" />
+ </setting>
+ <setting name="send_standby_on_sleep"
+ user-configurable="true">
+ <allowed-values>
+ <value string-value="to_tv" />
+ <value string-value="broadcast" />
+ <value string-value="none" />
+ </allowed-values>
+ <default-value string-value="to_tv" />
+ </setting>
+ <setting name="power_state_change_on_active_source_lost"
+ user-configurable="false">
+ <allowed-values>
+ <value string-value="none" />
+ <value string-value="standby_now" />
+ </allowed-values>
+ <default-value string-value="none" />
+ </setting>
+ <setting name="system_audio_mode_muting"
+ user-configurable="false">
+ <allowed-values>
+ <value string-value="0" />
+ <value string-value="1" />
+ </allowed-values>
+ <default-value string-value="1" />
+ </setting>
+</cec-settings>
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index d7e6e41..3dd1534 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -158,7 +158,8 @@
* - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not
* supported.
*/
-int AImageDecoder_createFromAAsset(struct AAsset* asset, AImageDecoder** outDecoder)
+int AImageDecoder_createFromAAsset(struct AAsset* _Nonnull asset,
+ AImageDecoder* _Nonnull * _Nonnull outDecoder)
__INTRODUCED_IN(30);
/**
@@ -189,7 +190,8 @@
* - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not
* supported.
*/
-int AImageDecoder_createFromFd(int fd, AImageDecoder** outDecoder) __INTRODUCED_IN(30);
+int AImageDecoder_createFromFd(int fd, AImageDecoder* _Nonnull * _Nonnull outDecoder)
+ __INTRODUCED_IN(30);
/**
* Create a new AImageDecoder from a buffer.
@@ -218,15 +220,16 @@
* - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not
* supported.
*/
-int AImageDecoder_createFromBuffer(const void* buffer, size_t length,
- AImageDecoder** outDecoder) __INTRODUCED_IN(30);
+int AImageDecoder_createFromBuffer(const void* _Nonnull buffer, size_t length,
+ AImageDecoder* _Nonnull * _Nonnull outDecoder)
+ __INTRODUCED_IN(30);
/**
* Delete the AImageDecoder.
*
* Available since API level 30.
*/
-void AImageDecoder_delete(AImageDecoder* decoder) __INTRODUCED_IN(30);
+void AImageDecoder_delete(AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(30);
/**
* Choose the desired output format.
@@ -247,7 +250,7 @@
* - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION}: The
* {@link AndroidBitmapFormat} is incompatible with the image.
*/
-int AImageDecoder_setAndroidBitmapFormat(AImageDecoder*,
+int AImageDecoder_setAndroidBitmapFormat(AImageDecoder* _Nonnull decoder,
int32_t format) __INTRODUCED_IN(30);
/**
@@ -270,7 +273,7 @@
* - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
* {@link AImageDecoder} is null.
*/
-int AImageDecoder_setUnpremultipliedRequired(AImageDecoder*,
+int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* _Nonnull decoder,
bool unpremultipliedRequired) __INTRODUCED_IN(30);
/**
@@ -295,7 +298,8 @@
* {@link AImageDecoder} is null or |dataspace| does not correspond to an
* {@link ADataSpace} value.
*/
-int AImageDecoder_setDataSpace(AImageDecoder*, int32_t dataspace) __INTRODUCED_IN(30);
+int AImageDecoder_setDataSpace(AImageDecoder* _Nonnull decoder, int32_t dataspace)
+ __INTRODUCED_IN(30);
/**
* Specify the output size for a decoded image.
@@ -324,7 +328,8 @@
* or the scale is incompatible with a previous call to
* {@link AImageDecoder_setUnpremultipliedRequired}(true).
*/
-int AImageDecoder_setTargetSize(AImageDecoder*, int32_t width, int32_t height) __INTRODUCED_IN(30);
+int AImageDecoder_setTargetSize(AImageDecoder* _Nonnull decoder, int32_t width,
+ int32_t height) __INTRODUCED_IN(30);
/**
@@ -353,8 +358,9 @@
* - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
* {@link AImageDecoder}, |width| or |height| is null or |sampleSize| is < 1.
*/
-int AImageDecoder_computeSampledSize(const AImageDecoder*, int sampleSize,
- int32_t* width, int32_t* height) __INTRODUCED_IN(30);
+int AImageDecoder_computeSampledSize(const AImageDecoder* _Nonnull decoder, int sampleSize,
+ int32_t* _Nonnull width, int32_t* _Nonnull height)
+ __INTRODUCED_IN(30);
/**
* Specify how to crop the output after scaling (if any).
*
@@ -380,7 +386,7 @@
* {@link AImageDecoder} is null or the crop is not contained by the
* (possibly scaled) image dimensions.
*/
-int AImageDecoder_setCrop(AImageDecoder*, ARect crop) __INTRODUCED_IN(30);
+int AImageDecoder_setCrop(AImageDecoder* _Nonnull decoder, ARect crop) __INTRODUCED_IN(30);
struct AImageDecoderHeaderInfo;
/**
@@ -399,8 +405,8 @@
*
* Available since API level 30.
*/
-const AImageDecoderHeaderInfo* AImageDecoder_getHeaderInfo(
- const AImageDecoder*) __INTRODUCED_IN(30);
+const AImageDecoderHeaderInfo* _Nonnull AImageDecoder_getHeaderInfo(
+ const AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(30);
/**
* Report the native width of the encoded image. This is also the logical
@@ -410,7 +416,8 @@
*
* Available since API level 30.
*/
-int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo* _Nonnull)
+ __INTRODUCED_IN(30);
/**
* Report the native height of the encoded image. This is also the logical
@@ -420,7 +427,8 @@
*
* Available since API level 30.
*/
-int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo* _Nonnull)
+ __INTRODUCED_IN(30);
/**
* Report the mimeType of the encoded image.
@@ -429,8 +437,8 @@
*
* @return a string literal describing the mime type.
*/
-const char* AImageDecoderHeaderInfo_getMimeType(
- const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+const char* _Nonnull AImageDecoderHeaderInfo_getMimeType(
+ const AImageDecoderHeaderInfo* _Nonnull) __INTRODUCED_IN(30);
/**
* Report the {@link AndroidBitmapFormat} the AImageDecoder will decode to
@@ -441,7 +449,7 @@
* Available since API level 30.
*/
int32_t AImageDecoderHeaderInfo_getAndroidBitmapFormat(
- const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+ const AImageDecoderHeaderInfo* _Nonnull) __INTRODUCED_IN(30);
/**
* Report how the {@link AImageDecoder} will handle alpha by default. If the image
@@ -453,7 +461,7 @@
* Available since API level 30.
*/
int AImageDecoderHeaderInfo_getAlphaFlags(
- const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+ const AImageDecoderHeaderInfo* _Nonnull) __INTRODUCED_IN(30);
/**
* Report the dataspace the AImageDecoder will decode to by default.
@@ -474,7 +482,7 @@
* no corresponding {@link ADataSpace}.
*/
int32_t AImageDecoderHeaderInfo_getDataSpace(
- const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+ const AImageDecoderHeaderInfo* _Nonnull) __INTRODUCED_IN(30);
/**
* Return the minimum stride that can be used in
@@ -489,13 +497,17 @@
*
* Available since API level 30.
*/
-size_t AImageDecoder_getMinimumStride(AImageDecoder*) __INTRODUCED_IN(30);
+size_t AImageDecoder_getMinimumStride(AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(30);
/**
* Decode the image into pixels, using the settings of the {@link AImageDecoder}.
*
* Available since API level 30.
*
+ * Starting in API level 31, it can be used to decode all of the frames of an
+ * animated image (i.e. GIF, WebP, HEIF) using new APIs (TODO (scroggo): list
+ * and describe here).
+ *
* @param decoder Opaque object representing the decoder.
* @param pixels On success, will be filled with the result
* of the decode. Must be large enough to hold |size| bytes.
@@ -523,12 +535,64 @@
* - {@link ANDROID_IMAGE_DECODER_INTERNAL_ERROR}: Some other error, like a
* failure to allocate memory.
*/
-int AImageDecoder_decodeImage(AImageDecoder* decoder,
- void* pixels, size_t stride,
+int AImageDecoder_decodeImage(AImageDecoder* _Nonnull decoder,
+ void* _Nonnull pixels, size_t stride,
size_t size) __INTRODUCED_IN(30);
#endif // __ANDROID_API__ >= 30
+#if __ANDROID_API__ >= 31
+
+/**
+ * Return true iff the image is animated - i.e. has multiple frames.
+ *
+ * Introduced in API 31.
+ *
+ * This may require seeking past the first frame to verify whether
+ * there is a following frame (e.g. for GIF).
+ *
+ * Errors:
+ * - returns false if |decoder| is null.
+ */
+bool AImageDecoder_isAnimated(AImageDecoder* _Nonnull decoder)
+ __INTRODUCED_IN(31);
+
+enum {
+ /*
+ * Reported by {@link AImageDecoder_getRepeatCount} if the
+ * animation should repeat forever.
+ */
+ ANDROID_IMAGE_DECODER_INFINITE = INT32_MAX,
+};
+
+/**
+ * Report how many times the animation should repeat.
+ *
+ * Introduced in API 31.
+ *
+ * This does not include the first play through. e.g. a repeat
+ * count of 4 means that each frame is played 5 times.
+ *
+ * {@link ANDROID_IMAGE_DECODER_INFINITE} means to repeat forever.
+ *
+ * This may require seeking.
+ *
+ * For non-animated formats, this returns 0. It may return non-zero for
+ * an image with only one frame (i.e. {@link AImageDecoder_isAnimated} returns
+ * false) if the encoded image contains a repeat count.
+ *
+ * @return Number of times to repeat on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The AImageDecoder
+ * is null.
+ */
+int32_t AImageDecoder_getRepeatCount(AImageDecoder* _Nonnull decoder);
+ __INTRODUCED_IN(31);
+
+#endif // __ANDROID_API__ >= 31
+
#ifdef __cplusplus
}
#endif
diff --git a/include/ftl/StaticVector.h b/include/ftl/StaticVector.h
new file mode 100644
index 0000000..b586e91
--- /dev/null
+++ b/include/ftl/StaticVector.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <memory>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace android::ftl {
+
+// Fixed-capacity, statically allocated counterpart of std::vector. Akin to std::array, StaticVector
+// allocates contiguous storage for N elements of type T at compile time, but stores at most (rather
+// than exactly) N elements. Unlike std::array, its default constructor does not require T to have a
+// default constructor, since elements are constructed in-place as the vector grows. Operations that
+// insert an element, such as push_back and emplace, fail when the vector is full. The API otherwise
+// adheres to standard containers, except the unstable_erase operation that does not shift elements,
+// and the replace operation that destructively emplaces.
+//
+// StaticVector<T, 1> is analogous to an iterable std::optional, but StaticVector<T, 0> is an error.
+//
+// Example usage:
+//
+// ftl::StaticVector<char, 3> vector;
+// assert(vector.empty());
+//
+// vector = {'a', 'b'};
+// assert(vector.size() == 2u);
+//
+// vector.push_back('c');
+// assert(vector.full());
+//
+// assert(!vector.push_back('d'));
+// assert(vector.size() == 3u);
+//
+// vector.unstable_erase(vector.begin());
+// assert(vector == (ftl::StaticVector{'c', 'b'}));
+//
+// vector.pop_back();
+// assert(vector.back() == 'c');
+//
+// const char array[] = "hi";
+// vector = ftl::StaticVector(array);
+// assert(vector == (ftl::StaticVector{'h', 'i', '\0'}));
+//
+template <typename T, size_t N>
+class StaticVector {
+ static_assert(N > 0);
+
+ template <typename I>
+ using IsInputIterator = std::is_base_of<std::input_iterator_tag,
+ typename std::iterator_traits<I>::iterator_category>;
+
+public:
+ using value_type = T;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+
+ using pointer = value_type*;
+ using reference = value_type&;
+ using iterator = pointer;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+
+ using const_pointer = const value_type*;
+ using const_reference = const value_type&;
+ using const_iterator = const_pointer;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ // Creates an empty vector.
+ StaticVector() = default;
+
+ // Copies and moves a vector, respectively.
+ StaticVector(const StaticVector& other) : StaticVector(other.begin(), other.end()) {}
+ StaticVector(StaticVector&& other) { swap<Empty>(other); }
+
+ // Copies at most N elements from a smaller convertible vector.
+ template <typename U, size_t M, typename = std::enable_if_t<M <= N>>
+ StaticVector(const StaticVector<U, M>& other) : StaticVector(other.begin(), other.end()) {}
+
+ // Copies at most N elements from an array.
+ template <typename U, size_t M>
+ explicit StaticVector(U (&array)[M]) : StaticVector(std::begin(array), std::end(array)) {}
+
+ // Copies at most N elements from the range [first, last).
+ template <typename Iterator, typename = std::enable_if_t<IsInputIterator<Iterator>{}>>
+ StaticVector(Iterator first, Iterator last)
+ : mSize(std::min(max_size(), static_cast<size_type>(std::distance(first, last)))) {
+ std::uninitialized_copy(first, first + mSize, begin());
+ }
+
+ // Constructs at most N elements. The template arguments T and N are inferred using the
+ // deduction guide defined below. Note that T is determined from the first element, and
+ // subsequent elements must have convertible types:
+ //
+ // ftl::StaticVector vector = {1, 2, 3};
+ // static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<int, 3>>);
+ //
+ // const auto copy = "quince"s;
+ // auto move = "tart"s;
+ // ftl::StaticVector vector = {copy, std::move(move)};
+ //
+ // static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<std::string, 2>>);
+ //
+ template <typename E, typename... Es,
+ typename = std::enable_if_t<std::is_constructible_v<value_type, E>>>
+ StaticVector(E&& element, Es&&... elements)
+ : StaticVector(std::index_sequence<0>{}, std::forward<E>(element),
+ std::forward<Es>(elements)...) {
+ static_assert(sizeof...(elements) < N, "Too many elements");
+ }
+
+ // Constructs at most N elements. The template arguments T and N are inferred using the
+ // deduction guide defined below. Element types must be convertible to the specified T:
+ //
+ // ftl::StaticVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+ // static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<std::string, 3>>);
+ //
+ template <typename... Es>
+ explicit StaticVector(std::in_place_type_t<T>, Es... elements)
+ : StaticVector(std::forward<Es>(elements)...) {}
+
+ ~StaticVector() { std::destroy(begin(), end()); }
+
+ StaticVector& operator=(const StaticVector& other) {
+ StaticVector copy(other);
+ swap(copy);
+ return *this;
+ }
+
+ StaticVector& operator=(StaticVector&& other) {
+ std::destroy(begin(), end());
+ mSize = 0;
+ swap<Empty>(other);
+ return *this;
+ }
+
+ template <typename = void>
+ void swap(StaticVector&);
+
+ size_type max_size() const { return N; }
+ size_type size() const { return mSize; }
+
+ bool empty() const { return size() == 0; }
+ bool full() const { return size() == max_size(); }
+
+ iterator begin() { return std::launder(reinterpret_cast<pointer>(mData)); }
+ const_iterator begin() const { return cbegin(); }
+ const_iterator cbegin() const { return mut().begin(); }
+
+ iterator end() { return begin() + size(); }
+ const_iterator end() const { return cend(); }
+ const_iterator cend() const { return mut().end(); }
+
+ reverse_iterator rbegin() { return std::make_reverse_iterator(end()); }
+ const_reverse_iterator rbegin() const { return crbegin(); }
+ const_reverse_iterator crbegin() const { return mut().rbegin(); }
+
+ reverse_iterator rend() { return std::make_reverse_iterator(begin()); }
+ const_reverse_iterator rend() const { return crend(); }
+ const_reverse_iterator crend() const { return mut().rend(); }
+
+ iterator last() { return end() - 1; }
+ const_iterator last() const { return mut().last(); }
+
+ reference front() { return *begin(); }
+ const_reference front() const { return mut().front(); }
+
+ reference back() { return *last(); }
+ const_reference back() const { return mut().back(); }
+
+ reference operator[](size_type i) { return *(begin() + i); }
+ const_reference operator[](size_type i) const { return mut()[i]; }
+
+ // Replaces an element, and returns an iterator to it. If the vector is full, the element is not
+ // replaced, and the end iterator is returned.
+ template <typename... Args>
+ iterator replace(const_iterator cit, Args&&... args) {
+ if (full()) return end();
+ // Append element, and move into place if not last.
+ emplace_back(std::forward<Args>(args)...);
+ if (cit != last()) unstable_erase(cit);
+ return const_cast<iterator>(cit);
+ }
+
+ // Appends an element, and returns an iterator to it. If the vector is full, the element is not
+ // inserted, and the end iterator is returned.
+ template <typename... Args>
+ iterator emplace_back(Args&&... args) {
+ if (full()) return end();
+ const iterator it = construct_at(end(), std::forward<Args>(args)...);
+ ++mSize;
+ return it;
+ }
+
+ // Erases an element, but does not preserve order. Rather than shifting subsequent elements,
+ // this moves the last element to the slot of the erased element.
+ void unstable_erase(const_iterator it) {
+ std::destroy_at(it);
+ if (it != last()) {
+ // Move last element and destroy its source for destructor side effects.
+ construct_at(it, std::move(back()));
+ std::destroy_at(last());
+ }
+ --mSize;
+ }
+
+ bool push_back(value_type v) {
+ // Two statements for sequence point.
+ const iterator it = emplace_back(std::move(v));
+ return it != end();
+ }
+
+ void pop_back() { unstable_erase(last()); }
+
+private:
+ struct Empty {};
+
+ StaticVector& mut() const { return *const_cast<StaticVector*>(this); }
+
+ // Recursion for variadic constructor.
+ template <size_t I, typename E, typename... Es>
+ StaticVector(std::index_sequence<I>, E&& element, Es&&... elements)
+ : StaticVector(std::index_sequence<I + 1>{}, std::forward<Es>(elements)...) {
+ construct_at(begin() + I, std::forward<E>(element));
+ }
+
+ // Base case for variadic constructor.
+ template <size_t I>
+ explicit StaticVector(std::index_sequence<I>) : mSize(I) {}
+
+ // TODO: Replace with std::construct_at in C++20.
+ template <typename... Args>
+ static pointer construct_at(const_iterator it, Args&&... args) {
+ void* const ptr = const_cast<void*>(static_cast<const void*>(it));
+ return new (ptr) value_type{std::forward<Args>(args)...};
+ }
+
+ size_type mSize = 0;
+ std::aligned_storage_t<sizeof(value_type), alignof(value_type)> mData[N];
+};
+
+// Deduction guide for array constructor.
+template <typename T, size_t N>
+StaticVector(T (&)[N]) -> StaticVector<std::remove_cv_t<T>, N>;
+
+// Deduction guide for variadic constructor.
+template <typename T, typename... Us, typename V = std::decay_t<T>,
+ typename = std::enable_if_t<(std::is_constructible_v<V, Us> && ...)>>
+StaticVector(T&&, Us&&...) -> StaticVector<V, 1 + sizeof...(Us)>;
+
+// Deduction guide for in-place constructor.
+template <typename T, typename... Us>
+StaticVector(std::in_place_type_t<T>, Us&&...) -> StaticVector<T, sizeof...(Us)>;
+
+template <typename T, size_t N>
+template <typename E>
+void StaticVector<T, N>::swap(StaticVector& other) {
+ auto [to, from] = std::make_pair(this, &other);
+ if (from == this) return;
+
+ // Assume this vector has fewer elements, so the excess of the other vector will be moved to it.
+ auto [min, max] = std::make_pair(size(), other.size());
+
+ // No elements to swap if moving into an empty vector.
+ if constexpr (std::is_same_v<E, Empty>) {
+ assert(min == 0);
+ } else {
+ if (min > max) {
+ std::swap(from, to);
+ std::swap(min, max);
+ }
+
+ // Swap elements [0, min).
+ std::swap_ranges(begin(), begin() + min, other.begin());
+
+ // No elements to move if sizes are equal.
+ if (min == max) return;
+ }
+
+ // Move elements [min, max) and destroy their source for destructor side effects.
+ const auto [first, last] = std::make_pair(from->begin() + min, from->begin() + max);
+ std::uninitialized_move(first, last, to->begin() + min);
+ std::destroy(first, last);
+
+ std::swap(mSize, other.mSize);
+}
+
+template <typename T, size_t N>
+inline void swap(StaticVector<T, N>& lhs, StaticVector<T, N>& rhs) {
+ lhs.swap(rhs);
+}
+
+// TODO: Replace with operator<=> in C++20.
+template <typename T, size_t N, size_t M>
+inline bool operator==(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+ return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+template <typename T, size_t N, size_t M>
+inline bool operator<(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+ return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+}
+
+template <typename T, size_t N, size_t M>
+inline bool operator>(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+ return rhs < lhs;
+}
+
+template <typename T, size_t N, size_t M>
+inline bool operator!=(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+ return !(lhs == rhs);
+}
+
+template <typename T, size_t N, size_t M>
+inline bool operator>=(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+ return !(lhs < rhs);
+}
+
+template <typename T, size_t N, size_t M>
+inline bool operator<=(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+ return !(rhs < lhs);
+}
+
+} // namespace android::ftl
diff --git a/include/gfx/.clang-format b/include/gfx/.clang-format
deleted file mode 100644
index 86763a0..0000000
--- a/include/gfx/.clang-format
+++ /dev/null
@@ -1,11 +0,0 @@
-BasedOnStyle: Google
-
-AccessModifierOffset: -2
-AllowShortFunctionsOnASingleLine: Inline
-BinPackParameters: false
-ColumnLimit: 100
-CommentPragmas: NOLINT:.*
-ConstructorInitializerAllOnOneLineOrOnePerLine: true
-ConstructorInitializerIndentWidth: 2
-ContinuationIndentWidth: 8
-IndentWidth: 4
diff --git a/include/input/Input.h b/include/input/Input.h
index 7d81fed..d3a9694 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -177,9 +177,7 @@
namespace android {
-#ifdef __ANDROID__
class Parcel;
-#endif
const char* inputEventTypeToString(int32_t type);
@@ -346,10 +344,8 @@
return getAxisValue(AMOTION_EVENT_AXIS_Y);
}
-#ifdef __ANDROID__
status_t readFromParcel(Parcel* parcel);
status_t writeToParcel(Parcel* parcel) const;
-#endif
bool operator==(const PointerCoords& other) const;
inline bool operator!=(const PointerCoords& other) const {
@@ -708,10 +704,8 @@
// Matrix is in row-major form and compatible with SkMatrix.
void transform(const std::array<float, 9>& matrix);
-#ifdef __ANDROID__
status_t readFromParcel(Parcel* parcel);
status_t writeToParcel(Parcel* parcel) const;
-#endif
static bool isTouchEvent(uint32_t source, int32_t action);
inline bool isTouchEvent() const {
@@ -730,7 +724,7 @@
static const char* getLabel(int32_t axis);
static int32_t getAxisFromLabel(const char* label);
- static const char* actionToString(int32_t action);
+ static std::string actionToString(int32_t action);
protected:
int32_t mAction;
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index d874347..339c7eb 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -19,9 +19,7 @@
#include <stdint.h>
-#ifdef __ANDROID__
#include <binder/IBinder.h>
-#endif
#include <android-base/result.h>
#include <input/Input.h>
@@ -134,13 +132,11 @@
void tryRemapKey(int32_t scanCode, int32_t metaState,
int32_t* outKeyCode, int32_t* outMetaState) const;
-#ifdef __ANDROID__
/* Reads a key map from a parcel. */
static std::shared_ptr<KeyCharacterMap> readFromParcel(Parcel* parcel);
/* Writes a key map to a parcel. */
void writeToParcel(Parcel* parcel) const;
-#endif
KeyCharacterMap(const KeyCharacterMap& other);
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index e4ea60f..e1cbc19 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -49,7 +49,7 @@
int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
if (fd >= 0) {
- if (mapfd(fd, size) == NO_ERROR) {
+ if (mapfd(fd, true, size) == NO_ERROR) {
if (flags & READ_ONLY) {
ashmem_set_prot_region(fd, PROT_READ);
}
@@ -70,7 +70,7 @@
if (fd >= 0) {
const size_t pagesize = getpagesize();
size = ((size + pagesize-1) & ~(pagesize-1));
- if (mapfd(fd, size) == NO_ERROR) {
+ if (mapfd(fd, false, size) == NO_ERROR) {
mDevice = device;
}
}
@@ -82,7 +82,7 @@
{
const size_t pagesize = getpagesize();
size = ((size + pagesize-1) & ~(pagesize-1));
- mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), size, offset);
+ mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
}
status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device)
@@ -98,7 +98,7 @@
return NO_ERROR;
}
-status_t MemoryHeapBase::mapfd(int fd, size_t size, off_t offset)
+status_t MemoryHeapBase::mapfd(int fd, bool writeableByCaller, size_t size, off_t offset)
{
if (size == 0) {
// try to figure out the size automatically
@@ -116,8 +116,12 @@
}
if ((mFlags & DONT_MAP_LOCALLY) == 0) {
+ int prot = PROT_READ;
+ if (writeableByCaller || (mFlags & READ_ONLY) == 0) {
+ prot |= PROT_WRITE;
+ }
void* base = (uint8_t*)mmap(nullptr, size,
- PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
+ prot, MAP_SHARED, fd, offset);
if (base == MAP_FAILED) {
ALOGE("mmap(fd=%d, size=%zu) failed (%s)",
fd, size, strerror(errno));
diff --git a/libs/binder/ParcelableHolder.cpp b/libs/binder/ParcelableHolder.cpp
index e9df279..b2b8671 100644
--- a/libs/binder/ParcelableHolder.cpp
+++ b/libs/binder/ParcelableHolder.cpp
@@ -27,7 +27,6 @@
namespace android {
namespace os {
status_t ParcelableHolder::writeToParcel(Parcel* p) const {
- std::lock_guard<std::mutex> l(mMutex);
RETURN_ON_FAILURE(p->writeInt32(static_cast<int32_t>(this->getStability())));
if (this->mParcelPtr) {
RETURN_ON_FAILURE(p->writeInt32(this->mParcelPtr->dataSize()));
@@ -53,7 +52,6 @@
}
status_t ParcelableHolder::readFromParcel(const Parcel* p) {
- std::lock_guard<std::mutex> l(mMutex);
this->mStability = static_cast<Stability>(p->readInt32());
this->mParcelable = nullptr;
this->mParcelableName = std::nullopt;
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index 52bd5de..0ece121 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -51,6 +51,8 @@
/*
* maps memory from ashmem, with the given name for debugging
+ * if the READ_ONLY flag is set, the memory will be writeable by the calling process,
+ * but not by others. this is NOT the case with the other ctors.
*/
explicit MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = nullptr);
@@ -78,7 +80,7 @@
int flags = 0, const char* device = nullptr);
private:
- status_t mapfd(int fd, size_t size, off_t offset = 0);
+ status_t mapfd(int fd, bool writeableByCaller, size_t size, off_t offset = 0);
int mFD;
size_t mSize;
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index b6814aa..4ea3dd3 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -59,7 +59,6 @@
template <typename T>
bool setParcelable(std::shared_ptr<T> p) {
- std::lock_guard<std::mutex> l(mMutex);
static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
if (p && this->getStability() > p->getStability()) {
return false;
@@ -73,7 +72,6 @@
template <typename T>
std::shared_ptr<T> getParcelable() const {
static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
- std::lock_guard<std::mutex> l(mMutex);
const std::string& parcelableDesc = T::getParcelableDescriptor();
if (!this->mParcelPtr) {
if (!this->mParcelable || !this->mParcelableName) {
@@ -103,7 +101,7 @@
return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
}
- Stability getStability() const override { return mStability; };
+ Stability getStability() const override { return mStability; }
inline bool operator!=(const ParcelableHolder& rhs) const {
return std::tie(mParcelable, mParcelPtr, mStability) !=
@@ -135,7 +133,6 @@
mutable std::optional<std::string> mParcelableName;
mutable std::unique_ptr<Parcel> mParcelPtr;
Stability mStability;
- mutable std::mutex mMutex;
};
} // namespace os
} // namespace android
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 4fd0657..e4d86ae 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -35,6 +35,8 @@
defaults: ["libbinder_ndk_host_user"],
host_supported: true,
+ llndk_stubs: "libbinder_ndk.llndk",
+
export_include_dirs: [
"include_cpp",
"include_ndk",
@@ -120,7 +122,7 @@
}
llndk_library {
- name: "libbinder_ndk",
+ name: "libbinder_ndk.llndk",
symbol_file: "libbinder_ndk.map.txt",
export_include_dirs: [
"include_cpp",
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 09949ea..054aebe 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -45,7 +45,7 @@
std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
if (static_cast<size_t>(length) > vec->max_size()) return false;
- vec->resize(length);
+ vec->resize(static_cast<size_t>(length));
*outBuffer = vec->data();
return true;
}
@@ -66,7 +66,7 @@
*vec = std::optional<std::vector<T>>(std::vector<T>{});
if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
- (*vec)->resize(length);
+ (*vec)->resize(static_cast<size_t>(length));
*outBuffer = (*vec)->data();
return true;
@@ -90,7 +90,7 @@
std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
if (static_cast<size_t>(length) > vec->max_size()) return false;
- vec->resize(length);
+ vec->resize(static_cast<size_t>(length));
return true;
}
@@ -117,7 +117,7 @@
*vec = std::optional<std::vector<T>>(std::vector<T>{});
if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
- (*vec)->resize(length);
+ (*vec)->resize(static_cast<size_t>(length));
return true;
}
@@ -257,7 +257,7 @@
if (length <= 0) return false;
std::string* str = static_cast<std::string*>(stringData);
- str->resize(length - 1);
+ str->resize(static_cast<size_t>(length) - 1);
*buffer = &(*str)[0];
return true;
}
@@ -279,7 +279,7 @@
}
*str = std::optional<std::string>(std::string{});
- (*str)->resize(length - 1);
+ (*str)->resize(static_cast<size_t>(length) - 1);
*buffer = &(**str)[0];
return true;
}
@@ -303,7 +303,7 @@
const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData);
const std::string& element = vec->at(index);
- *outLength = element.size();
+ *outLength = static_cast<int32_t>(element.size());
return element.c_str();
}
@@ -337,7 +337,7 @@
return nullptr;
}
- *outLength = element->size();
+ *outLength = static_cast<int32_t>(element->size());
return element->c_str();
}
@@ -345,7 +345,7 @@
* Convenience API for writing a std::string.
*/
static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) {
- return AParcel_writeString(parcel, str.c_str(), str.size());
+ return AParcel_writeString(parcel, str.c_str(), static_cast<int32_t>(str.size()));
}
/**
@@ -365,7 +365,7 @@
return AParcel_writeString(parcel, nullptr, -1);
}
- return AParcel_writeString(parcel, str->c_str(), str->size());
+ return AParcel_writeString(parcel, str->c_str(), static_cast<int32_t>(str->size()));
}
/**
@@ -383,7 +383,7 @@
static inline binder_status_t AParcel_writeVector(AParcel* parcel,
const std::vector<std::string>& vec) {
const void* vectorData = static_cast<const void*>(&vec);
- return AParcel_writeStringArray(parcel, vectorData, vec.size(),
+ return AParcel_writeStringArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
AParcel_stdVectorStringElementGetter);
}
@@ -404,7 +404,8 @@
static inline binder_status_t AParcel_writeVector(
AParcel* parcel, const std::optional<std::vector<std::optional<std::string>>>& vec) {
const void* vectorData = static_cast<const void*>(&vec);
- return AParcel_writeStringArray(parcel, vectorData, (vec ? vec->size() : -1),
+ return AParcel_writeStringArray(parcel, vectorData,
+ (vec ? static_cast<int32_t>(vec->size()) : -1),
AParcel_nullableStdVectorStringElementGetter);
}
@@ -545,7 +546,7 @@
template <typename P>
static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<P>& vec) {
const void* vectorData = static_cast<const void*>(&vec);
- return AParcel_writeParcelableArray(parcel, vectorData, vec.size(),
+ return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
AParcel_writeStdVectorParcelableElement<P>);
}
@@ -564,7 +565,7 @@
* Writes a vector of int32_t to the next location in a non-null parcel.
*/
inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
- return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
+ return AParcel_writeInt32Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
}
/**
@@ -597,7 +598,7 @@
* Writes a vector of uint32_t to the next location in a non-null parcel.
*/
inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
- return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
+ return AParcel_writeUint32Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
}
/**
@@ -631,7 +632,7 @@
* Writes a vector of int64_t to the next location in a non-null parcel.
*/
inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
- return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
+ return AParcel_writeInt64Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
}
/**
@@ -664,7 +665,7 @@
* Writes a vector of uint64_t to the next location in a non-null parcel.
*/
inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
- return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
+ return AParcel_writeUint64Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
}
/**
@@ -698,7 +699,7 @@
* Writes a vector of float to the next location in a non-null parcel.
*/
inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
- return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
+ return AParcel_writeFloatArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
}
/**
@@ -731,7 +732,7 @@
* Writes a vector of double to the next location in a non-null parcel.
*/
inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
- return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
+ return AParcel_writeDoubleArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
}
/**
@@ -764,8 +765,8 @@
* Writes a vector of bool to the next location in a non-null parcel.
*/
inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) {
- return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), vec.size(),
- AParcel_stdVectorGetter<bool>);
+ return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec),
+ static_cast<int32_t>(vec.size()), AParcel_stdVectorGetter<bool>);
}
/**
@@ -801,7 +802,7 @@
* Writes a vector of char16_t to the next location in a non-null parcel.
*/
inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
- return AParcel_writeCharArray(parcel, vec.data(), vec.size());
+ return AParcel_writeCharArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
}
/**
@@ -834,7 +835,8 @@
* Writes a vector of uint8_t to the next location in a non-null parcel.
*/
inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint8_t>& vec) {
- return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(vec.data()), vec.size());
+ return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(vec.data()),
+ static_cast<int32_t>(vec.size()));
}
/**
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 6701518..dfcf4dc 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -25,6 +25,8 @@
*/
#pragma once
+#include <android/binder_parcel_utils.h>
+#include <optional>
namespace ndk {
// Also see Parcelable.h in libbinder.
@@ -33,6 +35,89 @@
STABILITY_LOCAL,
STABILITY_VINTF, // corresponds to @VintfStability
};
+#define RETURN_ON_FAILURE(expr) \
+ do { \
+ binder_status_t _status = (expr); \
+ if (_status != STATUS_OK) return _status; \
+ } while (false)
+
+class AParcelableHolder {
+ public:
+ AParcelableHolder() = delete;
+ explicit AParcelableHolder(parcelable_stability_t stability)
+ : mParcel(AParcel_create()), mStability(stability) {}
+
+ virtual ~AParcelableHolder() = default;
+
+ binder_status_t writeToParcel(AParcel* parcel) const {
+ RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
+ RETURN_ON_FAILURE(AParcel_writeInt32(parcel, AParcel_getDataSize(this->mParcel.get())));
+ RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0,
+ AParcel_getDataSize(this->mParcel.get())));
+ return STATUS_OK;
+ }
+
+ binder_status_t readFromParcel(const AParcel* parcel) {
+ AParcel_reset(mParcel.get());
+
+ RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
+ int32_t dataSize;
+ binder_status_t status = AParcel_readInt32(parcel, &dataSize);
+
+ if (status != STATUS_OK || dataSize < 0) {
+ return status != STATUS_OK ? status : STATUS_BAD_VALUE;
+ }
+
+ int32_t dataStartPos = AParcel_getDataPosition(parcel);
+
+ if (dataStartPos > INT32_MAX - dataSize) {
+ return STATUS_BAD_VALUE;
+ }
+
+ status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ return AParcel_setDataPosition(parcel, dataStartPos + dataSize);
+ }
+
+ template <typename T>
+ bool setParcelable(T* p) {
+ if (p && this->mStability > T::_aidl_stability) {
+ return false;
+ }
+ AParcel_reset(mParcel.get());
+ AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
+ p->writeToParcel(mParcel.get());
+ return true;
+ }
+
+ template <typename T>
+ std::unique_ptr<T> getParcelable() const {
+ const std::string parcelableDesc(T::descriptor);
+ AParcel_setDataPosition(mParcel.get(), 0);
+ if (AParcel_getDataSize(mParcel.get()) == 0) {
+ return nullptr;
+ }
+ std::string parcelableDescInParcel;
+ binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
+ if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) {
+ return nullptr;
+ }
+ std::unique_ptr<T> ret = std::make_unique<T>();
+ status = ret->readFromParcel(this->mParcel.get());
+ if (status != STATUS_OK) {
+ return nullptr;
+ }
+ return std::move(ret);
+ }
+
+ private:
+ mutable ndk::ScopedAParcel mParcel;
+ parcelable_stability_t mStability;
+};
+
+#undef RETURN_ON_FAILURE
} // namespace ndk
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index a031e29..93c3f32 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -1120,6 +1120,53 @@
// @END-PRIMITIVE-READ-WRITE
#endif //__ANDROID_API__ >= 29
+#if __ANDROID_API__ >= 31
+/**
+ * Reset the parcel to the initial status.
+ *
+ * Available since API level 31.
+ *
+ * \param parcel The parcel of which to be reset.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_reset(AParcel* parcel) __INTRODUCED_IN(31);
+
+/**
+ * Gets the size of the parcel.
+ *
+ * Available since API level 31.
+ *
+ * \param parcel The parcel of which to get the size.
+ *
+ * \return The size of the parcel.
+ */
+int32_t AParcel_getDataSize(const AParcel* parcel) __INTRODUCED_IN(31);
+
+/**
+ * Copy the data of a parcel to other parcel.
+ *
+ * Available since API level 31.
+ *
+ * \param from The source
+ * \param to The detination
+ * \param start The position where the copied data starts.
+ * \param size The amount of data which will be copied.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_appendFrom(const AParcel* from, AParcel* to, int32_t start, int32_t size)
+ __INTRODUCED_IN(31);
+
+/**
+ * Creates a parcel.
+ *
+ * Available since API level 31.
+ *
+ * \return A parcel which is not related to any IBinder objects.
+ */
+AParcel* AParcel_create() __INTRODUCED_IN(31);
+#endif //__ANDROID_API__ >= 31
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 1701fb5..947cc98 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -120,6 +120,11 @@
AServiceManager_isDeclared; # apex llndk
AServiceManager_registerLazyService; # llndk
AServiceManager_waitForService; # apex llndk
+
+ AParcel_reset;
+ AParcel_getDataSize;
+ AParcel_appendFrom;
+ AParcel_create;
};
LIBBINDER_NDK_PLATFORM {
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 722ae23..2f95318 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -647,4 +647,22 @@
return parcel->get()->allowFds();
}
+binder_status_t AParcel_reset(AParcel* parcel) {
+ parcel->get()->freeData();
+ return STATUS_OK;
+}
+
+int32_t AParcel_getDataSize(const AParcel* parcel) {
+ return parcel->get()->dataSize();
+}
+
+binder_status_t AParcel_appendFrom(const AParcel* from, AParcel* to, int32_t start, int32_t size) {
+ status_t status = to->get()->appendFrom(from->get(), start, size);
+ return PruneStatusT(status);
+}
+
+AParcel* AParcel_create() {
+ return new AParcel(nullptr);
+}
+
// @END
diff --git a/libs/binder/parcel_fuzzer/Android.bp b/libs/binder/parcel_fuzzer/Android.bp
index 1a67898..c5b3d80 100644
--- a/libs/binder/parcel_fuzzer/Android.bp
+++ b/libs/binder/parcel_fuzzer/Android.bp
@@ -18,6 +18,7 @@
],
static_libs: [
"libbase",
+ "libbinder_random_parcel",
"libcgrouprc",
"libcgrouprc_format",
"libcutils",
@@ -47,3 +48,20 @@
// produced, you may find uncommenting the below line very useful.
// cflags: ["-DENABLE_LOG_FUZZ"],
}
+
+cc_library_static {
+ name: "libbinder_random_parcel",
+ host_supported: true,
+ srcs: [
+ "random_fd.cpp",
+ "random_parcel.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+ local_include_dirs: ["include_random_parcel"],
+ export_include_dirs: ["include_random_parcel"],
+}
diff --git a/libs/binder/parcel_fuzzer/binder_ndk.cpp b/libs/binder/parcel_fuzzer/binder_ndk.cpp
index 29da8f7..008780c 100644
--- a/libs/binder/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/parcel_fuzzer/binder_ndk.cpp
@@ -18,6 +18,7 @@
#include "binder_ndk.h"
#include <android/binder_parcel_utils.h>
+#include <android/binder_parcelable_utils.h>
#include "util.h"
@@ -54,6 +55,25 @@
binder_status_t status = AParcel_readStatusHeader(p.aParcel(), t.getR());
FUZZ_LOG() << "read status header: " << status;
},
+ [](const NdkParcelAdapter& p, uint8_t /*data*/) {
+ FUZZ_LOG() << "about to getDataSize the parcel";
+ AParcel_getDataSize(p.aParcel());
+ FUZZ_LOG() << "getDataSize done";
+ },
+ [](const NdkParcelAdapter& p, uint8_t data) {
+ FUZZ_LOG() << "about to read a ParcelableHolder";
+ ndk::AParcelableHolder ph {(data % 2 == 1) ? ndk::STABILITY_LOCAL : ndk::STABILITY_VINTF};
+ binder_status_t status = AParcel_readParcelable(p.aParcel(), &ph);
+ FUZZ_LOG() << "read the ParcelableHolder: " << status;
+ },
+ [](const NdkParcelAdapter& p, uint8_t data) {
+ FUZZ_LOG() << "about to appendFrom";
+ AParcel* parcel = AParcel_create();
+ binder_status_t status = AParcel_appendFrom(p.aParcel(), parcel, 0, data);
+ AParcel_delete(parcel);
+ FUZZ_LOG() << "appendFrom: " << status;
+ },
+
PARCEL_READ(int32_t, AParcel_readInt32),
PARCEL_READ(uint32_t, AParcel_readUint32),
PARCEL_READ(int64_t, AParcel_readInt64),
diff --git a/libs/binder/parcel_fuzzer/random_fd.h b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/random_fd.h
rename to libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
diff --git a/libs/binder/parcel_fuzzer/random_parcel.h b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
similarity index 88%
rename from libs/binder/parcel_fuzzer/random_parcel.h
rename to libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 2923c47..b92a6a9 100644
--- a/libs/binder/parcel_fuzzer/random_parcel.h
+++ b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -16,12 +16,9 @@
#pragma once
-#include "binder_ndk.h"
-
#include <binder/Parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
namespace android {
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
-void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider);
} // namespace android
diff --git a/libs/binder/parcel_fuzzer/main.cpp b/libs/binder/parcel_fuzzer/main.cpp
index 46bf417..386c70b 100644
--- a/libs/binder/parcel_fuzzer/main.cpp
+++ b/libs/binder/parcel_fuzzer/main.cpp
@@ -18,10 +18,10 @@
#include "binder.h"
#include "binder_ndk.h"
#include "hwbinder.h"
-#include "random_parcel.h"
#include "util.h"
#include <android-base/logging.h>
+#include <fuzzbinder/random_parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <cstdlib>
@@ -30,9 +30,14 @@
using android::fillRandomParcel;
void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
+ // TODO: functionality to create random parcels for libhwbinder parcels
std::vector<uint8_t> input = provider.ConsumeRemainingBytes<uint8_t>();
p->setData(input.data(), input.size());
}
+static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider) {
+ // fill underlying parcel using functions to fill random libbinder parcel
+ fillRandomParcel(p->parcel(), std::move(provider));
+}
template <typename P>
void doFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads,
diff --git a/libs/binder/parcel_fuzzer/random_fd.cpp b/libs/binder/parcel_fuzzer/random_fd.cpp
index eb80ece..cef6adb 100644
--- a/libs/binder/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/parcel_fuzzer/random_fd.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "random_fd.h"
+#include <fuzzbinder/random_fd.h>
#include <fcntl.h>
diff --git a/libs/binder/parcel_fuzzer/random_parcel.cpp b/libs/binder/parcel_fuzzer/random_parcel.cpp
index 3dae904..9ca4c8a 100644
--- a/libs/binder/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/parcel_fuzzer/random_parcel.cpp
@@ -14,20 +14,15 @@
* limitations under the License.
*/
-#include "random_parcel.h"
-
-#include "random_fd.h"
+#include <fuzzbinder/random_parcel.h>
#include <android-base/logging.h>
#include <binder/IServiceManager.h>
+#include <fuzzbinder/random_fd.h>
#include <utils/String16.h>
namespace android {
-void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider) {
- fillRandomParcel(p->parcel(), std::move(provider));
-}
-
class NamedBinder : public BBinder {
public:
NamedBinder(const String16& descriptor) : mDescriptor(descriptor) {}
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 5e785b6..6058430 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -425,6 +425,7 @@
uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0;
do {
+ if (key.bucket > (gNCpus - 1) / CPUS_PER_ENTRY) return {};
if (lastUpdate) {
auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate);
if (!uidUpdated.has_value()) return {};
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index ea2a200..0d5f412 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -387,6 +387,28 @@
}
}
+TEST(TimeInStateTest, AllUidConcurrentTimesFailsOnInvalidBucket) {
+ uint32_t uid = 0;
+ {
+ // Find an unused UID
+ auto map = getUidsConcurrentTimes();
+ ASSERT_TRUE(map.has_value());
+ ASSERT_FALSE(map->empty());
+ for (const auto &kv : *map) uid = std::max(uid, kv.first);
+ ++uid;
+ }
+ android::base::unique_fd fd{
+ bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+ ASSERT_GE(fd, 0);
+ uint32_t nCpus = get_nprocs_conf();
+ uint32_t maxBucket = (nCpus - 1) / CPUS_PER_ENTRY;
+ time_key_t key = {.uid = uid, .bucket = maxBucket + 1};
+ std::vector<concurrent_val_t> vals(nCpus);
+ ASSERT_FALSE(writeToMapEntry(fd, &key, vals.data(), BPF_NOEXIST));
+ EXPECT_FALSE(getUidsConcurrentTimes().has_value());
+ ASSERT_FALSE(deleteMapEntry(fd, &key));
+}
+
TEST(TimeInStateTest, AllUidTimesConsistent) {
auto tisMap = getUidsCpuFreqTimes();
ASSERT_TRUE(tisMap.has_value());
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 8f092f6..143fa13 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -33,6 +33,7 @@
"/system/bin/mediaextractor", // media.extractor
"/system/bin/mediametrics", // media.metrics
"/system/bin/mediaserver",
+ "/system/bin/mediatranscoding", // media.transcoding
"/system/bin/netd",
"/system/bin/sdcard",
"/apex/com.android.os.statsd/bin/statsd",
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
new file mode 100644
index 0000000..e11be57
--- /dev/null
+++ b/libs/ftl/Android.bp
@@ -0,0 +1,16 @@
+cc_test {
+ name: "ftl_test",
+ test_suites: ["device-tests"],
+ sanitize: {
+ address: true,
+ },
+ srcs: [
+ "StaticVector_test.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wpedantic",
+ ],
+}
diff --git a/libs/ftl/StaticVector_test.cpp b/libs/ftl/StaticVector_test.cpp
new file mode 100644
index 0000000..06e4659
--- /dev/null
+++ b/libs/ftl/StaticVector_test.cpp
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ftl/StaticVector.h>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+
+using namespace std::string_literals;
+
+namespace android::test {
+
+using ftl::StaticVector;
+
+// Keep in sync with example usage in header file.
+TEST(StaticVector, Example) {
+ ftl::StaticVector<char, 3> vector;
+ EXPECT_TRUE(vector.empty());
+
+ vector = {'a', 'b'};
+ EXPECT_EQ(vector.size(), 2u);
+
+ vector.push_back('c');
+ EXPECT_TRUE(vector.full());
+
+ EXPECT_FALSE(vector.push_back('d'));
+ EXPECT_EQ(vector.size(), 3u);
+
+ vector.unstable_erase(vector.begin());
+ EXPECT_EQ(vector, (ftl::StaticVector{'c', 'b'}));
+
+ vector.pop_back();
+ EXPECT_EQ(vector.back(), 'c');
+
+ const char array[] = "hi";
+ vector = ftl::StaticVector(array);
+ EXPECT_EQ(vector, (ftl::StaticVector{'h', 'i', '\0'}));
+}
+
+TEST(StaticVector, Construct) {
+ {
+ // Default constructor.
+ StaticVector<std::string, 2> vector;
+ EXPECT_TRUE(vector.empty());
+ }
+ {
+ // Array constructor.
+ const float kFloats[] = {.1f, .2f, .3f};
+ StaticVector vector(kFloats);
+ EXPECT_EQ(vector, (StaticVector{.1f, .2f, .3f}));
+ }
+ {
+ // Iterator constructor.
+ const char chars[] = "abcdef";
+ std::string string(chars);
+ StaticVector<char, sizeof(chars)> vector(string.begin(), string.end());
+
+ EXPECT_STREQ(vector.begin(), chars);
+ }
+ {
+ // Variadic constructor with same types.
+ StaticVector vector = {1, 2, 3};
+
+ static_assert(std::is_same_v<decltype(vector), StaticVector<int, 3>>);
+ EXPECT_EQ(vector, (StaticVector{1, 2, 3}));
+ }
+ {
+ // Variadic constructor with different types.
+ const auto copy = "quince"s;
+ auto move = "tart"s;
+ StaticVector vector = {copy, std::move(move)};
+
+ static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 2>>);
+ EXPECT_EQ(vector, (StaticVector{"quince"s, "tart"s}));
+ }
+ {
+ // In-place constructor with same types.
+ StaticVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+
+ static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 3>>);
+ EXPECT_EQ(vector, (StaticVector{"red"s, "velvet"s, "cake"s}));
+ }
+ {
+ // In-place constructor with different types.
+ const auto copy = "red"s;
+ auto move = "velvet"s;
+ std::initializer_list<char> list = {'c', 'a', 'k', 'e'};
+ StaticVector vector(std::in_place_type<std::string>, copy.c_str(), std::move(move), list);
+
+ static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 3>>);
+ EXPECT_EQ(vector, (StaticVector{"red"s, "velvet"s, "cake"s}));
+ }
+}
+
+TEST(StaticVector, String) {
+ StaticVector<char, 10> chars;
+ char c = 'a';
+ std::generate_n(std::back_inserter(chars), chars.max_size(), [&c] { return c++; });
+ chars.back() = '\0';
+
+ EXPECT_STREQ(chars.begin(), "abcdefghi");
+
+ // Constructor takes iterator range.
+ const char kString[] = "123456";
+ StaticVector<char, 10> string(std::begin(kString), std::end(kString));
+
+ EXPECT_STREQ(string.begin(), "123456");
+ EXPECT_EQ(string.size(), 7u);
+
+ // Similar to emplace, but replaces rather than inserts.
+ const auto it = string.replace(string.begin() + 5, '\0');
+ EXPECT_NE(it, string.end());
+ EXPECT_STREQ(string.begin(), "12345");
+
+ swap(chars, string);
+
+ EXPECT_STREQ(chars.begin(), "12345");
+ EXPECT_STREQ(string.begin(), "abcdefghi");
+}
+
+TEST(StaticVector, CopyableElement) {
+ struct Pair {
+ const int a, b;
+ bool operator==(Pair p) const { return p.a == a && p.b == b; }
+ };
+
+ StaticVector<Pair, 5> pairs;
+
+ EXPECT_TRUE(pairs.empty());
+ EXPECT_EQ(pairs.max_size(), 5u);
+
+ for (size_t i = 0; i < pairs.max_size(); ++i) {
+ EXPECT_EQ(pairs.size(), i);
+
+ const int a = static_cast<int>(i) * 2;
+ const auto it = pairs.emplace_back(a, a + 1);
+ ASSERT_NE(it, pairs.end());
+ EXPECT_EQ(*it, (Pair{a, a + 1}));
+ }
+
+ EXPECT_TRUE(pairs.full());
+ EXPECT_EQ(pairs.size(), 5u);
+
+ // Insertion fails if the vector is full.
+ const auto it = pairs.emplace_back(10, 11);
+ EXPECT_EQ(it, pairs.end());
+
+ EXPECT_EQ(pairs, (StaticVector{Pair{0, 1}, Pair{2, 3}, Pair{4, 5}, Pair{6, 7}, Pair{8, 9}}));
+
+ // Constructor takes at most N elements.
+ StaticVector<int, 6> sums = {0, 0, 0, 0, 0, -1};
+ EXPECT_TRUE(sums.full());
+
+ // Random-access iterators comply with standard.
+ std::transform(pairs.begin(), pairs.end(), sums.begin(), [](Pair p) { return p.a + p.b; });
+ EXPECT_EQ(sums, (StaticVector{1, 5, 9, 13, 17, -1}));
+
+ sums.pop_back();
+ std::reverse(sums.begin(), sums.end());
+
+ EXPECT_EQ(sums, (StaticVector{17, 13, 9, 5, 1}));
+}
+
+TEST(StaticVector, MovableElement) {
+ // Construct std::string elements in-place from C-style strings. Without std::in_place_type, the
+ // element type would be deduced from the first element, i.e. const char*.
+ StaticVector strings(std::in_place_type<std::string>, "", "", "", "cake", "velvet", "red", "");
+ strings.pop_back();
+
+ EXPECT_EQ(strings.max_size(), 7u);
+ EXPECT_EQ(strings.size(), 6u);
+
+ // Erase "cake" and append a substring copy.
+ {
+ auto it = std::find_if(strings.begin(), strings.end(),
+ [](const auto& s) { return !s.empty(); });
+ ASSERT_FALSE(it == strings.end());
+ EXPECT_EQ(*it, "cake");
+
+ strings.unstable_erase(it);
+
+ // Construct std::string from first 4 characters of C-style string.
+ it = strings.emplace_back("cakewalk", 4u);
+ ASSERT_NE(it, strings.end());
+ EXPECT_EQ(*it, "cake"s);
+ }
+
+ strings[1] = "quince"s;
+
+ // Replace last empty string with "tart".
+ {
+ const auto rit = std::find(strings.rbegin(), strings.rend(), std::string());
+ ASSERT_FALSE(rit == strings.rend());
+
+ std::initializer_list<char> list = {'t', 'a', 'r', 't'};
+ const auto it = strings.replace(rit.base() - 1, list);
+ EXPECT_NE(it, strings.end());
+ }
+
+ strings.front().assign("pie");
+
+ EXPECT_EQ(strings, (StaticVector{"pie"s, "quince"s, "tart"s, "red"s, "velvet"s, "cake"s}));
+}
+
+TEST(StaticVector, ReverseTruncate) {
+ StaticVector<std::string, 10> strings("pie", "quince", "tart", "red", "velvet", "cake");
+ EXPECT_FALSE(strings.full());
+
+ for (auto it = strings.begin(); it != strings.end(); ++it) {
+ strings.replace(it, strings.back());
+ strings.pop_back();
+ }
+
+ EXPECT_EQ(strings, (StaticVector{"cake"s, "velvet"s, "red"s}));
+}
+
+TEST(StaticVector, Sort) {
+ StaticVector<std::string, 7> strings("pie", "quince", "tart", "red", "velvet", "cake");
+ EXPECT_FALSE(strings.full());
+
+ auto sorted = std::move(strings);
+ EXPECT_TRUE(strings.empty());
+
+ std::sort(sorted.begin(), sorted.end());
+ EXPECT_EQ(sorted, (StaticVector{"cake"s, "pie"s, "quince"s, "red"s, "tart"s, "velvet"s}));
+
+ // Constructor takes array reference.
+ {
+ const char* kStrings[] = {"cake", "lie"};
+ strings = StaticVector(kStrings);
+ }
+
+ EXPECT_GT(sorted, strings);
+ swap(sorted, strings);
+ EXPECT_LT(sorted, strings);
+
+ // Append remaining elements, such that "pie" is the only difference.
+ sorted.replace(sorted.end(), "quince");
+ for (const char* str : {"red", "tart", "velvet"}) sorted.emplace_back(str);
+
+ EXPECT_NE(sorted, strings);
+
+ sorted.replace(sorted.begin() + 1, "pie");
+ EXPECT_EQ(sorted, strings);
+}
+
+namespace {
+
+struct DestroyCounts {
+ DestroyCounts(int& live, int& dead) : counts{live, dead} {}
+ DestroyCounts(const DestroyCounts& other) : counts(other.counts) {}
+ DestroyCounts(DestroyCounts&& other) : counts(other.counts) { other.alive = false; }
+ ~DestroyCounts() { ++(alive ? counts.live : counts.dead); }
+
+ struct {
+ int& live;
+ int& dead;
+ } counts;
+
+ bool alive = true;
+};
+
+void swap(DestroyCounts& lhs, DestroyCounts& rhs) {
+ std::swap(lhs.alive, rhs.alive);
+}
+
+} // namespace
+
+TEST(StaticVector, Destroy) {
+ int live = 0;
+ int dead = 0;
+
+ { StaticVector<DestroyCounts, 5> counts; }
+ EXPECT_EQ(0, live);
+ EXPECT_EQ(0, dead);
+
+ {
+ StaticVector<DestroyCounts, 5> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ }
+ EXPECT_EQ(3, live);
+ EXPECT_EQ(0, dead);
+
+ live = 0;
+ {
+ StaticVector<DestroyCounts, 5> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ auto copy = counts;
+ }
+ EXPECT_EQ(6, live);
+ EXPECT_EQ(0, dead);
+
+ live = 0;
+ {
+ StaticVector<DestroyCounts, 5> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ auto move = std::move(counts);
+ }
+ EXPECT_EQ(3, live);
+ EXPECT_EQ(3, dead);
+
+ live = dead = 0;
+ {
+ StaticVector<DestroyCounts, 5> counts1;
+ counts1.emplace_back(live, dead);
+ counts1.emplace_back(live, dead);
+ counts1.emplace_back(live, dead);
+
+ StaticVector<DestroyCounts, 5> counts2;
+ counts2.emplace_back(live, dead);
+
+ swap(counts1, counts2);
+
+ EXPECT_EQ(0, live);
+ EXPECT_EQ(2, dead);
+
+ dead = 0;
+ }
+ EXPECT_EQ(4, live);
+ EXPECT_EQ(0, dead);
+}
+
+} // namespace android::test
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index 66fb295..cc31cd5 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -38,14 +38,14 @@
],
shared_libs: [
- "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common-unstable-ndk_platform",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
"liblog",
],
export_shared_lib_headers: [
- "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common-unstable-ndk_platform",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
],
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 87f7972..ff64d65 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -23,6 +23,7 @@
#include <gui/BLASTBufferQueue.h>
#include <gui/BufferItemConsumer.h>
#include <gui/GLConsumer.h>
+#include <gui/Surface.h>
#include <utils/Trace.h>
@@ -213,12 +214,9 @@
ATRACE_CALL();
BQA_LOGV("processNextBufferLocked useNextTransaction=%s", toString(useNextTransaction));
- // Wait to acquire a buffer if there are no frames available or we have acquired the maximum
+ // Wait to acquire a buffer if there are no frames available or we have acquired the max
// number of buffers.
- // As a special case, we wait for the first callback before acquiring the second buffer so we
- // can ensure the first buffer is presented if multiple buffers are queued in succession.
- if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 ||
- (!mInitialCallbackReceived && mNumAcquired == 1)) {
+ if (mNumFrameAvailable == 0 || maxBuffersAcquired()) {
BQA_LOGV("processNextBufferLocked waiting for frame available or callback");
return;
}
@@ -241,6 +239,7 @@
status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, -1, false);
if (status != OK) {
+ BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str());
return;
}
auto buffer = bufferItem.mGraphicBuffer;
@@ -248,14 +247,15 @@
if (buffer == nullptr) {
mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
+ BQA_LOGE("Buffer was empty");
return;
}
if (rejectBuffer(bufferItem)) {
BQA_LOGE("rejecting buffer:configured size=%dx%d, buffer{size=%dx%d transform=%d}", mWidth,
mHeight, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
- mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
- return;
+ // TODO(b/168917217) temporarily don't reject buffers until we can synchronize buffer size
+ // changes from ViewRootImpl.
}
mNumAcquired++;
@@ -302,23 +302,31 @@
return item.mCrop;
}
-void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) {
+void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
ATRACE_CALL();
std::unique_lock _lock{mMutex};
const bool nextTransactionSet = mNextTransaction != nullptr;
- BQA_LOGV("onFrameAvailable nextTransactionSet=%s", toString(nextTransactionSet));
+ BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s mFlushShadowQueue=%s",
+ item.mFrameNumber, toString(nextTransactionSet), toString(mFlushShadowQueue));
- if (nextTransactionSet) {
- while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) {
+ if (nextTransactionSet || mFlushShadowQueue) {
+ while (mNumFrameAvailable > 0 || maxBuffersAcquired()) {
+ BQA_LOGV("waiting in onFrameAvailable...");
mCallbackCV.wait(_lock);
}
}
+ mFlushShadowQueue = false;
// add to shadow queue
mNumFrameAvailable++;
processNextBufferLocked(true);
}
+void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) {
+ BQA_LOGV("onFrameReplaced framenumber=%" PRIu64, item.mFrameNumber);
+ // Do nothing since we are not storing unacquired buffer items locally.
+}
+
void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
std::lock_guard _lock{mMutex};
mNextTransaction = t;
@@ -341,4 +349,72 @@
// reject buffers if the buffer size doesn't match.
return bufWidth != mWidth || bufHeight != mHeight;
}
+
+// Check if we have acquired the maximum number of buffers.
+// As a special case, we wait for the first callback before acquiring the second buffer so we
+// can ensure the first buffer is presented if multiple buffers are queued in succession.
+bool BLASTBufferQueue::maxBuffersAcquired() const {
+ return mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 ||
+ (!mInitialCallbackReceived && mNumAcquired == 1);
+}
+
+class BBQSurface : public Surface {
+private:
+ sp<BLASTBufferQueue> mBbq;
+public:
+ BBQSurface(const sp<IGraphicBufferProducer>& igbp, bool controlledByApp,
+ const sp<IBinder>& scHandle, const sp<BLASTBufferQueue>& bbq)
+ : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {}
+
+ void allocateBuffers() override {
+ uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth;
+ uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight;
+ auto gbp = getIGraphicBufferProducer();
+ std::thread ([reqWidth, reqHeight, gbp=getIGraphicBufferProducer(),
+ reqFormat=mReqFormat, reqUsage=mReqUsage] () {
+ gbp->allocateBuffers(reqWidth, reqHeight,
+ reqFormat, reqUsage);
+
+ }).detach();
+ }
+
+ status_t setFrameRate(float frameRate, int8_t compatibility) override {
+ if (!ValidateFrameRate(frameRate, compatibility, "BBQSurface::setFrameRate")) {
+ return BAD_VALUE;
+ }
+ return mBbq->setFrameRate(frameRate, compatibility);
+ }
+
+ status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId) override {
+ return mBbq->setFrameTimelineVsync(frameTimelineVsyncId);
+ }
+};
+
+// TODO: Can we coalesce this with frame updates? Need to confirm
+// no timing issues.
+status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility) {
+ std::unique_lock _lock{mMutex};
+ SurfaceComposerClient::Transaction t;
+
+ return t.setFrameRate(mSurfaceControl, frameRate, compatibility)
+ .apply();
+}
+
+status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) {
+ std::unique_lock _lock{mMutex};
+ SurfaceComposerClient::Transaction t;
+
+ return t.setFrameTimelineVsync(mSurfaceControl, frameTimelineVsyncId)
+ .apply();
+}
+
+sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
+ std::unique_lock _lock{mMutex};
+ sp<IBinder> scHandle = nullptr;
+ if (includeSurfaceControlHandle && mSurfaceControl) {
+ scHandle = mSurfaceControl->getHandle();
+ }
+ return new BBQSurface(mProducer, true, scHandle, this);
+}
+
} // namespace android
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 7e894b4..abfee61 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -73,8 +73,8 @@
nsecs_t vsyncTimestamp;
PhysicalDisplayId vsyncDisplayId;
uint32_t vsyncCount;
- int64_t vsyncId;
- if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncId)) {
+ VsyncEventData vsyncEventData;
+ if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
}
@@ -117,13 +117,14 @@
nsecs_t vsyncTimestamp;
PhysicalDisplayId vsyncDisplayId;
uint32_t vsyncCount;
- int64_t vsyncId;
- if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncId)) {
+ VsyncEventData vsyncEventData;
+ if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
", displayId=%s, count=%d, vsyncId=%" PRId64,
- this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount, vsyncId);
+ this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
+ vsyncEventData.id);
mWaitingForVsync = false;
- dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncId);
+ dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
}
return 1; // keep the callback
@@ -131,11 +132,11 @@
bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
PhysicalDisplayId* outDisplayId,
- uint32_t* outCount, int64_t* outVsyncId) {
+ uint32_t* outCount,
+ VsyncEventData* outVsyncEventData) {
bool gotVsync = false;
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
ssize_t n;
- *outVsyncId = 0;
while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
for (ssize_t i = 0; i < n; i++) {
@@ -148,7 +149,8 @@
*outTimestamp = ev.header.timestamp;
*outDisplayId = ev.header.displayId;
*outCount = ev.vsync.count;
- *outVsyncId = ev.vsync.vsyncId;
+ outVsyncEventData->id = ev.vsync.vsyncId;
+ outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp;
break;
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 964195d..6f92233 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -888,7 +888,7 @@
}
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig,
+ int32_t defaultConfig, bool allowGroupSwitching,
float primaryRefreshRateMin,
float primaryRefreshRateMax,
float appRequestRefreshRateMin,
@@ -909,6 +909,11 @@
ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result);
return result;
}
+ result = data.writeBool(allowGroupSwitching);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs failed to write allowGroupSwitching: %d", result);
+ return result;
+ }
result = data.writeFloat(primaryRefreshRateMin);
if (result != NO_ERROR) {
ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMin: %d", result);
@@ -943,12 +948,14 @@
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
+ bool* outAllowGroupSwitching,
float* outPrimaryRefreshRateMin,
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
float* outAppRequestRefreshRateMax) {
- if (!outDefaultConfig || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax ||
- !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
+ if (!outDefaultConfig || !outAllowGroupSwitching || !outPrimaryRefreshRateMin ||
+ !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin ||
+ !outAppRequestRefreshRateMax) {
return BAD_VALUE;
}
Parcel data, reply;
@@ -973,6 +980,11 @@
ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result);
return result;
}
+ result = reply.readBool(outAllowGroupSwitching);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs failed to read allowGroupSwitching: %d", result);
+ return result;
+ }
result = reply.readFloat(outPrimaryRefreshRateMin);
if (result != NO_ERROR) {
ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMin: %d", result);
@@ -1829,6 +1841,13 @@
ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultConfig: %d", result);
return result;
}
+ bool allowGroupSwitching;
+ result = data.readBool(&allowGroupSwitching);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read allowGroupSwitching: %d",
+ result);
+ return result;
+ }
float primaryRefreshRateMin;
result = data.readFloat(&primaryRefreshRateMin);
if (result != NO_ERROR) {
@@ -1857,10 +1876,10 @@
result);
return result;
}
- result =
- setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
- primaryRefreshRateMax, appRequestRefreshRateMin,
- appRequestRefreshRateMax);
+ result = setDesiredDisplayConfigSpecs(displayToken, defaultConfig, allowGroupSwitching,
+ primaryRefreshRateMin, primaryRefreshRateMax,
+ appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
if (result != NO_ERROR) {
ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: "
"%d",
@@ -1874,13 +1893,14 @@
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> displayToken = data.readStrongBinder();
int32_t defaultConfig;
+ bool allowGroupSwitching;
float primaryRefreshRateMin;
float primaryRefreshRateMax;
float appRequestRefreshRateMin;
float appRequestRefreshRateMax;
status_t result =
- getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
+ getDesiredDisplayConfigSpecs(displayToken, &defaultConfig, &allowGroupSwitching,
&primaryRefreshRateMin, &primaryRefreshRateMax,
&appRequestRefreshRateMin,
&appRequestRefreshRateMax);
@@ -1896,6 +1916,12 @@
ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result);
return result;
}
+ result = reply->writeBool(allowGroupSwitching);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write allowGroupSwitching: %d",
+ result);
+ return result;
+ }
result = reply->writeFloat(primaryRefreshRateMin);
if (result != NO_ERROR) {
ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMin: %d",
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 8594ab3..9722f36 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -44,7 +44,6 @@
cornerRadius(0.0f),
backgroundBlurRadius(0),
barrierFrameNumber(0),
- overrideScalingMode(-1),
transform(0),
transformToDisplayInverse(false),
crop(Rect::INVALID_RECT),
@@ -86,7 +85,6 @@
SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, barrierSurfaceControl_legacy);
SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, reparentSurfaceControl);
SAFE_PARCEL(output.writeUint64, barrierFrameNumber);
- SAFE_PARCEL(output.writeInt32, overrideScalingMode);
SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, relativeLayerSurfaceControl);
SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, parentSurfaceControlForChild);
SAFE_PARCEL(output.writeFloat, color.r);
@@ -148,6 +146,21 @@
SAFE_PARCEL(output.writeByte, frameRateCompatibility);
SAFE_PARCEL(output.writeUint32, fixedTransformHint);
SAFE_PARCEL(output.writeUint64, frameNumber);
+ SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId);
+
+ SAFE_PARCEL(output.writeUint32, blurRegions.size());
+ for (auto region : blurRegions) {
+ SAFE_PARCEL(output.writeUint32, region.blurRadius);
+ SAFE_PARCEL(output.writeFloat, region.cornerRadiusTL);
+ SAFE_PARCEL(output.writeFloat, region.cornerRadiusTR);
+ SAFE_PARCEL(output.writeFloat, region.cornerRadiusBL);
+ SAFE_PARCEL(output.writeFloat, region.cornerRadiusBR);
+ SAFE_PARCEL(output.writeFloat, region.alpha);
+ SAFE_PARCEL(output.writeInt32, region.left);
+ SAFE_PARCEL(output.writeInt32, region.top);
+ SAFE_PARCEL(output.writeInt32, region.right);
+ SAFE_PARCEL(output.writeInt32, region.bottom);
+ }
return NO_ERROR;
}
@@ -176,7 +189,6 @@
SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &barrierSurfaceControl_legacy);
SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &reparentSurfaceControl);
SAFE_PARCEL(input.readUint64, &barrierFrameNumber);
- SAFE_PARCEL(input.readInt32, &overrideScalingMode);
SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &relativeLayerSurfaceControl);
SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &parentSurfaceControlForChild);
@@ -253,6 +265,25 @@
SAFE_PARCEL(input.readUint32, &tmpUint32);
fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
SAFE_PARCEL(input.readUint64, &frameNumber);
+ SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId);
+
+ uint32_t numRegions = 0;
+ SAFE_PARCEL(input.readUint32, &numRegions);
+ blurRegions.clear();
+ for (uint32_t i = 0; i < numRegions; i++) {
+ BlurRegion region;
+ SAFE_PARCEL(input.readUint32, ®ion.blurRadius);
+ SAFE_PARCEL(input.readFloat, ®ion.cornerRadiusTL);
+ SAFE_PARCEL(input.readFloat, ®ion.cornerRadiusTR);
+ SAFE_PARCEL(input.readFloat, ®ion.cornerRadiusBL);
+ SAFE_PARCEL(input.readFloat, ®ion.cornerRadiusBR);
+ SAFE_PARCEL(input.readFloat, ®ion.alpha);
+ SAFE_PARCEL(input.readInt32, ®ion.left);
+ SAFE_PARCEL(input.readInt32, ®ion.top);
+ SAFE_PARCEL(input.readInt32, ®ion.right);
+ SAFE_PARCEL(input.readInt32, ®ion.bottom);
+ blurRegions.push_back(region);
+ }
return NO_ERROR;
}
@@ -376,15 +407,15 @@
what |= eBackgroundBlurRadiusChanged;
backgroundBlurRadius = other.backgroundBlurRadius;
}
+ if (other.what & eBlurRegionsChanged) {
+ what |= eBlurRegionsChanged;
+ blurRegions = other.blurRegions;
+ }
if (other.what & eDeferTransaction_legacy) {
what |= eDeferTransaction_legacy;
barrierSurfaceControl_legacy = other.barrierSurfaceControl_legacy;
barrierFrameNumber = other.barrierFrameNumber;
}
- if (other.what & eOverrideScalingModeChanged) {
- what |= eOverrideScalingModeChanged;
- overrideScalingMode = other.overrideScalingMode;
- }
if (other.what & eReparentChildren) {
what |= eReparentChildren;
reparentSurfaceControl = other.reparentSurfaceControl;
@@ -593,6 +624,7 @@
SAFE_PARCEL(output.writeBool, captureSecureLayers);
SAFE_PARCEL(output.writeInt32, uid);
SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(dataspace));
+ SAFE_PARCEL(output.writeBool, allowProtected);
return NO_ERROR;
}
@@ -606,6 +638,7 @@
SAFE_PARCEL(input.readInt32, &uid);
SAFE_PARCEL(input.readInt32, &value);
dataspace = static_cast<ui::Dataspace>(value);
+ SAFE_PARCEL(input.readBool, &allowProtected);
return NO_ERROR;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 9ce8442..c1155ab 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -63,7 +63,8 @@
} // namespace
-Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
+Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp,
+ const sp<IBinder>& surfaceControlHandle)
: mGraphicBufferProducer(bufferProducer),
mCrop(Rect::EMPTY_RECT),
mBufferAge(0),
@@ -111,6 +112,7 @@
mProducerControlledByApp = controlledByApp;
mSwapIntervalZero = false;
mMaxBufferCount = NUM_BUFFER_SLOTS;
+ mSurfaceControlHandle = surfaceControlHandle;
}
Surface::~Surface() {
@@ -1521,7 +1523,7 @@
auto frameTimelineVsyncId = static_cast<int64_t>(va_arg(args, int64_t));
ALOGV("Surface::dispatchSetFrameTimelineVsync");
- return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, frameTimelineVsyncId);
+ return setFrameTimelineVsync(frameTimelineVsyncId);
}
bool Surface::transformToDisplayInverse() {
@@ -2288,4 +2290,9 @@
return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility);
}
+status_t Surface::setFrameTimelineVsync(int64_t frameTimelineVsyncId) {
+ return composerService()->setFrameTimelineVsync(mGraphicBufferProducer,
+ frameTimelineVsyncId);
+}
+
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 0068ccf..039e900 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -695,8 +695,6 @@
}
}
- mListenerCallbacks.clear();
-
cacheBuffers();
Vector<ComposerState> composerStates;
@@ -709,10 +707,7 @@
composerStates.add(kv.second);
}
- mComposerStates.clear();
-
- displayStates = mDisplayStates;
- mDisplayStates.clear();
+ displayStates = std::move(mDisplayStates);
if (mForceSynchronous) {
flags |= ISurfaceComposer::eSynchronous;
@@ -733,21 +728,16 @@
flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd;
}
- mForceSynchronous = false;
- mAnimation = false;
- mEarlyWakeup = false;
- mExplicitEarlyWakeupStart = false;
- mExplicitEarlyWakeupEnd = false;
-
- uint64_t transactionId = mId;
- mId = generateId();
-
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken,
mInputWindowCommands, mDesiredPresentTime,
{} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
- hasListenerCallbacks, listenerCallbacks, transactionId);
- mInputWindowCommands.clear();
+ hasListenerCallbacks, listenerCallbacks, mId);
+ mId = generateId();
+
+ // Clear the current states and flags
+ clear();
+
mStatus = NO_ERROR;
return NO_ERROR;
}
@@ -1027,6 +1017,18 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBlurRegions(
+ const sp<SurfaceControl>& sc, const std::vector<BlurRegion>& blurRegions) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eBlurRegionsChanged;
+ s->blurRegions = blurRegions;
+ return *this;
+}
+
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(
const sp<SurfaceControl>& sc, const sp<SurfaceControl>& barrierSurfaceControl,
@@ -1353,35 +1355,6 @@
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverrideScalingMode(
- const sp<SurfaceControl>& sc, int32_t overrideScalingMode) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
-
- switch (overrideScalingMode) {
- case NATIVE_WINDOW_SCALING_MODE_FREEZE:
- case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
- case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
- case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
- case -1:
- break;
- default:
- ALOGE("unknown scaling mode: %d",
- overrideScalingMode);
- mStatus = BAD_VALUE;
- return *this;
- }
-
- s->what |= layer_state_t::eOverrideScalingModeChanged;
- s->overrideScalingMode = overrideScalingMode;
-
- registerSurfaceControlForCallback(sc);
- return *this;
-}
-
#ifndef NO_INPUT
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo(
const sp<SurfaceControl>& sc,
@@ -1539,6 +1512,19 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync(
+ const sp<SurfaceControl>& sc, int64_t frameTimelineVsyncId) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eFrameTimelineVsyncChanged;
+ s->frameTimelineVsyncId = frameTimelineVsyncId;
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -1654,11 +1640,11 @@
sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags,
- SurfaceControl* parent,
+ const sp<IBinder>& parentHandle,
LayerMetadata metadata,
uint32_t* outTransformHint) {
sp<SurfaceControl> s;
- createSurfaceChecked(name, w, h, format, &s, flags, parent, std::move(metadata),
+ createSurfaceChecked(name, w, h, format, &s, flags, parentHandle, std::move(metadata),
outTransformHint);
return s;
}
@@ -1695,20 +1681,16 @@
status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
PixelFormat format,
sp<SurfaceControl>* outSurface, uint32_t flags,
- SurfaceControl* parent, LayerMetadata metadata,
+ const sp<IBinder>& parentHandle,
+ LayerMetadata metadata,
uint32_t* outTransformHint) {
sp<SurfaceControl> sur;
status_t err = mStatus;
if (mStatus == NO_ERROR) {
sp<IBinder> handle;
- sp<IBinder> parentHandle;
sp<IGraphicBufferProducer> gbp;
- if (parent != nullptr) {
- parentHandle = parent->getHandle();
- }
-
uint32_t transformHint = 0;
int32_t id = -1;
err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),
@@ -1803,27 +1785,24 @@
return ComposerService::getComposerService()->getActiveConfig(display);
}
-status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig,
- float primaryRefreshRateMin,
- float primaryRefreshRateMax,
- float appRequestRefreshRateMin,
- float appRequestRefreshRateMax) {
+status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(
+ const sp<IBinder>& displayToken, int32_t defaultConfig, bool allowGroupSwitching,
+ float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
return ComposerService::getComposerService()
- ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
- primaryRefreshRateMax, appRequestRefreshRateMin,
- appRequestRefreshRateMax);
+ ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, allowGroupSwitching,
+ primaryRefreshRateMin, primaryRefreshRateMax,
+ appRequestRefreshRateMin, appRequestRefreshRateMax);
}
-status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultConfig,
- float* outPrimaryRefreshRateMin,
- float* outPrimaryRefreshRateMax,
- float* outAppRequestRefreshRateMin,
- float* outAppRequestRefreshRateMax) {
+status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(
+ const sp<IBinder>& displayToken, int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
+ float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
return ComposerService::getComposerService()
- ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outPrimaryRefreshRateMin,
- outPrimaryRefreshRateMax, outAppRequestRefreshRateMin,
+ ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outAllowGroupSwitching,
+ outPrimaryRefreshRateMin, outPrimaryRefreshRateMax,
+ outAppRequestRefreshRateMin,
outAppRequestRefreshRateMax);
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 5b1a018..2300e81 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -72,9 +72,10 @@
sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
return mProducer;
}
+ sp<Surface> getSurface(bool includeSurfaceControlHandle);
void onBufferFreed(const wp<GraphicBuffer>&/* graphicBuffer*/) override { /* TODO */ }
- void onFrameReplaced(const BufferItem& item) override {onFrameAvailable(item);}
+ void onFrameReplaced(const BufferItem& item) override;
void onFrameAvailable(const BufferItem& item) override;
void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
@@ -82,6 +83,10 @@
void setNextTransaction(SurfaceComposerClient::Transaction *t);
void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height);
+ void flushShadowQueue() { mFlushShadowQueue = true; }
+
+ status_t setFrameRate(float frameRate, int8_t compatibility);
+ status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId);
virtual ~BLASTBufferQueue() = default;
@@ -93,9 +98,10 @@
BLASTBufferQueue(const BLASTBufferQueue& rhs);
void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex);
- Rect computeCrop(const BufferItem& item);
+ Rect computeCrop(const BufferItem& item) REQUIRES(mMutex);
// Return true if we need to reject the buffer based on the scaling mode and the buffer size.
- bool rejectBuffer(const BufferItem& item) const;
+ bool rejectBuffer(const BufferItem& item) const REQUIRES(mMutex);
+ bool maxBuffersAcquired() const REQUIRES(mMutex);
std::string mName;
sp<SurfaceControl> mSurfaceControl;
@@ -130,6 +136,9 @@
sp<BLASTBufferItemConsumer> mBufferItemConsumer;
SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex);
+ // If set to true, the next queue buffer will wait until the shadow queue has been processed by
+ // the adapter.
+ bool mFlushShadowQueue = false;
};
} // namespace android
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index cf598ea..c65618b 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -20,6 +20,17 @@
namespace android {
+struct VsyncEventData {
+ // The Vsync Id corresponsing to this vsync event. This will be used to
+ // populate ISurfaceComposer::setFrameTimelineVsync and
+ // SurfaceComposerClient::setFrameTimelineVsync
+ int64_t id = ISurfaceComposer::INVALID_VSYNC_ID;
+
+ // The deadline in CLOCK_MONOTONIC that the app needs to complete its
+ // frame by (both on the CPU and the GPU)
+ int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
+};
+
class DisplayEventDispatcher : public LooperCallback {
public:
explicit DisplayEventDispatcher(
@@ -44,7 +55,7 @@
bool mWaitingForVsync;
virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
- int64_t vsyncId) = 0;
+ VsyncEventData vsyncEventData) = 0;
virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
bool connected) = 0;
virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
@@ -54,6 +65,6 @@
virtual void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) = 0;
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
- uint32_t* outCount, int64_t* outVsyncId);
+ uint32_t* outCount, VsyncEventData* outVsyncEventData);
};
} // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index a416147..5cd9356 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -395,7 +395,7 @@
* returned from getDisplayConfigs().
*/
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig,
+ int32_t defaultConfig, bool allowGroupSwitching,
float primaryRefreshRateMin,
float primaryRefreshRateMax,
float appRequestRefreshRateMin,
@@ -403,6 +403,7 @@
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
+ bool* outAllowGroupSwitching,
float* outPrimaryRefreshRateMin,
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index ff395ec..a73d9a6 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -51,6 +51,7 @@
#include <gui/LayerMetadata.h>
#include <gui/SurfaceControl.h>
#include <math/vec3.h>
+#include <ui/BlurRegion.h>
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -94,7 +95,7 @@
eLayerStackChanged = 0x00000080,
eCropChanged_legacy = 0x00000100,
eDeferTransaction_legacy = 0x00000200,
- eOverrideScalingModeChanged = 0x00000400,
+ /* was ScalingModeChanged, now available 0x00000400, */
eShadowRadiusChanged = 0x00000800,
eReparentChildren = 0x00001000,
eDetachChildren = 0x00002000,
@@ -127,6 +128,8 @@
eProducerDisconnect = 0x100'00000000,
eFixedTransformHintChanged = 0x200'00000000,
eFrameNumberChanged = 0x400'00000000,
+ eFrameTimelineVsyncChanged = 0x800'00000000,
+ eBlurRegionsChanged = 0x1000'00000000,
};
layer_state_t();
@@ -163,7 +166,6 @@
sp<SurfaceControl> barrierSurfaceControl_legacy;
sp<SurfaceControl> reparentSurfaceControl;
uint64_t barrierFrameNumber;
- int32_t overrideScalingMode;
sp<SurfaceControl> relativeLayerSurfaceControl;
@@ -186,6 +188,7 @@
int32_t api;
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
+ std::vector<BlurRegion> blurRegions;
#ifndef NO_INPUT
sp<InputWindowHandle> inputHandle = new InputWindowHandle();
@@ -228,6 +231,8 @@
// Used by BlastBufferQueue to forward the framenumber generated by the
// graphics producer.
uint64_t frameNumber;
+
+ int64_t frameTimelineVsyncId;
};
struct ComposerState {
@@ -319,6 +324,14 @@
// NOTE: In normal cases, we want the screen to be captured in display's colorspace.
ui::Dataspace dataspace = ui::Dataspace::UNKNOWN;
+ // The receiver of the capture can handle protected buffer. A protected buffer has
+ // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour.
+ // Any read/write access from unprotected context will result in undefined behaviour.
+ // Protected contents are typically DRM contents. This has no direct implication to the
+ // secure property of the surface, which is specified by the application explicitly to avoid
+ // the contents being accessed/captured by screenshot or unsecure display.
+ bool allowProtected = false;
+
virtual status_t write(Parcel& output) const;
virtual status_t read(const Parcel& input);
};
@@ -346,7 +359,7 @@
sp<GraphicBuffer> buffer;
bool capturedSecureLayers{false};
ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB};
- status_t result = NO_ERROR;
+ status_t result = OK;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index a68f2e7..4aa076e 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -68,7 +68,6 @@
: public ANativeObjectBase<ANativeWindow, Surface, RefBase>
{
public:
-
/*
* creates a Surface from the given IGraphicBufferProducer (which concrete
* implementation is a BufferQueue).
@@ -83,9 +82,15 @@
*
* the controlledByApp flag indicates that this Surface (producer) is
* controlled by the application. This flag is used at connect time.
+ *
+ * Pass in the SurfaceControlHandle to store a weak reference to the layer
+ * that the Surface was created from. This handle can be used to create a
+ * child surface without using the IGBP to identify the layer. This is used
+ * for surfaces created by the BlastBufferQueue whose IGBP is created on the
+ * client and cannot be verified in SF.
*/
- explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer,
- bool controlledByApp = false);
+ explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false,
+ const sp<IBinder>& surfaceControlHandle = nullptr);
/* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
* Surface was created with. Usually it's an error to use the
@@ -93,6 +98,8 @@
*/
sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
+ sp<IBinder> getSurfaceControlHandle() const { return mSurfaceControlHandle; }
+
/* convenience function to check that the given surface is non NULL as
* well as its IGraphicBufferProducer */
static bool isValid(const sp<Surface>& surface) {
@@ -120,7 +127,7 @@
* delay during dequeueBuffer. If there are already the maximum number of
* buffers allocated, this function has no effect.
*/
- void allocateBuffers();
+ virtual void allocateBuffers();
/* Sets the generation number on the IGraphicBufferProducer and updates the
* generation number on any buffers attached to the Surface after this call.
@@ -179,7 +186,8 @@
status_t getUniqueId(uint64_t* outId) const;
status_t getConsumerUsage(uint64_t* outUsage) const;
- status_t setFrameRate(float frameRate, int8_t compatibility);
+ virtual status_t setFrameRate(float frameRate, int8_t compatibility);
+ virtual status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId);
protected:
virtual ~Surface();
@@ -540,6 +548,11 @@
bool mEnableFrameTimestamps = false;
std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
+ // Reference to the SurfaceFlinger layer that was used to create this
+ // surface. This is only populated when the Surface is created from
+ // a BlastBufferQueue.
+ sp<IBinder> mSurfaceControlHandle;
+
bool mReportRemovedBuffers = false;
std::vector<sp<GraphicBuffer>> mRemovedBuffers;
int mMaxBufferCount;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 277060f..73909a3 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -29,6 +29,7 @@
#include <utils/SortedVector.h>
#include <utils/threads.h>
+#include <ui/BlurRegion.h>
#include <ui/ConfigStoreTypes.h>
#include <ui/DisplayedFrameStats.h>
#include <ui/FrameStats.h>
@@ -120,13 +121,15 @@
// Sets the refresh rate boundaries for the display.
static status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float primaryRefreshRateMin,
+ int32_t defaultConfig, bool allowGroupSwitching,
+ float primaryRefreshRateMin,
float primaryRefreshRateMax,
float appRequestRefreshRateMin,
float appRequestRefreshRateMax);
// Gets the refresh rate boundaries for the display.
static status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
+ bool* outAllowGroupSwitching,
float* outPrimaryRefreshRateMin,
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
@@ -253,13 +256,13 @@
static sp<SurfaceComposerClient> getDefault();
//! Create a surface
- sp<SurfaceControl> createSurface(const String8& name, // name of the surface
- uint32_t w, // width in pixel
- uint32_t h, // height in pixel
- PixelFormat format, // pixel-format desired
- uint32_t flags = 0, // usage flags
- SurfaceControl* parent = nullptr, // parent
- LayerMetadata metadata = LayerMetadata(), // metadata
+ sp<SurfaceControl> createSurface(const String8& name, // name of the surface
+ uint32_t w, // width in pixel
+ uint32_t h, // height in pixel
+ PixelFormat format, // pixel-format desired
+ uint32_t flags = 0, // usage flags
+ const sp<IBinder>& parentHandle = nullptr, // parentHandle
+ LayerMetadata metadata = LayerMetadata(), // metadata
uint32_t* outTransformHint = nullptr);
status_t createSurfaceChecked(const String8& name, // name of the surface
@@ -267,9 +270,9 @@
uint32_t h, // height in pixel
PixelFormat format, // pixel-format desired
sp<SurfaceControl>* outSurface,
- uint32_t flags = 0, // usage flags
- SurfaceControl* parent = nullptr, // parent
- LayerMetadata metadata = LayerMetadata(), // metadata
+ uint32_t flags = 0, // usage flags
+ const sp<IBinder>& parentHandle = nullptr, // parentHandle
+ LayerMetadata metadata = LayerMetadata(), // metadata
uint32_t* outTransformHint = nullptr);
//! Create a surface
@@ -437,6 +440,8 @@
Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius);
Transaction& setBackgroundBlurRadius(const sp<SurfaceControl>& sc,
int backgroundBlurRadius);
+ Transaction& setBlurRegions(const sp<SurfaceControl>& sc,
+ const std::vector<BlurRegion>& regions);
Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p);
// Defers applying any changes made in this transaction until the Layer
@@ -501,11 +506,6 @@
// Sometimes the WindowManager needs to extend their lifetime slightly
// in order to perform an exit animation or prevent flicker.
Transaction& detachChildren(const sp<SurfaceControl>& sc);
- // Set an override scaling mode as documented in <system/window.h>
- // the override scaling mode will take precedence over any client
- // specified scaling mode. -1 will clear the override scaling mode.
- Transaction& setOverrideScalingMode(const sp<SurfaceControl>& sc,
- int32_t overrideScalingMode);
#ifndef NO_INPUT
Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
@@ -537,6 +537,9 @@
// Sets the frame timeline vsync id received from choreographer that corresponds
// to the transaction.
Transaction& setFrameTimelineVsync(int64_t frameTimelineVsyncId);
+ // Variant that only applies to a specific SurfaceControl.
+ Transaction& setFrameTimelineVsync(const sp<SurfaceControl>& sc,
+ int64_t frameTimelineVsyncId);
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/gui/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h
index cc64fd4..f7dcbc6 100644
--- a/libs/gui/include/gui/view/Surface.h
+++ b/libs/gui/include/gui/view/Surface.h
@@ -21,6 +21,7 @@
#include <utils/StrongPointer.h>
#include <utils/String16.h>
+#include <binder/IBinder.h>
#include <binder/Parcelable.h>
namespace android {
@@ -43,6 +44,7 @@
String16 name;
sp<IGraphicBufferProducer> graphicBufferProducer;
+ sp<IBinder> surfaceControlHandle;
virtual status_t writeToParcel(Parcel* parcel) const override;
virtual status_t readFromParcel(const Parcel* parcel) override;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 5a376da..0cd3962 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -844,7 +844,7 @@
return NO_ERROR;
}
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
- int32_t /*defaultConfig*/,
+ int32_t /*defaultConfig*/, bool /*allowGroupSwitching*/,
float /*primaryRefreshRateMin*/,
float /*primaryRefreshRateMax*/,
float /*appRequestRefreshRateMin*/,
@@ -853,6 +853,7 @@
}
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
int32_t* /*outDefaultConfig*/,
+ bool* /*outAllowGroupSwitching*/,
float* /*outPrimaryRefreshRateMin*/,
float* /*outPrimaryRefreshRateMax*/,
float* /*outAppRequestRefreshRateMin*/,
diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp
index d64dfd5..3e49de6 100644
--- a/libs/gui/view/Surface.cpp
+++ b/libs/gui/view/Surface.cpp
@@ -45,7 +45,9 @@
if (res != OK) return res;
}
- return IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel);
+ res = IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel);
+ if (res != OK) return res;
+ return parcel->writeStrongBinder(surfaceControlHandle);
}
status_t Surface::readFromParcel(const Parcel* parcel) {
@@ -68,6 +70,7 @@
}
graphicBufferProducer = IGraphicBufferProducer::createFromParcel(parcel);
+ surfaceControlHandle = parcel->readStrongBinder();
return OK;
}
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index d8c3e6f..fce3000 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -40,8 +40,11 @@
"Keyboard.cpp",
"KeyCharacterMap.cpp",
"KeyLayoutMap.cpp",
+ "LatencyStatistics.cpp",
"PropertyMap.cpp",
"TouchVideoFrame.cpp",
+ "VelocityControl.cpp",
+ "VelocityTracker.cpp",
"VirtualKeyMap.cpp",
],
@@ -69,9 +72,6 @@
srcs: [
"InputTransport.cpp",
"InputWindow.cpp",
- "LatencyStatistics.cpp",
- "VelocityControl.cpp",
- "VelocityTracker.cpp",
"android/FocusRequest.aidl",
"android/InputApplicationInfo.aidl",
"android/os/IInputConstants.aidl",
@@ -99,12 +99,33 @@
shared: {
enabled: false,
},
+ include_dirs: [
+ "frameworks/native/libs/arect/include",
+ ],
+ },
+ linux_glibc: {
+ srcs: [
+ "InputTransport.cpp",
+ "InputWindow.cpp",
+ "android/FocusRequest.aidl",
+ "android/InputApplicationInfo.aidl",
+ "android/os/IInputConstants.aidl",
+ "android/os/IInputFlinger.aidl",
+ "android/os/ISetInputWindowsListener.aidl",
+ "android/os/TouchOcclusionMode.aidl",
+ ],
+ static_libs: [
+ "libhostgraphics",
+ ],
+ shared_libs: [
+ "libbinder",
+ ],
},
},
aidl: {
local_include_dirs: ["."],
- export_aidl_headers: true
+ export_aidl_headers: true,
},
}
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index fb2f186..ad7db75 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -19,18 +19,22 @@
#include <attestation/HmacKeyManager.h>
#include <cutils/compiler.h>
+#include <inttypes.h>
#include <limits.h>
#include <string.h>
+#include <android-base/stringprintf.h>
#include <input/Input.h>
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
-#ifdef __ANDROID__
#include <binder/Parcel.h>
+#ifdef __ANDROID__
#include <sys/random.h>
#endif
+using android::base::StringPrintf;
+
namespace android {
const char* motionClassificationToString(MotionClassification classification) {
@@ -250,7 +254,6 @@
setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset);
}
-#ifdef __ANDROID__
status_t PointerCoords::readFromParcel(Parcel* parcel) {
bits = parcel->readInt64();
@@ -274,7 +277,6 @@
}
return OK;
}
-#endif
void PointerCoords::tooManyAxes(int axis) {
ALOGW("Could not set value for axis %d because the PointerCoords structure is full and "
@@ -536,7 +538,6 @@
}
}
-#ifdef __ANDROID__
static status_t readFromParcel(ui::Transform& transform, const Parcel& parcel) {
float dsdx, dtdx, tx, dtdy, dsdy, ty;
status_t status = parcel.readFloat(&dsdx);
@@ -673,7 +674,6 @@
}
return OK;
}
-#endif
bool MotionEvent::isTouchEvent(uint32_t source, int32_t action) {
if (source & AINPUT_SOURCE_CLASS_POINTER) {
@@ -700,23 +700,37 @@
return InputEventLookup::getAxisByLabel(label);
}
-const char* MotionEvent::actionToString(int32_t action) {
+std::string MotionEvent::actionToString(int32_t action) {
// Convert MotionEvent action to string
switch (action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN:
return "DOWN";
- case AMOTION_EVENT_ACTION_MOVE:
- return "MOVE";
case AMOTION_EVENT_ACTION_UP:
return "UP";
+ case AMOTION_EVENT_ACTION_MOVE:
+ return "MOVE";
case AMOTION_EVENT_ACTION_CANCEL:
return "CANCEL";
+ case AMOTION_EVENT_ACTION_OUTSIDE:
+ return "OUTSIDE";
case AMOTION_EVENT_ACTION_POINTER_DOWN:
return "POINTER_DOWN";
case AMOTION_EVENT_ACTION_POINTER_UP:
return "POINTER_UP";
+ case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ return "HOVER_MOVE";
+ case AMOTION_EVENT_ACTION_SCROLL:
+ return "SCROLL";
+ case AMOTION_EVENT_ACTION_HOVER_ENTER:
+ return "HOVER_ENTER";
+ case AMOTION_EVENT_ACTION_HOVER_EXIT:
+ return "HOVER_EXIT";
+ case AMOTION_EVENT_ACTION_BUTTON_PRESS:
+ return "BUTTON_PRESS";
+ case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
+ return "BUTTON_RELEASE";
}
- return "UNKNOWN";
+ return android::base::StringPrintf("%" PRId32, action);
}
// --- FocusEvent ---
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 7ac8a2e..2623ecd 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -19,10 +19,7 @@
#include <stdlib.h>
#include <string.h>
-#ifdef __ANDROID__
#include <binder/Parcel.h>
-#endif
-
#include <android/keycodes.h>
#include <attestation/HmacKeyManager.h>
#include <input/InputEventLabels.h>
@@ -590,7 +587,6 @@
}
}
-#ifdef __ANDROID__
std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
if (parcel == nullptr) {
ALOGE("%s: Null parcel", __func__);
@@ -676,7 +672,6 @@
parcel->writeInt32(0);
}
}
-#endif
// --- KeyCharacterMap::Key ---
diff --git a/libs/input/TEST_MAPPING b/libs/input/TEST_MAPPING
new file mode 100644
index 0000000..9626d8d
--- /dev/null
+++ b/libs/input/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/native/services/inputflinger"
+ }
+ ]
+}
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 44147a5..b23aade 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -30,7 +30,8 @@
"liblog",
"libui",
"libutils",
- ]
+ ],
+ test_suites: ["device-tests"],
}
// NOTE: This is a compile time test, and does not need to be
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 1452745..4f53dc9 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -54,8 +54,12 @@
};
TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
+ ASSERT_NE(nullptr, mPublisher->getChannel());
+ ASSERT_NE(nullptr, mConsumer->getChannel());
EXPECT_EQ(mServerChannel.get(), mPublisher->getChannel().get());
EXPECT_EQ(mClientChannel.get(), mConsumer->getChannel().get());
+ ASSERT_EQ(mPublisher->getChannel()->getConnectionToken(),
+ mConsumer->getChannel()->getConnectionToken());
}
void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 470f28f..9e515cd 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -129,13 +129,14 @@
static Choreographer* getForThread();
virtual ~Choreographer() override EXCLUDES(gChoreographers.lock);
int64_t getVsyncId() const;
+ int64_t getFrameDeadline() const;
private:
Choreographer(const Choreographer&) = delete;
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
- int64_t vsyncId) override;
+ VsyncEventData vsyncEventData) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
nsecs_t vsyncPeriod) override;
@@ -149,7 +150,7 @@
std::vector<RefreshRateCallback> mRefreshRateCallbacks;
nsecs_t mLatestVsyncPeriod = -1;
- int64_t mLastVsyncId = -1;
+ VsyncEventData mLastVsyncEventData;
const sp<Looper> mLooper;
const std::thread::id mThreadId;
@@ -354,7 +355,8 @@
// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
// the internal display implicitly.
-void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t, int64_t vsyncId) {
+void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t,
+ VsyncEventData vsyncEventData) {
std::vector<FrameCallback> callbacks{};
{
std::lock_guard<std::mutex> _l{mLock};
@@ -364,7 +366,7 @@
mFrameCallbacks.pop();
}
}
- mLastVsyncId = vsyncId;
+ mLastVsyncEventData = vsyncEventData;
for (const auto& cb : callbacks) {
if (cb.callback64 != nullptr) {
cb.callback64(timestamp, cb.data);
@@ -410,7 +412,11 @@
}
int64_t Choreographer::getVsyncId() const {
- return mLastVsyncId;
+ return mLastVsyncEventData.id;
+}
+
+int64_t Choreographer::getFrameDeadline() const {
+ return mLastVsyncEventData.deadlineTimestamp;
}
} // namespace android
@@ -492,6 +498,10 @@
return AChoreographer_to_Choreographer(choreographer)->getVsyncId();
}
+int64_t AChoreographer_getFrameDeadline(const AChoreographer* choreographer) {
+ return AChoreographer_to_Choreographer(choreographer)->getFrameDeadline();
+}
+
} // namespace android
/* Glue for the NDK interface */
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index 1d57c15..d3a4a66 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -35,6 +35,13 @@
// this function from anywhere else will return an undefined value.
int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer);
+// Returns the deadline timestamp (in CLOCK_MONOTONIC) of the last frame callback.
+// Client are expected to call this function from their frame callback function
+// to get the deadline and use it to know whether a frame is likely to miss
+// presentation. Calling this function from anywhere else will return an undefined
+// value.
+int64_t AChoreographer_getFrameDeadline(const AChoreographer* choreographer);
+
// Trampoline functions allowing libandroid.so to define the NDK symbols without including
// the entirety of libnativedisplay as a whole static lib. As libnativedisplay
// maintains global state, libnativedisplay can never be directly statically
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 5ed2e49..fda6a20 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -30,6 +30,7 @@
android::AChoreographer_routeUnregisterRefreshRateCallback*;
android::AChoreographer_signalRefreshRateCallbacks*;
android::AChoreographer_getVsyncId*;
+ android::AChoreographer_getFrameDeadline*;
android::ADisplay_acquirePhysicalDisplays*;
android::ADisplay_release*;
android::ADisplay_getMaxSupportedFps*;
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 52d73e0..07e5d86 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -40,6 +40,7 @@
cc_library {
name: "libnativewindow",
+ llndk_stubs: "libnativewindow.llndk",
export_include_dirs: [
"include",
"include-private",
@@ -95,7 +96,7 @@
}
llndk_library {
- name: "libnativewindow",
+ name: "libnativewindow.llndk",
symbol_file: "libnativewindow.map.txt",
unversioned: true,
export_include_dirs: ["include"],
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 6adcbea..13577f7 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -735,9 +735,9 @@
bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(),
buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
if (!created) {
- ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
- buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
- buffer->getPixelFormat());
+ ALOGE("Failed to create image. id=%" PRIx64 " size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
+ buffer->getId(), buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
+ buffer->getUsage(), buffer->getPixelFormat());
return NO_INIT;
}
@@ -1218,6 +1218,11 @@
texCoords[2] = vec2(1.0, 1.0);
texCoords[3] = vec2(1.0, 0.0);
setupLayerTexturing(texture);
+
+ // Do not cache protected EGLImage, protected memory is limited.
+ if (gBuf->getUsage() & GRALLOC_USAGE_PROTECTED) {
+ unbindExternalTextureBuffer(gBuf->getId());
+ }
}
const half3 solidColor = layer->source.solidColor;
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 95e9367..d8d989e 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -21,6 +21,7 @@
#include <math/mat4.h>
#include <math/vec3.h>
#include <renderengine/Texture.h>
+#include <ui/BlurRegion.h>
#include <ui/Fence.h>
#include <ui/FloatRect.h>
#include <ui/GraphicBuffer.h>
@@ -151,6 +152,8 @@
ShadowSettings shadow;
int backgroundBlurRadius = 0;
+
+ std::vector<BlurRegion> blurRegions;
};
// Keep in sync with custom comparison function in
@@ -182,7 +185,29 @@
lhs.length == rhs.length && lhs.casterIsTranslucent == rhs.casterIsTranslucent;
}
+static inline bool operator==(const BlurRegion& lhs, const BlurRegion& rhs) {
+ return lhs.alpha == rhs.alpha && lhs.cornerRadiusTL == rhs.cornerRadiusTL &&
+ lhs.cornerRadiusTR == rhs.cornerRadiusTR && lhs.cornerRadiusBL == rhs.cornerRadiusBL &&
+ lhs.cornerRadiusBR == rhs.cornerRadiusBR && lhs.blurRadius == rhs.blurRadius &&
+ lhs.left == rhs.left && lhs.top == rhs.top && lhs.right == rhs.right &&
+ lhs.bottom == rhs.bottom;
+}
+
+static inline bool operator!=(const BlurRegion& lhs, const BlurRegion& rhs) {
+ return !(lhs == rhs);
+}
+
static inline bool operator==(const LayerSettings& lhs, const LayerSettings& rhs) {
+ if (lhs.blurRegions.size() != rhs.blurRegions.size()) {
+ return false;
+ }
+ const auto size = lhs.blurRegions.size();
+ for (size_t i = 0; i < size; i++) {
+ if (lhs.blurRegions[i] != rhs.blurRegions[i]) {
+ return false;
+ }
+ }
+
return lhs.geometry == rhs.geometry && lhs.source == rhs.source && lhs.alpha == rhs.alpha &&
lhs.sourceDataspace == rhs.sourceDataspace &&
lhs.colorTransform == rhs.colorTransform &&
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 69ad189..03c8e80 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -23,6 +23,14 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
+#include <sync/sync.h>
+#include <ui/BlurRegion.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Trace.h>
+#include "../gl/GLExtensions.h"
+#include "SkiaGLRenderEngine.h"
+#include "filters/BlurFilter.h"
+
#include <GrContextOptions.h>
#include <SkCanvas.h>
#include <SkColorFilter.h>
@@ -500,10 +508,25 @@
SkPaint paint;
const auto& bounds = layer->geometry.boundaries;
const auto dest = getSkRect(bounds);
+ std::unordered_map<uint32_t, sk_sp<SkSurface>> cachedBlurs;
- if (layer->backgroundBlurRadius > 0) {
- ATRACE_NAME("BackgroundBlur");
- mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius);
+ if (mBlurFilter) {
+ if (layer->backgroundBlurRadius > 0) {
+ ATRACE_NAME("BackgroundBlur");
+ auto blurredSurface =
+ mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius);
+ cachedBlurs[layer->backgroundBlurRadius] = blurredSurface;
+ }
+ if (layer->blurRegions.size() > 0) {
+ for (auto region : layer->blurRegions) {
+ if (cachedBlurs[region.blurRadius]) {
+ continue;
+ }
+ ATRACE_NAME("BlurRegion");
+ auto blurredSurface = mBlurFilter->generate(canvas, surface, region.blurRadius);
+ cachedBlurs[region.blurRadius] = blurredSurface;
+ }
+ }
}
if (layer->source.buffer.buffer) {
@@ -571,7 +594,11 @@
} else {
ATRACE_NAME("DrawColor");
const auto color = layer->source.solidColor;
- paint.setColor(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, layer->alpha});
+ paint.setShader(SkShaders::Color(SkColor4f{.fR = color.r,
+ .fG = color.g,
+ .fB = color.b,
+ layer->alpha},
+ nullptr));
}
paint.setColorFilter(SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)));
@@ -580,6 +607,10 @@
canvas->save();
canvas->concat(getSkM44(layer->geometry.positionTransform));
+ for (const auto effectRegion : layer->blurRegions) {
+ drawBlurRegion(canvas, effectRegion, dest, cachedBlurs[effectRegion.blurRadius]);
+ }
+
if (layer->shadow.length > 0) {
const auto rect = layer->geometry.roundedCornersRadius > 0
? getSkRect(layer->geometry.roundedCornersCrop)
@@ -592,6 +623,7 @@
} else {
canvas->drawRect(dest, paint);
}
+
canvas->restore();
}
{
@@ -678,6 +710,34 @@
flags);
}
+void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
+ const SkRect& layerBoundaries,
+ sk_sp<SkSurface> blurredSurface) {
+ ATRACE_CALL();
+ SkPaint paint;
+ paint.setAlpha(static_cast<int>(effectRegion.alpha * 255));
+ const auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
+ effectRegion.bottom);
+
+ const auto matrix = mBlurFilter->getShaderMatrix(
+ SkMatrix::MakeTrans(layerBoundaries.left(), layerBoundaries.top()));
+ paint.setShader(blurredSurface->makeImageSnapshot()->makeShader(matrix));
+
+ if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
+ effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
+ const SkVector radii[4] =
+ {SkVector::Make(effectRegion.cornerRadiusTL, effectRegion.cornerRadiusTL),
+ SkVector::Make(effectRegion.cornerRadiusTR, effectRegion.cornerRadiusTR),
+ SkVector::Make(effectRegion.cornerRadiusBL, effectRegion.cornerRadiusBL),
+ SkVector::Make(effectRegion.cornerRadiusBR, effectRegion.cornerRadiusBR)};
+ SkRRect roundedRect;
+ roundedRect.setRectRadii(rect, radii);
+ canvas->drawRRect(roundedRect, paint);
+ } else {
+ canvas->drawRect(rect, paint);
+ }
+}
+
EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
EGLContext shareContext, bool useContextPriority,
Protection protection) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index ed4ba11..0143445 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -75,6 +75,8 @@
bool waitFence(base::unique_fd fenceFd);
void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
const ShadowSettings& shadowSettings);
+ void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerBounds,
+ sk_sp<SkSurface> blurrendSurface);
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index eb791a7..f6a316f 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -55,8 +55,10 @@
mBlurEffect = std::move(blurEffect);
}
-void BlurFilter::draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t blurRadius) const {
+sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
+ const uint32_t blurRadius) const {
ATRACE_CALL();
+
// Kawase is an approximation of Gaussian, but it behaves differently from it.
// A radius transformation is required for approximating them, and also to introduce
// non-integer steps, necessary to smoothly interpolate large radii.
@@ -72,8 +74,10 @@
const float stepY = radiusByPasses;
// start by drawing and downscaling and doing the first blur pass
+ SkFilterOptions linear = {SkSamplingMode::kLinear, SkMipmapMode::kNone};
SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
- blurBuilder.child("input") = input->makeImageSnapshot()->makeShader();
+ blurBuilder.child("input") =
+ input->makeImageSnapshot()->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
blurBuilder.uniform("in_inverseScale") = kInverseInputScale;
blurBuilder.uniform("in_blurOffset") =
SkV2{stepX * kInverseInputScale, stepY * kInverseInputScale};
@@ -97,7 +101,9 @@
for (auto i = 1; i < numberOfPasses; i++) {
const float stepScale = (float)i * kInputScale;
- blurBuilder.child("input") = readSurface->makeImageSnapshot()->makeShader();
+ blurBuilder.child("input") =
+ readSurface->makeImageSnapshot()->makeShader(SkTileMode::kClamp,
+ SkTileMode::kClamp, linear);
blurBuilder.uniform("in_inverseScale") = 1.0f;
blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
@@ -107,25 +113,35 @@
drawSurface->getCanvas()->drawIRect(scaledInfo.bounds(), paint);
// Swap buffers for next iteration
- auto tmp = drawSurface;
+ const auto tmp = drawSurface;
drawSurface = readSurface;
readSurface = tmp;
blurBuilder.child("input") = nullptr;
}
lastDrawTarget = readSurface;
}
+ lastDrawTarget->flushAndSubmit();
+ return lastDrawTarget;
+}
- drawSurface->flushAndSubmit();
+sk_sp<SkSurface> BlurFilter::draw(SkCanvas* canvas, const sk_sp<SkSurface> input,
+ const uint32_t blurRadius) const {
+ ATRACE_CALL();
+ auto surface = generate(canvas, input, blurRadius);
- // do the final composition, with alpha blending to hide downscaling artifacts.
- {
- SkPaint paint;
- paint.setShader(lastDrawTarget->makeImageSnapshot()->makeShader(
- SkMatrix::MakeScale(kInverseInputScale)));
- paint.setFilterQuality(kLow_SkFilterQuality);
- paint.setAlpha(std::min(1.0f, (float)blurRadius / kMaxCrossFadeRadius) * 255);
- canvas->drawIRect(SkIRect::MakeWH(input->width(), input->height()), paint);
- }
+ SkPaint paint;
+ const auto image = surface->makeImageSnapshot();
+ paint.setShader(image->makeShader(SkMatrix::MakeScale(kInverseInputScale)));
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ paint.setAlpha(std::min(1.0f, (float)blurRadius / kMaxCrossFadeRadius) * 255);
+ canvas->drawIRect(SkIRect::MakeWH(input->width(), input->height()), paint);
+ return surface;
+}
+
+SkMatrix BlurFilter::getShaderMatrix(const SkMatrix& transformMatrix) const {
+ SkMatrix matrix;
+ matrix.setConcat(transformMatrix, SkMatrix::MakeScale(kInverseInputScale));
+ return matrix;
}
} // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 94b3673..6f973d7 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -47,8 +47,14 @@
explicit BlurFilter();
virtual ~BlurFilter(){};
- // Execute blur passes, rendering to a canvas.
- void draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t radius) const;
+ // Execute blur, saving it to a texture
+ sk_sp<SkSurface> generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
+ const uint32_t radius) const;
+ // Same as generate but also drawing to the screen
+ sk_sp<SkSurface> draw(SkCanvas* canvas, const sk_sp<SkSurface> input,
+ const uint32_t radius) const;
+ // Returns a matrix that should be applied to the blur shader
+ SkMatrix getShaderMatrix(const SkMatrix& transformMatrix) const;
private:
sk_sp<SkRuntimeEffect> mBlurEffect;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 3fa2e53..7c68aaa 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -140,7 +140,7 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
- "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common-unstable-ndk_platform",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
@@ -157,7 +157,7 @@
export_shared_lib_headers: [
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common-unstable-ndk_platform",
"android.hardware.graphics.mapper@4.0",
"libgralloctypes",
],
@@ -243,6 +243,8 @@
name: "libui_host_common",
srcs: [
"Rect.cpp",
- "PixelFormat.cpp"
+ "Region.cpp",
+ "PixelFormat.cpp",
+ "Transform.cpp"
],
}
diff --git a/libs/binder/parcel_fuzzer/random_parcel.h b/libs/ui/include/ui/BlurRegion.h
similarity index 67%
copy from libs/binder/parcel_fuzzer/random_parcel.h
copy to libs/ui/include/ui/BlurRegion.h
index 2923c47..c5a5d47 100644
--- a/libs/binder/parcel_fuzzer/random_parcel.h
+++ b/libs/ui/include/ui/BlurRegion.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,12 +16,21 @@
#pragma once
-#include "binder_ndk.h"
-
-#include <binder/Parcel.h>
-#include <fuzzer/FuzzedDataProvider.h>
+#include <inttypes.h>
namespace android {
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
-void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider);
-} // namespace android
+
+struct BlurRegion {
+ uint32_t blurRadius;
+ float cornerRadiusTL;
+ float cornerRadiusTR;
+ float cornerRadiusBL;
+ float cornerRadiusBR;
+ float alpha;
+ int left;
+ int top;
+ int right;
+ int bottom;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp b/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp
index afde5f7..1703f48 100644
--- a/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp
+++ b/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp
@@ -52,7 +52,7 @@
// Fuzzer for Serialization operations, this is mostly just lifted from the
// existing test cases to use fuzzed values as inputs.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+void FuzzSerializeDeserialize(const uint8_t* data, size_t size) {
FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
Payload result;
@@ -106,6 +106,10 @@
Deserialize(&vec_val, &result);
Serialize(t1_val, &result);
Deserialize(&t1_val, &result);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzSerializeDeserialize(data, size);
return 0;
}
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 9ca8b0b..393ced7 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -53,25 +53,25 @@
}
llndk_library {
- name: "libEGL",
+ name: "libEGL.llndk",
symbol_file: "libs/libEGL.map.txt",
export_include_dirs: ["include"],
}
llndk_library {
- name: "libGLESv1_CM",
+ name: "libGLESv1_CM.llndk",
symbol_file: "libs/libGLESv1_CM.map.txt",
export_include_dirs: ["include"],
}
llndk_library {
- name: "libGLESv2",
+ name: "libGLESv2.llndk",
symbol_file: "libs/libGLESv2.map.txt",
export_include_dirs: ["include"],
}
llndk_library {
- name: "libGLESv3",
+ name: "libGLESv3.llndk",
symbol_file: "libs/libGLESv3.map.txt",
export_include_dirs: ["include"],
}
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 3c76c62..77d887c 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -128,6 +128,7 @@
cc_library_shared {
name: "libEGL",
defaults: ["egl_libs_defaults"],
+ llndk_stubs: "libEGL.llndk",
srcs: [
"EGL/egl_tls.cpp",
"EGL/egl_cache.cpp",
@@ -193,6 +194,7 @@
cc_library_shared {
name: "libGLESv1_CM",
defaults: ["gles_libs_defaults"],
+ llndk_stubs: "libGLESv1_CM.llndk",
srcs: ["GLES_CM/gl.cpp"],
cflags: ["-DLOG_TAG=\"libGLESv1\""],
version_script: "libGLESv1_CM.map.txt",
@@ -204,6 +206,7 @@
cc_library_shared {
name: "libGLESv2",
defaults: ["gles_libs_defaults"],
+ llndk_stubs: "libGLESv2.llndk",
srcs: ["GLES2/gl2.cpp"],
cflags: ["-DLOG_TAG=\"libGLESv2\""],
@@ -218,6 +221,7 @@
cc_library_shared {
name: "libGLESv3",
defaults: ["gles_libs_defaults"],
+ llndk_stubs: "libGLESv3.llndk",
srcs: ["GLES2/gl2.cpp"],
cflags: ["-DLOG_TAG=\"libGLESv3\""],
}
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 9c80212..59ef3c8 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -15,6 +15,7 @@
*/
import java.io.PrintStream;
+import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
@@ -201,6 +202,33 @@
out.println(iii + ");");
}
+ // Function to automatically generate properly formatted function calls that
+ // comply with clang format rules
+ public static String formatFunctionCall(String indent, String functionCall) {
+ final int MAXLEN = 100;
+ String tokens[] = functionCall.split("\\(|\\)", 2);
+ String params[] = tokens[1].split(",\\s*");
+ String formatted = indent + tokens[0] + "(";
+ char[] chars = new char[indent.length() + tokens[0].length() + 1];
+ Arrays.fill(chars, ' ');
+ String multiIndent = new String(chars);
+ ArrayList<String> lines = new ArrayList<String>();
+ for(int i = 0; i < params.length; i++) {
+ String terminator = ((i == params.length - 1) ? "" : ",");
+ if(indent.length() + formatted.length() + params[i].length() > MAXLEN) {
+ lines.add(formatted);
+ if (!indent.equals(multiIndent)) {
+ indent = multiIndent;
+ }
+ formatted = indent + params[i] + terminator;
+ } else {
+ formatted += (i == 0 ? "" : " ") + params[i] + terminator;
+ }
+ }
+ lines.add(formatted);
+ return String.join("\n", lines);
+ }
+
void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
String iii) {
printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
@@ -1538,14 +1566,19 @@
"_exception ? JNI_ABORT : 0" : "0")) +
");");
} else {
- out.println(indent + indent +
+ String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
+ "_" + cfunc.getArgName(cIndex) + "BufferOffset";
+ String typeCast = "(char *)" + cfunc.getArgName(cIndex);
+ String withOffset = "(void *)(" + typeCast + " - " + bufferOffset + ")";
+ String releasePointerCall = (
"releasePointer(_env, " + array + ", " +
- cfunc.getArgName(cIndex) +
+ withOffset +
", " +
(cfunc.getArgType(cIndex).isConst() ?
"JNI_FALSE" : (emitExceptionCheck ?
"_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
");");
+ out.println(formatFunctionCall(indent + indent, releasePointerCall));
}
out.println(indent + "}");
}
diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp
index c78322e..3aa862f 100644
--- a/services/gpuservice/gpumem/GpuMem.cpp
+++ b/services/gpuservice/gpumem/GpuMem.cpp
@@ -43,18 +43,21 @@
// Make sure bpf programs are loaded
bpf::waitForProgsLoaded();
- int fd = bpf::bpfFdGet(kGpuMemTotalProgPath, BPF_F_RDONLY);
+ errno = 0;
+ int fd = bpf::retrieveProgram(kGpuMemTotalProgPath);
if (fd < 0) {
- ALOGE("Failed to retrieve pinned program from %s", kGpuMemTotalProgPath);
+ ALOGE("Failed to retrieve pinned program from %s [%d(%s)]", kGpuMemTotalProgPath, errno,
+ strerror(errno));
return;
}
// Attach the program to the tracepoint, and the tracepoint is automatically enabled here.
+ errno = 0;
int count = 0;
while (bpf_attach_tracepoint(fd, kGpuMemTraceGroup, kGpuMemTotalTracepoint) < 0) {
if (++count > kGpuWaitTimeout) {
- ALOGE("Failed to attach bpf program to %s/%s tracepoint", kGpuMemTraceGroup,
- kGpuMemTotalTracepoint);
+ ALOGE("Failed to attach bpf program to %s/%s tracepoint [%d(%s)]", kGpuMemTraceGroup,
+ kGpuMemTotalTracepoint, errno, strerror(errno));
return;
}
// Retry until GPU driver loaded or timeout.
@@ -62,9 +65,11 @@
}
// Use the read-only wrapper BpfMapRO to properly retrieve the read-only map.
+ errno = 0;
auto map = bpf::BpfMapRO<uint64_t, uint64_t>(kGpuMemTotalMapPath);
if (!map.isValid()) {
- ALOGE("Failed to create bpf map from %s", kGpuMemTotalMapPath);
+ ALOGE("Failed to create bpf map from %s [%d(%s)]", kGpuMemTotalMapPath, errno,
+ strerror(errno));
return;
}
setGpuMemTotalMap(map);
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index db81f5d..940a26b 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -38,4 +38,5 @@
static_libs: [
"libgmock",
],
+ require_root: true,
}
diff --git a/services/gpuservice/tests/unittests/AndroidTest.xml b/services/gpuservice/tests/unittests/AndroidTest.xml
index 66f51c7..72976a8 100644
--- a/services/gpuservice/tests/unittests/AndroidTest.xml
+++ b/services/gpuservice/tests/unittests/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="cleanup" value="true" />
<option name="push" value="gpuservice_unittest->/data/local/tmp/gpuservice_unittest" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<option name="test-suite-tag" value="apct" />
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index 824c01e..33520b2 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -7,6 +7,18 @@
"include-filter": "android.server.wm.WindowInputTests"
}
]
+ },
+ {
+ "name": "libinput_tests"
+ },
+ {
+ "name": "inputflinger_tests"
+ },
+ {
+ "name": "InputTests"
+ },
+ {
+ "name": "libinputservice_test"
}
]
}
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 34fa239..29df00b 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -59,7 +59,6 @@
EventEntry::EventEntry(int32_t id, Type type, nsecs_t eventTime, uint32_t policyFlags)
: id(id),
- refCount(1),
type(type),
eventTime(eventTime),
policyFlags(policyFlags),
@@ -70,15 +69,6 @@
releaseInjectionState();
}
-void EventEntry::release() {
- refCount -= 1;
- if (refCount == 0) {
- delete this;
- } else {
- ALOG_ASSERT(refCount > 0);
- }
-}
-
void EventEntry::releaseInjectionState() {
if (injectionState) {
injectionState->release();
@@ -151,11 +141,12 @@
if (!GetBoolProperty("ro.debuggable", false)) {
return "KeyEvent";
}
- return StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 ", action=%s, "
+ return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64
+ ", source=0x%08x, displayId=%" PRId32 ", action=%s, "
"flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
"repeatCount=%d), policyFlags=0x%08x",
- deviceId, source, displayId, KeyEvent::actionToString(action), flags,
- keyCode, scanCode, metaState, repeatCount, policyFlags);
+ deviceId, eventTime, source, displayId, KeyEvent::actionToString(action),
+ flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
}
void KeyEntry::recycle() {
@@ -210,15 +201,16 @@
return "MotionEvent";
}
std::string msg;
- msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32
+ msg += StringPrintf("MotionEvent(deviceId=%d, eventTime=%" PRIu64
+ ", source=0x%08x, displayId=%" PRId32
", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, "
"buttonState=0x%08x, "
"classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, "
"xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[",
- deviceId, source, displayId, MotionEvent::actionToString(action),
- actionButton, flags, metaState, buttonState,
- motionClassificationToString(classification), edgeFlags, xPrecision,
- yPrecision, xCursorPosition, yCursorPosition);
+ deviceId, eventTime, source, displayId,
+ MotionEvent::actionToString(action).c_str(), actionButton, flags, metaState,
+ buttonState, motionClassificationToString(classification), edgeFlags,
+ xPrecision, yPrecision, xCursorPosition, yCursorPosition);
for (uint32_t i = 0; i < pointerCount; i++) {
if (i) {
@@ -235,22 +227,16 @@
volatile int32_t DispatchEntry::sNextSeqAtomic;
-DispatchEntry::DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, ui::Transform transform,
- float globalScaleFactor)
+DispatchEntry::DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
+ ui::Transform transform, float globalScaleFactor)
: seq(nextSeq()),
- eventEntry(eventEntry),
+ eventEntry(std::move(eventEntry)),
targetFlags(targetFlags),
transform(transform),
globalScaleFactor(globalScaleFactor),
deliveryTime(0),
resolvedAction(0),
- resolvedFlags(0) {
- eventEntry->refCount += 1;
-}
-
-DispatchEntry::~DispatchEntry() {
- eventEntry->release();
-}
+ resolvedFlags(0) {}
uint32_t DispatchEntry::nextSeq() {
// Sequence number 0 is reserved and will never be returned.
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 47f75cbe..2b18180 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -54,7 +54,6 @@
}
int32_t id;
- mutable int32_t refCount;
Type type;
nsecs_t eventTime;
uint32_t policyFlags;
@@ -79,13 +78,12 @@
return isInjected() || IdGenerator::getSource(id) != IdGenerator::Source::INPUT_READER;
}
- void release();
-
virtual std::string getDescription() const = 0;
-protected:
EventEntry(int32_t id, Type type, nsecs_t eventTime, uint32_t policyFlags);
virtual ~EventEntry();
+
+protected:
void releaseInjectionState();
};
@@ -93,7 +91,6 @@
explicit ConfigurationChangedEntry(int32_t id, nsecs_t eventTime);
std::string getDescription() const override;
-protected:
virtual ~ConfigurationChangedEntry();
};
@@ -103,7 +100,6 @@
DeviceResetEntry(int32_t id, nsecs_t eventTime, int32_t deviceId);
std::string getDescription() const override;
-protected:
virtual ~DeviceResetEntry();
};
@@ -116,7 +112,6 @@
std::string_view reason);
std::string getDescription() const override;
-protected:
virtual ~FocusEntry();
};
@@ -149,7 +144,6 @@
std::string getDescription() const override;
void recycle();
-protected:
virtual ~KeyEntry();
};
@@ -182,7 +176,6 @@
float xOffset, float yOffset);
std::string getDescription() const override;
-protected:
virtual ~MotionEntry();
};
@@ -190,7 +183,7 @@
struct DispatchEntry {
const uint32_t seq; // unique sequence number, never 0
- EventEntry* eventEntry; // the event to dispatch
+ std::shared_ptr<EventEntry> eventEntry; // the event to dispatch
int32_t targetFlags;
ui::Transform transform;
float globalScaleFactor;
@@ -205,9 +198,8 @@
int32_t resolvedAction;
int32_t resolvedFlags;
- DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, ui::Transform transform,
- float globalScaleFactor);
- ~DispatchEntry();
+ DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
+ ui::Transform transform, float globalScaleFactor);
inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; }
@@ -252,7 +244,7 @@
// parameters for the command (usage varies by command)
sp<Connection> connection;
nsecs_t eventTime;
- KeyEntry* keyEntry;
+ std::shared_ptr<KeyEntry> keyEntry;
std::shared_ptr<InputApplicationHandle> inputApplicationHandle;
std::string reason;
int32_t userActivityEventType;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index d7aea4e..3135c19 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -37,6 +37,10 @@
// Log debug messages about input focus tracking.
static constexpr bool DEBUG_FOCUS = false;
+// Log debug messages about touch occlusion
+// STOPSHIP(b/169067926): Set to false
+static constexpr bool DEBUG_TOUCH_OCCLUSION = true;
+
// Log debug messages about the app switch latency optimization.
#define DEBUG_APP_SWITCH 0
@@ -311,19 +315,19 @@
}
static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
- EventEntry* eventEntry,
+ std::shared_ptr<EventEntry> eventEntry,
int32_t inputTargetFlags) {
if (inputTarget.useDefaultPointerTransform()) {
const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
- return std::make_unique<DispatchEntry>(eventEntry, // increments ref
- inputTargetFlags, transform,
+ return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
inputTarget.globalScaleFactor);
}
ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
- PointerCoords pointerCoords[motionEntry.pointerCount];
+ std::vector<PointerCoords> pointerCoords;
+ pointerCoords.resize(motionEntry.pointerCount);
// Use the first pointer information to normalize all other pointers. This could be any pointer
// as long as all other pointers are normalized to the same value and the final DispatchEntry
@@ -347,17 +351,18 @@
pointerCoords[pointerIndex].transform(inverseFirstTransform);
}
- MotionEntry* combinedMotionEntry =
- new MotionEntry(motionEntry.id, motionEntry.eventTime, motionEntry.deviceId,
- motionEntry.source, motionEntry.displayId, motionEntry.policyFlags,
- motionEntry.action, motionEntry.actionButton, motionEntry.flags,
- motionEntry.metaState, motionEntry.buttonState,
- motionEntry.classification, motionEntry.edgeFlags,
- motionEntry.xPrecision, motionEntry.yPrecision,
- motionEntry.xCursorPosition, motionEntry.yCursorPosition,
- motionEntry.downTime, motionEntry.pointerCount,
- motionEntry.pointerProperties, pointerCoords, 0 /* xOffset */,
- 0 /* yOffset */);
+ std::unique_ptr<MotionEntry> combinedMotionEntry =
+ std::make_unique<MotionEntry>(motionEntry.id, motionEntry.eventTime,
+ motionEntry.deviceId, motionEntry.source,
+ motionEntry.displayId, motionEntry.policyFlags,
+ motionEntry.action, motionEntry.actionButton,
+ motionEntry.flags, motionEntry.metaState,
+ motionEntry.buttonState, motionEntry.classification,
+ motionEntry.edgeFlags, motionEntry.xPrecision,
+ motionEntry.yPrecision, motionEntry.xCursorPosition,
+ motionEntry.yCursorPosition, motionEntry.downTime,
+ motionEntry.pointerCount, motionEntry.pointerProperties,
+ pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */);
if (motionEntry.injectionState) {
combinedMotionEntry->injectionState = motionEntry.injectionState;
@@ -365,10 +370,8 @@
}
std::unique_ptr<DispatchEntry> dispatchEntry =
- std::make_unique<DispatchEntry>(combinedMotionEntry, // increments ref
- inputTargetFlags, firstPointerTransform,
- inputTarget.globalScaleFactor);
- combinedMotionEntry->release();
+ std::make_unique<DispatchEntry>(std::move(combinedMotionEntry), inputTargetFlags,
+ firstPointerTransform, inputTarget.globalScaleFactor);
return dispatchEntry;
}
@@ -557,9 +560,7 @@
mNoFocusedWindowTimeoutTime = std::nullopt;
return LONG_LONG_MIN;
} else {
- // Keep waiting
- const nsecs_t millisRemaining = ns2ms(*mNoFocusedWindowTimeoutTime - currentTime);
- ALOGW("Still no focused window. Will drop the event in %" PRId64 "ms", millisRemaining);
+ // Keep waiting. We will drop the event when mNoFocusedWindowTimeoutTime comes.
nextAnrCheck = *mNoFocusedWindowTimeoutTime;
}
}
@@ -673,22 +674,24 @@
switch (mPendingEvent->type) {
case EventEntry::Type::CONFIGURATION_CHANGED: {
- ConfigurationChangedEntry* typedEntry =
- static_cast<ConfigurationChangedEntry*>(mPendingEvent);
+ const ConfigurationChangedEntry& typedEntry =
+ static_cast<const ConfigurationChangedEntry&>(*mPendingEvent);
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
dropReason = DropReason::NOT_DROPPED; // configuration changes are never dropped
break;
}
case EventEntry::Type::DEVICE_RESET: {
- DeviceResetEntry* typedEntry = static_cast<DeviceResetEntry*>(mPendingEvent);
+ const DeviceResetEntry& typedEntry =
+ static_cast<const DeviceResetEntry&>(*mPendingEvent);
done = dispatchDeviceResetLocked(currentTime, typedEntry);
dropReason = DropReason::NOT_DROPPED; // device resets are never dropped
break;
}
case EventEntry::Type::FOCUS: {
- FocusEntry* typedEntry = static_cast<FocusEntry*>(mPendingEvent);
+ std::shared_ptr<FocusEntry> typedEntry =
+ std::static_pointer_cast<FocusEntry>(mPendingEvent);
dispatchFocusLocked(currentTime, typedEntry);
done = true;
dropReason = DropReason::NOT_DROPPED; // focus events are never dropped
@@ -696,37 +699,38 @@
}
case EventEntry::Type::KEY: {
- KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
+ std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent);
if (isAppSwitchDue) {
- if (isAppSwitchKeyEvent(*typedEntry)) {
+ if (isAppSwitchKeyEvent(*keyEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DropReason::NOT_DROPPED) {
dropReason = DropReason::APP_SWITCH;
}
}
- if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
+ if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *keyEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
- done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
+ done = dispatchKeyLocked(currentTime, keyEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::Type::MOTION: {
- MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
+ std::shared_ptr<MotionEntry> motionEntry =
+ std::static_pointer_cast<MotionEntry>(mPendingEvent);
if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
dropReason = DropReason::APP_SWITCH;
}
- if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
+ if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
- done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
+ done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
break;
}
}
@@ -802,17 +806,18 @@
return false;
}
-bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
+bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newEntry) {
bool needWake = mInboundQueue.empty();
- mInboundQueue.push_back(entry);
+ mInboundQueue.push_back(std::move(newEntry));
+ EventEntry& entry = *(mInboundQueue.back());
traceInboundQueueLengthLocked();
- switch (entry->type) {
+ switch (entry.type) {
case EventEntry::Type::KEY: {
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
- const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*entry);
+ const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
if (isAppSwitchKeyEvent(keyEntry)) {
if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) {
mAppSwitchSawKeyDown = true;
@@ -831,8 +836,8 @@
}
case EventEntry::Type::MOTION: {
- if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(*entry))) {
- mNextUnblockedEvent = entry;
+ if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(entry))) {
+ mNextUnblockedEvent = mInboundQueue.back();
needWake = true;
}
break;
@@ -851,11 +856,9 @@
return needWake;
}
-void InputDispatcher::addRecentEventLocked(EventEntry* entry) {
- entry->refCount += 1;
+void InputDispatcher::addRecentEventLocked(std::shared_ptr<EventEntry> entry) {
mRecentQueue.push_back(entry);
if (mRecentQueue.size() > RECENT_QUEUE_MAX_SIZE) {
- mRecentQueue.front()->release();
mRecentQueue.pop_front();
}
}
@@ -1035,7 +1038,7 @@
void InputDispatcher::drainInboundQueueLocked() {
while (!mInboundQueue.empty()) {
- EventEntry* entry = mInboundQueue.front();
+ std::shared_ptr<EventEntry> entry = mInboundQueue.front();
mInboundQueue.pop_front();
releaseInboundEventLocked(entry);
}
@@ -1049,66 +1052,48 @@
}
}
-void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) {
+void InputDispatcher::releaseInboundEventLocked(std::shared_ptr<EventEntry> entry) {
InjectionState* injectionState = entry->injectionState;
if (injectionState && injectionState->injectionResult == InputEventInjectionResult::PENDING) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("Injected inbound event was dropped.");
#endif
- setInjectionResult(entry, InputEventInjectionResult::FAILED);
+ setInjectionResult(*entry, InputEventInjectionResult::FAILED);
}
if (entry == mNextUnblockedEvent) {
mNextUnblockedEvent = nullptr;
}
addRecentEventLocked(entry);
- entry->release();
}
void InputDispatcher::resetKeyRepeatLocked() {
if (mKeyRepeatState.lastKeyEntry) {
- mKeyRepeatState.lastKeyEntry->release();
mKeyRepeatState.lastKeyEntry = nullptr;
}
}
-KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) {
- KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
+std::shared_ptr<KeyEntry> InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) {
+ std::shared_ptr<KeyEntry> entry = mKeyRepeatState.lastKeyEntry;
- // Reuse the repeated key entry if it is otherwise unreferenced.
uint32_t policyFlags = entry->policyFlags &
(POLICY_FLAG_RAW_MASK | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED);
- if (entry->refCount == 1) {
- entry->recycle();
- entry->id = mIdGenerator.nextId();
- entry->eventTime = currentTime;
- entry->policyFlags = policyFlags;
- entry->repeatCount += 1;
- } else {
- KeyEntry* newEntry =
- new KeyEntry(mIdGenerator.nextId(), currentTime, entry->deviceId, entry->source,
- entry->displayId, policyFlags, entry->action, entry->flags,
- entry->keyCode, entry->scanCode, entry->metaState,
- entry->repeatCount + 1, entry->downTime);
- mKeyRepeatState.lastKeyEntry = newEntry;
- entry->release();
+ std::shared_ptr<KeyEntry> newEntry =
+ std::make_unique<KeyEntry>(mIdGenerator.nextId(), currentTime, entry->deviceId,
+ entry->source, entry->displayId, policyFlags, entry->action,
+ entry->flags, entry->keyCode, entry->scanCode,
+ entry->metaState, entry->repeatCount + 1, entry->downTime);
- entry = newEntry;
- }
- entry->syntheticRepeat = true;
-
- // Increment reference count since we keep a reference to the event in
- // mKeyRepeatState.lastKeyEntry in addition to the one we return.
- entry->refCount += 1;
-
+ newEntry->syntheticRepeat = true;
+ mKeyRepeatState.lastKeyEntry = newEntry;
mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay;
- return entry;
+ return newEntry;
}
bool InputDispatcher::dispatchConfigurationChangedLocked(nsecs_t currentTime,
- ConfigurationChangedEntry* entry) {
+ const ConfigurationChangedEntry& entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry->eventTime);
+ ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry.eventTime);
#endif
// Reset key repeating in case a keyboard device was added or removed or something.
@@ -1117,19 +1102,20 @@
// Enqueue a command to run outside the lock to tell the policy that the configuration changed.
std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
&InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
- commandEntry->eventTime = entry->eventTime;
+ commandEntry->eventTime = entry.eventTime;
postCommandLocked(std::move(commandEntry));
return true;
}
-bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime, DeviceResetEntry* entry) {
+bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime,
+ const DeviceResetEntry& entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry->eventTime,
- entry->deviceId);
+ ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry.eventTime,
+ entry.deviceId);
#endif
CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "device was reset");
- options.deviceId = entry->deviceId;
+ options.deviceId = entry.deviceId;
synthesizeCancelationEventsForAllConnectionsLocked(options);
return true;
}
@@ -1143,20 +1129,23 @@
mPendingEvent = nullptr;
}
- FocusEntry* focusEntry =
- new FocusEntry(mIdGenerator.nextId(), now(), windowToken, hasFocus, reason);
+ std::unique_ptr<FocusEntry> focusEntry =
+ std::make_unique<FocusEntry>(mIdGenerator.nextId(), now(), windowToken, hasFocus,
+ reason);
// This event should go to the front of the queue, but behind all other focus events
// Find the last focus event, and insert right after it
- std::deque<EventEntry*>::reverse_iterator it =
+ std::deque<std::shared_ptr<EventEntry>>::reverse_iterator it =
std::find_if(mInboundQueue.rbegin(), mInboundQueue.rend(),
- [](EventEntry* event) { return event->type == EventEntry::Type::FOCUS; });
+ [](const std::shared_ptr<EventEntry>& event) {
+ return event->type == EventEntry::Type::FOCUS;
+ });
// Maintain the order of focus events. Insert the entry after all other focus events.
- mInboundQueue.insert(it.base(), focusEntry);
+ mInboundQueue.insert(it.base(), std::move(focusEntry));
}
-void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, FocusEntry* entry) {
+void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<FocusEntry> entry) {
std::shared_ptr<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
if (channel == nullptr) {
return; // Window has gone away
@@ -1172,7 +1161,7 @@
dispatchEventLocked(currentTime, entry, {target});
}
-bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
+bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
if (!entry->dispatchInProgress) {
@@ -1200,10 +1189,9 @@
mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout;
}
mKeyRepeatState.lastKeyEntry = entry;
- entry->refCount += 1;
} else if (entry->action == AKEY_EVENT_ACTION_UP && mKeyRepeatState.lastKeyEntry &&
mKeyRepeatState.lastKeyEntry->deviceId != entry->deviceId) {
- // The stale device releases the key, reset staleDeviceId.
+ // The key on device 'deviceId' is still down, do not stop key repeat
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("deviceId=%d got KEY_UP as stale", entry->deviceId);
#endif
@@ -1246,7 +1234,6 @@
}
commandEntry->keyEntry = entry;
postCommandLocked(std::move(commandEntry));
- entry->refCount += 1;
return false; // wait for the command to run
} else {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
@@ -1259,7 +1246,7 @@
// Clean up if dropping the event.
if (*dropReason != DropReason::NOT_DROPPED) {
- setInjectionResult(entry,
+ setInjectionResult(*entry,
*dropReason == DropReason::POLICY ? InputEventInjectionResult::SUCCEEDED
: InputEventInjectionResult::FAILED);
mReporter->reportDroppedKey(entry->id);
@@ -1274,7 +1261,7 @@
return false;
}
- setInjectionResult(entry, injectionResult);
+ setInjectionResult(*entry, injectionResult);
if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
return true;
}
@@ -1298,7 +1285,7 @@
#endif
}
-bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry,
+bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<MotionEntry> entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
ATRACE_CALL();
// Preprocessing.
@@ -1310,7 +1297,7 @@
// Clean up if dropping the event.
if (*dropReason != DropReason::NOT_DROPPED) {
- setInjectionResult(entry,
+ setInjectionResult(*entry,
*dropReason == DropReason::POLICY ? InputEventInjectionResult::SUCCEEDED
: InputEventInjectionResult::FAILED);
return true;
@@ -1337,7 +1324,7 @@
return false;
}
- setInjectionResult(entry, injectionResult);
+ setInjectionResult(*entry, injectionResult);
if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) {
ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
return true;
@@ -1411,7 +1398,8 @@
#endif
}
-void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
+void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
+ std::shared_ptr<EventEntry> eventEntry,
const std::vector<InputTarget>& inputTargets) {
ATRACE_CALL();
#if DEBUG_DISPATCH_CYCLE
@@ -1774,6 +1762,12 @@
TouchOcclusionInfo occlusionInfo =
computeTouchOcclusionInfoLocked(newTouchedWindowHandle, x, y);
if (!isTouchTrustedLocked(occlusionInfo)) {
+ if (DEBUG_TOUCH_OCCLUSION) {
+ ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
+ for (const auto& log : occlusionInfo.debugInfo) {
+ ALOGD("%s", log.c_str());
+ }
+ }
onUntrustedTouchLocked(occlusionInfo.obscuringPackage);
if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {
ALOGW("Dropping untrusted touch event due to %s/%d",
@@ -2184,6 +2178,15 @@
auto otherInfo = otherHandle->getInfo();
if (!otherInfo->visible) {
return false;
+ } else if (otherInfo->alpha == 0 &&
+ otherInfo->flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE)) {
+ // Those act as if they were invisible, so we don't need to flag them.
+ // We do want to potentially flag touchable windows even if they have 0
+ // opacity, since they can consume touches and alter the effects of the
+ // user interaction (eg. apps that rely on
+ // FLAG_WINDOW_IS_PARTIALLY_OBSCURED should still be told about those
+ // windows), hence we also check for FLAG_NOT_TOUCHABLE.
+ return false;
} else if (info->ownerUid == otherInfo->ownerUid) {
// If ownerUid is the same we don't generate occlusion events as there
// is no security boundary within an uid.
@@ -2215,7 +2218,8 @@
*/
InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLocked(
const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
- int32_t displayId = windowHandle->getInfo()->displayId;
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ int32_t displayId = windowInfo->displayId;
const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId);
TouchOcclusionInfo info;
info.hasBlockingOcclusion = false;
@@ -2228,8 +2232,11 @@
}
const InputWindowInfo* otherInfo = otherHandle->getInfo();
if (canBeObscuredBy(windowHandle, otherHandle) &&
- windowHandle->getInfo()->ownerUid != otherInfo->ownerUid &&
- otherInfo->frameContainsPoint(x, y)) {
+ windowInfo->ownerUid != otherInfo->ownerUid && otherInfo->frameContainsPoint(x, y)) {
+ if (DEBUG_TOUCH_OCCLUSION) {
+ info.debugInfo.push_back(
+ dumpWindowForTouchOcclusion(otherInfo, /* isTouchedWindow */ false));
+ }
// canBeObscuredBy() has returned true above, which means this window is untrusted, so
// we perform the checks below to see if the touch can be propagated or not based on the
// window's touch occlusion mode
@@ -2255,9 +2262,26 @@
}
}
}
+ if (DEBUG_TOUCH_OCCLUSION) {
+ info.debugInfo.push_back(
+ dumpWindowForTouchOcclusion(windowInfo, /* isTouchedWindow */ true));
+ }
return info;
}
+std::string InputDispatcher::dumpWindowForTouchOcclusion(const InputWindowInfo* info,
+ bool isTouchedWindow) const {
+ return StringPrintf(INDENT2 "* %stype=%s, package=%s/%" PRId32 ", mode=%s, alpha=%.2f, "
+ "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32
+ "], window=%s, applicationInfo=%s, flags=%s\n",
+ (isTouchedWindow) ? "[TOUCHED] " : "",
+ NamedEnum::string(info->type).c_str(), info->packageName.c_str(),
+ info->ownerUid, toString(info->touchOcclusionMode).c_str(), info->alpha,
+ info->frameLeft, info->frameTop, info->frameRight, info->frameBottom,
+ info->name.c_str(), info->applicationInfo.name.c_str(),
+ info->flags.string().c_str());
+}
+
bool InputDispatcher::isTouchTrustedLocked(const TouchOcclusionInfo& occlusionInfo) const {
if (occlusionInfo.hasBlockingOcclusion) {
ALOGW("Untrusted touch due to occlusion by %s/%d", occlusionInfo.obscuringPackage.c_str(),
@@ -2380,7 +2404,7 @@
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
- EventEntry* eventEntry,
+ std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget) {
if (ATRACE_ENABLED()) {
std::string message =
@@ -2414,7 +2438,7 @@
const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
- MotionEntry* splitMotionEntry =
+ std::unique_ptr<MotionEntry> splitMotionEntry =
splitMotionEvent(originalMotionEntry, inputTarget.pointerIds);
if (!splitMotionEntry) {
return; // split event was dropped
@@ -2424,8 +2448,8 @@
connection->getInputChannelName().c_str());
logOutboundMotionDetails(" ", *splitMotionEntry);
}
- enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget);
- splitMotionEntry->release();
+ enqueueDispatchEntriesLocked(currentTime, connection, std::move(splitMotionEntry),
+ inputTarget);
return;
}
}
@@ -2436,7 +2460,7 @@
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
- EventEntry* eventEntry,
+ std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget) {
if (ATRACE_ENABLED()) {
std::string message =
@@ -2468,7 +2492,7 @@
}
void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
- EventEntry* eventEntry,
+ std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget,
int32_t dispatchMode) {
if (ATRACE_ENABLED()) {
@@ -2490,11 +2514,11 @@
// Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
// different EventEntry than what was passed in.
- EventEntry* newEntry = dispatchEntry->eventEntry;
+ EventEntry& newEntry = *(dispatchEntry->eventEntry);
// Apply target flags and update the connection's input state.
- switch (newEntry->type) {
+ switch (newEntry.type) {
case EventEntry::Type::KEY: {
- const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*newEntry);
+ const KeyEntry& keyEntry = static_cast<const KeyEntry&>(newEntry);
dispatchEntry->resolvedEventId = keyEntry.id;
dispatchEntry->resolvedAction = keyEntry.action;
dispatchEntry->resolvedFlags = keyEntry.flags;
@@ -2511,7 +2535,7 @@
}
case EventEntry::Type::MOTION: {
- const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*newEntry);
+ const MotionEntry& motionEntry = static_cast<const MotionEntry&>(newEntry);
// Assign a default value to dispatchEntry that will never be generated by InputReader,
// and assign a InputDispatcher value if it doesn't change in the if-else chain below.
constexpr int32_t DEFAULT_RESOLVED_EVENT_ID =
@@ -2582,7 +2606,7 @@
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("%s events should not go to apps",
- EventEntry::typeToString(newEntry->type));
+ EventEntry::typeToString(newEntry.type));
break;
}
}
@@ -2706,39 +2730,38 @@
// Publish the event.
status_t status;
- EventEntry* eventEntry = dispatchEntry->eventEntry;
- switch (eventEntry->type) {
+ const EventEntry& eventEntry = *(dispatchEntry->eventEntry);
+ switch (eventEntry.type) {
case EventEntry::Type::KEY: {
- const KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
- std::array<uint8_t, 32> hmac = getSignature(*keyEntry, *dispatchEntry);
+ const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry);
+ std::array<uint8_t, 32> hmac = getSignature(keyEntry, *dispatchEntry);
// Publish the key event.
- status =
- connection->inputPublisher
- .publishKeyEvent(dispatchEntry->seq, dispatchEntry->resolvedEventId,
- keyEntry->deviceId, keyEntry->source,
- keyEntry->displayId, std::move(hmac),
- dispatchEntry->resolvedAction,
- dispatchEntry->resolvedFlags, keyEntry->keyCode,
- keyEntry->scanCode, keyEntry->metaState,
- keyEntry->repeatCount, keyEntry->downTime,
- keyEntry->eventTime);
+ status = connection->inputPublisher
+ .publishKeyEvent(dispatchEntry->seq,
+ dispatchEntry->resolvedEventId, keyEntry.deviceId,
+ keyEntry.source, keyEntry.displayId,
+ std::move(hmac), dispatchEntry->resolvedAction,
+ dispatchEntry->resolvedFlags, keyEntry.keyCode,
+ keyEntry.scanCode, keyEntry.metaState,
+ keyEntry.repeatCount, keyEntry.downTime,
+ keyEntry.eventTime);
break;
}
case EventEntry::Type::MOTION: {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
+ const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
PointerCoords scaledCoords[MAX_POINTERS];
- const PointerCoords* usingCoords = motionEntry->pointerCoords;
+ const PointerCoords* usingCoords = motionEntry.pointerCoords;
// Set the X and Y offset and X and Y scale depending on the input source.
- if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) &&
+ if ((motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) &&
!(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
float globalScaleFactor = dispatchEntry->globalScaleFactor;
if (globalScaleFactor != 1.0f) {
- for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
- scaledCoords[i] = motionEntry->pointerCoords[i];
+ for (uint32_t i = 0; i < motionEntry.pointerCount; i++) {
+ scaledCoords[i] = motionEntry.pointerCoords[i];
// Don't apply window scale here since we don't want scale to affect raw
// coordinates. The scale will be sent back to the client and applied
// later when requesting relative coordinates.
@@ -2750,43 +2773,42 @@
} else {
// We don't want the dispatch target to know.
if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
- for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
+ for (uint32_t i = 0; i < motionEntry.pointerCount; i++) {
scaledCoords[i].clear();
}
usingCoords = scaledCoords;
}
}
- std::array<uint8_t, 32> hmac = getSignature(*motionEntry, *dispatchEntry);
+ std::array<uint8_t, 32> hmac = getSignature(motionEntry, *dispatchEntry);
// Publish the motion event.
status = connection->inputPublisher
.publishMotionEvent(dispatchEntry->seq,
dispatchEntry->resolvedEventId,
- motionEntry->deviceId, motionEntry->source,
- motionEntry->displayId, std::move(hmac),
+ motionEntry.deviceId, motionEntry.source,
+ motionEntry.displayId, std::move(hmac),
dispatchEntry->resolvedAction,
- motionEntry->actionButton,
+ motionEntry.actionButton,
dispatchEntry->resolvedFlags,
- motionEntry->edgeFlags, motionEntry->metaState,
- motionEntry->buttonState,
- motionEntry->classification,
+ motionEntry.edgeFlags, motionEntry.metaState,
+ motionEntry.buttonState,
+ motionEntry.classification,
dispatchEntry->transform,
- motionEntry->xPrecision,
- motionEntry->yPrecision,
- motionEntry->xCursorPosition,
- motionEntry->yCursorPosition,
- motionEntry->downTime, motionEntry->eventTime,
- motionEntry->pointerCount,
- motionEntry->pointerProperties, usingCoords);
- reportTouchEventForStatistics(*motionEntry);
+ motionEntry.xPrecision, motionEntry.yPrecision,
+ motionEntry.xCursorPosition,
+ motionEntry.yCursorPosition,
+ motionEntry.downTime, motionEntry.eventTime,
+ motionEntry.pointerCount,
+ motionEntry.pointerProperties, usingCoords);
+ reportTouchEventForStatistics(motionEntry);
break;
}
case EventEntry::Type::FOCUS: {
- FocusEntry* focusEntry = static_cast<FocusEntry*>(eventEntry);
+ const FocusEntry& focusEntry = static_cast<const FocusEntry&>(eventEntry);
status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq,
- focusEntry->id,
- focusEntry->hasFocus,
+ focusEntry.id,
+ focusEntry.hasFocus,
mInTouchMode);
break;
}
@@ -2794,7 +2816,7 @@
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events",
- EventEntry::typeToString(eventEntry->type));
+ EventEntry::typeToString(eventEntry.type));
return;
}
}
@@ -2932,7 +2954,7 @@
void InputDispatcher::releaseDispatchEntry(DispatchEntry* dispatchEntry) {
if (dispatchEntry->hasForegroundTarget()) {
- decrementPendingForegroundDispatches(dispatchEntry->eventEntry);
+ decrementPendingForegroundDispatches(*(dispatchEntry->eventEntry));
}
delete dispatchEntry;
}
@@ -3048,7 +3070,7 @@
nsecs_t currentTime = now();
- std::vector<EventEntry*> cancelationEvents =
+ std::vector<std::unique_ptr<EventEntry>> cancelationEvents =
connection->inputState.synthesizeCancelationEvents(currentTime, options);
if (cancelationEvents.empty()) {
@@ -3073,7 +3095,7 @@
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
for (size_t i = 0; i < cancelationEvents.size(); i++) {
- EventEntry* cancelationEventEntry = cancelationEvents[i];
+ std::unique_ptr<EventEntry> cancelationEventEntry = std::move(cancelationEvents[i]);
switch (cancelationEventEntry->type) {
case EventEntry::Type::KEY: {
logOutboundKeyDetails("cancel - ",
@@ -3097,10 +3119,8 @@
}
}
- enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
- target, InputTarget::FLAG_DISPATCH_AS_IS);
-
- cancelationEventEntry->release();
+ enqueueDispatchEntryLocked(connection, std::move(cancelationEventEntry), target,
+ InputTarget::FLAG_DISPATCH_AS_IS);
}
startDispatchCycleLocked(currentTime, connection);
@@ -3114,7 +3134,7 @@
nsecs_t currentTime = now();
- std::vector<EventEntry*> downEvents =
+ std::vector<std::unique_ptr<EventEntry>> downEvents =
connection->inputState.synthesizePointerDownEvents(currentTime);
if (downEvents.empty()) {
@@ -3137,7 +3157,7 @@
target.inputChannel = connection->inputChannel;
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
- for (EventEntry* downEventEntry : downEvents) {
+ for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) {
switch (downEventEntry->type) {
case EventEntry::Type::MOTION: {
logOutboundMotionDetails("down - ",
@@ -3155,17 +3175,15 @@
}
}
- enqueueDispatchEntryLocked(connection, downEventEntry, // increments ref
- target, InputTarget::FLAG_DISPATCH_AS_IS);
-
- downEventEntry->release();
+ enqueueDispatchEntryLocked(connection, std::move(downEventEntry), target,
+ InputTarget::FLAG_DISPATCH_AS_IS);
}
startDispatchCycleLocked(currentTime, connection);
}
-MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry& originalMotionEntry,
- BitSet32 pointerIds) {
+std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent(
+ const MotionEntry& originalMotionEntry, BitSet32 pointerIds) {
ALOG_ASSERT(pointerIds.value != 0);
uint32_t splitPointerIndexMap[MAX_POINTERS];
@@ -3238,17 +3256,22 @@
originalMotionEntry.id, newId);
ATRACE_NAME(message.c_str());
}
- MotionEntry* splitMotionEntry =
- new MotionEntry(newId, originalMotionEntry.eventTime, originalMotionEntry.deviceId,
- originalMotionEntry.source, originalMotionEntry.displayId,
- originalMotionEntry.policyFlags, action,
- originalMotionEntry.actionButton, originalMotionEntry.flags,
- originalMotionEntry.metaState, originalMotionEntry.buttonState,
- originalMotionEntry.classification, originalMotionEntry.edgeFlags,
- originalMotionEntry.xPrecision, originalMotionEntry.yPrecision,
- originalMotionEntry.xCursorPosition,
- originalMotionEntry.yCursorPosition, originalMotionEntry.downTime,
- splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0);
+ std::unique_ptr<MotionEntry> splitMotionEntry =
+ std::make_unique<MotionEntry>(newId, originalMotionEntry.eventTime,
+ originalMotionEntry.deviceId, originalMotionEntry.source,
+ originalMotionEntry.displayId,
+ originalMotionEntry.policyFlags, action,
+ originalMotionEntry.actionButton,
+ originalMotionEntry.flags, originalMotionEntry.metaState,
+ originalMotionEntry.buttonState,
+ originalMotionEntry.classification,
+ originalMotionEntry.edgeFlags,
+ originalMotionEntry.xPrecision,
+ originalMotionEntry.yPrecision,
+ originalMotionEntry.xCursorPosition,
+ originalMotionEntry.yCursorPosition,
+ originalMotionEntry.downTime, splitPointerCount,
+ splitPointerProperties, splitPointerCoords, 0, 0);
if (originalMotionEntry.injectionState) {
splitMotionEntry->injectionState = originalMotionEntry.injectionState;
@@ -3267,9 +3290,9 @@
{ // acquire lock
std::scoped_lock _l(mLock);
- ConfigurationChangedEntry* newEntry =
- new ConfigurationChangedEntry(args->id, args->eventTime);
- needWake = enqueueInboundEventLocked(newEntry);
+ std::unique_ptr<ConfigurationChangedEntry> newEntry =
+ std::make_unique<ConfigurationChangedEntry>(args->id, args->eventTime);
+ needWake = enqueueInboundEventLocked(std::move(newEntry));
} // release lock
if (needWake) {
@@ -3373,12 +3396,13 @@
mLock.lock();
}
- KeyEntry* newEntry =
- new KeyEntry(args->id, args->eventTime, args->deviceId, args->source,
- args->displayId, policyFlags, args->action, flags, keyCode,
- args->scanCode, metaState, repeatCount, args->downTime);
+ std::unique_ptr<KeyEntry> newEntry =
+ std::make_unique<KeyEntry>(args->id, args->eventTime, args->deviceId, args->source,
+ args->displayId, policyFlags, args->action, flags,
+ keyCode, args->scanCode, metaState, repeatCount,
+ args->downTime);
- needWake = enqueueInboundEventLocked(newEntry);
+ needWake = enqueueInboundEventLocked(std::move(newEntry));
mLock.unlock();
} // release lock
@@ -3459,16 +3483,18 @@
}
// Just enqueue a new motion event.
- MotionEntry* newEntry =
- new MotionEntry(args->id, args->eventTime, args->deviceId, args->source,
- args->displayId, policyFlags, args->action, args->actionButton,
- args->flags, args->metaState, args->buttonState,
- args->classification, args->edgeFlags, args->xPrecision,
- args->yPrecision, args->xCursorPosition, args->yCursorPosition,
- args->downTime, args->pointerCount, args->pointerProperties,
- args->pointerCoords, 0, 0);
+ std::unique_ptr<MotionEntry> newEntry =
+ std::make_unique<MotionEntry>(args->id, args->eventTime, args->deviceId,
+ args->source, args->displayId, policyFlags,
+ args->action, args->actionButton, args->flags,
+ args->metaState, args->buttonState,
+ args->classification, args->edgeFlags,
+ args->xPrecision, args->yPrecision,
+ args->xCursorPosition, args->yCursorPosition,
+ args->downTime, args->pointerCount,
+ args->pointerProperties, args->pointerCoords, 0, 0);
- needWake = enqueueInboundEventLocked(newEntry);
+ needWake = enqueueInboundEventLocked(std::move(newEntry));
mLock.unlock();
} // release lock
@@ -3503,9 +3529,9 @@
{ // acquire lock
std::scoped_lock _l(mLock);
- DeviceResetEntry* newEntry =
- new DeviceResetEntry(args->id, args->eventTime, args->deviceId);
- needWake = enqueueInboundEventLocked(newEntry);
+ std::unique_ptr<DeviceResetEntry> newEntry =
+ std::make_unique<DeviceResetEntry>(args->id, args->eventTime, args->deviceId);
+ needWake = enqueueInboundEventLocked(std::move(newEntry));
} // release lock
if (needWake) {
@@ -3528,7 +3554,7 @@
policyFlags |= POLICY_FLAG_TRUSTED;
}
- std::queue<EventEntry*> injectedEntries;
+ std::queue<std::unique_ptr<EventEntry>> injectedEntries;
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY: {
const KeyEvent& incomingKey = static_cast<const KeyEvent&>(*event);
@@ -3562,13 +3588,14 @@
}
mLock.lock();
- KeyEntry* injectedEntry =
- new KeyEntry(incomingKey.getId(), incomingKey.getEventTime(),
- VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
- incomingKey.getDisplayId(), policyFlags, action, flags, keyCode,
- incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(),
- incomingKey.getDownTime());
- injectedEntries.push(injectedEntry);
+ std::unique_ptr<KeyEntry> injectedEntry =
+ std::make_unique<KeyEntry>(incomingKey.getId(), incomingKey.getEventTime(),
+ VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
+ incomingKey.getDisplayId(), policyFlags, action,
+ flags, keyCode, incomingKey.getScanCode(), metaState,
+ incomingKey.getRepeatCount(),
+ incomingKey.getDownTime());
+ injectedEntries.push(std::move(injectedEntry));
break;
}
@@ -3596,37 +3623,46 @@
mLock.lock();
const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
- MotionEntry* injectedEntry =
- new MotionEntry(motionEvent->getId(), *sampleEventTimes, VIRTUAL_KEYBOARD_ID,
- motionEvent->getSource(), motionEvent->getDisplayId(),
- policyFlags, action, actionButton, motionEvent->getFlags(),
- motionEvent->getMetaState(), motionEvent->getButtonState(),
- motionEvent->getClassification(), motionEvent->getEdgeFlags(),
- motionEvent->getXPrecision(), motionEvent->getYPrecision(),
- motionEvent->getRawXCursorPosition(),
- motionEvent->getRawYCursorPosition(),
- motionEvent->getDownTime(), uint32_t(pointerCount),
- pointerProperties, samplePointerCoords,
- motionEvent->getXOffset(), motionEvent->getYOffset());
- injectedEntries.push(injectedEntry);
+ std::unique_ptr<MotionEntry> injectedEntry =
+ std::make_unique<MotionEntry>(motionEvent->getId(), *sampleEventTimes,
+ VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
+ motionEvent->getDisplayId(), policyFlags, action,
+ actionButton, motionEvent->getFlags(),
+ motionEvent->getMetaState(),
+ motionEvent->getButtonState(),
+ motionEvent->getClassification(),
+ motionEvent->getEdgeFlags(),
+ motionEvent->getXPrecision(),
+ motionEvent->getYPrecision(),
+ motionEvent->getRawXCursorPosition(),
+ motionEvent->getRawYCursorPosition(),
+ motionEvent->getDownTime(),
+ uint32_t(pointerCount), pointerProperties,
+ samplePointerCoords, motionEvent->getXOffset(),
+ motionEvent->getYOffset());
+ injectedEntries.push(std::move(injectedEntry));
for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
sampleEventTimes += 1;
samplePointerCoords += pointerCount;
- MotionEntry* nextInjectedEntry =
- new MotionEntry(motionEvent->getId(), *sampleEventTimes,
- VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
- motionEvent->getDisplayId(), policyFlags, action,
- actionButton, motionEvent->getFlags(),
- motionEvent->getMetaState(), motionEvent->getButtonState(),
- motionEvent->getClassification(),
- motionEvent->getEdgeFlags(), motionEvent->getXPrecision(),
- motionEvent->getYPrecision(),
- motionEvent->getRawXCursorPosition(),
- motionEvent->getRawYCursorPosition(),
- motionEvent->getDownTime(), uint32_t(pointerCount),
- pointerProperties, samplePointerCoords,
- motionEvent->getXOffset(), motionEvent->getYOffset());
- injectedEntries.push(nextInjectedEntry);
+ std::unique_ptr<MotionEntry> nextInjectedEntry =
+ std::make_unique<MotionEntry>(motionEvent->getId(), *sampleEventTimes,
+ VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
+ motionEvent->getDisplayId(), policyFlags,
+ action, actionButton, motionEvent->getFlags(),
+ motionEvent->getMetaState(),
+ motionEvent->getButtonState(),
+ motionEvent->getClassification(),
+ motionEvent->getEdgeFlags(),
+ motionEvent->getXPrecision(),
+ motionEvent->getYPrecision(),
+ motionEvent->getRawXCursorPosition(),
+ motionEvent->getRawYCursorPosition(),
+ motionEvent->getDownTime(),
+ uint32_t(pointerCount), pointerProperties,
+ samplePointerCoords,
+ motionEvent->getXOffset(),
+ motionEvent->getYOffset());
+ injectedEntries.push(std::move(nextInjectedEntry));
}
break;
}
@@ -3646,7 +3682,7 @@
bool needWake = false;
while (!injectedEntries.empty()) {
- needWake |= enqueueInboundEventLocked(injectedEntries.front());
+ needWake |= enqueueInboundEventLocked(std::move(injectedEntries.front()));
injectedEntries.pop();
}
@@ -3753,9 +3789,9 @@
mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
}
-void InputDispatcher::setInjectionResult(EventEntry* entry,
+void InputDispatcher::setInjectionResult(EventEntry& entry,
InputEventInjectionResult injectionResult) {
- InjectionState* injectionState = entry->injectionState;
+ InjectionState* injectionState = entry.injectionState;
if (injectionState) {
#if DEBUG_INJECTION
ALOGD("Setting input event injection result to %d. "
@@ -3763,7 +3799,7 @@
injectionResult, injectionState->injectorPid, injectionState->injectorUid);
#endif
- if (injectionState->injectionIsAsync && !(entry->policyFlags & POLICY_FLAG_FILTERED)) {
+ if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) {
// Log the outcome since the injector did not wait for the injection result.
switch (injectionResult) {
case InputEventInjectionResult::SUCCEEDED:
@@ -3789,15 +3825,15 @@
}
}
-void InputDispatcher::incrementPendingForegroundDispatches(EventEntry* entry) {
- InjectionState* injectionState = entry->injectionState;
+void InputDispatcher::incrementPendingForegroundDispatches(EventEntry& entry) {
+ InjectionState* injectionState = entry.injectionState;
if (injectionState) {
injectionState->pendingForegroundDispatches += 1;
}
}
-void InputDispatcher::decrementPendingForegroundDispatches(EventEntry* entry) {
- InjectionState* injectionState = entry->injectionState;
+void InputDispatcher::decrementPendingForegroundDispatches(EventEntry& entry) {
+ InjectionState* injectionState = entry.injectionState;
if (injectionState) {
injectionState->pendingForegroundDispatches -= 1;
@@ -4485,7 +4521,7 @@
// Dump recently dispatched or dropped events from oldest to newest.
if (!mRecentQueue.empty()) {
dump += StringPrintf(INDENT "RecentQueue: length=%zu\n", mRecentQueue.size());
- for (EventEntry* entry : mRecentQueue) {
+ for (std::shared_ptr<EventEntry>& entry : mRecentQueue) {
dump += INDENT2;
dump += entry->getDescription();
dump += StringPrintf(", age=%" PRId64 "ms\n", ns2ms(currentTime - entry->eventTime));
@@ -4508,7 +4544,7 @@
// Dump inbound events from oldest to newest.
if (!mInboundQueue.empty()) {
dump += StringPrintf(INDENT "InboundQueue: length=%zu\n", mInboundQueue.size());
- for (EventEntry* entry : mInboundQueue) {
+ for (std::shared_ptr<EventEntry>& entry : mInboundQueue) {
dump += INDENT2;
dump += entry->getDescription();
dump += StringPrintf(", age=%" PRId64 "ms\n", ns2ms(currentTime - entry->eventTime));
@@ -5001,8 +5037,8 @@
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
CommandEntry* commandEntry) {
- KeyEntry* entry = commandEntry->keyEntry;
- KeyEvent event = createKeyEvent(*entry);
+ KeyEntry& entry = *(commandEntry->keyEntry);
+ KeyEvent event = createKeyEvent(entry);
mLock.unlock();
@@ -5010,7 +5046,7 @@
sp<IBinder> token = commandEntry->inputChannel != nullptr
? commandEntry->inputChannel->getConnectionToken()
: nullptr;
- nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry->policyFlags);
+ nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry.policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",
std::to_string(t.duration().count()).c_str());
@@ -5019,14 +5055,13 @@
mLock.lock();
if (delay < 0) {
- entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
+ entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
} else if (!delay) {
- entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
+ entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
} else {
- entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
- entry->interceptKeyWakeupTime = now() + delay;
+ entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
+ entry.interceptKeyWakeupTime = now() + delay;
}
- entry->release();
}
void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) {
@@ -5070,11 +5105,11 @@
bool restartEvent;
if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
+ KeyEntry& keyEntry = static_cast<KeyEntry&>(*(dispatchEntry->eventEntry));
restartEvent =
afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
} else if (dispatchEntry->eventEntry->type == EventEntry::Type::MOTION) {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
+ MotionEntry& motionEntry = static_cast<MotionEntry&>(*(dispatchEntry->eventEntry));
restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry,
handled);
} else {
@@ -5109,20 +5144,20 @@
bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
DispatchEntry* dispatchEntry,
- KeyEntry* keyEntry, bool handled) {
- if (keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK) {
+ KeyEntry& keyEntry, bool handled) {
+ if (keyEntry.flags & AKEY_EVENT_FLAG_FALLBACK) {
if (!handled) {
// Report the key as unhandled, since the fallback was not handled.
- mReporter->reportUnhandledKey(keyEntry->id);
+ mReporter->reportUnhandledKey(keyEntry.id);
}
return false;
}
// Get the fallback key state.
// Clear it out after dispatching the UP.
- int32_t originalKeyCode = keyEntry->keyCode;
+ int32_t originalKeyCode = keyEntry.keyCode;
int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode);
- if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
+ if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
connection->inputState.removeFallbackKey(originalKeyCode);
}
@@ -5135,16 +5170,15 @@
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("Unhandled key event: Asking policy to cancel fallback action. "
"keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount,
- keyEntry->policyFlags);
+ keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
#endif
- KeyEvent event = createKeyEvent(*keyEntry);
+ KeyEvent event = createKeyEvent(keyEntry);
event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED);
mLock.unlock();
mPolicy->dispatchUnhandledKey(connection->inputChannel->getConnectionToken(), &event,
- keyEntry->policyFlags, &event);
+ keyEntry.policyFlags, &event);
mLock.lock();
@@ -5163,13 +5197,13 @@
// If the application did not handle a non-fallback key, first check
// that we are in a good state to perform unhandled key event processing
// Then ask the policy what to do with it.
- bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN && keyEntry->repeatCount == 0;
+ bool initialDown = keyEntry.action == AKEY_EVENT_ACTION_DOWN && keyEntry.repeatCount == 0;
if (fallbackKeyCode == -1 && !initialDown) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("Unhandled key event: Skipping unhandled key event processing "
"since this is not an initial down. "
"keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- originalKeyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags);
+ originalKeyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
#endif
return false;
}
@@ -5178,15 +5212,15 @@
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("Unhandled key event: Asking policy to perform fallback action. "
"keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags);
+ keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
#endif
- KeyEvent event = createKeyEvent(*keyEntry);
+ KeyEvent event = createKeyEvent(keyEntry);
mLock.unlock();
bool fallback =
mPolicy->dispatchUnhandledKey(connection->inputChannel->getConnectionToken(),
- &event, keyEntry->policyFlags, &event);
+ &event, keyEntry.policyFlags, &event);
mLock.lock();
@@ -5234,7 +5268,7 @@
fallback = false;
fallbackKeyCode = AKEYCODE_UNKNOWN;
- if (keyEntry->action != AKEY_EVENT_ACTION_UP) {
+ if (keyEntry.action != AKEY_EVENT_ACTION_UP) {
connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode);
}
}
@@ -5254,22 +5288,22 @@
if (fallback) {
// Restart the dispatch cycle using the fallback key.
- keyEntry->eventTime = event.getEventTime();
- keyEntry->deviceId = event.getDeviceId();
- keyEntry->source = event.getSource();
- keyEntry->displayId = event.getDisplayId();
- keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
- keyEntry->keyCode = fallbackKeyCode;
- keyEntry->scanCode = event.getScanCode();
- keyEntry->metaState = event.getMetaState();
- keyEntry->repeatCount = event.getRepeatCount();
- keyEntry->downTime = event.getDownTime();
- keyEntry->syntheticRepeat = false;
+ keyEntry.eventTime = event.getEventTime();
+ keyEntry.deviceId = event.getDeviceId();
+ keyEntry.source = event.getSource();
+ keyEntry.displayId = event.getDisplayId();
+ keyEntry.flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
+ keyEntry.keyCode = fallbackKeyCode;
+ keyEntry.scanCode = event.getScanCode();
+ keyEntry.metaState = event.getMetaState();
+ keyEntry.repeatCount = event.getRepeatCount();
+ keyEntry.downTime = event.getDownTime();
+ keyEntry.syntheticRepeat = false;
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("Unhandled key event: Dispatching fallback key. "
"originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
- originalKeyCode, fallbackKeyCode, keyEntry->metaState);
+ originalKeyCode, fallbackKeyCode, keyEntry.metaState);
#endif
return true; // restart the event
} else {
@@ -5278,7 +5312,7 @@
#endif
// Report the key as unhandled, since there is no fallback key.
- mReporter->reportUnhandledKey(keyEntry->id);
+ mReporter->reportUnhandledKey(keyEntry.id);
}
}
return false;
@@ -5286,7 +5320,7 @@
bool InputDispatcher::afterMotionEventLockedInterruptible(const sp<Connection>& connection,
DispatchEntry* dispatchEntry,
- MotionEntry* motionEntry, bool handled) {
+ MotionEntry& motionEntry, bool handled) {
return false;
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 235a8d3..4565151 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -158,9 +158,9 @@
sp<Looper> mLooper;
- EventEntry* mPendingEvent GUARDED_BY(mLock);
- std::deque<EventEntry*> mInboundQueue GUARDED_BY(mLock);
- std::deque<EventEntry*> mRecentQueue GUARDED_BY(mLock);
+ std::shared_ptr<EventEntry> mPendingEvent GUARDED_BY(mLock);
+ std::deque<std::shared_ptr<EventEntry>> mInboundQueue GUARDED_BY(mLock);
+ std::deque<std::shared_ptr<EventEntry>> mRecentQueue GUARDED_BY(mLock);
std::deque<std::unique_ptr<CommandEntry>> mCommandQueue GUARDED_BY(mLock);
DropReason mLastDropReason GUARDED_BY(mLock);
@@ -175,7 +175,7 @@
void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) REQUIRES(mLock);
// Enqueues an inbound event. Returns true if mLooper->wake() should be called.
- bool enqueueInboundEventLocked(EventEntry* entry) REQUIRES(mLock);
+ bool enqueueInboundEventLocked(std::unique_ptr<EventEntry> entry) REQUIRES(mLock);
// Cleans up input state when dropping an inbound event.
void dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) REQUIRES(mLock);
@@ -185,7 +185,7 @@
std::string_view reason) REQUIRES(mLock);
// Adds an event to a queue of recent events for debugging purposes.
- void addRecentEventLocked(EventEntry* entry) REQUIRES(mLock);
+ void addRecentEventLocked(std::shared_ptr<EventEntry> entry) REQUIRES(mLock);
// App switch latency optimization.
bool mAppSwitchSawKeyDown GUARDED_BY(mLock);
@@ -197,7 +197,7 @@
// Blocked event latency optimization. Drops old events when the user intends
// to transfer focus to a new application.
- EventEntry* mNextUnblockedEvent GUARDED_BY(mLock);
+ std::shared_ptr<EventEntry> mNextUnblockedEvent GUARDED_BY(mLock);
sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y,
TouchState* touchState,
@@ -242,21 +242,21 @@
// Event injection and synchronization.
std::condition_variable mInjectionResultAvailable;
bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
- void setInjectionResult(EventEntry* entry,
+ void setInjectionResult(EventEntry& entry,
android::os::InputEventInjectionResult injectionResult);
std::condition_variable mInjectionSyncFinished;
- void incrementPendingForegroundDispatches(EventEntry* entry);
- void decrementPendingForegroundDispatches(EventEntry* entry);
+ void incrementPendingForegroundDispatches(EventEntry& entry);
+ void decrementPendingForegroundDispatches(EventEntry& entry);
// Key repeat tracking.
struct KeyRepeatState {
- KeyEntry* lastKeyEntry; // or null if no repeat
+ std::shared_ptr<KeyEntry> lastKeyEntry; // or null if no repeat
nsecs_t nextRepeatTime;
} mKeyRepeatState GUARDED_BY(mLock);
void resetKeyRepeatLocked() REQUIRES(mLock);
- KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime) REQUIRES(mLock);
+ std::shared_ptr<KeyEntry> synthesizeKeyRepeatLocked(nsecs_t currentTime) REQUIRES(mLock);
// Key replacement tracking
struct KeyReplacement {
@@ -292,7 +292,7 @@
// Inbound event processing.
void drainInboundQueueLocked() REQUIRES(mLock);
void releasePendingEventLocked() REQUIRES(mLock);
- void releaseInboundEventLocked(EventEntry* entry) REQUIRES(mLock);
+ void releaseInboundEventLocked(std::shared_ptr<EventEntry> entry) REQUIRES(mLock);
// Dispatch state.
bool mDispatchEnabled GUARDED_BY(mLock);
@@ -356,15 +356,17 @@
const std::vector<InputTarget>& targets) REQUIRES(mLock);
// Dispatch inbound events.
- bool dispatchConfigurationChangedLocked(nsecs_t currentTime, ConfigurationChangedEntry* entry)
+ bool dispatchConfigurationChangedLocked(nsecs_t currentTime,
+ const ConfigurationChangedEntry& entry) REQUIRES(mLock);
+ bool dispatchDeviceResetLocked(nsecs_t currentTime, const DeviceResetEntry& entry)
REQUIRES(mLock);
- bool dispatchDeviceResetLocked(nsecs_t currentTime, DeviceResetEntry* entry) REQUIRES(mLock);
- bool dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason,
- nsecs_t* nextWakeupTime) REQUIRES(mLock);
- bool dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason,
- nsecs_t* nextWakeupTime) REQUIRES(mLock);
- void dispatchFocusLocked(nsecs_t currentTime, FocusEntry* entry) REQUIRES(mLock);
- void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
+ bool dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
+ DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
+ bool dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<MotionEntry> entry,
+ DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
+ void dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<FocusEntry> entry)
+ REQUIRES(mLock);
+ void dispatchEventLocked(nsecs_t currentTime, std::shared_ptr<EventEntry> entry,
const std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
void logOutboundKeyDetails(const char* prefix, const KeyEntry& entry);
@@ -461,6 +463,7 @@
float obscuringOpacity;
std::string obscuringPackage;
int32_t obscuringUid;
+ std::vector<std::string> debugInfo;
};
TouchOcclusionInfo computeTouchOcclusionInfoLocked(const sp<InputWindowHandle>& windowHandle,
@@ -469,6 +472,7 @@
bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, int32_t x,
int32_t y) const REQUIRES(mLock);
bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
+ std::string dumpWindowForTouchOcclusion(const InputWindowInfo* info, bool isTouchWindow) const;
std::string getApplicationWindowLabel(
const std::shared_ptr<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle);
@@ -478,12 +482,12 @@
// with the mutex held makes it easier to ensure that connection invariants are maintained.
// If needed, the methods post commands to run later once the critical bits are done.
void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget& inputTarget)
+ std::shared_ptr<EventEntry>, const InputTarget& inputTarget)
REQUIRES(mLock);
void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget& inputTarget)
+ std::shared_ptr<EventEntry>, const InputTarget& inputTarget)
REQUIRES(mLock);
- void enqueueDispatchEntryLocked(const sp<Connection>& connection, EventEntry* eventEntry,
+ void enqueueDispatchEntryLocked(const sp<Connection>& connection, std::shared_ptr<EventEntry>,
const InputTarget& inputTarget, int32_t dispatchMode)
REQUIRES(mLock);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
@@ -517,7 +521,8 @@
REQUIRES(mLock);
// Splitting motion events across windows.
- MotionEntry* splitMotionEvent(const MotionEntry& originalMotionEntry, BitSet32 pointerIds);
+ std::unique_ptr<MotionEntry> splitMotionEvent(const MotionEntry& originalMotionEntry,
+ BitSet32 pointerIds);
// Reset and drop everything the dispatcher is doing.
void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock);
@@ -566,10 +571,10 @@
REQUIRES(mLock);
void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
bool afterKeyEventLockedInterruptible(const sp<Connection>& connection,
- DispatchEntry* dispatchEntry, KeyEntry* keyEntry,
+ DispatchEntry* dispatchEntry, KeyEntry& keyEntry,
bool handled) REQUIRES(mLock);
bool afterMotionEventLockedInterruptible(const sp<Connection>& connection,
- DispatchEntry* dispatchEntry, MotionEntry* motionEntry,
+ DispatchEntry* dispatchEntry, MotionEntry& motionEntry,
bool handled) REQUIRES(mLock);
void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
KeyEvent createKeyEvent(const KeyEntry& entry);
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index 386056d..1656a21 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -265,17 +265,18 @@
}
}
-std::vector<EventEntry*> InputState::synthesizeCancelationEvents(
+std::vector<std::unique_ptr<EventEntry>> InputState::synthesizeCancelationEvents(
nsecs_t currentTime, const CancelationOptions& options) {
- std::vector<EventEntry*> events;
+ std::vector<std::unique_ptr<EventEntry>> events;
for (KeyMemento& memento : mKeyMementos) {
if (shouldCancelKey(memento, options)) {
- events.push_back(new KeyEntry(mIdGenerator.nextId(), currentTime, memento.deviceId,
- memento.source, memento.displayId, memento.policyFlags,
- AKEY_EVENT_ACTION_UP,
- memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode,
- memento.scanCode, memento.metaState, 0 /*repeatCount*/,
- memento.downTime));
+ events.push_back(
+ std::make_unique<KeyEntry>(mIdGenerator.nextId(), currentTime, memento.deviceId,
+ memento.source, memento.displayId,
+ memento.policyFlags, AKEY_EVENT_ACTION_UP,
+ memento.flags | AKEY_EVENT_FLAG_CANCELED,
+ memento.keyCode, memento.scanCode, memento.metaState,
+ 0 /*repeatCount*/, memento.downTime));
}
}
@@ -283,22 +284,26 @@
if (shouldCancelMotion(memento, options)) {
const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
: AMOTION_EVENT_ACTION_CANCEL;
- events.push_back(new MotionEntry(mIdGenerator.nextId(), currentTime, memento.deviceId,
- memento.source, memento.displayId, memento.policyFlags,
- action, 0 /*actionButton*/, memento.flags, AMETA_NONE,
- 0 /*buttonState*/, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
- memento.yPrecision, memento.xCursorPosition,
- memento.yCursorPosition, memento.downTime,
- memento.pointerCount, memento.pointerProperties,
- memento.pointerCoords, 0 /*xOffset*/, 0 /*yOffset*/));
+ events.push_back(
+ std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
+ memento.deviceId, memento.source,
+ memento.displayId, memento.policyFlags, action,
+ 0 /*actionButton*/, memento.flags, AMETA_NONE,
+ 0 /*buttonState*/, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+ memento.yPrecision, memento.xCursorPosition,
+ memento.yCursorPosition, memento.downTime,
+ memento.pointerCount, memento.pointerProperties,
+ memento.pointerCoords, 0 /*xOffset*/,
+ 0 /*yOffset*/));
}
}
return events;
}
-std::vector<EventEntry*> InputState::synthesizePointerDownEvents(nsecs_t currentTime) {
- std::vector<EventEntry*> events;
+std::vector<std::unique_ptr<EventEntry>> InputState::synthesizePointerDownEvents(
+ nsecs_t currentTime) {
+ std::vector<std::unique_ptr<EventEntry>> events;
for (MotionMemento& memento : mMotionMementos) {
if (!(memento.source & AINPUT_SOURCE_CLASS_POINTER)) {
continue;
@@ -333,15 +338,17 @@
: AMOTION_EVENT_ACTION_POINTER_DOWN
| (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
- events.push_back(new MotionEntry(mIdGenerator.nextId(), currentTime, memento.deviceId,
- memento.source, memento.displayId, memento.policyFlags,
- action, 0 /*actionButton*/, memento.flags, AMETA_NONE,
- 0 /*buttonState*/, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
- memento.yPrecision, memento.xCursorPosition,
- memento.yCursorPosition, memento.downTime,
- pointerCount, pointerProperties, pointerCoords,
- 0 /*xOffset*/, 0 /*yOffset*/));
+ events.push_back(
+ std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
+ memento.deviceId, memento.source,
+ memento.displayId, memento.policyFlags, action,
+ 0 /*actionButton*/, memento.flags, AMETA_NONE,
+ 0 /*buttonState*/, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+ memento.yPrecision, memento.xCursorPosition,
+ memento.yCursorPosition, memento.downTime,
+ pointerCount, pointerProperties, pointerCoords,
+ 0 /*xOffset*/, 0 /*yOffset*/));
}
memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
index d97a664..74ae21f 100644
--- a/services/inputflinger/dispatcher/InputState.h
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -51,11 +51,11 @@
bool trackMotion(const MotionEntry& entry, int32_t action, int32_t flags);
// Synthesizes cancelation events for the current state and resets the tracked state.
- std::vector<EventEntry*> synthesizeCancelationEvents(nsecs_t currentTime,
- const CancelationOptions& options);
+ std::vector<std::unique_ptr<EventEntry>> synthesizeCancelationEvents(
+ nsecs_t currentTime, const CancelationOptions& options);
// Synthesizes down events for the current state.
- std::vector<EventEntry*> synthesizePointerDownEvents(nsecs_t currentTime);
+ std::vector<std::unique_ptr<EventEntry>> synthesizePointerDownEvents(nsecs_t currentTime);
// Clears the current state.
void clear();
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 6465cc9..8cb7194 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -48,4 +48,5 @@
"libc++fs"
],
require_root: true,
+ test_suites: ["device-tests"],
}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index c77298e..d302f98 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -204,8 +204,8 @@
layer.frameNumber = mCurrentFrameNumber;
layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
- // TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
+ const bool useFiltering =
+ targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering();
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
@@ -527,10 +527,6 @@
}
uint32_t BufferLayer::getEffectiveScalingMode() const {
- if (mOverrideScalingMode >= 0) {
- return mOverrideScalingMode;
- }
-
return mBufferInfo.mScaleMode;
}
@@ -826,6 +822,10 @@
}
}
+bool BufferLayer::bufferNeedsFiltering() const {
+ return isFixedSize();
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 1cd753b..deaf846 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -94,8 +94,7 @@
bool hasReadyFrame() const override;
- // Returns the current scaling mode, unless mOverrideScalingMode
- // is set, in which case, it returns mOverrideScalingMode
+ // Returns the current scaling mode
uint32_t getEffectiveScalingMode() const override;
// Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
@@ -116,6 +115,10 @@
ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; }
+ // Returns true if the transformed buffer size does not match the layer size and we need
+ // to apply filtering.
+ virtual bool bufferNeedsFiltering() const;
+
protected:
struct BufferInfo {
nsecs_t mDesiredPresentTime;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 7c73df2..69d2d11 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -503,6 +503,9 @@
BufferLayerConsumer::Image::Image(const sp<GraphicBuffer>& graphicBuffer,
renderengine::RenderEngine& engine)
: mGraphicBuffer(graphicBuffer), mRE(engine) {
+ if (graphicBuffer != nullptr && (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED)) {
+ return;
+ }
mRE.cacheExternalTextureBuffer(mGraphicBuffer);
}
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 51c7ed5..9ab2974 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -239,7 +239,7 @@
bool queuedBuffer = false;
const int32_t layerId = getSequence();
LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
- getProducerStickyTransform() != 0, mName, mOverrideScalingMode,
+ getProducerStickyTransform() != 0, mName,
getTransformToDisplayInverse());
if (isRemovedFromCurrentState()) {
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 66b4e19..a64b243 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -48,7 +48,6 @@
BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args)
: BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) {
- mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
}
@@ -263,6 +262,8 @@
bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
nsecs_t postTime, nsecs_t desiredPresentTime,
const client_cache_t& clientCacheId, uint64_t frameNumber) {
+ ATRACE_CALL();
+
if (mCurrentState.buffer) {
mReleasePreviousBuffer = true;
}
@@ -681,6 +682,10 @@
mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId);
}
+uint32_t BufferStateLayer::getEffectiveScalingMode() const {
+ return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+}
+
Rect BufferStateLayer::computeCrop(const State& s) {
if (s.crop.isEmpty() && s.buffer) {
return s.buffer->getBounds();
@@ -739,6 +744,31 @@
static_cast<float>(s.active.transform.ty() + s.active.h)),
radius);
}
+
+bool BufferStateLayer::bufferNeedsFiltering() const {
+ const State& s(getDrawingState());
+ if (!s.buffer) {
+ return false;
+ }
+
+ uint32_t bufferWidth = s.buffer->width;
+ uint32_t bufferHeight = s.buffer->height;
+
+ // Undo any transformations on the buffer and return the result.
+ if (s.transform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+
+ if (s.transformToDisplayInverse) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+ }
+
+ const Rect layerSize{getBounds()};
+ return layerSize.width() != bufferWidth || layerSize.height() != bufferHeight;
+}
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index c13f5e8..104a13b 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -92,7 +92,6 @@
return false;
}
bool setCrop_legacy(const Rect& /*crop*/) override { return false; }
- bool setOverrideScalingMode(int32_t /*overrideScalingMode*/) override { return false; }
void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/,
uint64_t /*frameNumber*/) override {}
void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/,
@@ -110,6 +109,7 @@
bool fenceHasSignaled() const override;
bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
bool onPreComposition(nsecs_t refreshStartTime) override;
+ uint32_t getEffectiveScalingMode() const override;
protected:
void gatherBufferInfo() override;
@@ -143,6 +143,8 @@
bool willPresentCurrentTransaction() const;
+ bool bufferNeedsFiltering() const override;
+
static const std::array<float, 16> IDENTITY_MATRIX;
std::unique_ptr<renderengine::Image> mTextureImage;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 77400eb..5a3b9ac 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -20,6 +20,7 @@
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
+#include <ui/BlurRegion.h>
#include <ui/FloatRect.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -118,6 +119,9 @@
// length of the shadow in screen space
float shadowRadius{0.f};
+ // List of regions that require blur
+ std::vector<BlurRegion> blurRegions;
+
/*
* Geometry state
*/
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index d590f23..3be1cc4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -167,6 +167,11 @@
const Rect& orientedDisplaySpaceRect) = 0;
// Sets the bounds to use
virtual void setDisplaySize(const ui::Size&) = 0;
+ // Gets the transform hint used in layers that belong to this output. Used to guide
+ // composition orientation so that HW overlay can be used when display isn't in its natural
+ // orientation on some devices. Therefore usually we only use transform hint from display
+ // output.
+ virtual ui::Transform::RotationFlags getTransformHint() const = 0;
// Sets the layer stack filtering settings for this output. See
// belongsInOutput for full details.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 5b832a5..651230c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -42,6 +42,7 @@
const Rect& orientedDisplaySpaceRect) override;
void setDisplaySize(const ui::Size&) override;
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
+ ui::Transform::RotationFlags getTransformHint() const override;
void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
void setColorProfile(const ColorProfile&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d6fbd7f..95db4da 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -39,6 +39,7 @@
MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
+ MOCK_CONST_METHOD0(getTransformHint, ui::Transform::RotationFlags());
MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD1(setColorProfile, void(const ColorProfile&));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 04dceae..3852f45 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -192,6 +192,10 @@
dirtyEntireOutput();
}
+ui::Transform::RotationFlags Output::getTransformHint() const {
+ return static_cast<ui::Transform::RotationFlags>(getState().transform.getOrientation());
+}
+
void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) {
auto& outputState = editState();
outputState.layerStackId = layerStackId;
@@ -665,7 +669,8 @@
compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
compositionengine::OutputLayer* layerRequestingBgComposition = nullptr;
for (auto* layer : getOutputLayersOrderedByZ()) {
- if (layer->getLayerFE().getCompositionState()->backgroundBlurRadius > 0) {
+ if (layer->getLayerFE().getCompositionState()->backgroundBlurRadius > 0 ||
+ layer->getLayerFE().getCompositionState()->blurRegions.size() > 0) {
layerRequestingBgComposition = layer;
}
}
@@ -897,6 +902,8 @@
needsProtected == renderEngine.isProtected()) {
mRenderSurface->setProtected(needsProtected);
}
+ } else if (!outputState.isSecure && renderEngine.isProtected()) {
+ renderEngine.useProtectedContext(false);
}
base::unique_fd fd;
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 6d01bf1..1befbf8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -160,6 +160,7 @@
EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
}
DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index b5cda68..84c027b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -81,6 +81,7 @@
MOCK_METHOD2(onHotplug,
std::optional<DisplayIdentificationInfo>(hal::HWDisplayId, hal::Connection));
+ MOCK_CONST_METHOD0(updatesDeviceProductInfoOnHotplugReconnect, bool());
MOCK_METHOD2(onVsync, bool(hal::HWDisplayId, int64_t));
MOCK_METHOD2(setVsyncEnabled, void(PhysicalDisplayId, hal::Vsync));
MOCK_CONST_METHOD1(getRefreshTimestamp, nsecs_t(PhysicalDisplayId));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 1e10365..9badb99 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -268,6 +268,8 @@
EXPECT_EQ(orientation, state.framebufferSpace.orientation);
EXPECT_EQ(state.displaySpace.content, state.transform.transform(state.layerStackSpace.content));
+
+ EXPECT_EQ(ui::Transform::ROT_90, mOutput->getTransformHint());
}
TEST_F(OutputTest, setProjectionWithSmallFramebufferWorks) {
@@ -2950,6 +2952,7 @@
mOutput.mState.usesClientComposition = false;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
@@ -2962,6 +2965,7 @@
mOutput.mState.flipClientTarget = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(mOutputBuffer));
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
@@ -2971,6 +2975,7 @@
TEST_F(OutputComposeSurfacesTest, doesMinimalWorkIfDequeueBufferFailsForClientComposition) {
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(nullptr));
@@ -2983,6 +2988,7 @@
mOutput.mState.flipClientTarget = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(nullptr));
@@ -2993,6 +2999,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3015,6 +3022,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3042,6 +3050,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3070,6 +3079,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3098,6 +3108,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3129,6 +3140,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r2}))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r3}));
@@ -3151,6 +3163,7 @@
struct OutputComposeSurfacesTest_UsesExpectedDisplaySettings : public OutputComposeSurfacesTest {
OutputComposeSurfacesTest_UsesExpectedDisplaySettings() {
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3298,6 +3311,8 @@
mOutput.mState.isSecure = false;
mLayer2.mLayerFEState.hasProtectedContent = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
+ EXPECT_CALL(mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
@@ -3390,6 +3405,7 @@
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
@@ -3998,6 +4014,34 @@
mOutput->updateAndWriteCompositionState(args);
}
+TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) {
+ InjectedLayer layer1;
+ InjectedLayer layer2;
+ InjectedLayer layer3;
+
+ // Layer requesting blur, or below, should request client composition.
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(false));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(false));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(false));
+
+ BlurRegion region;
+ layer2.layerFEState.blurRegions.push_back(region);
+
+ injectOutputLayer(layer1);
+ injectOutputLayer(layer2);
+ injectOutputLayer(layer3);
+
+ mOutput->editState().isEnabled = true;
+
+ CompositionRefreshArgs args;
+ args.updatingGeometryThisFrame = false;
+ args.devOptForceClientComposition = false;
+ mOutput->updateAndWriteCompositionState(args);
+}
+
TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenRequests) {
// In split-screen landscape mode, the screen is rotated 90 degrees, with
// one layer on the left covering the left side of the output, and one layer
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 5bd7a1f..cbc201f 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -248,6 +248,10 @@
return mCompositionDisplay->getState().layerStackId;
}
+ui::Transform::RotationFlags DisplayDevice::getTransformHint() const {
+ return mCompositionDisplay->getTransformHint();
+}
+
const ui::Transform& DisplayDevice::getTransform() const {
return mCompositionDisplay->getState().transform;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index fa684c0..cc38ab0 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -95,10 +95,7 @@
static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
- ui::Transform::RotationFlags getTransformHint() const {
- return static_cast<ui::Transform::RotationFlags>(getTransform().getOrientation());
- }
-
+ ui::Transform::RotationFlags getTransformHint() const;
const ui::Transform& getTransform() const;
const Rect& getLayerStackSpaceRect() const;
const Rect& getOrientedDisplaySpaceRect() const;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 2fdbd3a..1548d18 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -26,6 +26,7 @@
#include "HWComposer.h"
+#include <android-base/properties.h>
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -38,6 +39,7 @@
#include "../Layer.h" // needed only for debugging
#include "../Promise.h"
#include "../SurfaceFlinger.h"
+#include "../SurfaceFlingerProperties.h"
#include "ComposerHal.h"
#include "HWC2.h"
@@ -143,12 +145,13 @@
namespace impl {
-HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer) : mComposer(std::move(composer)) {
-}
+HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer)
+ : mComposer(std::move(composer)),
+ mUpdateDeviceProductInfoOnHotplugReconnect(
+ android::sysprop::update_device_product_info_on_hotplug_reconnect(false)) {}
HWComposer::HWComposer(const std::string& composerServiceName)
- : mComposer(std::make_unique<Hwc2::impl::Composer>(composerServiceName)) {
-}
+ : HWComposer(std::make_unique<Hwc2::impl::Composer>(composerServiceName)) {}
HWComposer::~HWComposer() {
mDisplayData.clear();
@@ -204,6 +207,10 @@
}
}
+bool HWComposer::updatesDeviceProductInfoOnHotplugReconnect() const {
+ return mUpdateDeviceProductInfoOnHotplugReconnect;
+}
+
bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) {
const auto displayId = toPhysicalDisplayId(hwcDisplayId);
if (!displayId) {
@@ -888,6 +895,16 @@
info = DisplayIdentificationInfo{.id = *displayId,
.name = std::string(),
.deviceProductInfo = std::nullopt};
+ if (mUpdateDeviceProductInfoOnHotplugReconnect) {
+ uint8_t port;
+ DisplayIdentificationData data;
+ getDisplayIdentificationData(hwcDisplayId, &port, &data);
+ if (auto newInfo = parseDisplayIdentificationData(port, data)) {
+ info->deviceProductInfo = std::move(newInfo->deviceProductInfo);
+ } else {
+ ALOGE("Failed to parse identification data for display %" PRIu64, hwcDisplayId);
+ }
+ }
} else {
uint8_t port;
DisplayIdentificationData data;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 028a9a4..d8af5bf 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -173,6 +173,10 @@
virtual std::optional<DisplayIdentificationInfo> onHotplug(hal::HWDisplayId,
hal::Connection) = 0;
+ // If true we'll update the DeviceProductInfo on subsequent hotplug connected events.
+ // TODO(b/157555476): Remove when the framework has proper support for headless mode
+ virtual bool updatesDeviceProductInfoOnHotplugReconnect() const = 0;
+
virtual bool onVsync(hal::HWDisplayId, int64_t timestamp) = 0;
virtual void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) = 0;
@@ -303,10 +307,12 @@
// Events handling ---------------------------------------------------------
- // Returns stable display ID (and display name on connection of new or previously disconnected
+ // Returns PhysicalDisplayId (and display name on connection of new or previously disconnected
// display), or std::nullopt if hotplug event was ignored.
std::optional<DisplayIdentificationInfo> onHotplug(hal::HWDisplayId, hal::Connection) override;
+ bool updatesDeviceProductInfoOnHotplugReconnect() const override;
+
bool onVsync(hal::HWDisplayId, int64_t timestamp) override;
void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) override;
@@ -400,6 +406,8 @@
bool mHasMultiDisplaySupport = false;
RandomDisplayIdGenerator<HalVirtualDisplayId> mVirtualIdGenerator{getMaxVirtualDisplayCount()};
+
+ const bool mUpdateDeviceProductInfoOnHotplugReconnect;
};
} // namespace impl
diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp
index 9a6b328..20486e0 100644
--- a/services/surfaceflinger/DisplayRenderArea.cpp
+++ b/services/surfaceflinger/DisplayRenderArea.cpp
@@ -26,8 +26,7 @@
return RenderArea::RotationFlags::ROT_0;
}
- const ui::Rotation orientation = display.getPhysicalOrientation() + display.getOrientation();
- return ui::Transform::toRotationFlags(orientation);
+ return ui::Transform::toRotationFlags(display.getOrientation());
}
} // namespace
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index bef52b7..ffae56f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -482,6 +482,7 @@
compositionState->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
compositionState->alpha = alpha;
compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
+ compositionState->blurRegions = drawingState.blurRegions;
}
void Layer::prepareGeometryCompositionState() {
@@ -550,7 +551,8 @@
isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
// Force client composition for special cases known only to the front-end.
- if (isHdrY410() || usesRoundedCorners || drawShadows()) {
+ if (isHdrY410() || usesRoundedCorners || drawShadows() ||
+ getDrawingState().blurRegions.size() > 0) {
compositionState->forceClientComposition = true;
}
}
@@ -646,6 +648,7 @@
layerSettings.alpha = alpha;
layerSettings.sourceDataspace = getDataSpace();
layerSettings.backgroundBlurRadius = getBackgroundBlurRadius();
+ layerSettings.blurRegions = getBlurRegions();
return layerSettings;
}
@@ -1035,6 +1038,12 @@
mCurrentState.inputInfoChanged = false;
}
+ // Add the callbacks from the drawing state into the current state. This is so when the current
+ // state gets copied to drawing, we don't lose the callback handles that are still in drawing.
+ for (auto& handle : s.callbackHandles) {
+ c.callbackHandles.push_back(handle);
+ }
+
// Commit the transaction
commitTransaction(c);
mPendingStatesSnapshot = mPendingStates;
@@ -1280,6 +1289,14 @@
return true;
}
+bool Layer::setBlurRegions(const std::vector<BlurRegion>& blurRegions) {
+ mCurrentState.sequence++;
+ mCurrentState.blurRegions = blurRegions;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
bool Layer::setFlags(uint8_t flags, uint8_t mask) {
const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
if (mCurrentState.flags == newFlags) return false;
@@ -1301,13 +1318,6 @@
return true;
}
-bool Layer::setOverrideScalingMode(int32_t scalingMode) {
- if (scalingMode == mOverrideScalingMode) return false;
- mOverrideScalingMode = scalingMode;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
bool Layer::setMetadata(const LayerMetadata& data) {
if (!mCurrentState.metadata.merge(data, true /* eraseEmpty */)) return false;
mCurrentState.sequence++;
@@ -1463,7 +1473,6 @@
}
void Layer::setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime) {
- mCurrentState.sequence++;
mCurrentState.frameTimelineVsyncId = frameTimelineVsyncId;
mCurrentState.postTime = postTime;
mCurrentState.modified = true;
@@ -2175,6 +2184,10 @@
return getDrawingState().backgroundBlurRadius;
}
+const std::vector<BlurRegion>& Layer::getBlurRegions() const {
+ return getDrawingState().blurRegions;
+}
+
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
@@ -2454,6 +2467,7 @@
ySurfaceInset = std::round(ySurfaceInset * yScale);
}
+ // Transform the layer bounds from layer coordinate space to display coordinate space.
Rect transformedLayerBounds = t.transform(layerBounds);
// clamp inset to layer bounds
@@ -2478,7 +2492,7 @@
transformedLayerBounds.bottom = tmp;
}
- // Input coordinate should match the layer bounds.
+ // Input coordinates should be in display coordinate space.
info.frameLeft = transformedLayerBounds.left;
info.frameTop = transformedLayerBounds.top;
info.frameRight = transformedLayerBounds.right;
@@ -2491,7 +2505,7 @@
// the final frame calculated.
// 1. Take the original transform set on the window and get the inverse transform. This is
// used to get the final bounds in display space (ignorning the transform). Apply the
- // inverse transform on the layerBounds to get the untransformed frame (in display space)
+ // inverse transform on the layerBounds to get the untransformed frame (in layer space)
// 2. Take the top and left of the untransformed frame to get the real position on screen.
// Apply the layer transform on top/left so it includes any scale or rotation. These will
// be the new translation values for the transform.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2321247..5cb56a5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -26,6 +26,7 @@
#include <renderengine/Mesh.h>
#include <renderengine/Texture.h>
#include <sys/types.h>
+#include <ui/BlurRegion.h>
#include <ui/FloatRect.h>
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
@@ -255,6 +256,9 @@
// be rendered around the layer.
float shadowRadius;
+ // Layer regions that are made of custom materials, like frosted glass
+ std::vector<BlurRegion> blurRegions;
+
// Priority of the layer assigned by Window Manager.
int32_t frameRateSelectionPriority;
@@ -341,7 +345,6 @@
//
// The first set of geometry functions are controlled by the scaling mode, described
// in window.h. The scaling mode may be set by the client, as it submits buffers.
- // This value may be overriden through SurfaceControl, with setOverrideScalingMode.
//
// Put simply, if our scaling mode is SCALING_MODE_FREEZE, then
// matrix updates will not be applied while a resize is pending
@@ -392,6 +395,7 @@
// When non-zero, everything below this layer will be blurred by backgroundBlurRadius, which
// is specified in pixels.
virtual bool setBackgroundBlurRadius(int backgroundBlurRadius);
+ virtual bool setBlurRegions(const std::vector<BlurRegion>& effectRegions);
virtual bool setTransparentRegionHint(const Region& transparent);
virtual bool setFlags(uint8_t flags, uint8_t mask);
virtual bool setLayerStack(uint32_t layerStack);
@@ -399,7 +403,6 @@
virtual void deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle,
uint64_t frameNumber);
virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber);
- virtual bool setOverrideScalingMode(int32_t overrideScalingMode);
virtual bool setMetadata(const LayerMetadata& data);
virtual void setChildrenDrawingParent(const sp<Layer>&);
virtual bool reparent(const sp<IBinder>& newParentHandle);
@@ -467,7 +470,7 @@
virtual bool canReceiveInput() const;
/*
- * isProtected - true if the layer may contain protected content in the
+ * isProtected - true if the layer may contain protected contents in the
* GRALLOC_USAGE_PROTECTED sense.
*/
virtual bool isProtected() const { return false; }
@@ -679,7 +682,8 @@
/*
* isSecure - true if this surface is secure, that is if it prevents
- * screenshots or VNC servers.
+ * screenshots or VNC servers. A surface can be set to be secure by the
+ * application, being secure doesn't mean the surface has DRM contents.
*/
bool isSecure() const;
@@ -1003,7 +1007,6 @@
bool mIsActiveBufferUpdatedForGpu = true;
// We encode unset as -1.
- int32_t mOverrideScalingMode{-1};
std::atomic<uint64_t> mCurrentFrameNumber{0};
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering{false};
@@ -1080,7 +1083,8 @@
sp<Layer> getRootLayer();
// Cached properties computed from drawing state
- // Effective transform taking into account parent transforms and any parent scaling.
+ // Effective transform taking into account parent transforms and any parent scaling, which is
+ // a transform from the current layer coordinate space to display(screen) coordinate space.
ui::Transform mEffectiveTransform;
// Bounds of the layer before any transformation is applied and before it has been cropped
@@ -1111,6 +1115,9 @@
// final shadow radius for this layer. If a shadow is specified for a layer, then effective
// shadow radius is the set shadow radius, otherwise its the parent's shadow radius.
float mEffectiveShadowRadius = 0.f;
+
+ // A list of regions on this layer that should have blurs.
+ const std::vector<BlurRegion>& getBlurRegions() const;
};
} // namespace android
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index e6c8654..053b7f7 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -29,13 +29,12 @@
LayerRejecter::LayerRejecter(Layer::State& front, Layer::State& current,
bool& recomputeVisibleRegions, bool stickySet, const std::string& name,
- int32_t overrideScalingMode, bool transformToDisplayInverse)
+ bool transformToDisplayInverse)
: mFront(front),
mCurrent(current),
mRecomputeVisibleRegions(recomputeVisibleRegions),
mStickyTransformSet(stickySet),
mName(name),
- mOverrideScalingMode(overrideScalingMode),
mTransformToDisplayInverse(transformToDisplayInverse) {}
bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item) {
@@ -59,7 +58,7 @@
}
}
- int actualScalingMode = mOverrideScalingMode >= 0 ? mOverrideScalingMode : item.mScalingMode;
+ int actualScalingMode = item.mScalingMode;
bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
if (mFront.active_legacy != mFront.requested_legacy) {
if (isFixedSize ||
diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h
index fb5c750..4981f45 100644
--- a/services/surfaceflinger/LayerRejecter.h
+++ b/services/surfaceflinger/LayerRejecter.h
@@ -24,7 +24,7 @@
class LayerRejecter : public BufferLayerConsumer::BufferRejecter {
public:
LayerRejecter(Layer::State& front, Layer::State& current, bool& recomputeVisibleRegions,
- bool stickySet, const std::string& name, int32_t overrideScalingMode,
+ bool stickySet, const std::string& name,
bool transformToDisplayInverse);
virtual bool reject(const sp<GraphicBuffer>&, const BufferItem&);
@@ -35,7 +35,6 @@
bool& mRecomputeVisibleRegions;
const bool mStickyTransformSet;
const std::string& mName;
- const int32_t mOverrideScalingMode;
const bool mTransformToDisplayInverse;
};
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index a90d05e..2783800 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -20,6 +20,21 @@
#include <sstream>
#include <thread>
+namespace {
+using namespace std::chrono_literals;
+
+constexpr int64_t kNsToSeconds = std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
+
+// The syscall interface uses a pair of integers for the timestamp. The first
+// (tv_sec) is the whole count of seconds. The second (tv_nsec) is the
+// nanosecond part of the count. This function takes care of translation.
+void calculateTimeoutTime(std::chrono::nanoseconds timestamp, timespec* spec) {
+ clock_gettime(CLOCK_MONOTONIC, spec);
+ spec->tv_sec += static_cast<__kernel_time_t>(timestamp.count() / kNsToSeconds);
+ spec->tv_nsec += timestamp.count() % kNsToSeconds;
+}
+} // namespace
+
namespace android {
namespace scheduler {
@@ -32,81 +47,95 @@
}
void OneShotTimer::start() {
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mState = TimerState::RESET;
+ sem_init(&mSemaphore, 0, 0);
+
+ if (!mThread.joinable()) {
+ // Only create thread if it has not been created.
+ mThread = std::thread(&OneShotTimer::loop, this);
}
- mThread = std::thread(&OneShotTimer::loop, this);
}
void OneShotTimer::stop() {
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mState = TimerState::STOPPED;
- }
- mCondition.notify_all();
+ mStopTriggered = true;
+ sem_post(&mSemaphore);
+
if (mThread.joinable()) {
mThread.join();
+ sem_destroy(&mSemaphore);
}
}
void OneShotTimer::loop() {
+ TimerState state = TimerState::RESET;
while (true) {
bool triggerReset = false;
bool triggerTimeout = false;
- {
- std::lock_guard<std::mutex> lock(mMutex);
- if (mState == TimerState::STOPPED) {
- break;
- }
- if (mState == TimerState::IDLE) {
- mCondition.wait(mMutex);
- continue;
- }
-
- if (mState == TimerState::RESET) {
- triggerReset = true;
- }
+ state = checkForResetAndStop(state);
+ if (state == TimerState::STOPPED) {
+ break;
}
+
+ if (state == TimerState::IDLE) {
+ sem_wait(&mSemaphore);
+ continue;
+ }
+
+ if (state == TimerState::RESET) {
+ triggerReset = true;
+ }
+
if (triggerReset && mResetCallback) {
mResetCallback();
}
- { // lock the mutex again. someone might have called stop meanwhile
- std::lock_guard<std::mutex> lock(mMutex);
- if (mState == TimerState::STOPPED) {
- break;
- }
+ state = checkForResetAndStop(state);
+ if (state == TimerState::STOPPED) {
+ break;
+ }
- auto triggerTime = std::chrono::steady_clock::now() + mInterval;
- mState = TimerState::WAITING;
- while (mState == TimerState::WAITING) {
- constexpr auto zero = std::chrono::steady_clock::duration::zero();
- auto waitTime = triggerTime - std::chrono::steady_clock::now();
- if (waitTime > zero) mCondition.wait_for(mMutex, waitTime);
- if (mState == TimerState::RESET) {
- triggerTime = std::chrono::steady_clock::now() + mInterval;
- mState = TimerState::WAITING;
- } else if (mState == TimerState::WAITING &&
- (triggerTime - std::chrono::steady_clock::now()) <= zero) {
- triggerTimeout = true;
- mState = TimerState::IDLE;
- }
+ auto triggerTime = std::chrono::steady_clock::now() + mInterval;
+ state = TimerState::WAITING;
+ while (state == TimerState::WAITING) {
+ constexpr auto zero = std::chrono::steady_clock::duration::zero();
+ // Wait for mInterval time for semaphore signal.
+ struct timespec ts;
+ calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts);
+ sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
+
+ state = checkForResetAndStop(state);
+ if (state == TimerState::RESET) {
+ triggerTime = std::chrono::steady_clock::now() + mInterval;
+ state = TimerState::WAITING;
+ } else if (state == TimerState::WAITING &&
+ (triggerTime - std::chrono::steady_clock::now()) <= zero) {
+ triggerTimeout = true;
+ state = TimerState::IDLE;
}
}
+
if (triggerTimeout && mTimeoutCallback) {
mTimeoutCallback();
}
}
}
-void OneShotTimer::reset() {
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mState = TimerState::RESET;
+OneShotTimer::TimerState OneShotTimer::checkForResetAndStop(TimerState state) {
+ // Stop takes precedence of the reset.
+ if (mStopTriggered.exchange(false)) {
+ return TimerState::STOPPED;
}
- mCondition.notify_all();
+ // If the state was stopped, the thread was joined, and we cannot reset
+ // the timer anymore.
+ if (state != TimerState::STOPPED && mResetTriggered.exchange(false)) {
+ return TimerState::RESET;
+ }
+ return state;
+}
+
+void OneShotTimer::reset() {
+ mResetTriggered = true;
+ sem_post(&mSemaphore);
}
std::string OneShotTimer::dump() const {
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h
index b005754..8bbd4f5 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -16,6 +16,7 @@
#pragma once
+#include <semaphore.h>
#include <chrono>
#include <condition_variable>
#include <thread>
@@ -70,17 +71,15 @@
// Function that loops until the condition for stopping is met.
void loop();
+ // Checks whether mResetTriggered and mStopTriggered were set and updates
+ // mState if so.
+ TimerState checkForResetAndStop(TimerState state);
+
// Thread waiting for timer to expire.
std::thread mThread;
- // Condition used to notify mThread.
- std::condition_variable_any mCondition;
-
- // Lock used for synchronizing the waiting thread with the application thread.
- std::mutex mMutex;
-
- // Current timer state
- TimerState mState GUARDED_BY(mMutex) = TimerState::RESET;
+ // Semaphore to keep mThread synchronized.
+ sem_t mSemaphore;
// Interval after which timer expires.
const Interval mInterval;
@@ -90,6 +89,12 @@
// Callback that happens when timer expires.
const TimeoutCallback mTimeoutCallback;
+
+ // After removing lock guarding mState, the state can be now accessed at
+ // any time. Keep a bool if the reset or stop were requested, and occasionally
+ // check in the main loop if they were.
+ std::atomic<bool> mResetTriggered = false;
+ std::atomic<bool> mStopTriggered = false;
};
} // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 8661b6e..7ab49a9 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -48,6 +48,13 @@
}
}
+std::string RefreshRateConfigs::Policy::toString() {
+ return base::StringPrintf("default config ID: %d, allowGroupSwitching = %d"
+ ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]",
+ defaultConfig.value(), allowGroupSwitching, primaryRange.min,
+ primaryRange.max, appRequestRange.min, appRequestRange.max);
+}
+
const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(
const std::vector<LayerRequirement>& layers) const {
std::lock_guard lock(mLock);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index eed8486..280ed62 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -108,6 +108,10 @@
std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;
struct Policy {
+ private:
+ static constexpr int kAllowGroupSwitchingDefault = false;
+
+ public:
struct Range {
float min = 0;
float max = std::numeric_limits<float>::max();
@@ -122,6 +126,8 @@
// The default config, used to ensure we only initiate display config switches within the
// same config group as defaultConfigId's group.
HwcConfigIndexType defaultConfig;
+ // Whether or not we switch config groups to get the best frame rate.
+ bool allowGroupSwitching = kAllowGroupSwitchingDefault;
// The primary refresh rate range represents display manager's general guidance on the
// display configs we'll consider when switching refresh rates. Unless we get an explicit
// signal from an app, we should stay within this range.
@@ -133,15 +139,23 @@
// app request range. The app request range will be greater than or equal to the primary
// refresh rate range, never smaller.
Range appRequestRange;
- // Whether or not we switch config groups to get the best frame rate. Only used by tests.
- bool allowGroupSwitching = false;
Policy() = default;
+
Policy(HwcConfigIndexType defaultConfig, const Range& range)
- : Policy(defaultConfig, range, range) {}
+ : Policy(defaultConfig, kAllowGroupSwitchingDefault, range, range) {}
+
+ Policy(HwcConfigIndexType defaultConfig, bool allowGroupSwitching, const Range& range)
+ : Policy(defaultConfig, allowGroupSwitching, range, range) {}
+
Policy(HwcConfigIndexType defaultConfig, const Range& primaryRange,
const Range& appRequestRange)
+ : Policy(defaultConfig, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {}
+
+ Policy(HwcConfigIndexType defaultConfig, bool allowGroupSwitching,
+ const Range& primaryRange, const Range& appRequestRange)
: defaultConfig(defaultConfig),
+ allowGroupSwitching(allowGroupSwitching),
primaryRange(primaryRange),
appRequestRange(appRequestRange) {}
@@ -152,6 +166,7 @@
}
bool operator!=(const Policy& other) const { return !(*this == other); }
+ std::string toString();
};
// Return code set*Policy() to indicate the current policy is unchanged.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 31c380e..fde38c9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -357,7 +357,9 @@
hasWideColorDisplay = has_wide_color_display(false);
- useColorManagement = use_color_management(false);
+ // Android 12 and beyond, color management in display pipeline is turned on
+ // by default.
+ useColorManagement = use_color_management(true);
mDefaultCompositionDataspace =
static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB));
@@ -1041,7 +1043,12 @@
} else {
const HwcConfigIndexType config(mode);
const float fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps();
- const scheduler::RefreshRateConfigs::Policy policy{config, {fps, fps}};
+ // Keep the old switching type.
+ const auto allowGroupSwitching =
+ mRefreshRateConfigs->getCurrentPolicy().allowGroupSwitching;
+ const scheduler::RefreshRateConfigs::Policy policy{config,
+ allowGroupSwitching,
+ {fps, fps}};
constexpr bool kOverridePolicy = false;
return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
@@ -1848,16 +1855,18 @@
bool refreshNeeded;
{
- ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled);
+ mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) ||
+ mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) ||
+ mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS);
+ const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
+ ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);
mFrameTimeline->setSfWakeUp(vsyncId, frameStart);
refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
- if (mTracingEnabled) {
- mAddCompositionStateToTrace =
- mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION);
- if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) {
+ if (tracePreComposition) {
+ if (mVisibleRegionsDirty) {
mTracing.notifyLocked("visibleRegionsDirty");
}
}
@@ -2007,12 +2016,15 @@
modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
mLayersWithQueuedFrames.clear();
- if (mVisibleRegionsDirty) {
- mVisibleRegionsDirty = false;
- if (mTracingEnabled && mAddCompositionStateToTrace) {
+ if (mTracingEnabled && mTracePostComposition) {
+ // This may block if SurfaceTracing is running in sync mode.
+ if (mVisibleRegionsDirty) {
mTracing.notify("visibleRegionsDirty");
+ } else if (mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS)) {
+ mTracing.notify("bufferLatched");
}
}
+ mVisibleRegionsDirty = false;
if (mCompositionEngine->needsAnotherUpdate()) {
signalLayerUpdate();
@@ -2313,7 +2325,7 @@
void SurfaceFlinger::processDisplayHotplugEventsLocked() {
for (const auto& event : mPendingHotplugEvents) {
- const std::optional<DisplayIdentificationInfo> info =
+ std::optional<DisplayIdentificationInfo> info =
getHwComposer().onHotplug(event.hwcDisplayId, event.connection);
if (!info) {
@@ -2335,9 +2347,9 @@
state.physical = {.id = displayId,
.type = getHwComposer().getDisplayConnectionType(displayId),
.hwcDisplayId = event.hwcDisplayId,
- .deviceProductInfo = info->deviceProductInfo};
+ .deviceProductInfo = std::move(info->deviceProductInfo)};
state.isSecure = true; // All physical displays are currently considered secure.
- state.displayName = info->name;
+ state.displayName = std::move(info->name);
sp<IBinder> token = new BBinder();
mCurrentState.displays.add(token, state);
@@ -2349,7 +2361,10 @@
const auto token = it->second;
auto& state = mCurrentState.displays.editValueFor(token);
- state.sequenceId = DisplayDeviceState{}.sequenceId;
+ state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId
+ if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) {
+ state.physical->deviceProductInfo = std::move(info->deviceProductInfo);
+ }
}
} else {
ALOGV("Removing display %s", to_string(displayId).c_str());
@@ -3669,6 +3684,9 @@
if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur) {
if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
}
+ if (what & layer_state_t::eBlurRegionsChanged) {
+ if (layer->setBlurRegions(s.blurRegions)) 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,
@@ -3703,11 +3721,6 @@
if (what & layer_state_t::eDetachChildren) {
layer->detachChildren();
}
- if (what & layer_state_t::eOverrideScalingModeChanged) {
- layer->setOverrideScalingMode(s.overrideScalingMode);
- // We don't trigger a traversal here because if no other state is
- // changed, we don't want this to cause any more work
- }
if (what & layer_state_t::eTransformChanged) {
if (layer->setTransform(s.transform)) flags |= eTraversalNeeded;
}
@@ -3772,6 +3785,13 @@
flags |= eTraversalNeeded;
}
}
+ if (what & layer_state_t::eFrameTimelineVsyncChanged) {
+ layer->setFrameTimelineVsyncForTransaction(s.frameTimelineVsyncId, postTime);
+ } else {
+ // TODO (b/171252403) We are calling this too much, potentially triggering
+ // unnecessary work
+ layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime);
+ }
if (what & layer_state_t::eFixedTransformHintChanged) {
if (layer->setFixedTransformHint(s.fixedTransformHint)) {
flags |= eTraversalNeeded | eTransformHintUpdateNeeded;
@@ -3831,8 +3851,6 @@
}
}
- layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime);
-
if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
// Do not put anything that updates layer state or modifies flags after
// setTransactionCompletedListener
@@ -4274,7 +4292,7 @@
status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) {
if (asProto && mTracing.isEnabled()) {
- mTracing.writeToFileAsync();
+ mTracing.writeToFile();
}
return doDump(fd, DumpArgs(), asProto);
@@ -4358,21 +4376,14 @@
dispSyncPresentTimeOffset, getVsyncPeriodFromHWC());
scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy();
- StringAppendF(&result,
- "DesiredDisplayConfigSpecs (DisplayManager): default config ID: %d"
- ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
- policy.defaultConfig.value(), policy.primaryRange.min, policy.primaryRange.max,
- policy.appRequestRange.min, policy.appRequestRange.max);
+ StringAppendF(&result, "DesiredDisplayConfigSpecs (DisplayManager): %s\n\n",
+ policy.toString().c_str());
StringAppendF(&result, "(config override by backdoor: %s)\n\n",
mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
if (currentPolicy != policy) {
- StringAppendF(&result,
- "DesiredDisplayConfigSpecs (Override): default config ID: %d"
- ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
- currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
- currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
- currentPolicy.appRequestRange.max);
+ StringAppendF(&result, "DesiredDisplayConfigSpecs (Override): %s\n\n",
+ currentPolicy.toString().c_str());
}
mScheduler->dump(mAppConnectionHandle, result);
@@ -5098,19 +5109,19 @@
}
case 1025: { // Set layer tracing
n = data.readInt32();
+ bool tracingEnabledChanged;
if (n) {
ALOGD("LayerTracing enabled");
- mTracingEnabledChanged = mTracing.enable();
- reply->writeInt32(NO_ERROR);
+ tracingEnabledChanged = mTracing.enable();
+ if (tracingEnabledChanged) {
+ schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait();
+ }
} else {
ALOGD("LayerTracing disabled");
- mTracingEnabledChanged = mTracing.disable();
- if (mTracingEnabledChanged) {
- reply->writeInt32(mTracing.writeToFile());
- } else {
- reply->writeInt32(NO_ERROR);
- }
+ tracingEnabledChanged = mTracing.disable();
}
+ mTracingEnabledChanged = tracingEnabledChanged;
+ reply->writeInt32(NO_ERROR);
return NO_ERROR;
}
case 1026: { // Get layer tracing status
@@ -5383,6 +5394,45 @@
return PERMISSION_DENIED;
}
+status_t SurfaceFlinger::setSchedFifo(bool enabled) {
+ static constexpr int kFifoPriority = 2;
+ static constexpr int kOtherPriority = 0;
+
+ struct sched_param param = {0};
+ int sched_policy;
+ if (enabled) {
+ sched_policy = SCHED_FIFO;
+ param.sched_priority = kFifoPriority;
+ } else {
+ sched_policy = SCHED_OTHER;
+ param.sched_priority = kOtherPriority;
+ }
+
+ if (sched_setscheduler(0, sched_policy, ¶m) != 0) {
+ return -errno;
+ }
+ return NO_ERROR;
+}
+
+sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) {
+ if (const sp<IBinder> displayToken =
+ getPhysicalDisplayTokenLocked(PhysicalDisplayId{displayOrLayerStack})) {
+ return getDisplayDeviceLocked(displayToken);
+ }
+ // Couldn't find display by displayId. Try to get display by layerStack since virtual displays
+ // may not have a displayId.
+ return getDisplayByLayerStack(displayOrLayerStack);
+}
+
+sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) {
+ for (const auto& [token, display] : mDisplays) {
+ if (display->getLayerStack() == layerStack) {
+ return display;
+ }
+ }
+ return nullptr;
+}
+
status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
@@ -5431,46 +5481,7 @@
};
return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
- args.pixelFormat, captureListener);
-}
-
-status_t SurfaceFlinger::setSchedFifo(bool enabled) {
- static constexpr int kFifoPriority = 2;
- static constexpr int kOtherPriority = 0;
-
- struct sched_param param = {0};
- int sched_policy;
- if (enabled) {
- sched_policy = SCHED_FIFO;
- param.sched_priority = kFifoPriority;
- } else {
- sched_policy = SCHED_OTHER;
- param.sched_priority = kOtherPriority;
- }
-
- if (sched_setscheduler(0, sched_policy, ¶m) != 0) {
- return -errno;
- }
- return NO_ERROR;
-}
-
-sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) {
- if (const sp<IBinder> displayToken =
- getPhysicalDisplayTokenLocked(PhysicalDisplayId{displayOrLayerStack})) {
- return getDisplayDeviceLocked(displayToken);
- }
- // Couldn't find display by displayId. Try to get display by layerStack since virtual displays
- // may not have a displayId.
- return getDisplayByLayerStack(displayOrLayerStack);
-}
-
-sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) {
- for (const auto& [token, display] : mDisplays) {
- if (display->getLayerStack() == layerStack) {
- return display;
- }
- }
- return nullptr;
+ args.pixelFormat, args.allowProtected, captureListener);
}
status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack,
@@ -5505,7 +5516,8 @@
};
return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
- ui::PixelFormat::RGBA_8888, captureListener);
+ ui::PixelFormat::RGBA_8888, false /* allowProtected */,
+ captureListener);
}
status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
@@ -5626,18 +5638,32 @@
};
return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
- args.pixelFormat, captureListener);
+ args.pixelFormat, args.allowProtected, captureListener);
}
status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
TraverseLayersFunction traverseLayers,
ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
+ const bool allowProtected,
const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
- // TODO(b/116112787) Make buffer usage a parameter.
- const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+ // Loop over all visible layers to see whether there's any protected layer. A protected layer is
+ // typically a layer with DRM contents, or have the GRALLOC_USAGE_PROTECTED set on the buffer.
+ // A protected layer has no implication on whether it's secure, which is explicitly set by
+ // application to avoid being screenshot or drawn via unsecure display.
+ const bool supportsProtected = getRenderEngine().supportsProtectedContent();
+ bool hasProtectedLayer = false;
+ if (allowProtected && supportsProtected) {
+ traverseLayers([&](Layer* layer) {
+ hasProtectedLayer = hasProtectedLayer || (layer->isVisible() && layer->isProtected());
+ });
+ }
+
+ const uint32_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE |
+ (hasProtectedLayer && allowProtected && supportsProtected
+ ? GRALLOC_USAGE_PROTECTED
+ : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
sp<GraphicBuffer> buffer =
getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
static_cast<android_pixel_format>(reqPixelFormat),
@@ -5648,7 +5674,7 @@
status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
TraverseLayersFunction traverseLayers,
- sp<GraphicBuffer>& buffer, bool regionSampling,
+ sp<GraphicBuffer>& buffer, const bool regionSampling,
const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
@@ -5706,6 +5732,8 @@
captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure());
});
+ const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
+
// We allow the system server to take screenshots of secure layers for
// use in situations like the Screen-rotation animation and place
// the impetus on WindowManager to not persist them.
@@ -5750,14 +5778,13 @@
std::vector<Layer*> renderedLayers;
Region clearRegion = Region::INVALID_REGION;
traverseLayers([&](Layer* layer) {
- const bool supportProtectedContent = false;
Region clip(renderArea.getBounds());
compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
clip,
layer->needsFilteringForScreenshots(display.get(), transform) ||
renderArea.needsFiltering(),
renderArea.isSecure(),
- supportProtectedContent,
+ useProtected,
clearRegion,
layerStackSpaceRect,
clientCompositionDisplay.outputDataspace,
@@ -5795,7 +5822,7 @@
// there is no need for synchronization with the GPU.
base::unique_fd bufferFence;
base::unique_fd drawFence;
- getRenderEngine().useProtectedContext(false);
+ getRenderEngine().useProtectedContext(useProtected);
getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
/*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
@@ -5807,6 +5834,8 @@
layer->onLayerDisplayed(releaseFence);
}
}
+ // Always switch back to unprotected context.
+ getRenderEngine().useProtectedContext(false);
return NO_ERROR;
}
@@ -5948,12 +5977,10 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig,
- float primaryRefreshRateMin,
- float primaryRefreshRateMax,
- float appRequestRefreshRateMin,
- float appRequestRefreshRateMax) {
+status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(
+ const sp<IBinder>& displayToken, int32_t defaultConfig, bool allowGroupSwitching,
+ float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
ATRACE_CALL();
if (!displayToken) {
@@ -5972,6 +5999,7 @@
} else {
using Policy = scheduler::RefreshRateConfigs::Policy;
const Policy policy{HwcConfigIndexType(defaultConfig),
+ allowGroupSwitching,
{primaryRefreshRateMin, primaryRefreshRateMax},
{appRequestRefreshRateMin, appRequestRefreshRateMax}};
constexpr bool kOverridePolicy = false;
@@ -5983,12 +6011,10 @@
return future.get();
}
-status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultConfig,
- float* outPrimaryRefreshRateMin,
- float* outPrimaryRefreshRateMax,
- float* outAppRequestRefreshRateMin,
- float* outAppRequestRefreshRateMax) {
+status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(
+ const sp<IBinder>& displayToken, int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
+ float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
ATRACE_CALL();
if (!displayToken || !outDefaultConfig || !outPrimaryRefreshRateMin ||
@@ -6006,6 +6032,7 @@
scheduler::RefreshRateConfigs::Policy policy =
mRefreshRateConfigs->getDisplayManagerPolicy();
*outDefaultConfig = policy.defaultConfig.value();
+ *outAllowGroupSwitching = policy.allowGroupSwitching;
*outPrimaryRefreshRateMin = policy.primaryRange.min;
*outPrimaryRefreshRateMax = policy.primaryRange.max;
*outAppRequestRefreshRateMin = policy.appRequestRange.min;
@@ -6016,6 +6043,7 @@
} else {
const auto displayId = display->getPhysicalId();
*outDefaultConfig = getHwComposer().getActiveConfigIndex(displayId);
+ *outAllowGroupSwitching = false;
auto vsyncPeriod = getHwComposer().getActiveConfig(displayId)->getVsyncPeriod();
*outPrimaryRefreshRateMin = 1e9f / vsyncPeriod;
*outPrimaryRefreshRateMax = 1e9f / vsyncPeriod;
@@ -6146,8 +6174,8 @@
// This is a little racy, but not in a way that hurts anything. As we grab the
// defaultConfig from the display manager policy, we could be setting a new display
// manager policy, leaving us using a stale defaultConfig. The defaultConfig doesn't
- // matter for the override policy though, since we set allowGroupSwitching to true, so
- // it's not a problem.
+ // matter for the override policy though, since we set allowGroupSwitching to
+ // true, so it's not a problem.
scheduler::RefreshRateConfigs::Policy overridePolicy;
overridePolicy.defaultConfig =
mRefreshRateConfigs->getDisplayManagerPolicy().defaultConfig;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f55dd90..a821d44 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -583,11 +583,12 @@
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, int32_t displayModeId,
- float primaryRefreshRateMin, float primaryRefreshRateMax,
+ bool allowGroupSwitching, float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
float appRequestRefreshRateMin,
float appRequestRefreshRateMax) override;
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultConfig,
+ int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
float* outPrimaryRefreshRateMin,
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
@@ -797,13 +798,14 @@
// Boot animation, on/off animations and screen capture
void startBootAnim();
+ status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
+ ui::PixelFormat, const bool allowProtected,
+ const sp<IScreenCaptureListener>&);
+ status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&,
+ bool regionSampling, const sp<IScreenCaptureListener>&);
status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
const sp<GraphicBuffer>&, bool forSystem, int* outSyncFd,
bool regionSampling, ScreenCaptureResults&);
- status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
- ui::PixelFormat, const sp<IScreenCaptureListener>&);
- status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&,
- bool regionSampling, const sp<IScreenCaptureListener>&);
sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock);
@@ -1133,7 +1135,7 @@
SurfaceTracing mTracing{*this};
std::mutex mTracingLock;
bool mTracingEnabled = false;
- bool mAddCompositionStateToTrace = false;
+ bool mTracePostComposition = false;
std::atomic<bool> mTracingEnabledChanged = false;
const std::shared_ptr<TimeStats> mTimeStats;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 9d78702..97725ec 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -371,5 +371,10 @@
return primaries;
}
+bool update_device_product_info_on_hotplug_reconnect(bool defaultValue) {
+ return SurfaceFlingerProperties::update_device_product_info_on_hotplug_reconnect().value_or(
+ defaultValue);
+}
+
} // namespace sysprop
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index c63adfe..37a6b40 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -95,6 +95,9 @@
int32_t display_update_imminent_timeout_ms(int32_t defaultValue);
android::ui::DisplayPrimaries getDisplayNativePrimaries();
+
+bool update_device_product_info_on_hotplug_reconnect(bool defaultValue);
+
} // namespace sysprop
} // namespace android
#endif // SURFACEFLINGERPROPERTIES_H_
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index da58d4e..3548923 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -140,12 +140,12 @@
addCropLocked(transaction, layerId, layer->mCurrentState.crop_legacy);
addCornerRadiusLocked(transaction, layerId, layer->mCurrentState.cornerRadius);
addBackgroundBlurRadiusLocked(transaction, layerId, layer->mCurrentState.backgroundBlurRadius);
+ addBlurRegionsLocked(transaction, layerId, layer->mCurrentState.blurRegions);
if (layer->mCurrentState.barrierLayer_legacy != nullptr) {
addDeferTransactionLocked(transaction, layerId,
layer->mCurrentState.barrierLayer_legacy.promote(),
layer->mCurrentState.barrierFrameNumber);
}
- addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode());
addFlagsLocked(transaction, layerId, layer->mCurrentState.flags,
layer_state_t::eLayerHidden | layer_state_t::eLayerOpaque |
layer_state_t::eLayerSecure);
@@ -362,6 +362,25 @@
blurRadiusChange->set_background_blur_radius(backgroundBlurRadius);
}
+void SurfaceInterceptor::addBlurRegionsLocked(Transaction* transaction, int32_t layerId,
+ const std::vector<BlurRegion>& blurRegions) {
+ SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
+ BlurRegionsChange* blurRegionsChange(change->mutable_blur_regions());
+ for (const auto blurRegion : blurRegions) {
+ const auto blurRegionChange = blurRegionsChange->add_blur_regions();
+ blurRegionChange->set_blur_radius(blurRegion.blurRadius);
+ blurRegionChange->set_corner_radius_tl(blurRegion.cornerRadiusTL);
+ blurRegionChange->set_corner_radius_tr(blurRegion.cornerRadiusTR);
+ blurRegionChange->set_corner_radius_bl(blurRegion.cornerRadiusBL);
+ blurRegionChange->set_corner_radius_br(blurRegion.cornerRadiusBR);
+ blurRegionChange->set_alpha(blurRegion.alpha);
+ blurRegionChange->set_left(blurRegion.left);
+ blurRegionChange->set_top(blurRegion.top);
+ blurRegionChange->set_right(blurRegion.right);
+ blurRegionChange->set_bottom(blurRegion.bottom);
+ }
+}
+
void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber)
{
@@ -376,14 +395,6 @@
deferTransaction->set_frame_number(frameNumber);
}
-void SurfaceInterceptor::addOverrideScalingModeLocked(Transaction* transaction,
- int32_t layerId, int32_t overrideScalingMode)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- OverrideScalingModeChange* overrideChange(change->mutable_override_scaling_mode());
- overrideChange->set_override_scaling_mode(overrideScalingMode);
-}
-
void SurfaceInterceptor::addReparentLocked(Transaction* transaction, int32_t layerId,
int32_t parentId) {
SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
@@ -465,6 +476,9 @@
if (state.what & layer_state_t::eBackgroundBlurRadiusChanged) {
addBackgroundBlurRadiusLocked(transaction, layerId, state.backgroundBlurRadius);
}
+ if (state.what & layer_state_t::eBlurRegionsChanged) {
+ addBlurRegionsLocked(transaction, layerId, state.blurRegions);
+ }
if (state.what & layer_state_t::eDeferTransaction_legacy) {
sp<Layer> otherLayer = nullptr;
if (state.barrierSurfaceControl_legacy != nullptr) {
@@ -474,9 +488,6 @@
}
addDeferTransactionLocked(transaction, layerId, otherLayer, state.barrierFrameNumber);
}
- if (state.what & layer_state_t::eOverrideScalingModeChanged) {
- addOverrideScalingModeLocked(transaction, layerId, state.overrideScalingMode);
- }
if (state.what & layer_state_t::eReparent) {
auto parentHandle = (state.parentSurfaceControlForChild)
? state.parentSurfaceControlForChild->getHandle()
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 9ac189a..3df79c6 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -165,10 +165,10 @@
void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius);
void addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId,
int32_t backgroundBlurRadius);
+ void addBlurRegionsLocked(Transaction* transaction, int32_t layerId,
+ const std::vector<BlurRegion>& effectRegions);
void addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
const sp<const Layer>& layer, uint64_t frameNumber);
- void addOverrideScalingModeLocked(Transaction* transaction, int32_t layerId,
- int32_t overrideScalingMode);
void addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state);
void addTransactionLocked(Increment* increment, const Vector<ComposerState>& stateUpdates,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index d84ce69..1d1f0c5 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -14,9 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
#undef LOG_TAG
#define LOG_TAG "SurfaceTracing"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -32,65 +29,65 @@
namespace android {
-SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger)
- : mFlinger(flinger), mSfLock(flinger.mTracingLock) {}
+SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {}
-void SurfaceTracing::mainLoop() {
- bool enabled = addFirstEntry();
- while (enabled) {
- LayersTraceProto entry = traceWhenNotified();
- enabled = addTraceToBuffer(entry);
- }
-}
-
-bool SurfaceTracing::addFirstEntry() {
- LayersTraceProto entry;
- {
- std::scoped_lock lock(mSfLock);
- entry = traceLayersLocked("tracing.enable");
- }
- return addTraceToBuffer(entry);
-}
-
-LayersTraceProto SurfaceTracing::traceWhenNotified() {
- std::unique_lock<std::mutex> lock(mSfLock);
- mCanStartTrace.wait(lock);
- android::base::ScopedLockAssertion assumeLock(mSfLock);
- LayersTraceProto entry = traceLayersLocked(mWhere);
- mTracingInProgress = false;
- mMissedTraceEntries = 0;
- lock.unlock();
- return entry;
-}
-
-bool SurfaceTracing::addTraceToBuffer(LayersTraceProto& entry) {
+bool SurfaceTracing::enable() {
std::scoped_lock lock(mTraceLock);
- mBuffer.emplace(std::move(entry));
- if (mWriteToFile) {
- writeProtoFileLocked();
- mWriteToFile = false;
+ if (mEnabled) {
+ return false;
}
+
+ if (flagIsSet(TRACE_SYNC)) {
+ runner = std::make_unique<SurfaceTracing::Runner>(mFlinger, mConfig);
+ } else {
+ runner = std::make_unique<SurfaceTracing::AsyncRunner>(mFlinger, mConfig,
+ mFlinger.mTracingLock);
+ }
+ mEnabled = true;
+ return true;
+}
+
+bool SurfaceTracing::disable() {
+ std::scoped_lock lock(mTraceLock);
+ if (!mEnabled) {
+ return false;
+ }
+ mEnabled = false;
+ runner->stop();
+ return true;
+}
+
+bool SurfaceTracing::isEnabled() const {
+ std::scoped_lock lock(mTraceLock);
return mEnabled;
}
+status_t SurfaceTracing::writeToFile() {
+ std::scoped_lock lock(mTraceLock);
+ if (!mEnabled) {
+ return STATUS_OK;
+ }
+ return runner->writeToFile();
+}
+
void SurfaceTracing::notify(const char* where) {
- std::scoped_lock lock(mSfLock);
- notifyLocked(where);
+ if (mEnabled) {
+ runner->notify(where);
+ }
}
void SurfaceTracing::notifyLocked(const char* where) {
- mWhere = where;
- if (mTracingInProgress) {
- mMissedTraceEntries++;
+ if (mEnabled) {
+ runner->notifyLocked(where);
}
- mTracingInProgress = true;
- mCanStartTrace.notify_one();
}
-void SurfaceTracing::writeToFileAsync() {
+void SurfaceTracing::dump(std::string& result) const {
std::scoped_lock lock(mTraceLock);
- mWriteToFile = true;
- mCanStartTrace.notify_one();
+ base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
+ if (mEnabled) {
+ runner->dump(result);
+ }
}
void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
@@ -101,12 +98,12 @@
}
void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
- auto protoSize = proto.ByteSize();
+ size_t protoSize = static_cast<size_t>(proto.ByteSize());
while (mUsedInBytes + protoSize > mSizeInBytes) {
if (mStorage.empty()) {
return;
}
- mUsedInBytes -= mStorage.front().ByteSize();
+ mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize());
mStorage.pop();
}
mUsedInBytes += protoSize;
@@ -115,7 +112,7 @@
}
void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
- fileProto->mutable_entry()->Reserve(mStorage.size());
+ fileProto->mutable_entry()->Reserve(static_cast<int>(mStorage.size()));
while (!mStorage.empty()) {
auto entry = fileProto->add_entry();
@@ -124,85 +121,21 @@
}
}
-bool SurfaceTracing::enable() {
- std::scoped_lock lock(mTraceLock);
-
- if (mEnabled) {
- return false;
- }
-
- mBuffer.reset(mBufferSize);
- mEnabled = true;
- mThread = std::thread(&SurfaceTracing::mainLoop, this);
- return true;
+SurfaceTracing::Runner::Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config)
+ : mFlinger(flinger), mConfig(config) {
+ mBuffer.setSize(mConfig.bufferSize);
}
-status_t SurfaceTracing::writeToFile() {
- std::thread thread;
- {
- std::scoped_lock lock(mTraceLock);
- thread = std::move(mThread);
- }
- thread.join();
- return mLastErr;
+void SurfaceTracing::Runner::notify(const char* where) {
+ LayersTraceProto entry = traceLayers(where);
+ mBuffer.emplace(std::move(entry));
}
-bool SurfaceTracing::disable() {
- std::scoped_lock lock(mTraceLock);
-
- if (!mEnabled) {
- return false;
- }
-
- mEnabled = false;
- mWriteToFile = true;
- mCanStartTrace.notify_all();
- return true;
+status_t SurfaceTracing::Runner::stop() {
+ return writeToFile();
}
-bool SurfaceTracing::isEnabled() const {
- std::scoped_lock lock(mTraceLock);
- return mEnabled;
-}
-
-void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
- std::scoped_lock lock(mTraceLock);
- mBufferSize = bufferSizeInByte;
- mBuffer.setSize(bufferSizeInByte);
-}
-
-void SurfaceTracing::setTraceFlags(uint32_t flags) {
- std::scoped_lock lock(mSfLock);
- mTraceFlags = flags;
-}
-
-LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
- ATRACE_CALL();
-
- LayersTraceProto entry;
- entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
- entry.set_where(where);
- LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
-
- if (flagIsSetLocked(SurfaceTracing::TRACE_EXTRA)) {
- mFlinger.dumpOffscreenLayersProto(layers);
- }
- entry.mutable_layers()->Swap(&layers);
-
- if (mTraceFlags & SurfaceTracing::TRACE_HWC) {
- std::string hwcDump;
- mFlinger.dumpHwc(hwcDump);
- entry.set_hwc_blob(hwcDump);
- }
- if (!flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION)) {
- entry.set_excludes_composition_state(true);
- }
- entry.set_missed_entries(mMissedTraceEntries);
-
- return entry;
-}
-
-void SurfaceTracing::writeProtoFileLocked() {
+status_t SurfaceTracing::Runner::writeToFile() {
ATRACE_CALL();
LayersTraceFileProto fileProto;
@@ -211,33 +144,114 @@
fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
mBuffer.flush(&fileProto);
- mBuffer.reset(mBufferSize);
+ mBuffer.reset(mConfig.bufferSize);
if (!fileProto.SerializeToString(&output)) {
ALOGE("Could not save the proto file! Permission denied");
- mLastErr = PERMISSION_DENIED;
+ return PERMISSION_DENIED;
}
// -rw-r--r--
const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
- if (!android::base::WriteStringToFile(output, kDefaultFileName, mode, getuid(), getgid(),
+ if (!android::base::WriteStringToFile(output, DEFAULT_FILE_NAME, mode, getuid(), getgid(),
true)) {
ALOGE("Could not save the proto file! There are missing fields");
- mLastErr = PERMISSION_DENIED;
+ return PERMISSION_DENIED;
}
- mLastErr = NO_ERROR;
+ return NO_ERROR;
}
-void SurfaceTracing::dump(std::string& result) const {
- std::scoped_lock lock(mTraceLock);
- base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
+LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) {
+ ATRACE_CALL();
+
+ LayersTraceProto entry;
+ entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
+ entry.set_where(where);
+ LayersProto layers(mFlinger.dumpDrawingStateProto(mConfig.flags));
+
+ if (flagIsSet(SurfaceTracing::TRACE_EXTRA)) {
+ mFlinger.dumpOffscreenLayersProto(layers);
+ }
+ entry.mutable_layers()->Swap(&layers);
+
+ if (flagIsSet(SurfaceTracing::TRACE_HWC)) {
+ std::string hwcDump;
+ mFlinger.dumpHwc(hwcDump);
+ entry.set_hwc_blob(hwcDump);
+ }
+ if (!flagIsSet(SurfaceTracing::TRACE_COMPOSITION)) {
+ entry.set_excludes_composition_state(true);
+ }
+ entry.set_missed_entries(mMissedTraceEntries);
+
+ return entry;
+}
+
+void SurfaceTracing::Runner::dump(std::string& result) const {
base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n",
mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
float(mBuffer.size()) / float(1_MB));
}
-} // namespace android
+SurfaceTracing::AsyncRunner::AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config,
+ std::mutex& sfLock)
+ : SurfaceTracing::Runner(flinger, config), mSfLock(sfLock) {
+ mEnabled = true;
+ mThread = std::thread(&AsyncRunner::loop, this);
+}
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+void SurfaceTracing::AsyncRunner::loop() {
+ while (mEnabled) {
+ LayersTraceProto entry;
+ bool entryAdded = traceWhenNotified(&entry);
+ if (entryAdded) {
+ mBuffer.emplace(std::move(entry));
+ }
+ if (mWriteToFile) {
+ Runner::writeToFile();
+ mWriteToFile = false;
+ }
+ }
+}
+
+bool SurfaceTracing::AsyncRunner::traceWhenNotified(LayersTraceProto* outProto) {
+ std::unique_lock<std::mutex> lock(mSfLock);
+ mCanStartTrace.wait(lock);
+ if (!mAddEntry) {
+ return false;
+ }
+ *outProto = traceLayers(mWhere);
+ mAddEntry = false;
+ mMissedTraceEntries = 0;
+ return true;
+}
+
+void SurfaceTracing::AsyncRunner::notify(const char* where) {
+ std::scoped_lock lock(mSfLock);
+ notifyLocked(where);
+}
+
+void SurfaceTracing::AsyncRunner::notifyLocked(const char* where) {
+ mWhere = where;
+ if (mAddEntry) {
+ mMissedTraceEntries++;
+ }
+ mAddEntry = true;
+ mCanStartTrace.notify_one();
+}
+
+status_t SurfaceTracing::AsyncRunner::writeToFile() {
+ mWriteToFile = true;
+ mCanStartTrace.notify_one();
+ return STATUS_OK;
+}
+
+status_t SurfaceTracing::AsyncRunner::stop() {
+ mEnabled = false;
+ mCanStartTrace.notify_one();
+ mThread.join();
+ return Runner::writeToFile();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index f208eb8..576bba7 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -32,25 +32,31 @@
namespace android {
class SurfaceFlinger;
-
constexpr auto operator""_MB(unsigned long long const num) {
return num * 1024 * 1024;
}
/*
- * SurfaceTracing records layer states during surface flinging.
+ * SurfaceTracing records layer states during surface flinging. Manages tracing state and
+ * configuration.
*/
class SurfaceTracing {
public:
- explicit SurfaceTracing(SurfaceFlinger& flinger);
+ SurfaceTracing(SurfaceFlinger& flinger);
bool enable();
bool disable();
status_t writeToFile();
bool isEnabled() const;
+ /*
+ * Adds a trace entry, must be called from the drawing thread or while holding the
+ * SurfaceFlinger tracing lock.
+ */
void notify(const char* where);
- void notifyLocked(const char* where) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */;
+ /*
+ * Adds a trace entry, called while holding the SurfaceFlinger tracing lock.
+ */
+ void notifyLocked(const char* where) /* REQUIRES(mSfLock) */;
- void setBufferSize(size_t bufferSizeInByte);
- void writeToFileAsync();
+ void setBufferSize(size_t bufferSizeInBytes) { mConfig.bufferSize = bufferSizeInBytes; }
void dump(std::string& result) const;
enum : uint32_t {
@@ -59,18 +65,34 @@
TRACE_COMPOSITION = 1 << 2,
TRACE_EXTRA = 1 << 3,
TRACE_HWC = 1 << 4,
- TRACE_ALL = 0xffffffff
+ // Add non-geometry composition changes to the trace.
+ TRACE_BUFFERS = 1 << 5,
+ // Add entries from the drawing thread post composition.
+ TRACE_SYNC = 1 << 6,
+ TRACE_ALL = TRACE_CRITICAL | TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA,
};
- void setTraceFlags(uint32_t flags);
- bool flagIsSetLocked(uint32_t flags) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */ {
- return (mTraceFlags & flags) == flags;
- }
+ void setTraceFlags(uint32_t flags) { mConfig.flags = flags; }
+ bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; }
private:
- static constexpr auto kDefaultBufferCapInByte = 5_MB;
- static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb";
+ class Runner;
+ static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB;
+ static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.pb";
- class LayersTraceBuffer { // ring buffer
+ SurfaceFlinger& mFlinger;
+ mutable std::mutex mTraceLock;
+ bool mEnabled = false;
+ std::unique_ptr<Runner> runner;
+
+ struct Config {
+ uint32_t flags = TRACE_CRITICAL | TRACE_INPUT;
+ size_t bufferSize = DEFAULT_BUFFER_SIZE;
+ } mConfig;
+
+ /*
+ * ring buffer.
+ */
+ class LayersTraceBuffer {
public:
size_t size() const { return mSizeInBytes; }
size_t used() const { return mUsedInBytes; }
@@ -83,35 +105,59 @@
private:
size_t mUsedInBytes = 0U;
- size_t mSizeInBytes = 0U;
+ size_t mSizeInBytes = DEFAULT_BUFFER_SIZE;
std::queue<LayersTraceProto> mStorage;
};
- void mainLoop();
- bool addFirstEntry();
- LayersTraceProto traceWhenNotified();
- LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock);
+ /*
+ * Implements a synchronous way of adding trace entries. This must be called
+ * from the drawing thread.
+ */
+ class Runner {
+ public:
+ Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config);
+ virtual ~Runner() = default;
+ virtual status_t stop();
+ virtual status_t writeToFile();
+ virtual void notify(const char* where);
+ /* Cannot be called with a synchronous runner. */
+ virtual void notifyLocked(const char* /* where */) {}
+ void dump(std::string& result) const;
- // Returns true if trace is enabled.
- bool addTraceToBuffer(LayersTraceProto& entry);
- void writeProtoFileLocked() REQUIRES(mTraceLock);
+ protected:
+ bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; }
+ SurfaceFlinger& mFlinger;
+ SurfaceTracing::Config mConfig;
+ SurfaceTracing::LayersTraceBuffer mBuffer;
+ uint32_t mMissedTraceEntries = 0;
+ LayersTraceProto traceLayers(const char* where);
+ };
- SurfaceFlinger& mFlinger;
- status_t mLastErr = NO_ERROR;
- std::thread mThread;
- std::condition_variable mCanStartTrace;
+ /*
+ * Implements asynchronous way to add trace entries called from a separate thread while holding
+ * the SurfaceFlinger tracing lock. Trace entries may be missed if the tracing thread is not
+ * scheduled in time.
+ */
+ class AsyncRunner : public Runner {
+ public:
+ AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock);
+ virtual ~AsyncRunner() = default;
+ status_t stop() override;
+ status_t writeToFile() override;
+ void notify(const char* where) override;
+ void notifyLocked(const char* where);
- std::mutex& mSfLock;
- uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_CRITICAL | TRACE_INPUT;
- const char* mWhere GUARDED_BY(mSfLock) = "";
- uint32_t mMissedTraceEntries GUARDED_BY(mSfLock) = 0;
- bool mTracingInProgress GUARDED_BY(mSfLock) = false;
-
- mutable std::mutex mTraceLock;
- LayersTraceBuffer mBuffer GUARDED_BY(mTraceLock);
- size_t mBufferSize GUARDED_BY(mTraceLock) = kDefaultBufferCapInByte;
- bool mEnabled GUARDED_BY(mTraceLock) = false;
- bool mWriteToFile GUARDED_BY(mTraceLock) = false;
+ private:
+ std::mutex& mSfLock;
+ std::condition_variable mCanStartTrace;
+ std::thread mThread;
+ const char* mWhere = "";
+ bool mWriteToFile = false;
+ bool mEnabled = false;
+ bool mAddEntry = false;
+ void loop();
+ bool traceWhenNotified(LayersTraceProto* outProto);
+ };
};
} // namespace android
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index f3f5626..9f25674 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -125,6 +125,9 @@
int32 background_blur_radius = 52;
uint32 owner_uid = 53;
+
+ // Regions of a layer, where blur should be applied.
+ repeated BlurRegion blur_regions = 54;
}
message PositionProto {
@@ -211,3 +214,16 @@
// This will be a 4x4 matrix of float values
repeated float val = 1;
}
+
+message BlurRegion {
+ uint32 blur_radius = 1;
+ uint32 corner_radius_tl = 2;
+ uint32 corner_radius_tr = 3;
+ uint32 corner_radius_bl = 4;
+ float corner_radius_br = 5;
+ float alpha = 6;
+ int32 left = 7;
+ int32 top = 8;
+ int32 right = 9;
+ int32 bottom = 10;
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
index acf621e..990f3cf 100644
--- a/services/surfaceflinger/layerproto/layerstrace.proto
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -42,7 +42,7 @@
/* one window manager trace entry. */
message LayersTraceProto {
/* required: elapsed realtime in nanos since boot of when this entry was logged */
- optional fixed64 elapsed_realtime_nanos = 1;
+ optional sfixed64 elapsed_realtime_nanos = 1;
/* where the trace originated */
optional string where = 2;
@@ -56,5 +56,5 @@
optional bool excludes_composition_state = 5;
/* Number of missed entries since the last entry was recorded. */
- optional int32 missed_entries = 6;
+ optional uint32 missed_entries = 6;
}
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 7666f7f..421484f 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -435,3 +435,13 @@
access: Readonly
prop_name: "ro.surface_flinger.display_update_imminent_timeout_ms"
}
+
+
+# Updates the DeviceProductInfo when a hoplug reconnect event is processed
+prop {
+ api_name: "update_device_product_info_on_hotplug_reconnect"
+ type: Boolean
+ scope: Public
+ access: Readonly
+ prop_name: "ro.surface_flinger.update_device_product_info_on_hotplug_reconnect"
+}
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index ba60a7d..da66ece 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -124,6 +124,10 @@
prop_name: "ro.surface_flinger.supports_background_blur"
}
prop {
+ api_name: "update_device_product_info_on_hotplug_reconnect"
+ prop_name: "ro.surface_flinger.update_device_product_info_on_hotplug_reconnect"
+ }
+ prop {
api_name: "use_color_management"
prop_name: "ro.surface_flinger.use_color_management"
}
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index db5d820..02b4308 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -50,7 +50,7 @@
"android.hardware.graphics.composer@2.1",
],
shared_libs: [
- "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common-unstable-ndk_platform",
"android.hardware.graphics.common@1.2",
"libandroid",
"libbase",
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 7f541e2..9302463 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -218,18 +218,21 @@
TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
int32_t defaultConfig;
+ bool allowGroupSwitching;
float primaryFpsMin;
float primaryFpsMax;
float appRequestFpsMin;
float appRequestFpsMax;
status_t res =
SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
+ &allowGroupSwitching,
&primaryFpsMin, &primaryFpsMax,
&appRequestFpsMin,
&appRequestFpsMax);
ASSERT_EQ(res, NO_ERROR);
std::function<status_t()> condition = [=]() {
return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig,
+ allowGroupSwitching,
primaryFpsMin, primaryFpsMax,
appRequestFpsMin,
appRequestFpsMax);
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index debfe83..3a8b40f 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -14,16 +14,18 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
+#include <gtest/gtest.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <ui/DisplayConfig.h>
+#include <utils/Errors.h>
+#include <utils/Vector.h>
-#include <thread>
-#include "LayerTransactionTest.h"
+#include "utils/TransactionUtils.h"
+
namespace android {
-using android::hardware::graphics::common::V1_1::BufferUsage;
-
::testing::Environment* const binderEnv =
::testing::AddGlobalTestEnvironment(new BinderEnvironment());
@@ -31,32 +33,54 @@
* Test class for setting display configs and passing around refresh rate ranges.
*/
class RefreshRateRangeTest : public ::testing::Test {
+private:
+ int32_t initialDefaultConfig;
+ bool initialAllowGroupSwitching;
+ float initialPrimaryMin;
+ float initialPrimaryMax;
+ float initialAppRequestMin;
+ float initialAppRequestMax;
+
protected:
- void SetUp() override { mDisplayToken = SurfaceComposerClient::getInternalDisplayToken(); }
+ void SetUp() override {
+ mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
+ status_t res =
+ SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
+ &initialDefaultConfig,
+ &initialAllowGroupSwitching,
+ &initialPrimaryMin,
+ &initialPrimaryMax,
+ &initialAppRequestMin,
+ &initialAppRequestMax);
+ ASSERT_EQ(res, NO_ERROR);
+ }
+
+ void TearDown() override {
+ status_t res =
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken,
+ initialDefaultConfig,
+ initialAllowGroupSwitching,
+ initialPrimaryMin,
+ initialPrimaryMax,
+ initialAppRequestMin,
+ initialAppRequestMax);
+ ASSERT_EQ(res, NO_ERROR);
+ }
+
+ void testSetAllowGroupSwitching(bool allowGroupSwitching);
sp<IBinder> mDisplayToken;
};
TEST_F(RefreshRateRangeTest, setAllConfigs) {
- int32_t initialDefaultConfig;
- float initialPrimaryMin;
- float initialPrimaryMax;
- float initialAppRequestMin;
- float initialAppRequestMax;
- status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
- &initialDefaultConfig,
- &initialPrimaryMin,
- &initialPrimaryMax,
- &initialAppRequestMin,
- &initialAppRequestMax);
- ASSERT_EQ(res, NO_ERROR);
-
Vector<DisplayConfig> configs;
- res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
+ status_t res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
ASSERT_EQ(res, NO_ERROR);
+ ASSERT_GT(configs.size(), 0);
for (size_t i = 0; i < configs.size(); i++) {
- res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i,
+ res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken,
+ static_cast<int32_t>(i), false,
configs[i].refreshRate,
configs[i].refreshRate,
configs[i].refreshRate,
@@ -64,31 +88,58 @@
ASSERT_EQ(res, NO_ERROR);
int defaultConfig;
+ bool allowGroupSwitching;
float primaryRefreshRateMin;
float primaryRefreshRateMax;
float appRequestRefreshRateMin;
float appRequestRefreshRateMax;
res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
+ &allowGroupSwitching,
&primaryRefreshRateMin,
&primaryRefreshRateMax,
&appRequestRefreshRateMin,
&appRequestRefreshRateMax);
ASSERT_EQ(res, NO_ERROR);
ASSERT_EQ(defaultConfig, i);
+ ASSERT_EQ(allowGroupSwitching, false);
ASSERT_EQ(primaryRefreshRateMin, configs[i].refreshRate);
ASSERT_EQ(primaryRefreshRateMax, configs[i].refreshRate);
ASSERT_EQ(appRequestRefreshRateMin, configs[i].refreshRate);
ASSERT_EQ(appRequestRefreshRateMax, configs[i].refreshRate);
}
+}
- res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
- initialPrimaryMin, initialPrimaryMax,
- initialAppRequestMin,
- initialAppRequestMax);
+void RefreshRateRangeTest::testSetAllowGroupSwitching(bool allowGroupSwitching) {
+ status_t res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 0,
+ allowGroupSwitching, 0.f,
+ 90.f, 0.f, 90.f);
ASSERT_EQ(res, NO_ERROR);
+ int defaultConfig;
+ bool newAllowGroupSwitching;
+ float primaryRefreshRateMin;
+ float primaryRefreshRateMax;
+ float appRequestRefreshRateMin;
+ float appRequestRefreshRateMax;
+
+ res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
+ &newAllowGroupSwitching,
+ &primaryRefreshRateMin,
+ &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax);
+ ASSERT_EQ(res, NO_ERROR);
+ ASSERT_EQ(defaultConfig, 0);
+ ASSERT_EQ(newAllowGroupSwitching, allowGroupSwitching);
+ ASSERT_EQ(primaryRefreshRateMin, 0.f);
+ ASSERT_EQ(primaryRefreshRateMax, 90.f);
+ ASSERT_EQ(appRequestRefreshRateMin, 0.f);
+ ASSERT_EQ(appRequestRefreshRateMax, 90.f);
+}
+
+TEST_F(RefreshRateRangeTest, setAllowGroupSwitching) {
+ testSetAllowGroupSwitching(true);
+ testSetAllowGroupSwitching(false);
+ testSetAllowGroupSwitching(true);
}
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp
index 3dca391..fafb49e 100644
--- a/services/surfaceflinger/tests/EffectLayer_test.cpp
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -51,7 +51,7 @@
sp<SurfaceControl> effectLayer =
mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect,
- mParentLayer.get());
+ mParentLayer->getHandle());
EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
asTransaction([&](Transaction& t) {
@@ -72,7 +72,7 @@
PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceEffect |
ISurfaceComposerClient::eNoColorFill,
- mParentLayer.get());
+ mParentLayer->getHandle());
EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
asTransaction([&](Transaction& t) {
@@ -93,7 +93,7 @@
PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceEffect |
ISurfaceComposerClient::eNoColorFill,
- mParentLayer.get());
+ mParentLayer->getHandle());
EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
asTransaction([&](Transaction& t) {
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index cfec0d2..152d2d2 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -56,7 +56,7 @@
auto notSc = makeNotSurfaceControl();
ASSERT_EQ(nullptr,
mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0,
- notSc.get())
+ notSc->getHandle())
.get());
}
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 4947289..52e1a4d 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -179,19 +179,6 @@
}
}
-TEST_P(LayerRenderTypeTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition
- Transaction()
- .setSize(layer, 64, 64)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .apply();
- getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
-}
-
TEST_P(LayerRenderTypeTransactionTest, CreateLayer_BufferState) {
uint32_t transformHint = ui::Transform::ROT_INVALID;
sp<SurfaceControl> layer;
@@ -950,40 +937,6 @@
}
}
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition
- Transaction()
- .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
- .setSize(layer, 64, 64)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .apply();
- getScreenCapture()->expectColor(Rect(0, 0, 128, 128), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE));
-
- // XXX SCALE_CROP is not respected; calling setSize and
- // setOverrideScalingMode in separate transactions does not work
- // (b/69315456)
- Transaction()
- .setSize(layer, 64, 16)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .apply();
- {
- SCOPED_TRACE("SCALE_TO_WINDOW");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE, true /* filtered */);
- }
-}
-
TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index d4e952a..da71dad 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -16,6 +16,10 @@
#pragma once
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <gtest/gtest.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
@@ -75,8 +79,9 @@
PixelFormat format, uint32_t flags,
SurfaceControl* parent = nullptr,
uint32_t* outTransformHint = nullptr) {
- auto layer = client->createSurface(String8(name), width, height, format, flags, parent,
- LayerMetadata(), outTransformHint);
+ sp<IBinder> parentHandle = (parent) ? parent->getHandle() : nullptr;
+ auto layer = client->createSurface(String8(name), width, height, format, flags,
+ parentHandle, LayerMetadata(), outTransformHint);
EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
return layer;
}
@@ -299,3 +304,6 @@
};
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index 38da0b1..29473f2 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -566,7 +566,10 @@
}
asTransaction([&](Transaction& t) {
- t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ mFGSurfaceControl->getSurface()->setScalingMode(
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // Resubmit buffer with new scaling mode
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
// We cause scaling by 2.
t.setSize(mFGSurfaceControl, 128, 128);
});
@@ -673,7 +676,10 @@
}
asTransaction([&](Transaction& t) {
- t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ mFGSurfaceControl->getSurface()->setScalingMode(
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // Resubmit buffer with new scaling mode
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
// Set a scaling by 2.
t.setSize(mFGSurfaceControl, 128, 128);
});
@@ -705,7 +711,10 @@
// Change the size of the foreground to 128 * 64 so we can test rotation as well.
asTransaction([&](Transaction& t) {
- t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ mFGSurfaceControl->getSurface()->setScalingMode(
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // Resubmit buffer with new scaling mode
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
t.setSize(mFGSurfaceControl, 128, 64);
});
sp<Surface> s = mFGSurfaceControl->getSurface();
@@ -1019,12 +1028,13 @@
TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) {
sp<SurfaceControl> boundlessLayer =
mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */, mFGSurfaceControl.get());
+ 0 /* flags */, mFGSurfaceControl->getHandle());
ASSERT_TRUE(boundlessLayer != nullptr);
ASSERT_TRUE(boundlessLayer->isValid());
sp<SurfaceControl> colorLayer =
mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayer.get());
+ ISurfaceComposerClient::eFXSurfaceEffect,
+ boundlessLayer->getHandle());
ASSERT_TRUE(colorLayer != nullptr);
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 104d919..81e648a 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -39,7 +39,6 @@
using Trace = surfaceflinger::Trace;
using Increment = surfaceflinger::Increment;
-constexpr int32_t SCALING_UPDATE = 1;
constexpr uint32_t BUFFER_UPDATES = 18;
constexpr uint32_t LAYER_UPDATE = INT_MAX - 2;
constexpr uint32_t SIZE_UPDATE = 134;
@@ -52,6 +51,7 @@
constexpr float POSITION_UPDATE = 121;
const Rect CROP_UPDATE(16, 16, 32, 32);
const float SHADOW_RADIUS_UPDATE = 35.0f;
+std::vector<BlurRegion> BLUR_REGIONS_UPDATE;
const String8 DISPLAY_NAME("SurfaceInterceptor Display Test");
constexpr auto TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface";
@@ -182,6 +182,7 @@
bool cornerRadiusUpdateFound(const SurfaceChange& change, bool foundCornerRadius);
bool backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
bool foundBackgroundBlurRadius);
+ bool blurRegionsUpdateFound(const SurfaceChange& change, bool foundBlurRegions);
bool matrixUpdateFound(const SurfaceChange& change, bool foundMatrix);
bool scalingModeUpdateFound(const SurfaceChange& change, bool foundScalingMode);
bool transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion);
@@ -220,8 +221,8 @@
void cropUpdate(Transaction&);
void cornerRadiusUpdate(Transaction&);
void backgroundBlurRadiusUpdate(Transaction&);
+ void blurRegionsUpdate(Transaction&);
void matrixUpdate(Transaction&);
- void overrideScalingModeUpdate(Transaction&);
void transparentRegionHintUpdate(Transaction&);
void layerStackUpdate(Transaction&);
void hiddenFlagUpdate(Transaction&);
@@ -359,6 +360,12 @@
t.setBackgroundBlurRadius(mBGSurfaceControl, BACKGROUND_BLUR_RADIUS_UPDATE);
}
+void SurfaceInterceptorTest::blurRegionsUpdate(Transaction& t) {
+ BLUR_REGIONS_UPDATE.empty();
+ BLUR_REGIONS_UPDATE.push_back(BlurRegion());
+ t.setBlurRegions(mBGSurfaceControl, BLUR_REGIONS_UPDATE);
+}
+
void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
}
@@ -371,10 +378,6 @@
t.setMatrix(mBGSurfaceControl, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2);
}
-void SurfaceInterceptorTest::overrideScalingModeUpdate(Transaction& t) {
- t.setOverrideScalingMode(mBGSurfaceControl, SCALING_UPDATE);
-}
-
void SurfaceInterceptorTest::transparentRegionHintUpdate(Transaction& t) {
Region region(CROP_UPDATE);
t.setTransparentRegionHint(mBGSurfaceControl, region);
@@ -436,10 +439,10 @@
runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
runInTransaction(&SurfaceInterceptorTest::cornerRadiusUpdate);
runInTransaction(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate);
+ runInTransaction(&SurfaceInterceptorTest::blurRegionsUpdate);
runInTransaction(&SurfaceInterceptorTest::layerUpdate);
runInTransaction(&SurfaceInterceptorTest::cropUpdate);
runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
- runInTransaction(&SurfaceInterceptorTest::overrideScalingModeUpdate);
runInTransaction(&SurfaceInterceptorTest::transparentRegionHintUpdate);
runInTransaction(&SurfaceInterceptorTest::layerStackUpdate);
runInTransaction(&SurfaceInterceptorTest::hiddenFlagUpdate);
@@ -525,6 +528,17 @@
return foundBackgroundBlur;
}
+bool SurfaceInterceptorTest::blurRegionsUpdateFound(const SurfaceChange& change,
+ bool foundBlurRegions) {
+ bool hasBlurRegions(change.blur_regions().blur_regions_size() == BLUR_REGIONS_UPDATE.size());
+ if (hasBlurRegions && !foundBlurRegions) {
+ foundBlurRegions = true;
+ } else if (hasBlurRegions && foundBlurRegions) {
+ []() { FAIL(); }();
+ }
+ return foundBlurRegions;
+}
+
bool SurfaceInterceptorTest::layerUpdateFound(const SurfaceChange& change, bool foundLayer) {
bool hasLayer(change.layer().layer() == LAYER_UPDATE);
if (hasLayer && !foundLayer) {
@@ -561,17 +575,6 @@
return foundMatrix;
}
-bool SurfaceInterceptorTest::scalingModeUpdateFound(const SurfaceChange& change,
- bool foundScalingMode) {
- bool hasScalingUpdate(change.override_scaling_mode().override_scaling_mode() == SCALING_UPDATE);
- if (hasScalingUpdate && !foundScalingMode) {
- foundScalingMode = true;
- } else if (hasScalingUpdate && foundScalingMode) {
- [] () { FAIL(); }();
- }
- return foundScalingMode;
-}
-
bool SurfaceInterceptorTest::transparentRegionHintUpdateFound(const SurfaceChange& change,
bool foundTransparentRegion) {
auto traceRegion = change.transparent_region_hint().region(0);
@@ -724,12 +727,12 @@
case SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius:
foundUpdate = backgroundBlurRadiusUpdateFound(change, foundUpdate);
break;
+ case SurfaceChange::SurfaceChangeCase::kBlurRegions:
+ foundUpdate = blurRegionsUpdateFound(change, foundUpdate);
+ break;
case SurfaceChange::SurfaceChangeCase::kMatrix:
foundUpdate = matrixUpdateFound(change, foundUpdate);
break;
- case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode:
- foundUpdate = scalingModeUpdateFound(change, foundUpdate);
- break;
case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint:
foundUpdate = transparentRegionHintUpdateFound(change, foundUpdate);
break;
@@ -780,7 +783,6 @@
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kLayer));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kCrop));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kMatrix));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOverrideScalingMode));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kTransparentRegionHint));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kLayerStack));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kHiddenFlag));
@@ -911,13 +913,13 @@
SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius);
}
-TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
+TEST_F(SurfaceInterceptorTest, InterceptBlurRegionsUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::blurRegionsUpdate,
+ SurfaceChange::SurfaceChangeCase::kBlurRegions);
}
-TEST_F(SurfaceInterceptorTest, InterceptOverrideScalingModeUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::overrideScalingModeUpdate,
- SurfaceChange::SurfaceChangeCase::kOverrideScalingMode);
+TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
}
TEST_F(SurfaceInterceptorTest, InterceptTransparentRegionHintUpdateWorks) {
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 2861013..8d094e4 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -8,6 +8,7 @@
"FakeComposerUtils.cpp",
"SFFakeHwc_test.cpp"
],
+ require_root: true,
shared_libs: [
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 07c558f..0a70f5c 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -447,7 +447,7 @@
const auto& config = configs[i];
if (config.resolution.getWidth() == 800) {
EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
config.refreshRate,
config.refreshRate,
config.refreshRate,
@@ -553,7 +553,7 @@
const auto& config = configs[i];
if (config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
config.refreshRate,
config.refreshRate,
config.refreshRate,
@@ -670,7 +670,8 @@
if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::
- setDesiredDisplayConfigSpecs(display, i, configs[i].refreshRate,
+ setDesiredDisplayConfigSpecs(display, i, false,
+ configs[i].refreshRate,
configs[i].refreshRate,
configs[i].refreshRate,
configs[i].refreshRate));
@@ -716,7 +717,7 @@
const auto& config = configs[i];
if (config.refreshRate == 1e9f / 8'333'333) {
EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
config.refreshRate,
config.refreshRate,
config.refreshRate,
@@ -763,7 +764,7 @@
const auto& config = configs[i];
if (config.resolution.getWidth() == 1600 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
config.refreshRate,
config.refreshRate,
config.refreshRate,
@@ -1469,7 +1470,7 @@
Base::SetUp();
mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10,
PIXEL_FORMAT_RGBA_8888, 0,
- Base::mFGSurfaceControl.get());
+ Base::mFGSurfaceControl->getHandle());
fillSurfaceRGBA8(mChild, LIGHT_GRAY);
Base::sFakeComposer->runVSyncAndWait();
@@ -1653,7 +1654,7 @@
sp<SurfaceControl> childNewClient =
newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
PIXEL_FORMAT_RGBA_8888, 0,
- Base::mFGSurfaceControl.get());
+ Base::mFGSurfaceControl->getHandle());
ASSERT_TRUE(childNewClient != nullptr);
ASSERT_TRUE(childNewClient->isValid());
fillSurfaceRGBA8(childNewClient, LIGHT_GRAY);
@@ -1691,30 +1692,6 @@
EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
}
- void Test_InheritNonTransformScalingFromParent() {
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(Base::mFGSurfaceControl, 0, 0);
- }
-
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setOverrideScalingMode(Base::mFGSurfaceControl,
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- // We cause scaling by 2.
- ts.setSize(Base::mFGSurfaceControl, 128, 128);
- }
-
- auto referenceFrame = Base::mBaseFrame;
- referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
- referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
- referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f};
- EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
- }
-
// Regression test for b/37673612
void Test_ChildrenWithParentBufferTransform() {
{
@@ -1756,7 +1733,7 @@
mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10,
PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eHidden,
- Base::mFGSurfaceControl.get());
+ Base::mFGSurfaceControl->getHandle());
// Show the child layer in a deferred transaction
{
@@ -1823,10 +1800,6 @@
Test_DetachChildrenDifferentClient();
}
-TEST_F(ChildLayerTest_2_1, DISABLED_InheritNonTransformScalingFromParent) {
- Test_InheritNonTransformScalingFromParent();
-}
-
// Regression test for b/37673612
TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) {
Test_ChildrenWithParentBufferTransform();
@@ -1847,7 +1820,7 @@
Base::mComposerClient->createSurface(String8("Child surface"), 0, 0,
PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceEffect,
- Base::mFGSurfaceControl.get());
+ Base::mFGSurfaceControl->getHandle());
{
TransactionScope ts(*Base::sFakeComposer);
ts.setColor(Base::mChild,
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 9655cf3..8097a88 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -41,6 +41,8 @@
"DisplayIdentificationTest.cpp",
"DisplayIdGeneratorTest.cpp",
"DisplayTransactionTest.cpp",
+ "DisplayDevice_GetBestColorModeTest.cpp",
+ "DisplayDevice_SetProjectionTest.cpp",
"EventThreadTest.cpp",
"FrameTimelineTest.cpp",
"HWComposerTest.cpp",
@@ -50,6 +52,16 @@
"LayerMetadataTest.cpp",
"MessageQueueTest.cpp",
"PromiseTest.cpp",
+ "SurfaceFlinger_CreateDisplayTest.cpp",
+ "SurfaceFlinger_DestroyDisplayTest.cpp",
+ "SurfaceFlinger_GetDisplayNativePrimariesTest.cpp",
+ "SurfaceFlinger_HandleTransactionLockedTest.cpp",
+ "SurfaceFlinger_NotifyPowerBoostTest.cpp",
+ "SurfaceFlinger_OnHotplugReceivedTest.cpp",
+ "SurfaceFlinger_OnInitializeDisplaysTest.cpp",
+ "SurfaceFlinger_SetDisplayStateTest.cpp",
+ "SurfaceFlinger_SetPowerModeInternalTest.cpp",
+ "SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp",
"SchedulerTest.cpp",
"SchedulerUtilsTest.cpp",
"SetFrameRateTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_GetBestColorModeTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_GetBestColorModeTest.cpp
new file mode 100644
index 0000000..2e53cd1
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_GetBestColorModeTest.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+using hal::RenderIntent;
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+class GetBestColorModeTest : public DisplayTransactionTest {
+public:
+ void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
+
+ void addHwcColorModesMapping(ui::ColorMode colorMode,
+ std::vector<ui::RenderIntent> renderIntents) {
+ mHwcColorModes[colorMode] = renderIntents;
+ }
+
+ void setInputDataspace(ui::Dataspace dataspace) { mInputDataspace = dataspace; }
+
+ void setInputRenderIntent(ui::RenderIntent renderIntent) { mInputRenderIntent = renderIntent; }
+
+ void getBestColorMode() {
+ auto displayDevice =
+ injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) {
+ injector.setHwcColorModes(mHwcColorModes);
+ injector.setHasWideColorGamut(mHasWideColorGamut);
+ injector.setNativeWindow(mNativeWindow);
+ });
+
+ displayDevice->getCompositionDisplay()
+ ->getDisplayColorProfile()
+ ->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
+ &mOutColorMode, &mOutRenderIntent);
+ }
+
+ ui::Dataspace mOutDataspace;
+ ui::ColorMode mOutColorMode;
+ ui::RenderIntent mOutRenderIntent;
+
+private:
+ ui::Dataspace mInputDataspace;
+ ui::RenderIntent mInputRenderIntent;
+ bool mHasWideColorGamut = false;
+ std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> mHwcColorModes;
+};
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeSRGB) {
+ addHwcColorModesMapping(ui::ColorMode::SRGB,
+ std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+ setInputDataspace(ui::Dataspace::DISPLAY_P3);
+ setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+ setHasWideColorGamut(true);
+
+ getBestColorMode();
+
+ ASSERT_EQ(ui::Dataspace::V0_SRGB, mOutDataspace);
+ ASSERT_EQ(ui::ColorMode::SRGB, mOutColorMode);
+ ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDisplayP3) {
+ addHwcColorModesMapping(ui::ColorMode::DISPLAY_P3,
+ std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+ addHwcColorModesMapping(ui::ColorMode::SRGB,
+ std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+ addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
+ std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+ setInputDataspace(ui::Dataspace::DISPLAY_P3);
+ setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+ setHasWideColorGamut(true);
+
+ getBestColorMode();
+
+ ASSERT_EQ(ui::Dataspace::DISPLAY_P3, mOutDataspace);
+ ASSERT_EQ(ui::ColorMode::DISPLAY_P3, mOutColorMode);
+ ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDISPLAY_BT2020) {
+ addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
+ std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+ setInputDataspace(ui::Dataspace::DISPLAY_P3);
+ setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+ setHasWideColorGamut(true);
+
+ getBestColorMode();
+
+ ASSERT_EQ(ui::Dataspace::DISPLAY_BT2020, mOutDataspace);
+ ASSERT_EQ(ui::ColorMode::DISPLAY_BT2020, mOutColorMode);
+ ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp
new file mode 100644
index 0000000..9fe30f8
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+class DisplayDeviceSetProjectionTest : public DisplayTransactionTest {
+public:
+ static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080; // arbitrary
+ static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary
+
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_0 = 0;
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_90 = HAL_TRANSFORM_ROT_90;
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_180 = HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V;
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_270 =
+ HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+
+ DisplayDeviceSetProjectionTest(ui::Size flingerDisplaySize, ui::Size hardwareDisplaySize,
+ ui::Rotation physicalOrientation)
+ : mFlingerDisplaySize(flingerDisplaySize),
+ mHardwareDisplaySize(hardwareDisplaySize),
+ mPhysicalOrientation(physicalOrientation),
+ mDisplayDevice(createDisplayDevice()) {}
+
+ sp<DisplayDevice> createDisplayDevice() {
+ return injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) {
+ injector.setPhysicalOrientation(mPhysicalOrientation);
+ });
+ }
+
+ ui::Size swapWH(const ui::Size size) const { return ui::Size(size.height, size.width); }
+
+ void setProjectionForRotation0() {
+ // A logical rotation of 0 uses the SurfaceFlinger display size
+ mDisplayDevice->setProjection(ui::ROTATION_0, Rect(mFlingerDisplaySize),
+ Rect(mFlingerDisplaySize));
+ }
+
+ void setProjectionForRotation90() {
+ // A logical rotation of 90 uses the SurfaceFlinger display size with
+ // the width/height swapped.
+ mDisplayDevice->setProjection(ui::ROTATION_90, Rect(swapWH(mFlingerDisplaySize)),
+ Rect(swapWH(mFlingerDisplaySize)));
+ }
+
+ void setProjectionForRotation180() {
+ // A logical rotation of 180 uses the SurfaceFlinger display size
+ mDisplayDevice->setProjection(ui::ROTATION_180, Rect(mFlingerDisplaySize),
+ Rect(mFlingerDisplaySize));
+ }
+
+ void setProjectionForRotation270() {
+ // A logical rotation of 270 uses the SurfaceFlinger display size with
+ // the width/height swapped.
+ mDisplayDevice->setProjection(ui::ROTATION_270, Rect(swapWH(mFlingerDisplaySize)),
+ Rect(swapWH(mFlingerDisplaySize)));
+ }
+
+ void expectStateForHardwareTransform0() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(ui::ROTATION_0, compositionState.displaySpace.orientation);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ void expectStateForHardwareTransform90() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_90, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(ui::ROTATION_90, compositionState.displaySpace.orientation);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
+ // For 90, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
+ // size width and height swapped
+ EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
+ compositionState.orientedDisplaySpace.content);
+ EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ void expectStateForHardwareTransform180() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_180, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(ui::ROTATION_180, compositionState.displaySpace.orientation);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ void expectStateForHardwareTransform270() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_270, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(ui::ROTATION_270, compositionState.displaySpace.orientation);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
+ // For 270, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
+ // size width and height swapped
+ EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
+ compositionState.orientedDisplaySpace.content);
+ EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ const ui::Size mFlingerDisplaySize;
+ const ui::Size mHardwareDisplaySize;
+ const ui::Rotation mPhysicalOrientation;
+ const sp<DisplayDevice> mDisplayDevice;
+};
+
+struct DisplayDeviceSetProjectionTest_Installed0 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed0()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_0) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform270();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed90 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed90()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_90) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform0();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed180 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed180()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_180) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform90();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed270 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed270()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_270) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform180();
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index e055e95..db05d5a 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -14,160 +14,22 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
-#include <type_traits>
-
-#include <android/hardware/power/Boost.h>
-#include <binder/IPCThreadState.h>
-#include <compositionengine/Display.h>
-#include <compositionengine/DisplayColorProfile.h>
-#include <compositionengine/impl/Display.h>
-#include <compositionengine/impl/OutputCompositionState.h>
-#include <compositionengine/mock/Display.h>
-#include <compositionengine/mock/DisplayColorProfile.h>
-#include <compositionengine/mock/DisplaySurface.h>
-#include <compositionengine/mock/RenderSurface.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <gui/mock/GraphicBufferConsumer.h>
-#include <gui/mock/GraphicBufferProducer.h>
-#include <log/log.h>
-#include <private/android_filesystem_config.h>
-#include <renderengine/mock/RenderEngine.h>
-#include <ui/DebugUtils.h>
-
-#include "DisplayIdentificationTest.h"
-#include "TestableScheduler.h"
-#include "TestableSurfaceFlinger.h"
-#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/DisplayHardware/MockPowerAdvisor.h"
-#include "mock/MockEventThread.h"
-#include "mock/MockMessageQueue.h"
-#include "mock/MockNativeWindowSurface.h"
-#include "mock/MockSchedulerCallback.h"
-#include "mock/MockSurfaceInterceptor.h"
-#include "mock/MockVsyncController.h"
-#include "mock/system/window/MockNativeWindow.h"
+#include "DisplayTransactionTestHelpers.h"
namespace android {
-namespace {
-namespace hal = android::hardware::graphics::composer::hal;
-
-using android::hardware::power::Boost;
-
-using testing::_;
using testing::AnyNumber;
using testing::DoAll;
using testing::Mock;
-using testing::ResultOf;
using testing::Return;
-using testing::ReturnRefOfCopy;
using testing::SetArgPointee;
-using testing::StrictMock;
-using hal::ColorMode;
-using hal::Connection;
-using hal::DisplayCapability;
-using hal::DisplayType;
-using hal::Error;
-using hal::Hdr;
-using hal::HWDisplayId;
-using hal::IComposer;
-using hal::IComposerClient;
-using hal::PerFrameMetadataKey;
-using hal::PowerMode;
-using hal::RenderIntent;
+using android::hardware::graphics::composer::hal::HWDisplayId;
using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
-using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
-using HotplugEvent = TestableSurfaceFlinger::HotplugEvent;
-using HWC2Display = TestableSurfaceFlinger::HWC2Display;
-
-constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'667;
-constexpr int32_t DEFAULT_DPI = 320;
-constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565;
-
-constexpr int POWER_MODE_LEET = 1337; // An out of range power mode value
-
-/* ------------------------------------------------------------------------
- * Boolean avoidance
- *
- * To make calls and template instantiations more readable, we define some
- * local enums along with an implicit bool conversion.
- */
-
-#define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true };
-
-BOOL_SUBSTITUTE(Async);
-BOOL_SUBSTITUTE(Critical);
-BOOL_SUBSTITUTE(Primary);
-BOOL_SUBSTITUTE(Secure);
-BOOL_SUBSTITUTE(Virtual);
-
-/* ------------------------------------------------------------------------
- *
- */
-
-class DisplayTransactionTest : public testing::Test {
-public:
- DisplayTransactionTest();
- ~DisplayTransactionTest() override;
-
- // --------------------------------------------------------------------
- // Mock/Fake injection
-
- void injectMockScheduler();
- void injectMockComposer(int virtualDisplayCount);
- void injectFakeBufferQueueFactory();
- void injectFakeNativeWindowSurfaceFactory();
- sp<DisplayDevice> injectDefaultInternalDisplay(std::function<void(FakeDisplayDeviceInjector&)>);
-
- // --------------------------------------------------------------------
- // Postcondition helpers
-
- bool hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId);
- bool hasTransactionFlagSet(int flag);
- bool hasDisplayDevice(sp<IBinder> displayToken);
- sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
- bool hasCurrentDisplayState(sp<IBinder> displayToken);
- const DisplayDeviceState& getCurrentDisplayState(sp<IBinder> displayToken);
- bool hasDrawingDisplayState(sp<IBinder> displayToken);
- const DisplayDeviceState& getDrawingDisplayState(sp<IBinder> displayToken);
-
- // --------------------------------------------------------------------
- // Test instances
-
- TestableSurfaceFlinger mFlinger;
- sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
- sp<GraphicBuffer> mBuffer = new GraphicBuffer();
- Hwc2::mock::PowerAdvisor mPowerAdvisor;
-
- // 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.
- renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
- Hwc2::mock::Composer* mComposer = nullptr;
- mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
- sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor;
-
- mock::VsyncController* mVsyncController = new mock::VsyncController;
- mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker;
- mock::SchedulerCallback mSchedulerCallback;
- mock::EventThread* mEventThread = new mock::EventThread;
- mock::EventThread* mSFEventThread = new mock::EventThread;
-
- // These mocks are created only when expected to be created via a factory.
- sp<mock::GraphicBufferConsumer> mConsumer;
- sp<mock::GraphicBufferProducer> mProducer;
- surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
-};
DisplayTransactionTest::DisplayTransactionTest() {
const ::testing::TestInfo* const test_info =
@@ -330,3298 +192,4 @@
return mFlinger.mutableDrawingState().displays.valueFor(displayToken);
}
-/* ------------------------------------------------------------------------
- *
- */
-
-template <typename PhysicalDisplay>
-struct PhysicalDisplayIdType {};
-
-template <uint64_t displayId>
-using HalVirtualDisplayIdType = std::integral_constant<uint64_t, displayId>;
-
-struct GpuVirtualDisplayIdType {};
-
-template <typename>
-struct IsPhysicalDisplayId : std::bool_constant<false> {};
-
-template <typename PhysicalDisplay>
-struct IsPhysicalDisplayId<PhysicalDisplayIdType<PhysicalDisplay>> : std::bool_constant<true> {};
-
-template <typename>
-struct DisplayIdGetter;
-
-template <typename PhysicalDisplay>
-struct DisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
- static PhysicalDisplayId get() {
- if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
- return PhysicalDisplayId::fromPort(static_cast<bool>(PhysicalDisplay::PRIMARY)
- ? LEGACY_DISPLAY_TYPE_PRIMARY
- : LEGACY_DISPLAY_TYPE_EXTERNAL);
- }
-
- const auto info =
- parseDisplayIdentificationData(PhysicalDisplay::PORT,
- PhysicalDisplay::GET_IDENTIFICATION_DATA());
- return info ? info->id : PhysicalDisplayId::fromPort(PhysicalDisplay::PORT);
- }
-};
-
-template <uint64_t displayId>
-struct DisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
- static HalVirtualDisplayId get() { return HalVirtualDisplayId(displayId); }
-};
-
-template <>
-struct DisplayIdGetter<GpuVirtualDisplayIdType> {
- static GpuVirtualDisplayId get() { return GpuVirtualDisplayId(0); }
-};
-
-template <typename>
-struct DisplayConnectionTypeGetter {
- static constexpr std::optional<DisplayConnectionType> value;
-};
-
-template <typename PhysicalDisplay>
-struct DisplayConnectionTypeGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
- static constexpr std::optional<DisplayConnectionType> value = PhysicalDisplay::CONNECTION_TYPE;
-};
-
-template <typename>
-struct HwcDisplayIdGetter {
- static constexpr std::optional<HWDisplayId> value;
-};
-
-constexpr HWDisplayId HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID = 1010;
-
-template <uint64_t displayId>
-struct HwcDisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
- static constexpr std::optional<HWDisplayId> value = HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID;
-};
-
-template <typename PhysicalDisplay>
-struct HwcDisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
- static constexpr std::optional<HWDisplayId> value = PhysicalDisplay::HWC_DISPLAY_ID;
-};
-
-// DisplayIdType can be:
-// 1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC.
-// 2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC.
-// 3) GpuVirtualDisplayIdType for virtual display without HWC backing.
-template <typename DisplayIdType, int width, int height, Critical critical, Async async,
- Secure secure, Primary primary, int grallocUsage>
-struct DisplayVariant {
- using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
- using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
- using HWC_DISPLAY_ID_OPT = HwcDisplayIdGetter<DisplayIdType>;
-
- // The display width and height
- static constexpr int WIDTH = width;
- static constexpr int HEIGHT = height;
-
- static constexpr int GRALLOC_USAGE = grallocUsage;
-
- // Whether the display is virtual or physical
- static constexpr Virtual VIRTUAL =
- IsPhysicalDisplayId<DisplayIdType>{} ? Virtual::FALSE : Virtual::TRUE;
-
- // When creating native window surfaces for the framebuffer, whether those should be critical
- static constexpr Critical CRITICAL = critical;
-
- // When creating native window surfaces for the framebuffer, whether those should be async
- static constexpr Async ASYNC = async;
-
- // Whether the display should be treated as secure
- static constexpr Secure SECURE = secure;
-
- // Whether the display is primary
- static constexpr Primary PRIMARY = primary;
-
- static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
- auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
- if (auto displayId = PhysicalDisplayId::tryCast(DISPLAY_ID::get())) {
- ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal});
- } else {
- // We turn off the use of HwcVirtualDisplays, to prevent Composition Engine
- // from calling into HWComposer. This way all virtual displays will get
- // a GpuVirtualDisplayId, even if we are in the HwcVirtualDisplayVariant.
- // In this case we later override it by calling display.setDisplayIdForTesting().
- ceDisplayArgs.setUseHwcVirtualDisplays(false);
-
- GpuVirtualDisplayId desiredDisplayId = GpuVirtualDisplayId::tryCast(DISPLAY_ID::get())
- .value_or(GpuVirtualDisplayId(0));
-
- ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
- .WillByDefault(Return(desiredDisplayId));
-
- auto& generator = test->mFlinger.gpuVirtualDisplayIdGenerator();
- ceDisplayArgs.setGpuVirtualDisplayIdGenerator(generator);
- }
- ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor);
-
- auto compositionDisplay =
- compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
- ceDisplayArgs.build());
-
- if (HalVirtualDisplayId::tryCast(DISPLAY_ID::get())) {
- // CompositionEngine has assigned a placeholder GpuVirtualDisplayId and we need to
- // override it with the correct HalVirtualDisplayId.
- compositionDisplay->setDisplayIdForTesting(DISPLAY_ID::get());
- }
-
- auto injector = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay,
- CONNECTION_TYPE::value, HWC_DISPLAY_ID_OPT::value,
- static_cast<bool>(PRIMARY));
-
- injector.setSecure(static_cast<bool>(SECURE));
- injector.setNativeWindow(test->mNativeWindow);
-
- // Creating a DisplayDevice requires getting default dimensions from the
- // native window along with some other initial setup.
- EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
- EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
- EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
- .WillRepeatedly(Return(0));
- EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
- .WillRepeatedly(Return(0));
- EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
- .WillRepeatedly(Return(0));
- EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT))
- .WillRepeatedly(Return(0));
-
- return injector;
- }
-
- // Called by tests to set up any native window creation call expectations.
- static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow())
- .WillOnce(Return(test->mNativeWindow));
-
- EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
- EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
- EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
- .WillRepeatedly(Return(0));
- EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
- .WillRepeatedly(Return(0));
- EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
- .WillRepeatedly(Return(0));
- EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT))
- .WillRepeatedly(Return(0));
- }
-
- static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR));
- EXPECT_CALL(*test->mConsumer, setConsumerName(_)).WillRepeatedly(Return(NO_ERROR));
- EXPECT_CALL(*test->mConsumer, setConsumerUsageBits(GRALLOC_USAGE))
- .WillRepeatedly(Return(NO_ERROR));
- EXPECT_CALL(*test->mConsumer, setDefaultBufferSize(WIDTH, HEIGHT))
- .WillRepeatedly(Return(NO_ERROR));
- EXPECT_CALL(*test->mConsumer, setMaxAcquiredBufferCount(_))
- .WillRepeatedly(Return(NO_ERROR));
- }
-
- static void setupFramebufferProducerBufferQueueCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mProducer, allocateBuffers(0, 0, 0, 0)).WillRepeatedly(Return());
- }
-};
-
-template <HWDisplayId hwcDisplayId, DisplayType hwcDisplayType, typename DisplayVariant,
- typename PhysicalDisplay = void>
-struct HwcDisplayVariant {
- // The display id supplied by the HWC
- static constexpr HWDisplayId HWC_DISPLAY_ID = hwcDisplayId;
-
- // The HWC display type
- static constexpr DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
-
- // The HWC active configuration id
- static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
- static constexpr PowerMode INIT_POWER_MODE = PowerMode::ON;
-
- static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) {
- test->mFlinger.mutablePendingHotplugEvents().emplace_back(
- HotplugEvent{HWC_DISPLAY_ID, connection});
- }
-
- // Called by tests to inject a HWC display setup
- static void injectHwcDisplayWithNoDefaultCapabilities(DisplayTransactionTest* test) {
- const auto displayId = DisplayVariant::DISPLAY_ID::get();
- ASSERT_FALSE(GpuVirtualDisplayId::tryCast(displayId));
- FakeHwcDisplayInjector(displayId, HWC_DISPLAY_TYPE,
- static_cast<bool>(DisplayVariant::PRIMARY))
- .setHwcDisplayId(HWC_DISPLAY_ID)
- .setWidth(DisplayVariant::WIDTH)
- .setHeight(DisplayVariant::HEIGHT)
- .setActiveConfig(HWC_ACTIVE_CONFIG_ID)
- .setPowerMode(INIT_POWER_MODE)
- .inject(&test->mFlinger, test->mComposer);
- }
-
- // Called by tests to inject a HWC display setup
- static void injectHwcDisplay(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
- Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY_ID, INIT_POWER_MODE))
- .WillOnce(Return(Error::NONE));
- injectHwcDisplayWithNoDefaultCapabilities(test);
- }
-
- static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
- DisplayTransactionTest* test) {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
-
- auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
- .setPhysical({DisplayVariant::DISPLAY_ID::get(),
- PhysicalDisplay::CONNECTION_TYPE})
- .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT})
- .setIsSecure(static_cast<bool>(DisplayVariant::SECURE))
- .setPowerAdvisor(&test->mPowerAdvisor)
- .setName(std::string("Injected display for ") +
- test_info->test_case_name() + "." + test_info->name())
- .build();
-
- return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
- ceDisplayArgs);
- }
-
- static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
- constexpr auto CONNECTION_TYPE =
- PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
- ? IComposerClient::DisplayConnectionType::INTERNAL
- : IComposerClient::DisplayConnectionType::EXTERNAL;
-
- EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(CONNECTION_TYPE), Return(hal::V2_4::Error::NONE)));
-
- EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_))
- .WillOnce(Return(hal::Error::NONE));
- EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
- Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::WIDTH, _))
- .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::HEIGHT, _))
- .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::VSYNC_PERIOD, _))
- .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::DPI_X, _))
- .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::DPI_Y, _))
- .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::CONFIG_GROUP, _))
- .WillOnce(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
-
- if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
- EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
- .WillOnce(DoAll(SetArgPointee<1>(PhysicalDisplay::PORT),
- SetArgPointee<2>(PhysicalDisplay::GET_IDENTIFICATION_DATA()),
- Return(Error::NONE)));
- } else {
- EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
- .WillOnce(Return(Error::UNSUPPORTED));
- }
- }
-
- // Called by tests to set up HWC call expectations
- static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY_ID, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(HWC_ACTIVE_CONFIG_ID), Return(Error::NONE)));
- }
-};
-
-// Physical displays are expected to be synchronous, secure, and have a HWC display for output.
-constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
- GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
-
-template <typename PhysicalDisplay, int width, int height, Critical critical>
-struct PhysicalDisplayVariant
- : DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, critical,
- Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY,
- GRALLOC_USAGE_PHYSICAL_DISPLAY>,
- HwcDisplayVariant<PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL,
- DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height,
- critical, Async::FALSE, Secure::TRUE,
- PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
- PhysicalDisplay> {};
-
-template <bool hasIdentificationData>
-struct PrimaryDisplay {
- static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal;
- static constexpr Primary PRIMARY = Primary::TRUE;
- static constexpr uint8_t PORT = 255;
- static constexpr HWDisplayId HWC_DISPLAY_ID = 1001;
- static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
- static constexpr auto GET_IDENTIFICATION_DATA = getInternalEdid;
-};
-
-template <bool hasIdentificationData>
-struct ExternalDisplay {
- static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External;
- static constexpr Primary PRIMARY = Primary::FALSE;
- static constexpr uint8_t PORT = 254;
- static constexpr HWDisplayId HWC_DISPLAY_ID = 1002;
- static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
- static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
-};
-
-struct TertiaryDisplay {
- static constexpr Primary PRIMARY = Primary::FALSE;
- static constexpr uint8_t PORT = 253;
- static constexpr HWDisplayId HWC_DISPLAY_ID = 1003;
- static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
-};
-
-// A primary display is a physical display that is critical
-using PrimaryDisplayVariant =
- PhysicalDisplayVariant<PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
-
-// An external display is physical display that is not critical.
-using ExternalDisplayVariant =
- PhysicalDisplayVariant<ExternalDisplay<false>, 1920, 1280, Critical::FALSE>;
-
-using TertiaryDisplayVariant = PhysicalDisplayVariant<TertiaryDisplay, 1600, 1200, Critical::FALSE>;
-
-// A virtual display not supported by the HWC.
-constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
-
-template <int width, int height, Secure secure>
-struct NonHwcVirtualDisplayVariant
- : DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE, secure,
- Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY> {
- using Base =
- DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE,
- secure, Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
-
- static void injectHwcDisplay(DisplayTransactionTest*) {}
-
- static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
- DisplayTransactionTest* test) {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
-
- ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
- .WillByDefault(Return(Base::DISPLAY_ID::get()));
-
- auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
- .setPixels({Base::WIDTH, Base::HEIGHT})
- .setIsSecure(static_cast<bool>(Base::SECURE))
- .setPowerAdvisor(&test->mPowerAdvisor)
- .setName(std::string("Injected display for ") +
- test_info->test_case_name() + "." + test_info->name())
- .setGpuVirtualDisplayIdGenerator(
- test->mFlinger.gpuVirtualDisplayIdGenerator())
- .build();
-
- return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
- ceDisplayArgs);
- }
-
- static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
- }
-
- static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
- Base::setupNativeWindowSurfaceCreationCallExpectations(test);
- EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
- }
-};
-
-// A virtual display supported by the HWC.
-constexpr uint32_t GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY = GRALLOC_USAGE_HW_COMPOSER;
-
-template <int width, int height, Secure secure>
-struct HwcVirtualDisplayVariant
- : DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE, Async::TRUE,
- secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
- HwcDisplayVariant<HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL,
- DisplayVariant<HalVirtualDisplayIdType<42>, width, height,
- Critical::FALSE, Async::TRUE, secure, Primary::FALSE,
- GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> {
- using Base = DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE,
- Async::TRUE, secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>;
- using Self = HwcVirtualDisplayVariant<width, height, secure>;
-
- static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
- DisplayTransactionTest* test) {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
-
- // In order to prevent compostition engine calling into HWComposer, we
- // 1. turn off the use of HWC virtual displays,
- // 2. provide a GpuVirtualDisplayIdGenerator which always returns some fake ID
- // 3. override the ID by calling setDisplayIdForTesting()
-
- ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
- .WillByDefault(Return(GpuVirtualDisplayId(0)));
-
- auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
- .setUseHwcVirtualDisplays(false)
- .setPixels({Base::WIDTH, Base::HEIGHT})
- .setIsSecure(static_cast<bool>(Base::SECURE))
- .setPowerAdvisor(&test->mPowerAdvisor)
- .setName(std::string("Injected display for ") +
- test_info->test_case_name() + "." + test_info->name())
- .setGpuVirtualDisplayIdGenerator(
- test->mFlinger.gpuVirtualDisplayIdGenerator())
- .build();
-
- auto compositionDisplay =
- compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
- ceDisplayArgs);
- compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get());
-
- // Insert display data so that the HWC thinks it created the virtual display.
- if (const auto displayId = Base::DISPLAY_ID::get();
- HalVirtualDisplayId::tryCast(displayId)) {
- test->mFlinger.mutableHwcDisplayData().try_emplace(displayId);
- }
-
- return compositionDisplay;
- }
-
- static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
- Base::setupNativeWindowSurfaceCreationCallExpectations(test);
- EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
- }
-
- static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _))
- .WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
- }
-};
-
-// For this variant, SurfaceFlinger should not configure itself with wide
-// display support, so the display should not be configured for wide-color
-// support.
-struct WideColorSupportNotConfiguredVariant {
- static constexpr bool WIDE_COLOR_SUPPORTED = false;
-
- static void injectConfigChange(DisplayTransactionTest* test) {
- test->mFlinger.mutableHasWideColorDisplay() = false;
- test->mFlinger.mutableUseColorManagement() = false;
- test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
- }
-
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getColorModes(_, _)).Times(0);
- EXPECT_CALL(*test->mComposer, getRenderIntents(_, _, _)).Times(0);
- EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
- }
-};
-
-// For this variant, SurfaceFlinger should configure itself with wide display
-// support, and the display should respond with an non-empty list of supported
-// color modes. Wide-color support should be configured.
-template <typename Display>
-struct WideColorP3ColorimetricSupportedVariant {
- static constexpr bool WIDE_COLOR_SUPPORTED = true;
-
- static void injectConfigChange(DisplayTransactionTest* test) {
- test->mFlinger.mutableUseColorManagement() = true;
- test->mFlinger.mutableHasWideColorDisplay() = true;
- test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
- }
-
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_DATASPACE)).Times(1);
-
- EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::DISPLAY_P3})),
- Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getRenderIntents(Display::HWC_DISPLAY_ID, ColorMode::DISPLAY_P3, _))
- .WillOnce(DoAll(SetArgPointee<2>(
- std::vector<RenderIntent>({RenderIntent::COLORIMETRIC})),
- Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- setColorMode(Display::HWC_DISPLAY_ID, ColorMode::SRGB,
- RenderIntent::COLORIMETRIC))
- .WillOnce(Return(Error::NONE));
- }
-};
-
-// For this variant, SurfaceFlinger should configure itself with wide display
-// support, but the display should respond with an empty list of supported color
-// modes. Wide-color support for the display should not be configured.
-template <typename Display>
-struct WideColorNotSupportedVariant {
- static constexpr bool WIDE_COLOR_SUPPORTED = false;
-
- static void injectConfigChange(DisplayTransactionTest* test) {
- test->mFlinger.mutableUseColorManagement() = true;
- test->mFlinger.mutableHasWideColorDisplay() = true;
- }
-
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>()), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
- }
-};
-
-// For this variant, the display is not a HWC display, so no HDR support should
-// be configured.
-struct NonHwcDisplayHdrSupportVariant {
- static constexpr bool HDR10_PLUS_SUPPORTED = false;
- static constexpr bool HDR10_SUPPORTED = false;
- static constexpr bool HDR_HLG_SUPPORTED = false;
- static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getHdrCapabilities(_, _, _, _, _)).Times(0);
- }
-};
-
-template <typename Display>
-struct Hdr10PlusSupportedVariant {
- static constexpr bool HDR10_PLUS_SUPPORTED = true;
- static constexpr bool HDR10_SUPPORTED = true;
- static constexpr bool HDR_HLG_SUPPORTED = false;
- static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getHdrCapabilities(_, _, _, _, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({
- Hdr::HDR10_PLUS,
- Hdr::HDR10,
- })),
- Return(Error::NONE)));
- }
-};
-
-// For this variant, the composer should respond with a non-empty list of HDR
-// modes containing HDR10, so HDR10 support should be configured.
-template <typename Display>
-struct Hdr10SupportedVariant {
- static constexpr bool HDR10_PLUS_SUPPORTED = false;
- static constexpr bool HDR10_SUPPORTED = true;
- static constexpr bool HDR_HLG_SUPPORTED = false;
- static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::HDR10})),
- Return(Error::NONE)));
- }
-};
-
-// For this variant, the composer should respond with a non-empty list of HDR
-// modes containing HLG, so HLG support should be configured.
-template <typename Display>
-struct HdrHlgSupportedVariant {
- static constexpr bool HDR10_PLUS_SUPPORTED = false;
- static constexpr bool HDR10_SUPPORTED = false;
- static constexpr bool HDR_HLG_SUPPORTED = true;
- static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
- .WillOnce(
- DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::HLG})), Return(Error::NONE)));
- }
-};
-
-// For this variant, the composer should respond with a non-empty list of HDR
-// modes containing DOLBY_VISION, so DOLBY_VISION support should be configured.
-template <typename Display>
-struct HdrDolbyVisionSupportedVariant {
- static constexpr bool HDR10_PLUS_SUPPORTED = false;
- static constexpr bool HDR10_SUPPORTED = false;
- static constexpr bool HDR_HLG_SUPPORTED = false;
- static constexpr bool HDR_DOLBY_VISION_SUPPORTED = true;
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::DOLBY_VISION})),
- Return(Error::NONE)));
- }
-};
-
-// For this variant, the composer should respond with am empty list of HDR
-// modes, so no HDR support should be configured.
-template <typename Display>
-struct HdrNotSupportedVariant {
- static constexpr bool HDR10_PLUS_SUPPORTED = false;
- static constexpr bool HDR10_SUPPORTED = false;
- static constexpr bool HDR_HLG_SUPPORTED = false;
- static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>()), Return(Error::NONE)));
- }
-};
-
-struct NonHwcPerFrameMetadataSupportVariant {
- static constexpr int PER_FRAME_METADATA_KEYS = 0;
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(_)).Times(0);
- }
-};
-
-template <typename Display>
-struct NoPerFrameMetadataSupportVariant {
- static constexpr int PER_FRAME_METADATA_KEYS = 0;
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
- .WillOnce(Return(std::vector<PerFrameMetadataKey>()));
- }
-};
-
-template <typename Display>
-struct Smpte2086PerFrameMetadataSupportVariant {
- static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::SMPTE2086;
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
- .WillOnce(Return(std::vector<PerFrameMetadataKey>({
- PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X,
- PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y,
- PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X,
- PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y,
- PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X,
- PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y,
- PerFrameMetadataKey::WHITE_POINT_X,
- PerFrameMetadataKey::WHITE_POINT_Y,
- PerFrameMetadataKey::MAX_LUMINANCE,
- PerFrameMetadataKey::MIN_LUMINANCE,
- })));
- }
-};
-
-template <typename Display>
-struct Cta861_3_PerFrameMetadataSupportVariant {
- static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::CTA861_3;
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
- .WillOnce(Return(std::vector<PerFrameMetadataKey>({
- PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL,
- PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL,
- })));
- }
-};
-
-template <typename Display>
-struct Hdr10_Plus_PerFrameMetadataSupportVariant {
- static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::HDR10PLUS;
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
- .WillOnce(Return(std::vector<PerFrameMetadataKey>({
- PerFrameMetadataKey::HDR10_PLUS_SEI,
- })));
- }
-};
-/* ------------------------------------------------------------------------
- * Typical display configurations to test
- */
-
-template <typename DisplayPolicy, typename WideColorSupportPolicy, typename HdrSupportPolicy,
- typename PerFrameMetadataSupportPolicy>
-struct Case {
- using Display = DisplayPolicy;
- using WideColorSupport = WideColorSupportPolicy;
- using HdrSupport = HdrSupportPolicy;
- using PerFrameMetadataSupport = PerFrameMetadataSupportPolicy;
-};
-
-using SimplePrimaryDisplayCase =
- Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
- HdrNotSupportedVariant<PrimaryDisplayVariant>,
- NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using SimpleExternalDisplayCase =
- Case<ExternalDisplayVariant, WideColorNotSupportedVariant<ExternalDisplayVariant>,
- HdrNotSupportedVariant<ExternalDisplayVariant>,
- NoPerFrameMetadataSupportVariant<ExternalDisplayVariant>>;
-using SimpleTertiaryDisplayCase =
- Case<TertiaryDisplayVariant, WideColorNotSupportedVariant<TertiaryDisplayVariant>,
- HdrNotSupportedVariant<TertiaryDisplayVariant>,
- NoPerFrameMetadataSupportVariant<TertiaryDisplayVariant>>;
-using NonHwcVirtualDisplayCase =
- Case<NonHwcVirtualDisplayVariant<1024, 768, Secure::FALSE>,
- WideColorSupportNotConfiguredVariant, NonHwcDisplayHdrSupportVariant,
- NonHwcPerFrameMetadataSupportVariant>;
-using SimpleHwcVirtualDisplayVariant = HwcVirtualDisplayVariant<1024, 768, Secure::TRUE>;
-using HwcVirtualDisplayCase =
- Case<SimpleHwcVirtualDisplayVariant, WideColorSupportNotConfiguredVariant,
- HdrNotSupportedVariant<SimpleHwcVirtualDisplayVariant>,
- NoPerFrameMetadataSupportVariant<SimpleHwcVirtualDisplayVariant>>;
-using WideColorP3ColorimetricDisplayCase =
- Case<PrimaryDisplayVariant, WideColorP3ColorimetricSupportedVariant<PrimaryDisplayVariant>,
- HdrNotSupportedVariant<PrimaryDisplayVariant>,
- NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using Hdr10PlusDisplayCase =
- Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
- Hdr10SupportedVariant<PrimaryDisplayVariant>,
- Hdr10_Plus_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using Hdr10DisplayCase =
- Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
- Hdr10SupportedVariant<PrimaryDisplayVariant>,
- NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using HdrHlgDisplayCase =
- Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
- HdrHlgSupportedVariant<PrimaryDisplayVariant>,
- NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using HdrDolbyVisionDisplayCase =
- Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
- HdrDolbyVisionSupportedVariant<PrimaryDisplayVariant>,
- NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using HdrSmpte2086DisplayCase =
- Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
- HdrNotSupportedVariant<PrimaryDisplayVariant>,
- Smpte2086PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using HdrCta861_3_DisplayCase =
- Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
- HdrNotSupportedVariant<PrimaryDisplayVariant>,
- Cta861_3_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-
-/* ------------------------------------------------------------------------
- *
- * SurfaceFlinger::onHotplugReceived
- */
-
-TEST_F(DisplayTransactionTest, hotplugEnqueuesEventsForDisplayTransaction) {
- constexpr int currentSequenceId = 123;
- constexpr HWDisplayId hwcDisplayId1 = 456;
- constexpr HWDisplayId hwcDisplayId2 = 654;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // Set the current sequence id for accepted events
- mFlinger.mutableComposerSequenceId() = currentSequenceId;
-
- // Set the main thread id so that the current thread does not appear to be
- // the main thread.
- mFlinger.mutableMainThreadId() = std::thread::id();
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- // We expect invalidate() to be invoked once to trigger display transaction
- // processing.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-
- // --------------------------------------------------------------------
- // Invocation
-
- // Simulate two hotplug events (a connect and a disconnect)
- mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, Connection::CONNECTED);
- mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, Connection::DISCONNECTED);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The display transaction needed flag should be set.
- EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-
- // All events should be in the pending event queue.
- const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents();
- ASSERT_EQ(2u, pendingEvents.size());
- EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId);
- EXPECT_EQ(Connection::CONNECTED, pendingEvents[0].connection);
- EXPECT_EQ(hwcDisplayId2, pendingEvents[1].hwcDisplayId);
- EXPECT_EQ(Connection::DISCONNECTED, pendingEvents[1].connection);
-}
-
-TEST_F(DisplayTransactionTest, hotplugDiscardsUnexpectedEvents) {
- constexpr int currentSequenceId = 123;
- constexpr int otherSequenceId = 321;
- constexpr HWDisplayId displayId = 456;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // Set the current sequence id for accepted events
- mFlinger.mutableComposerSequenceId() = currentSequenceId;
-
- // Set the main thread id so that the current thread does not appear to be
- // the main thread.
- mFlinger.mutableMainThreadId() = std::thread::id();
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- // We do not expect any calls to invalidate().
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(0);
-
- // --------------------------------------------------------------------
- // Invocation
-
- // Call with an unexpected sequence id
- mFlinger.onHotplugReceived(otherSequenceId, displayId, Connection::INVALID);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The display transaction needed flag should not be set
- EXPECT_FALSE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-
- // There should be no pending events
- EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty());
-}
-
-TEST_F(DisplayTransactionTest, hotplugProcessesEnqueuedEventsIfCalledOnMainThread) {
- constexpr int currentSequenceId = 123;
- constexpr HWDisplayId displayId1 = 456;
-
- // --------------------------------------------------------------------
- // Note:
- // --------------------------------------------------------------------
- // This test case is a bit tricky. We want to verify that
- // onHotplugReceived() calls processDisplayHotplugEventsLocked(), but we
- // don't really want to provide coverage for everything the later function
- // does as there are specific tests for it.
- // --------------------------------------------------------------------
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // Set the current sequence id for accepted events
- mFlinger.mutableComposerSequenceId() = currentSequenceId;
-
- // Set the main thread id so that the current thread does appear to be the
- // main thread.
- mFlinger.mutableMainThreadId() = std::this_thread::get_id();
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- // We expect invalidate() to be invoked once to trigger display transaction
- // processing.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-
- // --------------------------------------------------------------------
- // Invocation
-
- // Simulate a disconnect on a display id that is not connected. This should
- // be enqueued by onHotplugReceived(), and dequeued by
- // processDisplayHotplugEventsLocked(), but then ignored as invalid.
- mFlinger.onHotplugReceived(currentSequenceId, displayId1, Connection::DISCONNECTED);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The display transaction needed flag should be set.
- EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-
- // There should be no event queued on return, as it should have been
- // processed.
- EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty());
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::createDisplay
- */
-
-TEST_F(DisplayTransactionTest, createDisplaySetsCurrentStateForNonsecureDisplay) {
- const String8 name("virtual.test");
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- // The call should notify the interceptor that a display was created.
- EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
-
- // --------------------------------------------------------------------
- // Invocation
-
- sp<IBinder> displayToken = mFlinger.createDisplay(name, false);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The display should have been added to the current state
- ASSERT_TRUE(hasCurrentDisplayState(displayToken));
- const auto& display = getCurrentDisplayState(displayToken);
- EXPECT_TRUE(display.isVirtual());
- EXPECT_FALSE(display.isSecure);
- EXPECT_EQ(name.string(), display.displayName);
-
- // --------------------------------------------------------------------
- // Cleanup conditions
-
- // Destroying the display invalidates the display state.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-}
-
-TEST_F(DisplayTransactionTest, createDisplaySetsCurrentStateForSecureDisplay) {
- const String8 name("virtual.test");
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- // The call should notify the interceptor that a display was created.
- EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
-
- // --------------------------------------------------------------------
- // Invocation
- int64_t oldId = IPCThreadState::self()->clearCallingIdentity();
- // Set the calling identity to graphics so captureDisplay with secure is allowed.
- IPCThreadState::self()->restoreCallingIdentity(static_cast<int64_t>(AID_GRAPHICS) << 32 |
- AID_GRAPHICS);
- sp<IBinder> displayToken = mFlinger.createDisplay(name, true);
- IPCThreadState::self()->restoreCallingIdentity(oldId);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The display should have been added to the current state
- ASSERT_TRUE(hasCurrentDisplayState(displayToken));
- const auto& display = getCurrentDisplayState(displayToken);
- EXPECT_TRUE(display.isVirtual());
- EXPECT_TRUE(display.isSecure);
- EXPECT_EQ(name.string(), display.displayName);
-
- // --------------------------------------------------------------------
- // Cleanup conditions
-
- // Destroying the display invalidates the display state.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::destroyDisplay
- */
-
-TEST_F(DisplayTransactionTest, destroyDisplayClearsCurrentStateForDisplay) {
- using Case = NonHwcVirtualDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A virtual display exists
- auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
- existing.inject();
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- // The call should notify the interceptor that a display was created.
- EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
-
- // Destroying the display invalidates the display state.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.destroyDisplay(existing.token());
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The display should have been removed from the current state
- EXPECT_FALSE(hasCurrentDisplayState(existing.token()));
-
- // Ths display should still exist in the drawing state
- EXPECT_TRUE(hasDrawingDisplayState(existing.token()));
-
- // The display transaction needed flasg should be set
- EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-}
-
-TEST_F(DisplayTransactionTest, destroyDisplayHandlesUnknownDisplay) {
- // --------------------------------------------------------------------
- // Preconditions
-
- sp<BBinder> displayToken = new BBinder();
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.destroyDisplay(displayToken);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::notifyPowerBoost
- */
-
-TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) {
- mFlinger.scheduler()->replaceTouchTimer(100);
- std::this_thread::sleep_for(10ms); // wait for callback to be triggered
- EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch
-
- std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
- EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
-
- EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::CAMERA_SHOT)));
- std::this_thread::sleep_for(10ms); // wait for callback to maybe be triggered
- EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
-
- std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
- EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
-
- EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::INTERACTION)));
- std::this_thread::sleep_for(10ms); // wait for callback to be triggered.
- EXPECT_TRUE(mFlinger.scheduler()->isTouchActive());
-}
-
-/* ------------------------------------------------------------------------
- * DisplayDevice::GetBestColorMode
- */
-class GetBestColorModeTest : public DisplayTransactionTest {
-public:
- void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
-
- void addHwcColorModesMapping(ui::ColorMode colorMode,
- std::vector<ui::RenderIntent> renderIntents) {
- mHwcColorModes[colorMode] = renderIntents;
- }
-
- void setInputDataspace(ui::Dataspace dataspace) { mInputDataspace = dataspace; }
-
- void setInputRenderIntent(ui::RenderIntent renderIntent) { mInputRenderIntent = renderIntent; }
-
- void getBestColorMode() {
- auto displayDevice =
- injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) {
- injector.setHwcColorModes(mHwcColorModes);
- injector.setHasWideColorGamut(mHasWideColorGamut);
- injector.setNativeWindow(mNativeWindow);
- });
-
- displayDevice->getCompositionDisplay()
- ->getDisplayColorProfile()
- ->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
- &mOutColorMode, &mOutRenderIntent);
- }
-
- ui::Dataspace mOutDataspace;
- ui::ColorMode mOutColorMode;
- ui::RenderIntent mOutRenderIntent;
-
-private:
- ui::Dataspace mInputDataspace;
- ui::RenderIntent mInputRenderIntent;
- bool mHasWideColorGamut = false;
- std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> mHwcColorModes;
-};
-
-TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeSRGB) {
- addHwcColorModesMapping(ui::ColorMode::SRGB,
- std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
- setInputDataspace(ui::Dataspace::DISPLAY_P3);
- setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
- setHasWideColorGamut(true);
-
- getBestColorMode();
-
- ASSERT_EQ(ui::Dataspace::V0_SRGB, mOutDataspace);
- ASSERT_EQ(ui::ColorMode::SRGB, mOutColorMode);
- ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
-}
-
-TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDisplayP3) {
- addHwcColorModesMapping(ui::ColorMode::DISPLAY_P3,
- std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
- addHwcColorModesMapping(ui::ColorMode::SRGB,
- std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
- addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
- std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
- setInputDataspace(ui::Dataspace::DISPLAY_P3);
- setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
- setHasWideColorGamut(true);
-
- getBestColorMode();
-
- ASSERT_EQ(ui::Dataspace::DISPLAY_P3, mOutDataspace);
- ASSERT_EQ(ui::ColorMode::DISPLAY_P3, mOutColorMode);
- ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
-}
-
-TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDISPLAY_BT2020) {
- addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
- std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
- setInputDataspace(ui::Dataspace::DISPLAY_P3);
- setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
- setHasWideColorGamut(true);
-
- getBestColorMode();
-
- ASSERT_EQ(ui::Dataspace::DISPLAY_BT2020, mOutDataspace);
- ASSERT_EQ(ui::ColorMode::DISPLAY_BT2020, mOutColorMode);
- ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
-}
-
-/* ------------------------------------------------------------------------
- * DisplayDevice::setProjection
- */
-
-class DisplayDeviceSetProjectionTest : public DisplayTransactionTest {
-public:
- static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080; // arbitrary
- static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary
-
- static constexpr int32_t TRANSFORM_FLAGS_ROT_0 = 0;
- static constexpr int32_t TRANSFORM_FLAGS_ROT_90 = HAL_TRANSFORM_ROT_90;
- static constexpr int32_t TRANSFORM_FLAGS_ROT_180 = HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V;
- static constexpr int32_t TRANSFORM_FLAGS_ROT_270 =
- HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
-
- DisplayDeviceSetProjectionTest(ui::Size flingerDisplaySize, ui::Size hardwareDisplaySize,
- ui::Rotation physicalOrientation)
- : mFlingerDisplaySize(flingerDisplaySize),
- mHardwareDisplaySize(hardwareDisplaySize),
- mPhysicalOrientation(physicalOrientation),
- mDisplayDevice(createDisplayDevice()) {}
-
- sp<DisplayDevice> createDisplayDevice() {
- return injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) {
- injector.setPhysicalOrientation(mPhysicalOrientation);
- });
- }
-
- ui::Size swapWH(const ui::Size size) const { return ui::Size(size.height, size.width); }
-
- void setProjectionForRotation0() {
- // A logical rotation of 0 uses the SurfaceFlinger display size
- mDisplayDevice->setProjection(ui::ROTATION_0, Rect(mFlingerDisplaySize),
- Rect(mFlingerDisplaySize));
- }
-
- void setProjectionForRotation90() {
- // A logical rotation of 90 uses the SurfaceFlinger display size with
- // the width/height swapped.
- mDisplayDevice->setProjection(ui::ROTATION_90, Rect(swapWH(mFlingerDisplaySize)),
- Rect(swapWH(mFlingerDisplaySize)));
- }
-
- void setProjectionForRotation180() {
- // A logical rotation of 180 uses the SurfaceFlinger display size
- mDisplayDevice->setProjection(ui::ROTATION_180, Rect(mFlingerDisplaySize),
- Rect(mFlingerDisplaySize));
- }
-
- void setProjectionForRotation270() {
- // A logical rotation of 270 uses the SurfaceFlinger display size with
- // the width/height swapped.
- mDisplayDevice->setProjection(ui::ROTATION_270, Rect(swapWH(mFlingerDisplaySize)),
- Rect(swapWH(mFlingerDisplaySize)));
- }
-
- void expectStateForHardwareTransform0() {
- const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
- EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width,
- mHardwareDisplaySize.height),
- compositionState.transform);
- EXPECT_EQ(ui::ROTATION_0, compositionState.displaySpace.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
- EXPECT_EQ(false, compositionState.needsFiltering);
- }
-
- void expectStateForHardwareTransform90() {
- const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
- EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_90, mHardwareDisplaySize.width,
- mHardwareDisplaySize.height),
- compositionState.transform);
- EXPECT_EQ(ui::ROTATION_90, compositionState.displaySpace.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
- // For 90, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
- // size width and height swapped
- EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
- compositionState.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
- EXPECT_EQ(false, compositionState.needsFiltering);
- }
-
- void expectStateForHardwareTransform180() {
- const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
- EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_180, mHardwareDisplaySize.width,
- mHardwareDisplaySize.height),
- compositionState.transform);
- EXPECT_EQ(ui::ROTATION_180, compositionState.displaySpace.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
- EXPECT_EQ(false, compositionState.needsFiltering);
- }
-
- void expectStateForHardwareTransform270() {
- const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
- EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_270, mHardwareDisplaySize.width,
- mHardwareDisplaySize.height),
- compositionState.transform);
- EXPECT_EQ(ui::ROTATION_270, compositionState.displaySpace.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
- // For 270, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
- // size width and height swapped
- EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
- compositionState.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
- EXPECT_EQ(false, compositionState.needsFiltering);
- }
-
- const ui::Size mFlingerDisplaySize;
- const ui::Size mHardwareDisplaySize;
- const ui::Rotation mPhysicalOrientation;
- const sp<DisplayDevice> mDisplayDevice;
-};
-
-struct DisplayDeviceSetProjectionTest_Installed0 : public DisplayDeviceSetProjectionTest {
- DisplayDeviceSetProjectionTest_Installed0()
- : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- ui::ROTATION_0) {}
-};
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith0OutputRotation) {
- setProjectionForRotation0();
- expectStateForHardwareTransform0();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith90OutputRotation) {
- setProjectionForRotation90();
- expectStateForHardwareTransform90();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith180OutputRotation) {
- setProjectionForRotation180();
- expectStateForHardwareTransform180();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith270OutputRotation) {
- setProjectionForRotation270();
- expectStateForHardwareTransform270();
-}
-
-struct DisplayDeviceSetProjectionTest_Installed90 : public DisplayDeviceSetProjectionTest {
- DisplayDeviceSetProjectionTest_Installed90()
- : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
- ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- ui::ROTATION_90) {}
-};
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith0OutputRotation) {
- setProjectionForRotation0();
- expectStateForHardwareTransform90();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith90OutputRotation) {
- setProjectionForRotation90();
- expectStateForHardwareTransform180();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith180OutputRotation) {
- setProjectionForRotation180();
- expectStateForHardwareTransform270();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith270OutputRotation) {
- setProjectionForRotation270();
- expectStateForHardwareTransform0();
-}
-
-struct DisplayDeviceSetProjectionTest_Installed180 : public DisplayDeviceSetProjectionTest {
- DisplayDeviceSetProjectionTest_Installed180()
- : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- ui::ROTATION_180) {}
-};
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith0OutputRotation) {
- setProjectionForRotation0();
- expectStateForHardwareTransform180();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith90OutputRotation) {
- setProjectionForRotation90();
- expectStateForHardwareTransform270();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith180OutputRotation) {
- setProjectionForRotation180();
- expectStateForHardwareTransform0();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith270OutputRotation) {
- setProjectionForRotation270();
- expectStateForHardwareTransform90();
-}
-
-struct DisplayDeviceSetProjectionTest_Installed270 : public DisplayDeviceSetProjectionTest {
- DisplayDeviceSetProjectionTest_Installed270()
- : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
- ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- ui::ROTATION_270) {}
-};
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith0OutputRotation) {
- setProjectionForRotation0();
- expectStateForHardwareTransform270();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith90OutputRotation) {
- setProjectionForRotation90();
- expectStateForHardwareTransform0();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith180OutputRotation) {
- setProjectionForRotation180();
- expectStateForHardwareTransform90();
-}
-
-TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith270OutputRotation) {
- setProjectionForRotation270();
- expectStateForHardwareTransform180();
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::getDisplayNativePrimaries
- */
-
-class GetDisplayNativePrimaries : public DisplayTransactionTest {
-public:
- GetDisplayNativePrimaries();
- void populateDummyDisplayNativePrimaries(ui::DisplayPrimaries& primaries);
- void checkDummyDisplayNativePrimaries(const ui::DisplayPrimaries& primaries);
-
-private:
- static constexpr float mStartingTestValue = 1.0f;
-};
-
-GetDisplayNativePrimaries::GetDisplayNativePrimaries() {
- SimplePrimaryDisplayCase::Display::injectHwcDisplay(this);
- injectFakeNativeWindowSurfaceFactory();
-}
-
-void GetDisplayNativePrimaries::populateDummyDisplayNativePrimaries(
- ui::DisplayPrimaries& primaries) {
- float startingVal = mStartingTestValue;
- primaries.red.X = startingVal++;
- primaries.red.Y = startingVal++;
- primaries.red.Z = startingVal++;
- primaries.green.X = startingVal++;
- primaries.green.Y = startingVal++;
- primaries.green.Z = startingVal++;
- primaries.blue.X = startingVal++;
- primaries.blue.Y = startingVal++;
- primaries.blue.Z = startingVal++;
- primaries.white.X = startingVal++;
- primaries.white.Y = startingVal++;
- primaries.white.Z = startingVal++;
-}
-
-void GetDisplayNativePrimaries::checkDummyDisplayNativePrimaries(
- const ui::DisplayPrimaries& primaries) {
- float startingVal = mStartingTestValue;
- EXPECT_EQ(primaries.red.X, startingVal++);
- EXPECT_EQ(primaries.red.Y, startingVal++);
- EXPECT_EQ(primaries.red.Z, startingVal++);
- EXPECT_EQ(primaries.green.X, startingVal++);
- EXPECT_EQ(primaries.green.Y, startingVal++);
- EXPECT_EQ(primaries.green.Z, startingVal++);
- EXPECT_EQ(primaries.blue.X, startingVal++);
- EXPECT_EQ(primaries.blue.Y, startingVal++);
- EXPECT_EQ(primaries.blue.Z, startingVal++);
- EXPECT_EQ(primaries.white.X, startingVal++);
- EXPECT_EQ(primaries.white.Y, startingVal++);
- EXPECT_EQ(primaries.white.Z, startingVal++);
-}
-
-TEST_F(GetDisplayNativePrimaries, nullDisplayToken) {
- ui::DisplayPrimaries primaries;
- EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(nullptr, primaries));
-}
-
-TEST_F(GetDisplayNativePrimaries, internalDisplayWithPrimariesData) {
- auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this);
- injector.inject();
- auto internalDisplayToken = injector.token();
-
- ui::DisplayPrimaries expectedPrimaries;
- populateDummyDisplayNativePrimaries(expectedPrimaries);
- mFlinger.setInternalDisplayPrimaries(expectedPrimaries);
-
- ui::DisplayPrimaries primaries;
- EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries));
-
- checkDummyDisplayNativePrimaries(primaries);
-}
-
-TEST_F(GetDisplayNativePrimaries, notInternalDisplayToken) {
- sp<BBinder> notInternalDisplayToken = new BBinder();
-
- ui::DisplayPrimaries primaries;
- populateDummyDisplayNativePrimaries(primaries);
- EXPECT_EQ(NAME_NOT_FOUND,
- mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries));
-
- // Check primaries argument wasn't modified in case of failure
- checkDummyDisplayNativePrimaries(primaries);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::setupNewDisplayDeviceInternal
- */
-
-class SetupNewDisplayDeviceInternalTest : public DisplayTransactionTest {
-public:
- template <typename T>
- void setupNewDisplayDeviceInternalTest();
-};
-
-template <typename Case>
-void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() {
- const sp<BBinder> displayToken = new BBinder();
- const sp<compositionengine::mock::DisplaySurface> displaySurface =
- new compositionengine::mock::DisplaySurface();
- const sp<mock::GraphicBufferProducer> producer = new mock::GraphicBufferProducer();
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // Wide color displays support is configured appropriately
- Case::WideColorSupport::injectConfigChange(this);
-
- // The display is setup with the HWC.
- Case::Display::injectHwcDisplay(this);
-
- // SurfaceFlinger will use a test-controlled factory for native window
- // surfaces.
- injectFakeNativeWindowSurfaceFactory();
-
- // A compositionengine::Display has already been created
- auto compositionDisplay = Case::Display::injectCompositionDisplay(this);
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- // Various native window calls will be made.
- Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
- Case::Display::setupHwcGetActiveConfigCallExpectations(this);
- Case::WideColorSupport::setupComposerCallExpectations(this);
- Case::HdrSupport::setupComposerCallExpectations(this);
- Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
-
- // --------------------------------------------------------------------
- // Invocation
-
- DisplayDeviceState state;
- if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
- const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get());
- ASSERT_TRUE(displayId);
- const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
- ASSERT_TRUE(hwcDisplayId);
- state.physical = {.id = *displayId, .type = *connectionType, .hwcDisplayId = *hwcDisplayId};
- }
-
- state.isSecure = static_cast<bool>(Case::Display::SECURE);
-
- auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
- displaySurface, producer);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- ASSERT_TRUE(device != nullptr);
- EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
- EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType());
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
- EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
- EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
- EXPECT_EQ(Case::Display::WIDTH, device->getWidth());
- EXPECT_EQ(Case::Display::HEIGHT, device->getHeight());
- EXPECT_EQ(Case::WideColorSupport::WIDE_COLOR_SUPPORTED, device->hasWideColorGamut());
- EXPECT_EQ(Case::HdrSupport::HDR10_PLUS_SUPPORTED, device->hasHDR10PlusSupport());
- EXPECT_EQ(Case::HdrSupport::HDR10_SUPPORTED, device->hasHDR10Support());
- EXPECT_EQ(Case::HdrSupport::HDR_HLG_SUPPORTED, device->hasHLGSupport());
- EXPECT_EQ(Case::HdrSupport::HDR_DOLBY_VISION_SUPPORTED, device->hasDolbyVisionSupport());
- // Note: This is not Case::Display::HWC_ACTIVE_CONFIG_ID as the ids are
- // remapped, and the test only ever sets up one config. If there were an error
- // looking up the remapped index, device->getActiveConfig() would be -1 instead.
- EXPECT_EQ(0, device->getActiveConfig().value());
- EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS,
- device->getSupportedPerFrameMetadata());
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createSimplePrimaryDisplay) {
- setupNewDisplayDeviceInternalTest<SimplePrimaryDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createSimpleExternalDisplay) {
- setupNewDisplayDeviceInternalTest<SimpleExternalDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createNonHwcVirtualDisplay) {
- setupNewDisplayDeviceInternalTest<NonHwcVirtualDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) {
- setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) {
- setupNewDisplayDeviceInternalTest<WideColorP3ColorimetricDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10PlusDisplay) {
- setupNewDisplayDeviceInternalTest<Hdr10PlusDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10Display) {
- setupNewDisplayDeviceInternalTest<Hdr10DisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdrHlgDisplay) {
- setupNewDisplayDeviceInternalTest<HdrHlgDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdrDolbyVisionDisplay) {
- setupNewDisplayDeviceInternalTest<HdrDolbyVisionDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdrSmpte2086DisplayCase) {
- setupNewDisplayDeviceInternalTest<HdrSmpte2086DisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdrCta816_3_DisplayCase) {
- setupNewDisplayDeviceInternalTest<HdrCta861_3_DisplayCase>();
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::handleTransactionLocked(eDisplayTransactionNeeded)
- */
-
-class HandleTransactionLockedTest : public DisplayTransactionTest {
-public:
- template <typename Case>
- void setupCommonPreconditions();
-
- template <typename Case, bool connected>
- static void expectHotplugReceived(mock::EventThread*);
-
- template <typename Case>
- void setupCommonCallExpectationsForConnectProcessing();
-
- template <typename Case>
- void setupCommonCallExpectationsForDisconnectProcessing();
-
- template <typename Case>
- void processesHotplugConnectCommon();
-
- template <typename Case>
- void ignoresHotplugConnectCommon();
-
- template <typename Case>
- void processesHotplugDisconnectCommon();
-
- template <typename Case>
- void verifyDisplayIsConnected(const sp<IBinder>& displayToken);
-
- template <typename Case>
- void verifyPhysicalDisplayIsConnected();
-
- void verifyDisplayIsNotConnected(const sp<IBinder>& displayToken);
-};
-
-template <typename Case>
-void HandleTransactionLockedTest::setupCommonPreconditions() {
- // Wide color displays support is configured appropriately
- Case::WideColorSupport::injectConfigChange(this);
-
- // SurfaceFlinger will use a test-controlled factory for BufferQueues
- injectFakeBufferQueueFactory();
-
- // SurfaceFlinger will use a test-controlled factory for native window
- // surfaces.
- injectFakeNativeWindowSurfaceFactory();
-}
-
-template <typename Case, bool connected>
-void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) {
- const auto convert = [](auto physicalDisplayId) {
- return std::make_optional(DisplayId{physicalDisplayId});
- };
-
- EXPECT_CALL(*eventThread,
- onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected))
- .Times(1);
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() {
- Case::Display::setupHwcHotplugCallExpectations(this);
-
- Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
- Case::Display::setupFramebufferProducerBufferQueueCallExpectations(this);
- Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
- Case::Display::setupHwcGetActiveConfigCallExpectations(this);
-
- Case::WideColorSupport::setupComposerCallExpectations(this);
- Case::HdrSupport::setupComposerCallExpectations(this);
- Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
-
- EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
- expectHotplugReceived<Case, true>(mEventThread);
- expectHotplugReceived<Case, true>(mSFEventThread);
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
- EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
-
- expectHotplugReceived<Case, false>(mEventThread);
- expectHotplugReceived<Case, false>(mSFEventThread);
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
- // The display device should have been set up in the list of displays.
- ASSERT_TRUE(hasDisplayDevice(displayToken));
- const auto& device = getDisplayDevice(displayToken);
- EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
- EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
-
- std::optional<DisplayDeviceState::Physical> expectedPhysical;
- if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
- const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get());
- ASSERT_TRUE(displayId);
- const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
- ASSERT_TRUE(hwcDisplayId);
- expectedPhysical = {.id = *displayId,
- .type = *connectionType,
- .hwcDisplayId = *hwcDisplayId};
- }
-
- // The display should have been set up in the current display state
- ASSERT_TRUE(hasCurrentDisplayState(displayToken));
- const auto& current = getCurrentDisplayState(displayToken);
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
- EXPECT_EQ(expectedPhysical, current.physical);
-
- // The display should have been set up in the drawing display state
- ASSERT_TRUE(hasDrawingDisplayState(displayToken));
- const auto& draw = getDrawingDisplayState(displayToken);
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
- EXPECT_EQ(expectedPhysical, draw.physical);
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
- // HWComposer should have an entry for the display
- EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
-
- // SF should have a display token.
- const auto displayId = Case::Display::DISPLAY_ID::get();
- ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
- auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId];
-
- verifyDisplayIsConnected<Case>(displayToken);
-}
-
-void HandleTransactionLockedTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
- EXPECT_FALSE(hasDisplayDevice(displayToken));
- EXPECT_FALSE(hasCurrentDisplayState(displayToken));
- EXPECT_FALSE(hasDrawingDisplayState(displayToken));
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::processesHotplugConnectCommon() {
- // --------------------------------------------------------------------
- // Preconditions
-
- setupCommonPreconditions<Case>();
-
- // A hotplug connect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- setupCommonCallExpectationsForConnectProcessing<Case>();
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- verifyPhysicalDisplayIsConnected<Case>();
-
- // --------------------------------------------------------------------
- // Cleanup conditions
-
- EXPECT_CALL(*mComposer,
- setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
- .WillOnce(Return(Error::NONE));
- EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::ignoresHotplugConnectCommon() {
- // --------------------------------------------------------------------
- // Preconditions
-
- setupCommonPreconditions<Case>();
-
- // A hotplug connect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // HWComposer should not have an entry for the display
- EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::processesHotplugDisconnectCommon() {
- // --------------------------------------------------------------------
- // Preconditions
-
- setupCommonPreconditions<Case>();
-
- // A hotplug disconnect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
-
- // The display is already completely set up.
- Case::Display::injectHwcDisplay(this);
- auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
- existing.inject();
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- EXPECT_CALL(*mComposer, getDisplayIdentificationData(Case::Display::HWC_DISPLAY_ID, _, _))
- .Times(0);
-
- setupCommonCallExpectationsForDisconnectProcessing<Case>();
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // HWComposer should not have an entry for the display
- EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
-
- // SF should not have a display token.
- const auto displayId = Case::Display::DISPLAY_ID::get();
- ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
-
- // The existing token should have been removed
- verifyDisplayIsNotConnected(existing.token());
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectPrimaryDisplay) {
- processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest,
- processesHotplugConnectPrimaryDisplayWithExternalAlreadyConnected) {
- // Inject an external display.
- ExternalDisplayVariant::injectHwcDisplay(this);
-
- processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) {
- // Inject a primary display.
- PrimaryDisplayVariant::injectHwcDisplay(this);
-
- processesHotplugConnectCommon<SimpleExternalDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) {
- // Inject both a primary and external display.
- PrimaryDisplayVariant::injectHwcDisplay(this);
- ExternalDisplayVariant::injectHwcDisplay(this);
-
- // TODO: This is an unnecessary call.
- EXPECT_CALL(*mComposer,
- getDisplayIdentificationData(TertiaryDisplayVariant::HWC_DISPLAY_ID, _, _))
- .WillOnce(DoAll(SetArgPointee<1>(TertiaryDisplay::PORT),
- SetArgPointee<2>(TertiaryDisplay::GET_IDENTIFICATION_DATA()),
- Return(Error::NONE)));
-
- ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
- processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectExternalDisplay) {
- processesHotplugDisconnectCommon<SimpleExternalDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectThenDisconnectPrimary) {
- using Case = SimplePrimaryDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- setupCommonPreconditions<Case>();
-
- // A hotplug connect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
- // A hotplug disconnect event is also enqueued for the same display
- Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- setupCommonCallExpectationsForConnectProcessing<Case>();
- setupCommonCallExpectationsForDisconnectProcessing<Case>();
-
- EXPECT_CALL(*mComposer,
- setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
- .WillOnce(Return(Error::NONE));
- EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // HWComposer should not have an entry for the display
- EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
-
- // SF should not have a display token.
- const auto displayId = Case::Display::DISPLAY_ID::get();
- ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
- using Case = SimplePrimaryDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- setupCommonPreconditions<Case>();
-
- // The display is already completely set up.
- Case::Display::injectHwcDisplay(this);
- auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
- existing.inject();
-
- // A hotplug disconnect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
- // A hotplug connect event is also enqueued for the same display
- Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- setupCommonCallExpectationsForConnectProcessing<Case>();
- setupCommonCallExpectationsForDisconnectProcessing<Case>();
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The existing token should have been removed
- verifyDisplayIsNotConnected(existing.token());
- const auto displayId = Case::Display::DISPLAY_ID::get();
- ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
- EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]);
-
- // A new display should be connected in its place
-
- verifyPhysicalDisplayIsConnected<Case>();
-
- // --------------------------------------------------------------------
- // Cleanup conditions
-
- EXPECT_CALL(*mComposer,
- setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
- .WillOnce(Return(Error::NONE));
- EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
-}
-
-TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) {
- using Case = HwcVirtualDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // The HWC supports at least one virtual display
- injectMockComposer(1);
-
- setupCommonPreconditions<Case>();
-
- // A virtual display was added to the current state, and it has a
- // surface(producer)
- sp<BBinder> displayToken = new BBinder();
-
- DisplayDeviceState state;
- state.isSecure = static_cast<bool>(Case::Display::SECURE);
-
- sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
- state.surface = surface;
- mFlinger.mutableCurrentState().displays.add(displayToken, state);
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
- Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
-
- EXPECT_CALL(*surface, query(NATIVE_WINDOW_WIDTH, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::WIDTH), Return(NO_ERROR)));
- EXPECT_CALL(*surface, query(NATIVE_WINDOW_HEIGHT, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::HEIGHT), Return(NO_ERROR)));
- EXPECT_CALL(*surface, query(NATIVE_WINDOW_FORMAT, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT),
- Return(NO_ERROR)));
- EXPECT_CALL(*surface, query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
-
- EXPECT_CALL(*surface, setAsyncMode(true)).Times(1);
-
- EXPECT_CALL(*mProducer, connect(_, NATIVE_WINDOW_API_EGL, false, _)).Times(1);
- EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1);
-
- Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this);
- Case::WideColorSupport::setupComposerCallExpectations(this);
- Case::HdrSupport::setupComposerCallExpectations(this);
- Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The display device should have been set up in the list of displays.
- verifyDisplayIsConnected<Case>(displayToken);
-
- // --------------------------------------------------------------------
- // Cleanup conditions
-
- EXPECT_CALL(*mComposer, destroyVirtualDisplay(Case::Display::HWC_DISPLAY_ID))
- .WillOnce(Return(Error::NONE));
- EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
-
- // Cleanup
- mFlinger.mutableCurrentState().displays.removeItem(displayToken);
- mFlinger.mutableDrawingState().displays.removeItem(displayToken);
-}
-
-TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) {
- using Case = HwcVirtualDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // The HWC supports at least one virtual display
- injectMockComposer(1);
-
- setupCommonPreconditions<Case>();
-
- // A virtual display was added to the current state, but it does not have a
- // surface.
- sp<BBinder> displayToken = new BBinder();
-
- DisplayDeviceState state;
- state.isSecure = static_cast<bool>(Case::Display::SECURE);
-
- mFlinger.mutableCurrentState().displays.add(displayToken, state);
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // There will not be a display device set up.
- EXPECT_FALSE(hasDisplayDevice(displayToken));
-
- // The drawing display state will be set from the current display state.
- ASSERT_TRUE(hasDrawingDisplayState(displayToken));
- const auto& draw = getDrawingDisplayState(displayToken);
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
-}
-
-TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
- using Case = HwcVirtualDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A virtual display is set up but is removed from the current state.
- const auto displayId = Case::Display::DISPLAY_ID::get();
- ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId));
- mFlinger.mutableHwcDisplayData().try_emplace(displayId);
- Case::Display::injectHwcDisplay(this);
- auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
- existing.inject();
- mFlinger.mutableCurrentState().displays.removeItem(existing.token());
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The existing token should have been removed
- verifyDisplayIsNotConnected(existing.token());
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) {
- using Case = NonHwcVirtualDisplayCase;
-
- constexpr uint32_t oldLayerStack = 0u;
- constexpr uint32_t newLayerStack = 123u;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // There is a change to the layerStack state
- display.mutableDrawingDisplayState().layerStack = oldLayerStack;
- display.mutableCurrentDisplayState().layerStack = newLayerStack;
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- EXPECT_EQ(newLayerStack, display.mutableDisplayDevice()->getLayerStack());
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
- using Case = NonHwcVirtualDisplayCase;
-
- constexpr ui::Rotation oldTransform = ui::ROTATION_0;
- constexpr ui::Rotation newTransform = ui::ROTATION_180;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // There is a change to the orientation state
- display.mutableDrawingDisplayState().orientation = oldTransform;
- display.mutableCurrentDisplayState().orientation = newTransform;
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation());
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackRectChanges) {
- using Case = NonHwcVirtualDisplayCase;
-
- const Rect oldLayerStackRect(0, 0, 0, 0);
- const Rect newLayerStackRect(0, 0, 123, 456);
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // There is a change to the layerStackSpaceRect state
- display.mutableDrawingDisplayState().layerStackSpaceRect = oldLayerStackRect;
- display.mutableCurrentDisplayState().layerStackSpaceRect = newLayerStackRect;
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- EXPECT_EQ(newLayerStackRect, display.mutableDisplayDevice()->getLayerStackSpaceRect());
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayFrameChanges) {
- using Case = NonHwcVirtualDisplayCase;
-
- const Rect oldFrame(0, 0, 0, 0);
- const Rect newFrame(0, 0, 123, 456);
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // There is a change to the layerStackSpaceRect state
- display.mutableDrawingDisplayState().orientedDisplaySpaceRect = oldFrame;
- display.mutableCurrentDisplayState().orientedDisplaySpaceRect = newFrame;
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- EXPECT_EQ(newFrame, display.mutableDisplayDevice()->getOrientedDisplaySpaceRect());
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) {
- using Case = NonHwcVirtualDisplayCase;
-
- constexpr int oldWidth = 0;
- constexpr int oldHeight = 10;
- constexpr int newWidth = 123;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto nativeWindow = new mock::NativeWindow();
- auto displaySurface = new compositionengine::mock::DisplaySurface();
- sp<GraphicBuffer> buf = new GraphicBuffer();
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.setNativeWindow(nativeWindow);
- display.setDisplaySurface(displaySurface);
- // Setup injection expections
- EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
- .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
- EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
- .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
- EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
- display.inject();
-
- // There is a change to the layerStackSpaceRect state
- display.mutableDrawingDisplayState().width = oldWidth;
- display.mutableDrawingDisplayState().height = oldHeight;
- display.mutableCurrentDisplayState().width = newWidth;
- display.mutableCurrentDisplayState().height = oldHeight;
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1);
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) {
- using Case = NonHwcVirtualDisplayCase;
-
- constexpr int oldWidth = 0;
- constexpr int oldHeight = 10;
- constexpr int newHeight = 123;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto nativeWindow = new mock::NativeWindow();
- auto displaySurface = new compositionengine::mock::DisplaySurface();
- sp<GraphicBuffer> buf = new GraphicBuffer();
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.setNativeWindow(nativeWindow);
- display.setDisplaySurface(displaySurface);
- // Setup injection expections
- EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
- .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
- EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
- .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
- EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
- display.inject();
-
- // There is a change to the layerStackSpaceRect state
- display.mutableDrawingDisplayState().width = oldWidth;
- display.mutableDrawingDisplayState().height = oldHeight;
- display.mutableCurrentDisplayState().width = oldWidth;
- display.mutableCurrentDisplayState().height = newHeight;
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1);
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::setDisplayStateLocked
- */
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWithUnknownDisplay) {
- // --------------------------------------------------------------------
- // Preconditions
-
- // We have an unknown display token not associated with a known display
- sp<BBinder> displayToken = new BBinder();
-
- // The requested display state references the unknown display.
- DisplayState state;
- state.what = DisplayState::eLayerStackChanged;
- state.token = displayToken;
- state.layerStack = 456;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags are empty
- EXPECT_EQ(0u, flags);
-
- // The display token still doesn't match anything known.
- EXPECT_FALSE(hasCurrentDisplayState(displayToken));
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWhenNoChanges) {
- using Case = SimplePrimaryDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is already set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // No changes are made to the display
- DisplayState state;
- state.what = 0;
- state.token = display.token();
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags are empty
- EXPECT_EQ(0u, flags);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfSurfaceDidNotChange) {
- using Case = SimplePrimaryDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is already set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // There is a surface that can be set.
- sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
-
- // The current display state has the surface set
- display.mutableCurrentDisplayState().surface = surface;
-
- // The incoming request sets the same surface
- DisplayState state;
- state.what = DisplayState::eSurfaceChanged;
- state.token = display.token();
- state.surface = surface;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags are empty
- EXPECT_EQ(0u, flags);
-
- // The current display state is unchanged.
- EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get());
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfSurfaceChanged) {
- using Case = SimplePrimaryDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is already set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // There is a surface that can be set.
- sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
-
- // The current display state does not have a surface
- display.mutableCurrentDisplayState().surface = nullptr;
-
- // The incoming request sets a surface
- DisplayState state;
- state.what = DisplayState::eSurfaceChanged;
- state.token = display.token();
- state.surface = surface;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags indicate a transaction is needed
- EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
- // The current display layer stack state is set to the new value
- EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get());
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfLayerStackDidNotChange) {
- using Case = SimplePrimaryDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is already set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The display has a layer stack set
- display.mutableCurrentDisplayState().layerStack = 456u;
-
- // The incoming request sets the same layer stack
- DisplayState state;
- state.what = DisplayState::eLayerStackChanged;
- state.token = display.token();
- state.layerStack = 456u;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags are empty
- EXPECT_EQ(0u, flags);
-
- // The current display state is unchanged
- EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfLayerStackChanged) {
- using Case = SimplePrimaryDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The display has a layer stack set
- display.mutableCurrentDisplayState().layerStack = 654u;
-
- // The incoming request sets a different layer stack
- DisplayState state;
- state.what = DisplayState::eLayerStackChanged;
- state.token = display.token();
- state.layerStack = 456u;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags indicate a transaction is needed
- EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
- // The desired display state has been set to the new value.
- EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) {
- using Case = SimplePrimaryDisplayCase;
- constexpr ui::Rotation initialOrientation = ui::ROTATION_180;
- const Rect initialOrientedDisplayRect = {1, 2, 3, 4};
- const Rect initialLayerStackRect = {5, 6, 7, 8};
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The current display state projection state is all set
- display.mutableCurrentDisplayState().orientation = initialOrientation;
- display.mutableCurrentDisplayState().orientedDisplaySpaceRect = initialOrientedDisplayRect;
- display.mutableCurrentDisplayState().layerStackSpaceRect = initialLayerStackRect;
-
- // The incoming request sets the same projection state
- DisplayState state;
- state.what = DisplayState::eDisplayProjectionChanged;
- state.token = display.token();
- state.orientation = initialOrientation;
- state.orientedDisplaySpaceRect = initialOrientedDisplayRect;
- state.layerStackSpaceRect = initialLayerStackRect;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags are empty
- EXPECT_EQ(0u, flags);
-
- // The current display state is unchanged
- EXPECT_EQ(initialOrientation, display.getCurrentDisplayState().orientation);
-
- EXPECT_EQ(initialOrientedDisplayRect,
- display.getCurrentDisplayState().orientedDisplaySpaceRect);
- EXPECT_EQ(initialLayerStackRect, display.getCurrentDisplayState().layerStackSpaceRect);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfOrientationChanged) {
- using Case = SimplePrimaryDisplayCase;
- constexpr ui::Rotation initialOrientation = ui::ROTATION_90;
- constexpr ui::Rotation desiredOrientation = ui::ROTATION_180;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The current display state has an orientation set
- display.mutableCurrentDisplayState().orientation = initialOrientation;
-
- // The incoming request sets a different orientation
- DisplayState state;
- state.what = DisplayState::eDisplayProjectionChanged;
- state.token = display.token();
- state.orientation = desiredOrientation;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags indicate a transaction is needed
- EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
- // The current display state has the new value.
- EXPECT_EQ(desiredOrientation, display.getCurrentDisplayState().orientation);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfFrameChanged) {
- using Case = SimplePrimaryDisplayCase;
- const Rect initialOrientedDisplayRect = {0, 0, 0, 0};
- const Rect desiredOrientedDisplayRect = {5, 6, 7, 8};
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The current display state does not have a orientedDisplaySpaceRect
- display.mutableCurrentDisplayState().orientedDisplaySpaceRect = initialOrientedDisplayRect;
-
- // The incoming request sets a orientedDisplaySpaceRect
- DisplayState state;
- state.what = DisplayState::eDisplayProjectionChanged;
- state.token = display.token();
- state.orientedDisplaySpaceRect = desiredOrientedDisplayRect;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags indicate a transaction is needed
- EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
- // The current display state has the new value.
- EXPECT_EQ(desiredOrientedDisplayRect,
- display.getCurrentDisplayState().orientedDisplaySpaceRect);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfLayerStackRectChanged) {
- using Case = SimplePrimaryDisplayCase;
- const Rect initialLayerStackRect = {0, 0, 0, 0};
- const Rect desiredLayerStackRect = {5, 6, 7, 8};
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The current display state does not have a layerStackSpaceRect
- display.mutableCurrentDisplayState().layerStackSpaceRect = initialLayerStackRect;
-
- // The incoming request sets a layerStackSpaceRect
- DisplayState state;
- state.what = DisplayState::eDisplayProjectionChanged;
- state.token = display.token();
- state.layerStackSpaceRect = desiredLayerStackRect;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags indicate a transaction is needed
- EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
- // The current display state has the new value.
- EXPECT_EQ(desiredLayerStackRect, display.getCurrentDisplayState().layerStackSpaceRect);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfSizeDidNotChange) {
- using Case = SimplePrimaryDisplayCase;
- constexpr uint32_t initialWidth = 1024;
- constexpr uint32_t initialHeight = 768;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The current display state has a size set
- display.mutableCurrentDisplayState().width = initialWidth;
- display.mutableCurrentDisplayState().height = initialHeight;
-
- // The incoming request sets the same display size
- DisplayState state;
- state.what = DisplayState::eDisplaySizeChanged;
- state.token = display.token();
- state.width = initialWidth;
- state.height = initialHeight;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags are empty
- EXPECT_EQ(0u, flags);
-
- // The current display state is unchanged
- EXPECT_EQ(initialWidth, display.getCurrentDisplayState().width);
- EXPECT_EQ(initialHeight, display.getCurrentDisplayState().height);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfWidthChanged) {
- using Case = SimplePrimaryDisplayCase;
- constexpr uint32_t initialWidth = 0;
- constexpr uint32_t desiredWidth = 1024;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The display does not yet have a width
- display.mutableCurrentDisplayState().width = initialWidth;
-
- // The incoming request sets a display width
- DisplayState state;
- state.what = DisplayState::eDisplaySizeChanged;
- state.token = display.token();
- state.width = desiredWidth;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags indicate a transaction is needed
- EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
- // The current display state has the new value.
- EXPECT_EQ(desiredWidth, display.getCurrentDisplayState().width);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfHeightChanged) {
- using Case = SimplePrimaryDisplayCase;
- constexpr uint32_t initialHeight = 0;
- constexpr uint32_t desiredHeight = 768;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A display is set up
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The display does not yet have a height
- display.mutableCurrentDisplayState().height = initialHeight;
-
- // The incoming request sets a display height
- DisplayState state;
- state.what = DisplayState::eDisplaySizeChanged;
- state.token = display.token();
- state.height = desiredHeight;
-
- // --------------------------------------------------------------------
- // Invocation
-
- uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The returned flags indicate a transaction is needed
- EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
- // The current display state has the new value.
- EXPECT_EQ(desiredHeight, display.getCurrentDisplayState().height);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::onInitializeDisplays
- */
-
-TEST_F(DisplayTransactionTest, onInitializeDisplaysSetsUpPrimaryDisplay) {
- using Case = SimplePrimaryDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A primary display is set up
- Case::Display::injectHwcDisplay(this);
- auto primaryDisplay = Case::Display::makeFakeExistingDisplayInjector(this);
- primaryDisplay.inject();
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- // We expect the surface interceptor to possibly be used, but we treat it as
- // disabled since it is called as a side effect rather than directly by this
- // function.
- EXPECT_CALL(*mSurfaceInterceptor, isEnabled()).WillOnce(Return(false));
-
- // We expect a call to get the active display config.
- Case::Display::setupHwcGetActiveConfigCallExpectations(this);
-
- // We expect invalidate() to be invoked once to trigger display transaction
- // processing.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-
- EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.onInitializeDisplays();
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The primary display should have a current state
- ASSERT_TRUE(hasCurrentDisplayState(primaryDisplay.token()));
- const auto& primaryDisplayState = getCurrentDisplayState(primaryDisplay.token());
- // The layer stack state should be set to zero
- EXPECT_EQ(0u, primaryDisplayState.layerStack);
- // The orientation state should be set to zero
- EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation);
-
- // The orientedDisplaySpaceRect state should be set to INVALID
- EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.orientedDisplaySpaceRect);
-
- // The layerStackSpaceRect state should be set to INVALID
- EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.layerStackSpaceRect);
-
- // The width and height should both be zero
- EXPECT_EQ(0u, primaryDisplayState.width);
- EXPECT_EQ(0u, primaryDisplayState.height);
-
- // The display should be set to PowerMode::ON
- ASSERT_TRUE(hasDisplayDevice(primaryDisplay.token()));
- auto displayDevice = primaryDisplay.mutableDisplayDevice();
- EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode());
-
- // The display refresh period should be set in the orientedDisplaySpaceRect tracker.
- FrameStats stats;
- mFlinger.getAnimFrameTracker().getStats(&stats);
- EXPECT_EQ(DEFAULT_REFRESH_RATE, stats.refreshPeriodNano);
-
- // The display transaction needed flag should be set.
- EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-
- // The compositor timing should be set to default values
- const auto& compositorTiming = mFlinger.getCompositorTiming();
- EXPECT_EQ(-DEFAULT_REFRESH_RATE, compositorTiming.deadline);
- EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.interval);
- EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.presentLatency);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::setPowerModeInternal
- */
-
-// Used when we simulate a display that supports doze.
-template <typename Display>
-struct DozeIsSupportedVariant {
- static constexpr bool DOZE_SUPPORTED = true;
- static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE =
- IComposerClient::PowerMode::DOZE;
- static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
- IComposerClient::PowerMode::DOZE_SUSPEND;
-
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(
- std::vector<DisplayCapability>({DisplayCapability::DOZE})),
- Return(Error::NONE)));
- }
-};
-
-template <typename Display>
-// Used when we simulate a display that does not support doze.
-struct DozeNotSupportedVariant {
- static constexpr bool DOZE_SUPPORTED = false;
- static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE =
- IComposerClient::PowerMode::ON;
- static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
- IComposerClient::PowerMode::ON;
-
- static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
- Return(Error::NONE)));
- }
-};
-
-struct EventThreadBaseSupportedVariant {
- static void setupVsyncAndEventThreadNoCallExpectations(DisplayTransactionTest* test) {
- // The callback should not be notified to toggle VSYNC.
- EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(_)).Times(0);
-
- // The event thread should not be notified.
- EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(0);
- EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(0);
- }
-};
-
-struct EventThreadNotSupportedVariant : public EventThreadBaseSupportedVariant {
- static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
- // These calls are only expected for the primary display.
-
- // Instead expect no calls.
- setupVsyncAndEventThreadNoCallExpectations(test);
- }
-
- static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
- // These calls are only expected for the primary display.
-
- // Instead expect no calls.
- setupVsyncAndEventThreadNoCallExpectations(test);
- }
-};
-
-struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant {
- static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
- // The callback should be notified to enable VSYNC.
- EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(true)).Times(1);
-
- // The event thread should be notified that the screen was acquired.
- EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(1);
- }
-
- static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
- // The callback should be notified to disable VSYNC.
- EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(false)).Times(1);
-
- // The event thread should not be notified that the screen was released.
- EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(1);
- }
-};
-
-struct DispSyncIsSupportedVariant {
- static void setupResetModelCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mVsyncController, startPeriodTransition(DEFAULT_REFRESH_RATE)).Times(1);
- EXPECT_CALL(*test->mVSyncTracker, resetModel()).Times(1);
- }
-};
-
-struct DispSyncNotSupportedVariant {
- static void setupResetModelCallExpectations(DisplayTransactionTest* /* test */) {}
-};
-
-// --------------------------------------------------------------------
-// Note:
-//
-// There are a large number of transitions we could test, however we only test a
-// selected subset which provides complete test coverage of the implementation.
-// --------------------------------------------------------------------
-
-template <PowerMode initialPowerMode, PowerMode targetPowerMode>
-struct TransitionVariantCommon {
- static constexpr auto INITIAL_POWER_MODE = initialPowerMode;
- static constexpr auto TARGET_POWER_MODE = targetPowerMode;
-
- static void verifyPostconditions(DisplayTransactionTest*) {}
-};
-
-struct TransitionOffToOnVariant : public TransitionVariantCommon<PowerMode::OFF, PowerMode::ON> {
- template <typename Case>
- static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
- Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
- Case::DispSync::setupResetModelCallExpectations(test);
- Case::setupRepaintEverythingCallExpectations(test);
- }
-
- static void verifyPostconditions(DisplayTransactionTest* test) {
- EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
- EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
- }
-};
-
-struct TransitionOffToDozeSuspendVariant
- : public TransitionVariantCommon<PowerMode::OFF, PowerMode::DOZE_SUSPEND> {
- template <typename Case>
- static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
- Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
- Case::setupRepaintEverythingCallExpectations(test);
- }
-
- static void verifyPostconditions(DisplayTransactionTest* test) {
- EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
- EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
- }
-};
-
-struct TransitionOnToOffVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::OFF> {
- template <typename Case>
- static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
- Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
- }
-
- static void verifyPostconditions(DisplayTransactionTest* test) {
- EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
- }
-};
-
-struct TransitionDozeSuspendToOffVariant
- : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::OFF> {
- template <typename Case>
- static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
- Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
- }
-
- static void verifyPostconditions(DisplayTransactionTest* test) {
- EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
- }
-};
-
-struct TransitionOnToDozeVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE> {
- template <typename Case>
- static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
- Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
- }
-};
-
-struct TransitionDozeSuspendToDozeVariant
- : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::DOZE> {
- template <typename Case>
- static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
- Case::DispSync::setupResetModelCallExpectations(test);
- Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
- }
-};
-
-struct TransitionDozeToOnVariant : public TransitionVariantCommon<PowerMode::DOZE, PowerMode::ON> {
- template <typename Case>
- static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
- Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
- }
-};
-
-struct TransitionDozeSuspendToOnVariant
- : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::ON> {
- template <typename Case>
- static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
- Case::DispSync::setupResetModelCallExpectations(test);
- Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
- }
-};
-
-struct TransitionOnToDozeSuspendVariant
- : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE_SUSPEND> {
- template <typename Case>
- static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
- Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
- }
-};
-
-struct TransitionOnToUnknownVariant
- : public TransitionVariantCommon<PowerMode::ON, static_cast<PowerMode>(POWER_MODE_LEET)> {
- template <typename Case>
- static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
- Case::setupNoComposerPowerModeCallExpectations(test);
- }
-};
-
-// --------------------------------------------------------------------
-// Note:
-//
-// Rather than testing the cartesian product of of
-// DozeIsSupported/DozeNotSupported with all other options, we use one for one
-// display type, and the other for another display type.
-// --------------------------------------------------------------------
-
-template <typename DisplayVariant, typename DozeVariant, typename EventThreadVariant,
- typename DispSyncVariant, typename TransitionVariant>
-struct DisplayPowerCase {
- using Display = DisplayVariant;
- using Doze = DozeVariant;
- using EventThread = EventThreadVariant;
- using DispSync = DispSyncVariant;
- using Transition = TransitionVariant;
-
- static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, PowerMode mode) {
- Display::injectHwcDisplayWithNoDefaultCapabilities(test);
- auto display = Display::makeFakeExistingDisplayInjector(test);
- display.inject();
- display.mutableDisplayDevice()->setPowerMode(mode);
- return display;
- }
-
- static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
- test->mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = enabled;
- }
-
- static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
- }
-
- static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test,
- PowerMode mode) {
- EXPECT_CALL(*test->mSurfaceInterceptor, isEnabled()).WillOnce(Return(true));
- EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, static_cast<int32_t>(mode)))
- .Times(1);
- }
-
- static void setupComposerCallExpectations(DisplayTransactionTest* test, PowerMode mode) {
- // Any calls to get the active config will return a default value.
- EXPECT_CALL(*test->mComposer, getActiveConfig(Display::HWC_DISPLAY_ID, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(Display::HWC_ACTIVE_CONFIG_ID),
- Return(Error::NONE)));
-
- // Any calls to get whether the display supports dozing will return the value set by the
- // policy variant.
- EXPECT_CALL(*test->mComposer, getDozeSupport(Display::HWC_DISPLAY_ID, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(Doze::DOZE_SUPPORTED), Return(Error::NONE)));
-
- EXPECT_CALL(*test->mComposer, setPowerMode(Display::HWC_DISPLAY_ID, mode)).Times(1);
- }
-
- static void setupNoComposerPowerModeCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, setPowerMode(Display::HWC_DISPLAY_ID, _)).Times(0);
- }
-};
-
-// A sample configuration for the primary display.
-// In addition to having event thread support, we emulate doze support.
-template <typename TransitionVariant>
-using PrimaryDisplayPowerCase =
- DisplayPowerCase<PrimaryDisplayVariant, DozeIsSupportedVariant<PrimaryDisplayVariant>,
- EventThreadIsSupportedVariant, DispSyncIsSupportedVariant,
- TransitionVariant>;
-
-// A sample configuration for the external display.
-// In addition to not having event thread support, we emulate not having doze
-// support.
-template <typename TransitionVariant>
-using ExternalDisplayPowerCase =
- DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant<ExternalDisplayVariant>,
- EventThreadNotSupportedVariant, DispSyncNotSupportedVariant,
- TransitionVariant>;
-
-class SetPowerModeInternalTest : public DisplayTransactionTest {
-public:
- template <typename Case>
- void transitionDisplayCommon();
-};
-
-template <PowerMode PowerMode>
-struct PowerModeInitialVSyncEnabled : public std::false_type {};
-
-template <>
-struct PowerModeInitialVSyncEnabled<PowerMode::ON> : public std::true_type {};
-
-template <>
-struct PowerModeInitialVSyncEnabled<PowerMode::DOZE> : public std::true_type {};
-
-template <typename Case>
-void SetPowerModeInternalTest::transitionDisplayCommon() {
- // --------------------------------------------------------------------
- // Preconditions
-
- Case::Doze::setupComposerCallExpectations(this);
- auto display =
- Case::injectDisplayWithInitialPowerMode(this, Case::Transition::INITIAL_POWER_MODE);
- Case::setInitialPrimaryHWVsyncEnabled(this,
- PowerModeInitialVSyncEnabled<
- Case::Transition::INITIAL_POWER_MODE>::value);
-
- // --------------------------------------------------------------------
- // Call Expectations
-
- Case::setupSurfaceInterceptorCallExpectations(this, Case::Transition::TARGET_POWER_MODE);
- Case::Transition::template setupCallExpectations<Case>(this);
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.setPowerModeInternal(display.mutableDisplayDevice(),
- Case::Transition::TARGET_POWER_MODE);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- Case::Transition::verifyPostconditions(this);
-}
-
-TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfNoChange) {
- using Case = SimplePrimaryDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // A primary display device is set up
- Case::Display::injectHwcDisplay(this);
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The display is already set to PowerMode::ON
- display.mutableDisplayDevice()->setPowerMode(PowerMode::ON);
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::ON);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
-}
-
-TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) {
- using Case = HwcVirtualDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // Insert display data so that the HWC thinks it created the virtual display.
- const auto displayId = Case::Display::DISPLAY_ID::get();
- ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId));
- mFlinger.mutableHwcDisplayData().try_emplace(displayId);
-
- // A virtual display device is set up
- Case::Display::injectHwcDisplay(this);
- auto display = Case::Display::makeFakeExistingDisplayInjector(this);
- display.inject();
-
- // The display is set to PowerMode::ON
- getDisplayDevice(display.token())->setPowerMode(PowerMode::ON);
-
- // --------------------------------------------------------------------
- // Invocation
-
- mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::OFF);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
- transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendPrimaryDisplay) {
- transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffPrimaryDisplay) {
- transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToOffVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffPrimaryDisplay) {
- transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozePrimaryDisplay) {
- transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozePrimaryDisplay) {
- transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnPrimaryDisplay) {
- transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnPrimaryDisplay) {
- transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendPrimaryDisplay) {
- transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownPrimaryDisplay) {
- transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToUnknownVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnExternalDisplay) {
- transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendExternalDisplay) {
- transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffExternalDisplay) {
- transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToOffVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffExternalDisplay) {
- transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeExternalDisplay) {
- transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) {
- transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnExternalDisplay) {
- transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) {
- transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) {
- transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownExternalDisplay) {
- transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToUnknownVariant>>();
-}
-
-} // namespace
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
new file mode 100644
index 0000000..01cdb28
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -0,0 +1,756 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <type_traits>
+#include "DisplayIdentificationTest.h"
+
+#include <binder/IPCThreadState.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/impl/Display.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/mock/Display.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <compositionengine/mock/RenderSurface.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/mock/GraphicBufferConsumer.h>
+#include <gui/mock/GraphicBufferProducer.h>
+#include <log/log.h>
+#include <private/android_filesystem_config.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <ui/DebugUtils.h>
+
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+#include "mock/MockNativeWindowSurface.h"
+#include "mock/MockSchedulerCallback.h"
+#include "mock/MockSurfaceInterceptor.h"
+#include "mock/MockVsyncController.h"
+#include "mock/system/window/MockNativeWindow.h"
+
+namespace android {
+
+// TODO: Do not polute the android namespace
+namespace hal = android::hardware::graphics::composer::hal;
+
+using testing::_;
+using testing::AnyNumber;
+using testing::DoAll;
+using testing::Mock;
+using testing::ResultOf;
+using testing::Return;
+using testing::SetArgPointee;
+
+using hal::ColorMode;
+using hal::Connection;
+using hal::DisplayCapability;
+using hal::DisplayType;
+using hal::Error;
+using hal::Hdr;
+using hal::HWDisplayId;
+using hal::IComposer;
+using hal::IComposerClient;
+using hal::PerFrameMetadataKey;
+using hal::PowerMode;
+
+class DisplayTransactionTest : public testing::Test {
+public:
+ ~DisplayTransactionTest() override;
+
+ // --------------------------------------------------------------------
+ // Mock/Fake injection
+
+ void injectMockScheduler();
+ void injectMockComposer(int virtualDisplayCount);
+ void injectFakeBufferQueueFactory();
+ void injectFakeNativeWindowSurfaceFactory();
+ sp<DisplayDevice> injectDefaultInternalDisplay(
+ std::function<void(TestableSurfaceFlinger::FakeDisplayDeviceInjector&)>);
+
+ // --------------------------------------------------------------------
+ // Postcondition helpers
+
+ bool hasPhysicalHwcDisplay(hal::HWDisplayId hwcDisplayId);
+ bool hasTransactionFlagSet(int flag);
+ bool hasDisplayDevice(sp<IBinder> displayToken);
+ sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
+ bool hasCurrentDisplayState(sp<IBinder> displayToken);
+ const DisplayDeviceState& getCurrentDisplayState(sp<IBinder> displayToken);
+ bool hasDrawingDisplayState(sp<IBinder> displayToken);
+ const DisplayDeviceState& getDrawingDisplayState(sp<IBinder> displayToken);
+
+ // --------------------------------------------------------------------
+ // Test instances
+
+ TestableSurfaceFlinger mFlinger;
+ sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
+ sp<GraphicBuffer> mBuffer = new GraphicBuffer();
+ Hwc2::mock::PowerAdvisor mPowerAdvisor;
+
+ // 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.
+ renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+ Hwc2::mock::Composer* mComposer = nullptr;
+ mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+ sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor;
+
+ mock::VsyncController* mVsyncController = new mock::VsyncController;
+ mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker;
+ mock::SchedulerCallback mSchedulerCallback;
+ mock::EventThread* mEventThread = new mock::EventThread;
+ mock::EventThread* mSFEventThread = new mock::EventThread;
+
+ // These mocks are created only when expected to be created via a factory.
+ sp<mock::GraphicBufferConsumer> mConsumer;
+ sp<mock::GraphicBufferProducer> mProducer;
+ surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
+
+protected:
+ DisplayTransactionTest();
+};
+
+constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'667;
+constexpr int32_t DEFAULT_DPI = 320;
+constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565;
+
+constexpr int POWER_MODE_LEET = 1337; // An out of range power mode value
+
+/* ------------------------------------------------------------------------
+ * Boolean avoidance
+ *
+ * To make calls and template instantiations more readable, we define some
+ * local enums along with an implicit bool conversion.
+ */
+
+#define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true };
+
+BOOL_SUBSTITUTE(Async);
+BOOL_SUBSTITUTE(Critical);
+BOOL_SUBSTITUTE(Primary);
+BOOL_SUBSTITUTE(Secure);
+BOOL_SUBSTITUTE(Virtual);
+
+template <typename PhysicalDisplay>
+struct PhysicalDisplayIdType {};
+
+template <uint64_t displayId>
+using HalVirtualDisplayIdType = std::integral_constant<uint64_t, displayId>;
+
+struct GpuVirtualDisplayIdType {};
+
+template <typename>
+struct IsPhysicalDisplayId : std::bool_constant<false> {};
+
+template <typename PhysicalDisplay>
+struct IsPhysicalDisplayId<PhysicalDisplayIdType<PhysicalDisplay>> : std::bool_constant<true> {};
+
+template <typename>
+struct DisplayIdGetter;
+
+template <typename PhysicalDisplay>
+struct DisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
+ static PhysicalDisplayId get() {
+ if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+ return PhysicalDisplayId::fromPort(static_cast<bool>(PhysicalDisplay::PRIMARY)
+ ? LEGACY_DISPLAY_TYPE_PRIMARY
+ : LEGACY_DISPLAY_TYPE_EXTERNAL);
+ }
+
+ const auto info =
+ parseDisplayIdentificationData(PhysicalDisplay::PORT,
+ PhysicalDisplay::GET_IDENTIFICATION_DATA());
+ return info ? info->id : PhysicalDisplayId::fromPort(PhysicalDisplay::PORT);
+ }
+};
+
+template <uint64_t displayId>
+struct DisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
+ static HalVirtualDisplayId get() { return HalVirtualDisplayId(displayId); }
+};
+
+template <>
+struct DisplayIdGetter<GpuVirtualDisplayIdType> {
+ static GpuVirtualDisplayId get() { return GpuVirtualDisplayId(0); }
+};
+
+template <typename>
+struct DisplayConnectionTypeGetter {
+ static constexpr std::optional<DisplayConnectionType> value;
+};
+
+template <typename PhysicalDisplay>
+struct DisplayConnectionTypeGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
+ static constexpr std::optional<DisplayConnectionType> value = PhysicalDisplay::CONNECTION_TYPE;
+};
+
+template <typename>
+struct HwcDisplayIdGetter {
+ static constexpr std::optional<HWDisplayId> value;
+};
+
+constexpr HWDisplayId HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID = 1010;
+
+template <uint64_t displayId>
+struct HwcDisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
+ static constexpr std::optional<HWDisplayId> value = HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID;
+};
+
+template <typename PhysicalDisplay>
+struct HwcDisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
+ static constexpr std::optional<HWDisplayId> value = PhysicalDisplay::HWC_DISPLAY_ID;
+};
+
+// DisplayIdType can be:
+// 1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC.
+// 2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC.
+// 3) GpuVirtualDisplayIdType for virtual display without HWC backing.
+template <typename DisplayIdType, int width, int height, Critical critical, Async async,
+ Secure secure, Primary primary, int grallocUsage>
+struct DisplayVariant {
+ using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
+ using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
+ using HWC_DISPLAY_ID_OPT = HwcDisplayIdGetter<DisplayIdType>;
+
+ // The display width and height
+ static constexpr int WIDTH = width;
+ static constexpr int HEIGHT = height;
+
+ static constexpr int GRALLOC_USAGE = grallocUsage;
+
+ // Whether the display is virtual or physical
+ static constexpr Virtual VIRTUAL =
+ IsPhysicalDisplayId<DisplayIdType>{} ? Virtual::FALSE : Virtual::TRUE;
+
+ // When creating native window surfaces for the framebuffer, whether those should be critical
+ static constexpr Critical CRITICAL = critical;
+
+ // When creating native window surfaces for the framebuffer, whether those should be async
+ static constexpr Async ASYNC = async;
+
+ // Whether the display should be treated as secure
+ static constexpr Secure SECURE = secure;
+
+ // Whether the display is primary
+ static constexpr Primary PRIMARY = primary;
+
+ static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
+ auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
+ if (auto displayId = PhysicalDisplayId::tryCast(DISPLAY_ID::get())) {
+ ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal});
+ } else {
+ // We turn off the use of HwcVirtualDisplays, to prevent Composition Engine
+ // from calling into HWComposer. This way all virtual displays will get
+ // a GpuVirtualDisplayId, even if we are in the HwcVirtualDisplayVariant.
+ // In this case we later override it by calling display.setDisplayIdForTesting().
+ ceDisplayArgs.setUseHwcVirtualDisplays(false);
+
+ GpuVirtualDisplayId desiredDisplayId = GpuVirtualDisplayId::tryCast(DISPLAY_ID::get())
+ .value_or(GpuVirtualDisplayId(0));
+
+ ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
+ .WillByDefault(Return(desiredDisplayId));
+
+ auto& generator = test->mFlinger.gpuVirtualDisplayIdGenerator();
+ ceDisplayArgs.setGpuVirtualDisplayIdGenerator(generator);
+ }
+ ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor);
+
+ auto compositionDisplay =
+ compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+ ceDisplayArgs.build());
+
+ if (HalVirtualDisplayId::tryCast(DISPLAY_ID::get())) {
+ // CompositionEngine has assigned a placeholder GpuVirtualDisplayId and we need to
+ // override it with the correct HalVirtualDisplayId.
+ compositionDisplay->setDisplayIdForTesting(DISPLAY_ID::get());
+ }
+
+ auto injector =
+ TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger,
+ compositionDisplay,
+ CONNECTION_TYPE::value,
+ HWC_DISPLAY_ID_OPT::value,
+ static_cast<bool>(PRIMARY));
+
+ injector.setSecure(static_cast<bool>(SECURE));
+ injector.setNativeWindow(test->mNativeWindow);
+
+ // Creating a DisplayDevice requires getting default dimensions from the
+ // native window along with some other initial setup.
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT))
+ .WillRepeatedly(Return(0));
+
+ return injector;
+ }
+
+ // Called by tests to set up any native window creation call expectations.
+ static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow())
+ .WillOnce(Return(test->mNativeWindow));
+
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT))
+ .WillRepeatedly(Return(0));
+ }
+
+ static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*test->mConsumer, setConsumerName(_)).WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(*test->mConsumer, setConsumerUsageBits(GRALLOC_USAGE))
+ .WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(*test->mConsumer, setDefaultBufferSize(WIDTH, HEIGHT))
+ .WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(*test->mConsumer, setMaxAcquiredBufferCount(_))
+ .WillRepeatedly(Return(NO_ERROR));
+ }
+
+ static void setupFramebufferProducerBufferQueueCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mProducer, allocateBuffers(0, 0, 0, 0)).WillRepeatedly(Return());
+ }
+};
+
+template <HWDisplayId hwcDisplayId, DisplayType hwcDisplayType, typename DisplayVariant,
+ typename PhysicalDisplay = void>
+struct HwcDisplayVariant {
+ // The display id supplied by the HWC
+ static constexpr HWDisplayId HWC_DISPLAY_ID = hwcDisplayId;
+
+ // The HWC display type
+ static constexpr DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
+
+ // The HWC active configuration id
+ static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
+ static constexpr PowerMode INIT_POWER_MODE = hal::PowerMode::ON;
+
+ static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) {
+ test->mFlinger.mutablePendingHotplugEvents().emplace_back(
+ TestableSurfaceFlinger::HotplugEvent{HWC_DISPLAY_ID, connection});
+ }
+
+ // Called by tests to inject a HWC display setup
+ static void injectHwcDisplayWithNoDefaultCapabilities(DisplayTransactionTest* test) {
+ const auto displayId = DisplayVariant::DISPLAY_ID::get();
+ ASSERT_FALSE(GpuVirtualDisplayId::tryCast(displayId));
+ TestableSurfaceFlinger::FakeHwcDisplayInjector(displayId, HWC_DISPLAY_TYPE,
+ static_cast<bool>(DisplayVariant::PRIMARY))
+ .setHwcDisplayId(HWC_DISPLAY_ID)
+ .setWidth(DisplayVariant::WIDTH)
+ .setHeight(DisplayVariant::HEIGHT)
+ .setActiveConfig(HWC_ACTIVE_CONFIG_ID)
+ .setPowerMode(INIT_POWER_MODE)
+ .inject(&test->mFlinger, test->mComposer);
+ }
+
+ // Called by tests to inject a HWC display setup
+ static void injectHwcDisplay(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
+ Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY_ID, INIT_POWER_MODE))
+ .WillOnce(Return(Error::NONE));
+ injectHwcDisplayWithNoDefaultCapabilities(test);
+ }
+
+ static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
+ DisplayTransactionTest* test) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
+ .setPhysical({DisplayVariant::DISPLAY_ID::get(),
+ PhysicalDisplay::CONNECTION_TYPE})
+ .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT})
+ .setIsSecure(static_cast<bool>(DisplayVariant::SECURE))
+ .setPowerAdvisor(&test->mPowerAdvisor)
+ .setName(std::string("Injected display for ") +
+ test_info->test_case_name() + "." + test_info->name())
+ .build();
+
+ return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+ ceDisplayArgs);
+ }
+
+ static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
+ constexpr auto CONNECTION_TYPE =
+ PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
+ ? IComposerClient::DisplayConnectionType::INTERNAL
+ : IComposerClient::DisplayConnectionType::EXTERNAL;
+
+ EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(CONNECTION_TYPE), Return(hal::V2_4::Error::NONE)));
+
+ EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_))
+ .WillOnce(Return(hal::Error::NONE));
+ EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
+ Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::WIDTH, _))
+ .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::HEIGHT, _))
+ .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::VSYNC_PERIOD, _))
+ .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::DPI_X, _))
+ .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::DPI_Y, _))
+ .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::CONFIG_GROUP, _))
+ .WillOnce(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
+
+ if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+ EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(PhysicalDisplay::PORT),
+ SetArgPointee<2>(PhysicalDisplay::GET_IDENTIFICATION_DATA()),
+ Return(Error::NONE)));
+ } else {
+ EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+ .WillOnce(Return(Error::UNSUPPORTED));
+ }
+ }
+
+ // Called by tests to set up HWC call expectations
+ static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY_ID, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(HWC_ACTIVE_CONFIG_ID), Return(Error::NONE)));
+ }
+};
+
+// Physical displays are expected to be synchronous, secure, and have a HWC display for output.
+constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
+
+template <typename PhysicalDisplay, int width, int height, Critical critical>
+struct PhysicalDisplayVariant
+ : DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, critical,
+ Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY,
+ GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+ HwcDisplayVariant<PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL,
+ DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height,
+ critical, Async::FALSE, Secure::TRUE,
+ PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+ PhysicalDisplay> {};
+
+template <bool hasIdentificationData>
+struct PrimaryDisplay {
+ static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal;
+ static constexpr Primary PRIMARY = Primary::TRUE;
+ static constexpr uint8_t PORT = 255;
+ static constexpr HWDisplayId HWC_DISPLAY_ID = 1001;
+ static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
+ static constexpr auto GET_IDENTIFICATION_DATA = getInternalEdid;
+};
+
+template <bool hasIdentificationData>
+struct ExternalDisplay {
+ static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External;
+ static constexpr Primary PRIMARY = Primary::FALSE;
+ static constexpr uint8_t PORT = 254;
+ static constexpr HWDisplayId HWC_DISPLAY_ID = 1002;
+ static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
+ static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
+};
+
+struct TertiaryDisplay {
+ static constexpr Primary PRIMARY = Primary::FALSE;
+ static constexpr uint8_t PORT = 253;
+ static constexpr HWDisplayId HWC_DISPLAY_ID = 1003;
+ static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
+};
+
+// A primary display is a physical display that is critical
+using PrimaryDisplayVariant =
+ PhysicalDisplayVariant<PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
+
+// An external display is physical display that is not critical.
+using ExternalDisplayVariant =
+ PhysicalDisplayVariant<ExternalDisplay<false>, 1920, 1280, Critical::FALSE>;
+
+using TertiaryDisplayVariant = PhysicalDisplayVariant<TertiaryDisplay, 1600, 1200, Critical::FALSE>;
+
+// A virtual display not supported by the HWC.
+constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
+
+template <int width, int height, Secure secure>
+struct NonHwcVirtualDisplayVariant
+ : DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY> {
+ using Base =
+ DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE,
+ secure, Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+
+ static void injectHwcDisplay(DisplayTransactionTest*) {}
+
+ static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
+ DisplayTransactionTest* test) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
+ .WillByDefault(Return(Base::DISPLAY_ID::get()));
+
+ auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
+ .setPixels({Base::WIDTH, Base::HEIGHT})
+ .setIsSecure(static_cast<bool>(Base::SECURE))
+ .setPowerAdvisor(&test->mPowerAdvisor)
+ .setName(std::string("Injected display for ") +
+ test_info->test_case_name() + "." + test_info->name())
+ .setGpuVirtualDisplayIdGenerator(
+ test->mFlinger.gpuVirtualDisplayIdGenerator())
+ .build();
+
+ return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+ ceDisplayArgs);
+ }
+
+ static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
+ }
+
+ static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
+ Base::setupNativeWindowSurfaceCreationCallExpectations(test);
+ EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
+ }
+};
+
+// A virtual display supported by the HWC.
+constexpr uint32_t GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY = GRALLOC_USAGE_HW_COMPOSER;
+
+template <int width, int height, Secure secure>
+struct HwcVirtualDisplayVariant
+ : DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE, Async::TRUE,
+ secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
+ HwcDisplayVariant<HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL,
+ DisplayVariant<HalVirtualDisplayIdType<42>, width, height,
+ Critical::FALSE, Async::TRUE, secure, Primary::FALSE,
+ GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> {
+ using Base = DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE,
+ Async::TRUE, secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>;
+ using Self = HwcVirtualDisplayVariant<width, height, secure>;
+
+ static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
+ DisplayTransactionTest* test) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ // In order to prevent compostition engine calling into HWComposer, we
+ // 1. turn off the use of HWC virtual displays,
+ // 2. provide a GpuVirtualDisplayIdGenerator which always returns some fake ID
+ // 3. override the ID by calling setDisplayIdForTesting()
+
+ ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
+ .WillByDefault(Return(GpuVirtualDisplayId(0)));
+
+ auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
+ .setUseHwcVirtualDisplays(false)
+ .setPixels({Base::WIDTH, Base::HEIGHT})
+ .setIsSecure(static_cast<bool>(Base::SECURE))
+ .setPowerAdvisor(&test->mPowerAdvisor)
+ .setName(std::string("Injected display for ") +
+ test_info->test_case_name() + "." + test_info->name())
+ .setGpuVirtualDisplayIdGenerator(
+ test->mFlinger.gpuVirtualDisplayIdGenerator())
+ .build();
+
+ auto compositionDisplay =
+ compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+ ceDisplayArgs);
+ compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get());
+
+ // Insert display data so that the HWC thinks it created the virtual display.
+ if (const auto displayId = Base::DISPLAY_ID::get();
+ HalVirtualDisplayId::tryCast(displayId)) {
+ test->mFlinger.mutableHwcDisplayData().try_emplace(displayId);
+ }
+
+ return compositionDisplay;
+ }
+
+ static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
+ Base::setupNativeWindowSurfaceCreationCallExpectations(test);
+ EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
+ }
+
+ static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
+ }
+};
+
+// For this variant, the display is not a HWC display, so no HDR support should
+// be configured.
+struct NonHwcDisplayHdrSupportVariant {
+ static constexpr bool HDR10_PLUS_SUPPORTED = false;
+ static constexpr bool HDR10_SUPPORTED = false;
+ static constexpr bool HDR_HLG_SUPPORTED = false;
+ static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getHdrCapabilities(_, _, _, _, _)).Times(0);
+ }
+};
+
+// For this variant, the composer should respond with am empty list of HDR
+// modes, so no HDR support should be configured.
+template <typename Display>
+struct HdrNotSupportedVariant {
+ static constexpr bool HDR10_PLUS_SUPPORTED = false;
+ static constexpr bool HDR10_SUPPORTED = false;
+ static constexpr bool HDR_HLG_SUPPORTED = false;
+ static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>()), Return(Error::NONE)));
+ }
+};
+
+struct NonHwcPerFrameMetadataSupportVariant {
+ static constexpr int PER_FRAME_METADATA_KEYS = 0;
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(_)).Times(0);
+ }
+};
+
+template <typename Display>
+struct NoPerFrameMetadataSupportVariant {
+ static constexpr int PER_FRAME_METADATA_KEYS = 0;
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+ .WillOnce(Return(std::vector<PerFrameMetadataKey>()));
+ }
+};
+
+// For this variant, SurfaceFlinger should configure itself with wide display
+// support, but the display should respond with an empty list of supported color
+// modes. Wide-color support for the display should not be configured.
+template <typename Display>
+struct WideColorNotSupportedVariant {
+ static constexpr bool WIDE_COLOR_SUPPORTED = false;
+
+ static void injectConfigChange(DisplayTransactionTest* test) {
+ test->mFlinger.mutableUseColorManagement() = true;
+ test->mFlinger.mutableHasWideColorDisplay() = true;
+ }
+
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>()), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
+ }
+};
+
+// For this variant, SurfaceFlinger should not configure itself with wide
+// display support, so the display should not be configured for wide-color
+// support.
+struct WideColorSupportNotConfiguredVariant {
+ static constexpr bool WIDE_COLOR_SUPPORTED = false;
+
+ static void injectConfigChange(DisplayTransactionTest* test) {
+ test->mFlinger.mutableHasWideColorDisplay() = false;
+ test->mFlinger.mutableUseColorManagement() = false;
+ test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
+ }
+
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getColorModes(_, _)).Times(0);
+ EXPECT_CALL(*test->mComposer, getRenderIntents(_, _, _)).Times(0);
+ EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * Typical display configurations to test
+ */
+
+template <typename DisplayPolicy, typename WideColorSupportPolicy, typename HdrSupportPolicy,
+ typename PerFrameMetadataSupportPolicy>
+struct Case {
+ using Display = DisplayPolicy;
+ using WideColorSupport = WideColorSupportPolicy;
+ using HdrSupport = HdrSupportPolicy;
+ using PerFrameMetadataSupport = PerFrameMetadataSupportPolicy;
+};
+
+using SimplePrimaryDisplayCase =
+ Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+ HdrNotSupportedVariant<PrimaryDisplayVariant>,
+ NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using SimpleExternalDisplayCase =
+ Case<ExternalDisplayVariant, WideColorNotSupportedVariant<ExternalDisplayVariant>,
+ HdrNotSupportedVariant<ExternalDisplayVariant>,
+ NoPerFrameMetadataSupportVariant<ExternalDisplayVariant>>;
+using SimpleTertiaryDisplayCase =
+ Case<TertiaryDisplayVariant, WideColorNotSupportedVariant<TertiaryDisplayVariant>,
+ HdrNotSupportedVariant<TertiaryDisplayVariant>,
+ NoPerFrameMetadataSupportVariant<TertiaryDisplayVariant>>;
+
+using NonHwcVirtualDisplayCase =
+ Case<NonHwcVirtualDisplayVariant<1024, 768, Secure::FALSE>,
+ WideColorSupportNotConfiguredVariant, NonHwcDisplayHdrSupportVariant,
+ NonHwcPerFrameMetadataSupportVariant>;
+using SimpleHwcVirtualDisplayVariant = HwcVirtualDisplayVariant<1024, 768, Secure::TRUE>;
+using HwcVirtualDisplayCase =
+ Case<SimpleHwcVirtualDisplayVariant, WideColorSupportNotConfiguredVariant,
+ HdrNotSupportedVariant<SimpleHwcVirtualDisplayVariant>,
+ NoPerFrameMetadataSupportVariant<SimpleHwcVirtualDisplayVariant>>;
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
new file mode 100644
index 0000000..2362a31
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+class CreateDisplayTest : public DisplayTransactionTest {};
+
+TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForNonsecureDisplay) {
+ const String8 name("virtual.test");
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ // The call should notify the interceptor that a display was created.
+ EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ sp<IBinder> displayToken = mFlinger.createDisplay(name, false);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The display should have been added to the current state
+ ASSERT_TRUE(hasCurrentDisplayState(displayToken));
+ const auto& display = getCurrentDisplayState(displayToken);
+ EXPECT_TRUE(display.isVirtual());
+ EXPECT_FALSE(display.isSecure);
+ EXPECT_EQ(name.string(), display.displayName);
+
+ // --------------------------------------------------------------------
+ // Cleanup conditions
+
+ // Destroying the display invalidates the display state.
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+}
+
+TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) {
+ const String8 name("virtual.test");
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ // The call should notify the interceptor that a display was created.
+ EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
+
+ // --------------------------------------------------------------------
+ // Invocation
+ int64_t oldId = IPCThreadState::self()->clearCallingIdentity();
+ // Set the calling identity to graphics so captureDisplay with secure is allowed.
+ IPCThreadState::self()->restoreCallingIdentity(static_cast<int64_t>(AID_GRAPHICS) << 32 |
+ AID_GRAPHICS);
+ sp<IBinder> displayToken = mFlinger.createDisplay(name, true);
+ IPCThreadState::self()->restoreCallingIdentity(oldId);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The display should have been added to the current state
+ ASSERT_TRUE(hasCurrentDisplayState(displayToken));
+ const auto& display = getCurrentDisplayState(displayToken);
+ EXPECT_TRUE(display.isVirtual());
+ EXPECT_TRUE(display.isSecure);
+ EXPECT_EQ(name.string(), display.displayName);
+
+ // --------------------------------------------------------------------
+ // Cleanup conditions
+
+ // Destroying the display invalidates the display state.
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
new file mode 100644
index 0000000..0614434
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+class DestroyDisplayTest : public DisplayTransactionTest {};
+
+TEST_F(DestroyDisplayTest, destroyDisplayClearsCurrentStateForDisplay) {
+ using Case = NonHwcVirtualDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A virtual display exists
+ auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+ existing.inject();
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ // The call should notify the interceptor that a display was created.
+ EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
+
+ // Destroying the display invalidates the display state.
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.destroyDisplay(existing.token());
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The display should have been removed from the current state
+ EXPECT_FALSE(hasCurrentDisplayState(existing.token()));
+
+ // Ths display should still exist in the drawing state
+ EXPECT_TRUE(hasDrawingDisplayState(existing.token()));
+
+ // The display transaction needed flasg should be set
+ EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+}
+
+TEST_F(DestroyDisplayTest, destroyDisplayHandlesUnknownDisplay) {
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ sp<BBinder> displayToken = new BBinder();
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.destroyDisplay(displayToken);
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
new file mode 100644
index 0000000..0171f1b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+class GetDisplayNativePrimaries : public DisplayTransactionTest {
+public:
+ GetDisplayNativePrimaries();
+ void populateDummyDisplayNativePrimaries(ui::DisplayPrimaries& primaries);
+ void checkDummyDisplayNativePrimaries(const ui::DisplayPrimaries& primaries);
+
+private:
+ static constexpr float mStartingTestValue = 1.0f;
+};
+
+GetDisplayNativePrimaries::GetDisplayNativePrimaries() {
+ SimplePrimaryDisplayCase::Display::injectHwcDisplay(this);
+ injectFakeNativeWindowSurfaceFactory();
+}
+
+void GetDisplayNativePrimaries::populateDummyDisplayNativePrimaries(
+ ui::DisplayPrimaries& primaries) {
+ float startingVal = mStartingTestValue;
+ primaries.red.X = startingVal++;
+ primaries.red.Y = startingVal++;
+ primaries.red.Z = startingVal++;
+ primaries.green.X = startingVal++;
+ primaries.green.Y = startingVal++;
+ primaries.green.Z = startingVal++;
+ primaries.blue.X = startingVal++;
+ primaries.blue.Y = startingVal++;
+ primaries.blue.Z = startingVal++;
+ primaries.white.X = startingVal++;
+ primaries.white.Y = startingVal++;
+ primaries.white.Z = startingVal++;
+}
+
+void GetDisplayNativePrimaries::checkDummyDisplayNativePrimaries(
+ const ui::DisplayPrimaries& primaries) {
+ float startingVal = mStartingTestValue;
+ EXPECT_EQ(primaries.red.X, startingVal++);
+ EXPECT_EQ(primaries.red.Y, startingVal++);
+ EXPECT_EQ(primaries.red.Z, startingVal++);
+ EXPECT_EQ(primaries.green.X, startingVal++);
+ EXPECT_EQ(primaries.green.Y, startingVal++);
+ EXPECT_EQ(primaries.green.Z, startingVal++);
+ EXPECT_EQ(primaries.blue.X, startingVal++);
+ EXPECT_EQ(primaries.blue.Y, startingVal++);
+ EXPECT_EQ(primaries.blue.Z, startingVal++);
+ EXPECT_EQ(primaries.white.X, startingVal++);
+ EXPECT_EQ(primaries.white.Y, startingVal++);
+ EXPECT_EQ(primaries.white.Z, startingVal++);
+}
+
+TEST_F(GetDisplayNativePrimaries, nullDisplayToken) {
+ ui::DisplayPrimaries primaries;
+ EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(nullptr, primaries));
+}
+
+TEST_F(GetDisplayNativePrimaries, internalDisplayWithPrimariesData) {
+ auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this);
+ injector.inject();
+ auto internalDisplayToken = injector.token();
+
+ ui::DisplayPrimaries expectedPrimaries;
+ populateDummyDisplayNativePrimaries(expectedPrimaries);
+ mFlinger.setInternalDisplayPrimaries(expectedPrimaries);
+
+ ui::DisplayPrimaries primaries;
+ EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries));
+
+ checkDummyDisplayNativePrimaries(primaries);
+}
+
+TEST_F(GetDisplayNativePrimaries, notInternalDisplayToken) {
+ sp<BBinder> notInternalDisplayToken = new BBinder();
+
+ ui::DisplayPrimaries primaries;
+ populateDummyDisplayNativePrimaries(primaries);
+ EXPECT_EQ(NAME_NOT_FOUND,
+ mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries));
+
+ // Check primaries argument wasn't modified in case of failure
+ checkDummyDisplayNativePrimaries(primaries);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
new file mode 100644
index 0000000..cd3f6ab
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
@@ -0,0 +1,734 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+class HandleTransactionLockedTest : public DisplayTransactionTest {
+public:
+ template <typename Case>
+ void setupCommonPreconditions();
+
+ template <typename Case, bool connected>
+ static void expectHotplugReceived(mock::EventThread*);
+
+ template <typename Case>
+ void setupCommonCallExpectationsForConnectProcessing();
+
+ template <typename Case>
+ void setupCommonCallExpectationsForDisconnectProcessing();
+
+ template <typename Case>
+ void processesHotplugConnectCommon();
+
+ template <typename Case>
+ void ignoresHotplugConnectCommon();
+
+ template <typename Case>
+ void processesHotplugDisconnectCommon();
+
+ template <typename Case>
+ void verifyDisplayIsConnected(const sp<IBinder>& displayToken);
+
+ template <typename Case>
+ void verifyPhysicalDisplayIsConnected();
+
+ void verifyDisplayIsNotConnected(const sp<IBinder>& displayToken);
+};
+
+template <typename Case>
+void HandleTransactionLockedTest::setupCommonPreconditions() {
+ // Wide color displays support is configured appropriately
+ Case::WideColorSupport::injectConfigChange(this);
+
+ // SurfaceFlinger will use a test-controlled factory for BufferQueues
+ injectFakeBufferQueueFactory();
+
+ // SurfaceFlinger will use a test-controlled factory for native window
+ // surfaces.
+ injectFakeNativeWindowSurfaceFactory();
+}
+
+template <typename Case, bool connected>
+void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) {
+ const auto convert = [](auto physicalDisplayId) {
+ return std::make_optional(DisplayId{physicalDisplayId});
+ };
+
+ EXPECT_CALL(*eventThread,
+ onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected))
+ .Times(1);
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() {
+ Case::Display::setupHwcHotplugCallExpectations(this);
+
+ Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
+ Case::Display::setupFramebufferProducerBufferQueueCallExpectations(this);
+ Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
+ Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+
+ Case::WideColorSupport::setupComposerCallExpectations(this);
+ Case::HdrSupport::setupComposerCallExpectations(this);
+ Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
+
+ EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
+ expectHotplugReceived<Case, true>(mEventThread);
+ expectHotplugReceived<Case, true>(mSFEventThread);
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
+ EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
+
+ expectHotplugReceived<Case, false>(mEventThread);
+ expectHotplugReceived<Case, false>(mSFEventThread);
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
+ // The display device should have been set up in the list of displays.
+ ASSERT_TRUE(hasDisplayDevice(displayToken));
+ const auto& device = getDisplayDevice(displayToken);
+ EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
+ EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
+
+ std::optional<DisplayDeviceState::Physical> expectedPhysical;
+ if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+ const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get());
+ ASSERT_TRUE(displayId);
+ const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
+ ASSERT_TRUE(hwcDisplayId);
+ expectedPhysical = {.id = *displayId,
+ .type = *connectionType,
+ .hwcDisplayId = *hwcDisplayId};
+ }
+
+ // The display should have been set up in the current display state
+ ASSERT_TRUE(hasCurrentDisplayState(displayToken));
+ const auto& current = getCurrentDisplayState(displayToken);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
+ EXPECT_EQ(expectedPhysical, current.physical);
+
+ // The display should have been set up in the drawing display state
+ ASSERT_TRUE(hasDrawingDisplayState(displayToken));
+ const auto& draw = getDrawingDisplayState(displayToken);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
+ EXPECT_EQ(expectedPhysical, draw.physical);
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
+ // HWComposer should have an entry for the display
+ EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+
+ // SF should have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
+ auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId];
+
+ verifyDisplayIsConnected<Case>(displayToken);
+}
+
+void HandleTransactionLockedTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
+ EXPECT_FALSE(hasDisplayDevice(displayToken));
+ EXPECT_FALSE(hasCurrentDisplayState(displayToken));
+ EXPECT_FALSE(hasDrawingDisplayState(displayToken));
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::processesHotplugConnectCommon() {
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ setupCommonPreconditions<Case>();
+
+ // A hotplug connect event is enqueued for a display
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ setupCommonCallExpectationsForConnectProcessing<Case>();
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ verifyPhysicalDisplayIsConnected<Case>();
+
+ // --------------------------------------------------------------------
+ // Cleanup conditions
+
+ EXPECT_CALL(*mComposer,
+ setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+ .WillOnce(Return(Error::NONE));
+ EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::ignoresHotplugConnectCommon() {
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ setupCommonPreconditions<Case>();
+
+ // A hotplug connect event is enqueued for a display
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // HWComposer should not have an entry for the display
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::processesHotplugDisconnectCommon() {
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ setupCommonPreconditions<Case>();
+
+ // A hotplug disconnect event is enqueued for a display
+ Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
+
+ // The display is already completely set up.
+ Case::Display::injectHwcDisplay(this);
+ auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+ existing.inject();
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ EXPECT_CALL(*mComposer, getDisplayIdentificationData(Case::Display::HWC_DISPLAY_ID, _, _))
+ .Times(0);
+
+ setupCommonCallExpectationsForDisconnectProcessing<Case>();
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // HWComposer should not have an entry for the display
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+
+ // SF should not have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+
+ // The existing token should have been removed
+ verifyDisplayIsNotConnected(existing.token());
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugConnectPrimaryDisplay) {
+ processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest,
+ processesHotplugConnectPrimaryDisplayWithExternalAlreadyConnected) {
+ // Inject an external display.
+ ExternalDisplayVariant::injectHwcDisplay(this);
+
+ processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) {
+ // Inject a primary display.
+ PrimaryDisplayVariant::injectHwcDisplay(this);
+
+ processesHotplugConnectCommon<SimpleExternalDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) {
+ // Inject both a primary and external display.
+ PrimaryDisplayVariant::injectHwcDisplay(this);
+ ExternalDisplayVariant::injectHwcDisplay(this);
+
+ // TODO: This is an unnecessary call.
+ EXPECT_CALL(*mComposer,
+ getDisplayIdentificationData(TertiaryDisplayVariant::HWC_DISPLAY_ID, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(TertiaryDisplay::PORT),
+ SetArgPointee<2>(TertiaryDisplay::GET_IDENTIFICATION_DATA()),
+ Return(Error::NONE)));
+
+ ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
+ processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectExternalDisplay) {
+ processesHotplugDisconnectCommon<SimpleExternalDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugConnectThenDisconnectPrimary) {
+ using Case = SimplePrimaryDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ setupCommonPreconditions<Case>();
+
+ // A hotplug connect event is enqueued for a display
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+ // A hotplug disconnect event is also enqueued for the same display
+ Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ setupCommonCallExpectationsForConnectProcessing<Case>();
+ setupCommonCallExpectationsForDisconnectProcessing<Case>();
+
+ EXPECT_CALL(*mComposer,
+ setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+ .WillOnce(Return(Error::NONE));
+ EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // HWComposer should not have an entry for the display
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+
+ // SF should not have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
+ using Case = SimplePrimaryDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ setupCommonPreconditions<Case>();
+
+ // The display is already completely set up.
+ Case::Display::injectHwcDisplay(this);
+ auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+ existing.inject();
+
+ // A hotplug disconnect event is enqueued for a display
+ Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
+ // A hotplug connect event is also enqueued for the same display
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ setupCommonCallExpectationsForConnectProcessing<Case>();
+ setupCommonCallExpectationsForDisconnectProcessing<Case>();
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The existing token should have been removed
+ verifyDisplayIsNotConnected(existing.token());
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
+ EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]);
+
+ // A new display should be connected in its place
+
+ verifyPhysicalDisplayIsConnected<Case>();
+
+ // --------------------------------------------------------------------
+ // Cleanup conditions
+
+ EXPECT_CALL(*mComposer,
+ setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+ .WillOnce(Return(Error::NONE));
+ EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+}
+
+TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) {
+ using Case = HwcVirtualDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // The HWC supports at least one virtual display
+ injectMockComposer(1);
+
+ setupCommonPreconditions<Case>();
+
+ // A virtual display was added to the current state, and it has a
+ // surface(producer)
+ sp<BBinder> displayToken = new BBinder();
+
+ DisplayDeviceState state;
+ state.isSecure = static_cast<bool>(Case::Display::SECURE);
+
+ sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
+ state.surface = surface;
+ mFlinger.mutableCurrentState().displays.add(displayToken, state);
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
+ Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
+
+ EXPECT_CALL(*surface, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::WIDTH), Return(NO_ERROR)));
+ EXPECT_CALL(*surface, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::HEIGHT), Return(NO_ERROR)));
+ EXPECT_CALL(*surface, query(NATIVE_WINDOW_FORMAT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT),
+ Return(NO_ERROR)));
+ EXPECT_CALL(*surface, query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
+
+ EXPECT_CALL(*surface, setAsyncMode(true)).Times(1);
+
+ EXPECT_CALL(*mProducer, connect(_, NATIVE_WINDOW_API_EGL, false, _)).Times(1);
+ EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1);
+
+ Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this);
+ Case::WideColorSupport::setupComposerCallExpectations(this);
+ Case::HdrSupport::setupComposerCallExpectations(this);
+ Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The display device should have been set up in the list of displays.
+ verifyDisplayIsConnected<Case>(displayToken);
+
+ // --------------------------------------------------------------------
+ // Cleanup conditions
+
+ EXPECT_CALL(*mComposer, destroyVirtualDisplay(Case::Display::HWC_DISPLAY_ID))
+ .WillOnce(Return(Error::NONE));
+ EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+
+ // Cleanup
+ mFlinger.mutableCurrentState().displays.removeItem(displayToken);
+ mFlinger.mutableDrawingState().displays.removeItem(displayToken);
+}
+
+TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) {
+ using Case = HwcVirtualDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // The HWC supports at least one virtual display
+ injectMockComposer(1);
+
+ setupCommonPreconditions<Case>();
+
+ // A virtual display was added to the current state, but it does not have a
+ // surface.
+ sp<BBinder> displayToken = new BBinder();
+
+ DisplayDeviceState state;
+ state.isSecure = static_cast<bool>(Case::Display::SECURE);
+
+ mFlinger.mutableCurrentState().displays.add(displayToken, state);
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // There will not be a display device set up.
+ EXPECT_FALSE(hasDisplayDevice(displayToken));
+
+ // The drawing display state will be set from the current display state.
+ ASSERT_TRUE(hasDrawingDisplayState(displayToken));
+ const auto& draw = getDrawingDisplayState(displayToken);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
+}
+
+TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
+ using Case = HwcVirtualDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A virtual display is set up but is removed from the current state.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId));
+ mFlinger.mutableHwcDisplayData().try_emplace(displayId);
+ Case::Display::injectHwcDisplay(this);
+ auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+ existing.inject();
+ mFlinger.mutableCurrentState().displays.removeItem(existing.token());
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The existing token should have been removed
+ verifyDisplayIsNotConnected(existing.token());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) {
+ using Case = NonHwcVirtualDisplayCase;
+
+ constexpr uint32_t oldLayerStack = 0u;
+ constexpr uint32_t newLayerStack = 123u;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // There is a change to the layerStack state
+ display.mutableDrawingDisplayState().layerStack = oldLayerStack;
+ display.mutableCurrentDisplayState().layerStack = newLayerStack;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ EXPECT_EQ(newLayerStack, display.mutableDisplayDevice()->getLayerStack());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
+ using Case = NonHwcVirtualDisplayCase;
+
+ constexpr ui::Rotation oldTransform = ui::ROTATION_0;
+ constexpr ui::Rotation newTransform = ui::ROTATION_180;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // There is a change to the orientation state
+ display.mutableDrawingDisplayState().orientation = oldTransform;
+ display.mutableCurrentDisplayState().orientation = newTransform;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackRectChanges) {
+ using Case = NonHwcVirtualDisplayCase;
+
+ const Rect oldLayerStackRect(0, 0, 0, 0);
+ const Rect newLayerStackRect(0, 0, 123, 456);
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // There is a change to the layerStackSpaceRect state
+ display.mutableDrawingDisplayState().layerStackSpaceRect = oldLayerStackRect;
+ display.mutableCurrentDisplayState().layerStackSpaceRect = newLayerStackRect;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ EXPECT_EQ(newLayerStackRect, display.mutableDisplayDevice()->getLayerStackSpaceRect());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayFrameChanges) {
+ using Case = NonHwcVirtualDisplayCase;
+
+ const Rect oldFrame(0, 0, 0, 0);
+ const Rect newFrame(0, 0, 123, 456);
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // There is a change to the layerStackSpaceRect state
+ display.mutableDrawingDisplayState().orientedDisplaySpaceRect = oldFrame;
+ display.mutableCurrentDisplayState().orientedDisplaySpaceRect = newFrame;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ EXPECT_EQ(newFrame, display.mutableDisplayDevice()->getOrientedDisplaySpaceRect());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) {
+ using Case = NonHwcVirtualDisplayCase;
+
+ constexpr int oldWidth = 0;
+ constexpr int oldHeight = 10;
+ constexpr int newWidth = 123;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto nativeWindow = new mock::NativeWindow();
+ auto displaySurface = new compositionengine::mock::DisplaySurface();
+ sp<GraphicBuffer> buf = new GraphicBuffer();
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.setNativeWindow(nativeWindow);
+ display.setDisplaySurface(displaySurface);
+ // Setup injection expectations
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
+ display.inject();
+
+ // There is a change to the layerStackSpaceRect state
+ display.mutableDrawingDisplayState().width = oldWidth;
+ display.mutableDrawingDisplayState().height = oldHeight;
+ display.mutableCurrentDisplayState().width = newWidth;
+ display.mutableCurrentDisplayState().height = oldHeight;
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) {
+ using Case = NonHwcVirtualDisplayCase;
+
+ constexpr int oldWidth = 0;
+ constexpr int oldHeight = 10;
+ constexpr int newHeight = 123;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto nativeWindow = new mock::NativeWindow();
+ auto displaySurface = new compositionengine::mock::DisplaySurface();
+ sp<GraphicBuffer> buf = new GraphicBuffer();
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.setNativeWindow(nativeWindow);
+ display.setDisplaySurface(displaySurface);
+ // Setup injection expectations
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
+ display.inject();
+
+ // There is a change to the layerStackSpaceRect state
+ display.mutableDrawingDisplayState().width = oldWidth;
+ display.mutableDrawingDisplayState().height = oldHeight;
+ display.mutableCurrentDisplayState().width = oldWidth;
+ display.mutableCurrentDisplayState().height = newHeight;
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
new file mode 100644
index 0000000..69e0501
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <android/hardware/power/Boost.h>
+
+namespace android {
+namespace {
+
+using android::hardware::power::Boost;
+
+TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) {
+ mFlinger.scheduler()->replaceTouchTimer(100);
+ std::this_thread::sleep_for(10ms); // wait for callback to be triggered
+ EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch
+
+ std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
+ EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+
+ EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::CAMERA_SHOT)));
+ std::this_thread::sleep_for(10ms); // wait for callback to maybe be triggered
+ EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+
+ std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
+ EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+
+ EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::INTERACTION)));
+ std::this_thread::sleep_for(10ms); // wait for callback to be triggered.
+ EXPECT_TRUE(mFlinger.scheduler()->isTouchActive());
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnHotplugReceivedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnHotplugReceivedTest.cpp
new file mode 100644
index 0000000..42f4cf3
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnHotplugReceivedTest.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+class OnHotplugReceivedTest : public DisplayTransactionTest {};
+
+TEST_F(OnHotplugReceivedTest, hotplugEnqueuesEventsForDisplayTransaction) {
+ constexpr int currentSequenceId = 123;
+ constexpr HWDisplayId hwcDisplayId1 = 456;
+ constexpr HWDisplayId hwcDisplayId2 = 654;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // Set the current sequence id for accepted events
+ mFlinger.mutableComposerSequenceId() = currentSequenceId;
+
+ // Set the main thread id so that the current thread does not appear to be
+ // the main thread.
+ mFlinger.mutableMainThreadId() = std::thread::id();
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ // We expect invalidate() to be invoked once to trigger display transaction
+ // processing.
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ // Simulate two hotplug events (a connect and a disconnect)
+ mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, Connection::CONNECTED);
+ mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, Connection::DISCONNECTED);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The display transaction needed flag should be set.
+ EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+ // All events should be in the pending event queue.
+ const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents();
+ ASSERT_EQ(2u, pendingEvents.size());
+ EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId);
+ EXPECT_EQ(Connection::CONNECTED, pendingEvents[0].connection);
+ EXPECT_EQ(hwcDisplayId2, pendingEvents[1].hwcDisplayId);
+ EXPECT_EQ(Connection::DISCONNECTED, pendingEvents[1].connection);
+}
+
+TEST_F(OnHotplugReceivedTest, hotplugDiscardsUnexpectedEvents) {
+ constexpr int currentSequenceId = 123;
+ constexpr int otherSequenceId = 321;
+ constexpr HWDisplayId displayId = 456;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // Set the current sequence id for accepted events
+ mFlinger.mutableComposerSequenceId() = currentSequenceId;
+
+ // Set the main thread id so that the current thread does not appear to be
+ // the main thread.
+ mFlinger.mutableMainThreadId() = std::thread::id();
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ // We do not expect any calls to invalidate().
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(0);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ // Call with an unexpected sequence id
+ mFlinger.onHotplugReceived(otherSequenceId, displayId, Connection::INVALID);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The display transaction needed flag should not be set
+ EXPECT_FALSE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+ // There should be no pending events
+ EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty());
+}
+
+TEST_F(OnHotplugReceivedTest, hotplugProcessesEnqueuedEventsIfCalledOnMainThread) {
+ constexpr int currentSequenceId = 123;
+ constexpr HWDisplayId displayId1 = 456;
+
+ // --------------------------------------------------------------------
+ // Note:
+ // --------------------------------------------------------------------
+ // This test case is a bit tricky. We want to verify that
+ // onHotplugReceived() calls processDisplayHotplugEventsLocked(), but we
+ // don't really want to provide coverage for everything the later function
+ // does as there are specific tests for it.
+ // --------------------------------------------------------------------
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // Set the current sequence id for accepted events
+ mFlinger.mutableComposerSequenceId() = currentSequenceId;
+
+ // Set the main thread id so that the current thread does appear to be the
+ // main thread.
+ mFlinger.mutableMainThreadId() = std::this_thread::get_id();
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ // We expect invalidate() to be invoked once to trigger display transaction
+ // processing.
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ // Simulate a disconnect on a display id that is not connected. This should
+ // be enqueued by onHotplugReceived(), and dequeued by
+ // processDisplayHotplugEventsLocked(), but then ignored as invalid.
+ mFlinger.onHotplugReceived(currentSequenceId, displayId1, Connection::DISCONNECTED);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The display transaction needed flag should be set.
+ EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+ // There should be no event queued on return, as it should have been
+ // processed.
+ EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty());
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
new file mode 100644
index 0000000..7a9403b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+class OnInitializeDisplaysTest : public DisplayTransactionTest {};
+
+TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) {
+ using Case = SimplePrimaryDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A primary display is set up
+ Case::Display::injectHwcDisplay(this);
+ auto primaryDisplay = Case::Display::makeFakeExistingDisplayInjector(this);
+ primaryDisplay.inject();
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ // We expect the surface interceptor to possibly be used, but we treat it as
+ // disabled since it is called as a side effect rather than directly by this
+ // function.
+ EXPECT_CALL(*mSurfaceInterceptor, isEnabled()).WillOnce(Return(false));
+
+ // We expect a call to get the active display config.
+ Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+
+ // We expect invalidate() to be invoked once to trigger display transaction
+ // processing.
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.onInitializeDisplays();
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The primary display should have a current state
+ ASSERT_TRUE(hasCurrentDisplayState(primaryDisplay.token()));
+ const auto& primaryDisplayState = getCurrentDisplayState(primaryDisplay.token());
+ // The layer stack state should be set to zero
+ EXPECT_EQ(0u, primaryDisplayState.layerStack);
+ // The orientation state should be set to zero
+ EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation);
+
+ // The orientedDisplaySpaceRect state should be set to INVALID
+ EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.orientedDisplaySpaceRect);
+
+ // The layerStackSpaceRect state should be set to INVALID
+ EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.layerStackSpaceRect);
+
+ // The width and height should both be zero
+ EXPECT_EQ(0u, primaryDisplayState.width);
+ EXPECT_EQ(0u, primaryDisplayState.height);
+
+ // The display should be set to PowerMode::ON
+ ASSERT_TRUE(hasDisplayDevice(primaryDisplay.token()));
+ auto displayDevice = primaryDisplay.mutableDisplayDevice();
+ EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode());
+
+ // The display refresh period should be set in the orientedDisplaySpaceRect tracker.
+ FrameStats stats;
+ mFlinger.getAnimFrameTracker().getStats(&stats);
+ EXPECT_EQ(DEFAULT_REFRESH_RATE, stats.refreshPeriodNano);
+
+ // The display transaction needed flag should be set.
+ EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+ // The compositor timing should be set to default values
+ const auto& compositorTiming = mFlinger.getCompositorTiming();
+ EXPECT_EQ(-DEFAULT_REFRESH_RATE, compositorTiming.deadline);
+ EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.interval);
+ EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.presentLatency);
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
new file mode 100644
index 0000000..be01984
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
@@ -0,0 +1,493 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+class SetDisplayStateLockedTest : public DisplayTransactionTest {};
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWithUnknownDisplay) {
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // We have an unknown display token not associated with a known display
+ sp<BBinder> displayToken = new BBinder();
+
+ // The requested display state references the unknown display.
+ DisplayState state;
+ state.what = DisplayState::eLayerStackChanged;
+ state.token = displayToken;
+ state.layerStack = 456;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags are empty
+ EXPECT_EQ(0u, flags);
+
+ // The display token still doesn't match anything known.
+ EXPECT_FALSE(hasCurrentDisplayState(displayToken));
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWhenNoChanges) {
+ using Case = SimplePrimaryDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is already set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // No changes are made to the display
+ DisplayState state;
+ state.what = 0;
+ state.token = display.token();
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags are empty
+ EXPECT_EQ(0u, flags);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfSurfaceDidNotChange) {
+ using Case = SimplePrimaryDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is already set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // There is a surface that can be set.
+ sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
+
+ // The current display state has the surface set
+ display.mutableCurrentDisplayState().surface = surface;
+
+ // The incoming request sets the same surface
+ DisplayState state;
+ state.what = DisplayState::eSurfaceChanged;
+ state.token = display.token();
+ state.surface = surface;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags are empty
+ EXPECT_EQ(0u, flags);
+
+ // The current display state is unchanged.
+ EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get());
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfSurfaceChanged) {
+ using Case = SimplePrimaryDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is already set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // There is a surface that can be set.
+ sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
+
+ // The current display state does not have a surface
+ display.mutableCurrentDisplayState().surface = nullptr;
+
+ // The incoming request sets a surface
+ DisplayState state;
+ state.what = DisplayState::eSurfaceChanged;
+ state.token = display.token();
+ state.surface = surface;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags indicate a transaction is needed
+ EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+ // The current display layer stack state is set to the new value
+ EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get());
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfLayerStackDidNotChange) {
+ using Case = SimplePrimaryDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is already set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The display has a layer stack set
+ display.mutableCurrentDisplayState().layerStack = 456u;
+
+ // The incoming request sets the same layer stack
+ DisplayState state;
+ state.what = DisplayState::eLayerStackChanged;
+ state.token = display.token();
+ state.layerStack = 456u;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags are empty
+ EXPECT_EQ(0u, flags);
+
+ // The current display state is unchanged
+ EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStackChanged) {
+ using Case = SimplePrimaryDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The display has a layer stack set
+ display.mutableCurrentDisplayState().layerStack = 654u;
+
+ // The incoming request sets a different layer stack
+ DisplayState state;
+ state.what = DisplayState::eLayerStackChanged;
+ state.token = display.token();
+ state.layerStack = 456u;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags indicate a transaction is needed
+ EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+ // The desired display state has been set to the new value.
+ EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) {
+ using Case = SimplePrimaryDisplayCase;
+ constexpr ui::Rotation initialOrientation = ui::ROTATION_180;
+ const Rect initialOrientedDisplayRect = {1, 2, 3, 4};
+ const Rect initialLayerStackRect = {5, 6, 7, 8};
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The current display state projection state is all set
+ display.mutableCurrentDisplayState().orientation = initialOrientation;
+ display.mutableCurrentDisplayState().orientedDisplaySpaceRect = initialOrientedDisplayRect;
+ display.mutableCurrentDisplayState().layerStackSpaceRect = initialLayerStackRect;
+
+ // The incoming request sets the same projection state
+ DisplayState state;
+ state.what = DisplayState::eDisplayProjectionChanged;
+ state.token = display.token();
+ state.orientation = initialOrientation;
+ state.orientedDisplaySpaceRect = initialOrientedDisplayRect;
+ state.layerStackSpaceRect = initialLayerStackRect;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags are empty
+ EXPECT_EQ(0u, flags);
+
+ // The current display state is unchanged
+ EXPECT_EQ(initialOrientation, display.getCurrentDisplayState().orientation);
+
+ EXPECT_EQ(initialOrientedDisplayRect,
+ display.getCurrentDisplayState().orientedDisplaySpaceRect);
+ EXPECT_EQ(initialLayerStackRect, display.getCurrentDisplayState().layerStackSpaceRect);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfOrientationChanged) {
+ using Case = SimplePrimaryDisplayCase;
+ constexpr ui::Rotation initialOrientation = ui::ROTATION_90;
+ constexpr ui::Rotation desiredOrientation = ui::ROTATION_180;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The current display state has an orientation set
+ display.mutableCurrentDisplayState().orientation = initialOrientation;
+
+ // The incoming request sets a different orientation
+ DisplayState state;
+ state.what = DisplayState::eDisplayProjectionChanged;
+ state.token = display.token();
+ state.orientation = desiredOrientation;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags indicate a transaction is needed
+ EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+ // The current display state has the new value.
+ EXPECT_EQ(desiredOrientation, display.getCurrentDisplayState().orientation);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfFrameChanged) {
+ using Case = SimplePrimaryDisplayCase;
+ const Rect initialOrientedDisplayRect = {0, 0, 0, 0};
+ const Rect desiredOrientedDisplayRect = {5, 6, 7, 8};
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The current display state does not have a orientedDisplaySpaceRect
+ display.mutableCurrentDisplayState().orientedDisplaySpaceRect = initialOrientedDisplayRect;
+
+ // The incoming request sets a orientedDisplaySpaceRect
+ DisplayState state;
+ state.what = DisplayState::eDisplayProjectionChanged;
+ state.token = display.token();
+ state.orientedDisplaySpaceRect = desiredOrientedDisplayRect;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags indicate a transaction is needed
+ EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+ // The current display state has the new value.
+ EXPECT_EQ(desiredOrientedDisplayRect,
+ display.getCurrentDisplayState().orientedDisplaySpaceRect);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStackRectChanged) {
+ using Case = SimplePrimaryDisplayCase;
+ const Rect initialLayerStackRect = {0, 0, 0, 0};
+ const Rect desiredLayerStackRect = {5, 6, 7, 8};
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The current display state does not have a layerStackSpaceRect
+ display.mutableCurrentDisplayState().layerStackSpaceRect = initialLayerStackRect;
+
+ // The incoming request sets a layerStackSpaceRect
+ DisplayState state;
+ state.what = DisplayState::eDisplayProjectionChanged;
+ state.token = display.token();
+ state.layerStackSpaceRect = desiredLayerStackRect;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags indicate a transaction is needed
+ EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+ // The current display state has the new value.
+ EXPECT_EQ(desiredLayerStackRect, display.getCurrentDisplayState().layerStackSpaceRect);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfSizeDidNotChange) {
+ using Case = SimplePrimaryDisplayCase;
+ constexpr uint32_t initialWidth = 1024;
+ constexpr uint32_t initialHeight = 768;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The current display state has a size set
+ display.mutableCurrentDisplayState().width = initialWidth;
+ display.mutableCurrentDisplayState().height = initialHeight;
+
+ // The incoming request sets the same display size
+ DisplayState state;
+ state.what = DisplayState::eDisplaySizeChanged;
+ state.token = display.token();
+ state.width = initialWidth;
+ state.height = initialHeight;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags are empty
+ EXPECT_EQ(0u, flags);
+
+ // The current display state is unchanged
+ EXPECT_EQ(initialWidth, display.getCurrentDisplayState().width);
+ EXPECT_EQ(initialHeight, display.getCurrentDisplayState().height);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfWidthChanged) {
+ using Case = SimplePrimaryDisplayCase;
+ constexpr uint32_t initialWidth = 0;
+ constexpr uint32_t desiredWidth = 1024;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The display does not yet have a width
+ display.mutableCurrentDisplayState().width = initialWidth;
+
+ // The incoming request sets a display width
+ DisplayState state;
+ state.what = DisplayState::eDisplaySizeChanged;
+ state.token = display.token();
+ state.width = desiredWidth;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags indicate a transaction is needed
+ EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+ // The current display state has the new value.
+ EXPECT_EQ(desiredWidth, display.getCurrentDisplayState().width);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfHeightChanged) {
+ using Case = SimplePrimaryDisplayCase;
+ constexpr uint32_t initialHeight = 0;
+ constexpr uint32_t desiredHeight = 768;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A display is set up
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The display does not yet have a height
+ display.mutableCurrentDisplayState().height = initialHeight;
+
+ // The incoming request sets a display height
+ DisplayState state;
+ state.what = DisplayState::eDisplaySizeChanged;
+ state.token = display.token();
+ state.height = desiredHeight;
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ // The returned flags indicate a transaction is needed
+ EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+ // The current display state has the new value.
+ EXPECT_EQ(desiredHeight, display.getCurrentDisplayState().height);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
new file mode 100644
index 0000000..2117628
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -0,0 +1,498 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+// Used when we simulate a display that supports doze.
+template <typename Display>
+struct DozeIsSupportedVariant {
+ static constexpr bool DOZE_SUPPORTED = true;
+ static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE =
+ IComposerClient::PowerMode::DOZE;
+ static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
+ IComposerClient::PowerMode::DOZE_SUSPEND;
+
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(
+ std::vector<DisplayCapability>({DisplayCapability::DOZE})),
+ Return(Error::NONE)));
+ }
+};
+
+template <typename Display>
+// Used when we simulate a display that does not support doze.
+struct DozeNotSupportedVariant {
+ static constexpr bool DOZE_SUPPORTED = false;
+ static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE =
+ IComposerClient::PowerMode::ON;
+ static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
+ IComposerClient::PowerMode::ON;
+
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
+ Return(Error::NONE)));
+ }
+};
+
+struct EventThreadBaseSupportedVariant {
+ static void setupVsyncAndEventThreadNoCallExpectations(DisplayTransactionTest* test) {
+ // The callback should not be notified to toggle VSYNC.
+ EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(_)).Times(0);
+
+ // The event thread should not be notified.
+ EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(0);
+ EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(0);
+ }
+};
+
+struct EventThreadNotSupportedVariant : public EventThreadBaseSupportedVariant {
+ static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
+ // These calls are only expected for the primary display.
+
+ // Instead expect no calls.
+ setupVsyncAndEventThreadNoCallExpectations(test);
+ }
+
+ static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
+ // These calls are only expected for the primary display.
+
+ // Instead expect no calls.
+ setupVsyncAndEventThreadNoCallExpectations(test);
+ }
+};
+
+struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant {
+ static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
+ // The callback should be notified to enable VSYNC.
+ EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(true)).Times(1);
+
+ // The event thread should be notified that the screen was acquired.
+ EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(1);
+ }
+
+ static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
+ // The callback should be notified to disable VSYNC.
+ EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(false)).Times(1);
+
+ // The event thread should not be notified that the screen was released.
+ EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(1);
+ }
+};
+
+struct DispSyncIsSupportedVariant {
+ static void setupResetModelCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mVsyncController, startPeriodTransition(DEFAULT_REFRESH_RATE)).Times(1);
+ EXPECT_CALL(*test->mVSyncTracker, resetModel()).Times(1);
+ }
+};
+
+struct DispSyncNotSupportedVariant {
+ static void setupResetModelCallExpectations(DisplayTransactionTest* /* test */) {}
+};
+
+// --------------------------------------------------------------------
+// Note:
+//
+// There are a large number of transitions we could test, however we only test a
+// selected subset which provides complete test coverage of the implementation.
+// --------------------------------------------------------------------
+
+template <PowerMode initialPowerMode, PowerMode targetPowerMode>
+struct TransitionVariantCommon {
+ static constexpr auto INITIAL_POWER_MODE = initialPowerMode;
+ static constexpr auto TARGET_POWER_MODE = targetPowerMode;
+
+ static void verifyPostconditions(DisplayTransactionTest*) {}
+};
+
+struct TransitionOffToOnVariant : public TransitionVariantCommon<PowerMode::OFF, PowerMode::ON> {
+ template <typename Case>
+ static void setupCallExpectations(DisplayTransactionTest* test) {
+ Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
+ Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::DispSync::setupResetModelCallExpectations(test);
+ Case::setupRepaintEverythingCallExpectations(test);
+ }
+
+ static void verifyPostconditions(DisplayTransactionTest* test) {
+ EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+ EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
+ }
+};
+
+struct TransitionOffToDozeSuspendVariant
+ : public TransitionVariantCommon<PowerMode::OFF, PowerMode::DOZE_SUSPEND> {
+ template <typename Case>
+ static void setupCallExpectations(DisplayTransactionTest* test) {
+ Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
+ Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+ Case::setupRepaintEverythingCallExpectations(test);
+ }
+
+ static void verifyPostconditions(DisplayTransactionTest* test) {
+ EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+ EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
+ }
+};
+
+struct TransitionOnToOffVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::OFF> {
+ template <typename Case>
+ static void setupCallExpectations(DisplayTransactionTest* test) {
+ Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+ Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
+ }
+
+ static void verifyPostconditions(DisplayTransactionTest* test) {
+ EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+ }
+};
+
+struct TransitionDozeSuspendToOffVariant
+ : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::OFF> {
+ template <typename Case>
+ static void setupCallExpectations(DisplayTransactionTest* test) {
+ Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+ Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
+ }
+
+ static void verifyPostconditions(DisplayTransactionTest* test) {
+ EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+ }
+};
+
+struct TransitionOnToDozeVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE> {
+ template <typename Case>
+ static void setupCallExpectations(DisplayTransactionTest* test) {
+ Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+ Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
+ }
+};
+
+struct TransitionDozeSuspendToDozeVariant
+ : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::DOZE> {
+ template <typename Case>
+ static void setupCallExpectations(DisplayTransactionTest* test) {
+ Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::DispSync::setupResetModelCallExpectations(test);
+ Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
+ }
+};
+
+struct TransitionDozeToOnVariant : public TransitionVariantCommon<PowerMode::DOZE, PowerMode::ON> {
+ template <typename Case>
+ static void setupCallExpectations(DisplayTransactionTest* test) {
+ Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+ Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
+ }
+};
+
+struct TransitionDozeSuspendToOnVariant
+ : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::ON> {
+ template <typename Case>
+ static void setupCallExpectations(DisplayTransactionTest* test) {
+ Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::DispSync::setupResetModelCallExpectations(test);
+ Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
+ }
+};
+
+struct TransitionOnToDozeSuspendVariant
+ : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE_SUSPEND> {
+ template <typename Case>
+ static void setupCallExpectations(DisplayTransactionTest* test) {
+ Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+ Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
+ }
+};
+
+struct TransitionOnToUnknownVariant
+ : public TransitionVariantCommon<PowerMode::ON, static_cast<PowerMode>(POWER_MODE_LEET)> {
+ template <typename Case>
+ static void setupCallExpectations(DisplayTransactionTest* test) {
+ Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+ Case::setupNoComposerPowerModeCallExpectations(test);
+ }
+};
+
+// --------------------------------------------------------------------
+// Note:
+//
+// Rather than testing the cartesian product of
+// DozeIsSupported/DozeNotSupported with all other options, we use one for one
+// display type, and the other for another display type.
+// --------------------------------------------------------------------
+
+template <typename DisplayVariant, typename DozeVariant, typename EventThreadVariant,
+ typename DispSyncVariant, typename TransitionVariant>
+struct DisplayPowerCase {
+ using Display = DisplayVariant;
+ using Doze = DozeVariant;
+ using EventThread = EventThreadVariant;
+ using DispSync = DispSyncVariant;
+ using Transition = TransitionVariant;
+
+ static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, PowerMode mode) {
+ Display::injectHwcDisplayWithNoDefaultCapabilities(test);
+ auto display = Display::makeFakeExistingDisplayInjector(test);
+ display.inject();
+ display.mutableDisplayDevice()->setPowerMode(mode);
+ return display;
+ }
+
+ static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
+ test->mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = enabled;
+ }
+
+ static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+ }
+
+ static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test,
+ PowerMode mode) {
+ EXPECT_CALL(*test->mSurfaceInterceptor, isEnabled()).WillOnce(Return(true));
+ EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, static_cast<int32_t>(mode)))
+ .Times(1);
+ }
+
+ static void setupComposerCallExpectations(DisplayTransactionTest* test, PowerMode mode) {
+ // Any calls to get the active config will return a default value.
+ EXPECT_CALL(*test->mComposer, getActiveConfig(Display::HWC_DISPLAY_ID, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(Display::HWC_ACTIVE_CONFIG_ID),
+ Return(Error::NONE)));
+
+ // Any calls to get whether the display supports dozing will return the value set by the
+ // policy variant.
+ EXPECT_CALL(*test->mComposer, getDozeSupport(Display::HWC_DISPLAY_ID, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(Doze::DOZE_SUPPORTED), Return(Error::NONE)));
+
+ EXPECT_CALL(*test->mComposer, setPowerMode(Display::HWC_DISPLAY_ID, mode)).Times(1);
+ }
+
+ static void setupNoComposerPowerModeCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, setPowerMode(Display::HWC_DISPLAY_ID, _)).Times(0);
+ }
+};
+
+// A sample configuration for the primary display.
+// In addition to having event thread support, we emulate doze support.
+template <typename TransitionVariant>
+using PrimaryDisplayPowerCase =
+ DisplayPowerCase<PrimaryDisplayVariant, DozeIsSupportedVariant<PrimaryDisplayVariant>,
+ EventThreadIsSupportedVariant, DispSyncIsSupportedVariant,
+ TransitionVariant>;
+
+// A sample configuration for the external display.
+// In addition to not having event thread support, we emulate not having doze
+// support.
+template <typename TransitionVariant>
+using ExternalDisplayPowerCase =
+ DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant<ExternalDisplayVariant>,
+ EventThreadNotSupportedVariant, DispSyncNotSupportedVariant,
+ TransitionVariant>;
+
+class SetPowerModeInternalTest : public DisplayTransactionTest {
+public:
+ template <typename Case>
+ void transitionDisplayCommon();
+};
+
+template <PowerMode PowerMode>
+struct PowerModeInitialVSyncEnabled : public std::false_type {};
+
+template <>
+struct PowerModeInitialVSyncEnabled<PowerMode::ON> : public std::true_type {};
+
+template <>
+struct PowerModeInitialVSyncEnabled<PowerMode::DOZE> : public std::true_type {};
+
+template <typename Case>
+void SetPowerModeInternalTest::transitionDisplayCommon() {
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ Case::Doze::setupComposerCallExpectations(this);
+ auto display =
+ Case::injectDisplayWithInitialPowerMode(this, Case::Transition::INITIAL_POWER_MODE);
+ Case::setInitialPrimaryHWVsyncEnabled(this,
+ PowerModeInitialVSyncEnabled<
+ Case::Transition::INITIAL_POWER_MODE>::value);
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ Case::setupSurfaceInterceptorCallExpectations(this, Case::Transition::TARGET_POWER_MODE);
+ Case::Transition::template setupCallExpectations<Case>(this);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.setPowerModeInternal(display.mutableDisplayDevice(),
+ Case::Transition::TARGET_POWER_MODE);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ Case::Transition::verifyPostconditions(this);
+}
+
+TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfNoChange) {
+ using Case = SimplePrimaryDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // A primary display device is set up
+ Case::Display::injectHwcDisplay(this);
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The display is already set to PowerMode::ON
+ display.mutableDisplayDevice()->setPowerMode(PowerMode::ON);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::ON);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
+}
+
+TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) {
+ using Case = HwcVirtualDisplayCase;
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // Insert display data so that the HWC thinks it created the virtual display.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId));
+ mFlinger.mutableHwcDisplayData().try_emplace(displayId);
+
+ // A virtual display device is set up
+ Case::Display::injectHwcDisplay(this);
+ auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+ display.inject();
+
+ // The display is set to PowerMode::ON
+ getDisplayDevice(display.token())->setPowerMode(PowerMode::ON);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::OFF);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
+ transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendPrimaryDisplay) {
+ transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffPrimaryDisplay) {
+ transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffPrimaryDisplay) {
+ transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozePrimaryDisplay) {
+ transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozePrimaryDisplay) {
+ transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnPrimaryDisplay) {
+ transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnPrimaryDisplay) {
+ transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendPrimaryDisplay) {
+ transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownPrimaryDisplay) {
+ transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToUnknownVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnExternalDisplay) {
+ transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendExternalDisplay) {
+ transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffExternalDisplay) {
+ transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffExternalDisplay) {
+ transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeExternalDisplay) {
+ transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) {
+ transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnExternalDisplay) {
+ transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) {
+ transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) {
+ transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownExternalDisplay) {
+ transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToUnknownVariant>>();
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
new file mode 100644
index 0000000..61f0788
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+using hal::RenderIntent;
+
+// For this variant, SurfaceFlinger should configure itself with wide display
+// support, and the display should respond with an non-empty list of supported
+// color modes. Wide-color support should be configured.
+template <typename Display>
+struct WideColorP3ColorimetricSupportedVariant {
+ static constexpr bool WIDE_COLOR_SUPPORTED = true;
+
+ static void injectConfigChange(DisplayTransactionTest* test) {
+ test->mFlinger.mutableUseColorManagement() = true;
+ test->mFlinger.mutableHasWideColorDisplay() = true;
+ test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
+ }
+
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_DATASPACE)).Times(1);
+
+ EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::DISPLAY_P3})),
+ Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getRenderIntents(Display::HWC_DISPLAY_ID, ColorMode::DISPLAY_P3, _))
+ .WillOnce(DoAll(SetArgPointee<2>(
+ std::vector<RenderIntent>({RenderIntent::COLORIMETRIC})),
+ Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ setColorMode(Display::HWC_DISPLAY_ID, ColorMode::SRGB,
+ RenderIntent::COLORIMETRIC))
+ .WillOnce(Return(Error::NONE));
+ }
+};
+
+template <typename Display>
+struct Hdr10PlusSupportedVariant {
+ static constexpr bool HDR10_PLUS_SUPPORTED = true;
+ static constexpr bool HDR10_SUPPORTED = true;
+ static constexpr bool HDR_HLG_SUPPORTED = false;
+ static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getHdrCapabilities(_, _, _, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({
+ Hdr::HDR10_PLUS,
+ Hdr::HDR10,
+ })),
+ Return(Error::NONE)));
+ }
+};
+
+// For this variant, the composer should respond with a non-empty list of HDR
+// modes containing HDR10, so HDR10 support should be configured.
+template <typename Display>
+struct Hdr10SupportedVariant {
+ static constexpr bool HDR10_PLUS_SUPPORTED = false;
+ static constexpr bool HDR10_SUPPORTED = true;
+ static constexpr bool HDR_HLG_SUPPORTED = false;
+ static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::HDR10})),
+ Return(Error::NONE)));
+ }
+};
+
+// For this variant, the composer should respond with a non-empty list of HDR
+// modes containing HLG, so HLG support should be configured.
+template <typename Display>
+struct HdrHlgSupportedVariant {
+ static constexpr bool HDR10_PLUS_SUPPORTED = false;
+ static constexpr bool HDR10_SUPPORTED = false;
+ static constexpr bool HDR_HLG_SUPPORTED = true;
+ static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+ .WillOnce(
+ DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::HLG})), Return(Error::NONE)));
+ }
+};
+
+// For this variant, the composer should respond with a non-empty list of HDR
+// modes containing DOLBY_VISION, so DOLBY_VISION support should be configured.
+template <typename Display>
+struct HdrDolbyVisionSupportedVariant {
+ static constexpr bool HDR10_PLUS_SUPPORTED = false;
+ static constexpr bool HDR10_SUPPORTED = false;
+ static constexpr bool HDR_HLG_SUPPORTED = false;
+ static constexpr bool HDR_DOLBY_VISION_SUPPORTED = true;
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::DOLBY_VISION})),
+ Return(Error::NONE)));
+ }
+};
+
+template <typename Display>
+struct Smpte2086PerFrameMetadataSupportVariant {
+ static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::SMPTE2086;
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+ .WillOnce(Return(std::vector<PerFrameMetadataKey>({
+ PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X,
+ PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y,
+ PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X,
+ PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y,
+ PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X,
+ PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y,
+ PerFrameMetadataKey::WHITE_POINT_X,
+ PerFrameMetadataKey::WHITE_POINT_Y,
+ PerFrameMetadataKey::MAX_LUMINANCE,
+ PerFrameMetadataKey::MIN_LUMINANCE,
+ })));
+ }
+};
+
+template <typename Display>
+struct Cta861_3_PerFrameMetadataSupportVariant {
+ static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::CTA861_3;
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+ .WillOnce(Return(std::vector<PerFrameMetadataKey>({
+ PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL,
+ PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL,
+ })));
+ }
+};
+
+template <typename Display>
+struct Hdr10_Plus_PerFrameMetadataSupportVariant {
+ static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::HDR10PLUS;
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+ .WillOnce(Return(std::vector<PerFrameMetadataKey>({
+ PerFrameMetadataKey::HDR10_PLUS_SEI,
+ })));
+ }
+};
+
+using WideColorP3ColorimetricDisplayCase =
+ Case<PrimaryDisplayVariant, WideColorP3ColorimetricSupportedVariant<PrimaryDisplayVariant>,
+ HdrNotSupportedVariant<PrimaryDisplayVariant>,
+ NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using Hdr10PlusDisplayCase =
+ Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+ Hdr10SupportedVariant<PrimaryDisplayVariant>,
+ Hdr10_Plus_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using Hdr10DisplayCase =
+ Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+ Hdr10SupportedVariant<PrimaryDisplayVariant>,
+ NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrHlgDisplayCase =
+ Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+ HdrHlgSupportedVariant<PrimaryDisplayVariant>,
+ NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrDolbyVisionDisplayCase =
+ Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+ HdrDolbyVisionSupportedVariant<PrimaryDisplayVariant>,
+ NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrSmpte2086DisplayCase =
+ Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+ HdrNotSupportedVariant<PrimaryDisplayVariant>,
+ Smpte2086PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrCta861_3_DisplayCase =
+ Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+ HdrNotSupportedVariant<PrimaryDisplayVariant>,
+ Cta861_3_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+
+class SetupNewDisplayDeviceInternalTest : public DisplayTransactionTest {
+public:
+ template <typename T>
+ void setupNewDisplayDeviceInternalTest();
+};
+
+template <typename Case>
+void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() {
+ const sp<BBinder> displayToken = new BBinder();
+ const sp<compositionengine::mock::DisplaySurface> displaySurface =
+ new compositionengine::mock::DisplaySurface();
+ const sp<mock::GraphicBufferProducer> producer = new mock::GraphicBufferProducer();
+
+ // --------------------------------------------------------------------
+ // Preconditions
+
+ // Wide color displays support is configured appropriately
+ Case::WideColorSupport::injectConfigChange(this);
+
+ // The display is setup with the HWC.
+ Case::Display::injectHwcDisplay(this);
+
+ // SurfaceFlinger will use a test-controlled factory for native window
+ // surfaces.
+ injectFakeNativeWindowSurfaceFactory();
+
+ // A compositionengine::Display has already been created
+ auto compositionDisplay = Case::Display::injectCompositionDisplay(this);
+
+ // --------------------------------------------------------------------
+ // Call Expectations
+
+ // Various native window calls will be made.
+ Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
+ Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+ Case::WideColorSupport::setupComposerCallExpectations(this);
+ Case::HdrSupport::setupComposerCallExpectations(this);
+ Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ DisplayDeviceState state;
+ if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+ const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get());
+ ASSERT_TRUE(displayId);
+ const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
+ ASSERT_TRUE(hwcDisplayId);
+ state.physical = {.id = *displayId, .type = *connectionType, .hwcDisplayId = *hwcDisplayId};
+ }
+
+ state.isSecure = static_cast<bool>(Case::Display::SECURE);
+
+ auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
+ displaySurface, producer);
+
+ // --------------------------------------------------------------------
+ // Postconditions
+
+ ASSERT_TRUE(device != nullptr);
+ EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
+ EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType());
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
+ EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
+ EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
+ EXPECT_EQ(Case::Display::WIDTH, device->getWidth());
+ EXPECT_EQ(Case::Display::HEIGHT, device->getHeight());
+ EXPECT_EQ(Case::WideColorSupport::WIDE_COLOR_SUPPORTED, device->hasWideColorGamut());
+ EXPECT_EQ(Case::HdrSupport::HDR10_PLUS_SUPPORTED, device->hasHDR10PlusSupport());
+ EXPECT_EQ(Case::HdrSupport::HDR10_SUPPORTED, device->hasHDR10Support());
+ EXPECT_EQ(Case::HdrSupport::HDR_HLG_SUPPORTED, device->hasHLGSupport());
+ EXPECT_EQ(Case::HdrSupport::HDR_DOLBY_VISION_SUPPORTED, device->hasDolbyVisionSupport());
+ // Note: This is not Case::Display::HWC_ACTIVE_CONFIG_ID as the ids are
+ // remapped, and the test only ever sets up one config. If there were an error
+ // looking up the remapped index, device->getActiveConfig() would be -1 instead.
+ EXPECT_EQ(0, device->getActiveConfig().value());
+ EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS,
+ device->getSupportedPerFrameMetadata());
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createSimplePrimaryDisplay) {
+ setupNewDisplayDeviceInternalTest<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createSimpleExternalDisplay) {
+ setupNewDisplayDeviceInternalTest<SimpleExternalDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createNonHwcVirtualDisplay) {
+ setupNewDisplayDeviceInternalTest<NonHwcVirtualDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) {
+ setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) {
+ setupNewDisplayDeviceInternalTest<WideColorP3ColorimetricDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10PlusDisplay) {
+ setupNewDisplayDeviceInternalTest<Hdr10PlusDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10Display) {
+ setupNewDisplayDeviceInternalTest<Hdr10DisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrHlgDisplay) {
+ setupNewDisplayDeviceInternalTest<HdrHlgDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrDolbyVisionDisplay) {
+ setupNewDisplayDeviceInternalTest<HdrDolbyVisionDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrSmpte2086DisplayCase) {
+ setupNewDisplayDeviceInternalTest<HdrSmpte2086DisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrCta816_3_DisplayCase) {
+ setupNewDisplayDeviceInternalTest<HdrCta861_3_DisplayCase>();
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h
index 8e1f943..5c5b18e 100644
--- a/services/surfaceflinger/tests/utils/TransactionUtils.h
+++ b/services/surfaceflinger/tests/utils/TransactionUtils.h
@@ -16,6 +16,9 @@
#pragma once
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <chrono>
#include <android/native_window.h>
@@ -181,3 +184,6 @@
};
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
index 0d4c55e..6589f74 100644
--- a/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
+++ b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
@@ -46,13 +46,26 @@
auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }
- bool hasCapabilities(vibrator::HalResult<vibrator::Capabilities> result,
- vibrator::Capabilities query) {
+ bool hasCapabilities(const vibrator::HalResult<vibrator::Capabilities>& result,
+ vibrator::Capabilities&& query, State& state) {
+ if (result.isFailed()) {
+ state.SkipWithError(result.errorMessage());
+ return false;
+ }
if (!result.isOk()) {
return false;
}
return (result.value() & query) == query;
}
+
+ template <class R>
+ bool checkHalResult(const vibrator::HalResult<R>& result, State& state) {
+ if (result.isFailed()) {
+ state.SkipWithError(result.errorMessage());
+ return false;
+ }
+ return true;
+ }
};
#define BENCHMARK_WRAPPER(fixt, test, code) \
@@ -79,7 +92,10 @@
BENCHMARK_WRAPPER(VibratorBench, ping, {
for (auto _ : state) {
- mController.ping();
+ state.ResumeTiming();
+ auto ret = mController.ping();
+ state.PauseTiming();
+ checkHalResult(ret, state);
}
});
@@ -95,9 +111,11 @@
for (auto _ : state) {
state.ResumeTiming();
- mController.on(duration, callback);
+ auto ret = mController.on(duration, callback);
state.PauseTiming();
- mController.off();
+ if (checkHalResult(ret, state)) {
+ checkHalResult(mController.off(), state);
+ }
}
});
@@ -107,16 +125,18 @@
for (auto _ : state) {
state.PauseTiming();
- mController.on(duration, callback);
+ if (!checkHalResult(mController.on(duration, callback), state)) {
+ continue;
+ }
state.ResumeTiming();
- mController.off();
+ checkHalResult(mController.off(), state);
}
});
BENCHMARK_WRAPPER(VibratorBench, setAmplitude, {
- auto capabilitiesResult = mController.getCapabilities();
+ auto result = mController.getCapabilities();
- if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::AMPLITUDE_CONTROL)) {
+ if (!hasCapabilities(result, vibrator::Capabilities::AMPLITUDE_CONTROL, state)) {
return;
}
@@ -128,18 +148,22 @@
state.PauseTiming();
vibrator::HalController controller;
controller.init();
- controller.on(duration, callback);
+ if (!checkHalResult(controller.on(duration, callback), state)) {
+ continue;
+ }
state.ResumeTiming();
- controller.setAmplitude(amplitude);
+ auto ret = controller.setAmplitude(amplitude);
state.PauseTiming();
- controller.off();
+ if (checkHalResult(ret, state)) {
+ checkHalResult(controller.off(), state);
+ }
}
});
BENCHMARK_WRAPPER(VibratorBench, setAmplitudeCached, {
- auto capabilitiesResult = mController.getCapabilities();
+ auto result = mController.getCapabilities();
- if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::AMPLITUDE_CONTROL)) {
+ if (!hasCapabilities(result, vibrator::Capabilities::AMPLITUDE_CONTROL, state)) {
return;
}
@@ -147,19 +171,19 @@
auto callback = []() {};
auto amplitude = UINT8_MAX;
- mController.on(duration, callback);
+ checkHalResult(mController.on(duration, callback), state);
for (auto _ : state) {
- mController.setAmplitude(amplitude);
+ checkHalResult(mController.setAmplitude(amplitude), state);
}
- mController.off();
+ checkHalResult(mController.off(), state);
});
BENCHMARK_WRAPPER(VibratorBench, setExternalControl, {
- auto capabilitiesResult = mController.getCapabilities();
+ auto result = mController.getCapabilities();
- if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::EXTERNAL_CONTROL)) {
+ if (!hasCapabilities(result, vibrator::Capabilities::EXTERNAL_CONTROL, state)) {
return;
}
@@ -168,43 +192,47 @@
vibrator::HalController controller;
controller.init();
state.ResumeTiming();
- controller.setExternalControl(true);
+ auto ret = controller.setExternalControl(true);
state.PauseTiming();
- controller.setExternalControl(false);
+ if (checkHalResult(ret, state)) {
+ checkHalResult(controller.setExternalControl(false), state);
+ }
}
});
BENCHMARK_WRAPPER(VibratorBench, setExternalControlCached, {
- auto capabilitiesResult = mController.getCapabilities();
+ auto result = mController.getCapabilities();
- if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::EXTERNAL_CONTROL)) {
+ if (!hasCapabilities(result, vibrator::Capabilities::EXTERNAL_CONTROL, state)) {
return;
}
for (auto _ : state) {
state.ResumeTiming();
- mController.setExternalControl(true);
+ auto ret = mController.setExternalControl(true);
state.PauseTiming();
- mController.setExternalControl(false);
+ if (checkHalResult(ret, state)) {
+ checkHalResult(mController.setExternalControl(false), state);
+ }
}
});
BENCHMARK_WRAPPER(VibratorBench, setExternalAmplitudeCached, {
- auto capabilitiesResult = mController.getCapabilities();
+ auto result = mController.getCapabilities();
- if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::EXTERNAL_AMPLITUDE_CONTROL)) {
+ if (!hasCapabilities(result, vibrator::Capabilities::EXTERNAL_AMPLITUDE_CONTROL, state)) {
return;
}
auto amplitude = UINT8_MAX;
- mController.setExternalControl(true);
+ checkHalResult(mController.setExternalControl(true), state);
for (auto _ : state) {
- mController.setAmplitude(amplitude);
+ checkHalResult(mController.setAmplitude(amplitude), state);
}
- mController.setExternalControl(false);
+ checkHalResult(mController.setExternalControl(false), state);
});
BENCHMARK_WRAPPER(VibratorBench, getCapabilities, {
@@ -213,16 +241,16 @@
vibrator::HalController controller;
controller.init();
state.ResumeTiming();
- controller.getCapabilities();
+ checkHalResult(controller.getCapabilities(), state);
}
});
BENCHMARK_WRAPPER(VibratorBench, getCapabilitiesCached, {
// First call to cache values.
- mController.getCapabilities();
+ checkHalResult(mController.getCapabilities(), state);
for (auto _ : state) {
- mController.getCapabilities();
+ checkHalResult(mController.getCapabilities(), state);
}
});
@@ -232,16 +260,16 @@
vibrator::HalController controller;
controller.init();
state.ResumeTiming();
- controller.getSupportedEffects();
+ checkHalResult(controller.getSupportedEffects(), state);
}
});
BENCHMARK_WRAPPER(VibratorBench, getSupportedEffectsCached, {
// First call to cache values.
- mController.getSupportedEffects();
+ checkHalResult(mController.getSupportedEffects(), state);
for (auto _ : state) {
- mController.getSupportedEffects();
+ checkHalResult(mController.getSupportedEffects(), state);
}
});
@@ -251,16 +279,16 @@
vibrator::HalController controller;
controller.init();
state.ResumeTiming();
- controller.getSupportedPrimitives();
+ checkHalResult(controller.getSupportedPrimitives(), state);
}
});
BENCHMARK_WRAPPER(VibratorBench, getSupportedPrimitivesCached, {
// First call to cache values.
- mController.getSupportedPrimitives();
+ checkHalResult(mController.getSupportedPrimitives(), state);
for (auto _ : state) {
- mController.getSupportedPrimitives();
+ checkHalResult(mController.getSupportedPrimitives(), state);
}
});
@@ -274,6 +302,10 @@
}
std::vector<hardware::vibrator::Effect> supported = effectsResult.value();
+ if (supported.empty()) {
+ return;
+ }
+
b->ArgNames({"Effect", "Strength"});
for (const auto& effect : enum_range<hardware::vibrator::Effect>()) {
if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
@@ -296,9 +328,9 @@
};
BENCHMARK_WRAPPER(VibratorEffectsBench, alwaysOnEnable, {
- auto capabilitiesResult = mController.getCapabilities();
+ auto result = mController.getCapabilities();
- if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::ALWAYS_ON_CONTROL)) {
+ if (!hasCapabilities(result, vibrator::Capabilities::ALWAYS_ON_CONTROL, state)) {
return;
}
@@ -308,16 +340,18 @@
for (auto _ : state) {
state.ResumeTiming();
- mController.alwaysOnEnable(id, effect, strength);
+ auto ret = mController.alwaysOnEnable(id, effect, strength);
state.PauseTiming();
- mController.alwaysOnDisable(id);
+ if (checkHalResult(ret, state)) {
+ checkHalResult(mController.alwaysOnDisable(id), state);
+ }
}
});
BENCHMARK_WRAPPER(VibratorEffectsBench, alwaysOnDisable, {
- auto capabilitiesResult = mController.getCapabilities();
+ auto result = mController.getCapabilities();
- if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::ALWAYS_ON_CONTROL)) {
+ if (!hasCapabilities(result, vibrator::Capabilities::ALWAYS_ON_CONTROL, state)) {
return;
}
@@ -327,9 +361,11 @@
for (auto _ : state) {
state.PauseTiming();
- mController.alwaysOnEnable(id, effect, strength);
+ if (!checkHalResult(mController.alwaysOnEnable(id, effect, strength), state)) {
+ continue;
+ }
state.ResumeTiming();
- mController.alwaysOnDisable(id);
+ checkHalResult(mController.alwaysOnDisable(id), state);
}
});
@@ -340,9 +376,11 @@
for (auto _ : state) {
state.ResumeTiming();
- mController.performEffect(effect, strength, callback);
+ auto ret = mController.performEffect(effect, strength, callback);
state.PauseTiming();
- mController.off();
+ if (checkHalResult(ret, state)) {
+ checkHalResult(mController.off(), state);
+ }
}
});
@@ -356,11 +394,18 @@
}
std::vector<hardware::vibrator::CompositePrimitive> supported = primitivesResult.value();
+ if (supported.empty()) {
+ return;
+ }
+
b->ArgNames({"Primitive"});
for (const auto& primitive : enum_range<hardware::vibrator::CompositePrimitive>()) {
if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) {
continue;
}
+ if (primitive == hardware::vibrator::CompositePrimitive::NOOP) {
+ continue;
+ }
b->Args({static_cast<long>(primitive)});
}
}
@@ -372,16 +417,16 @@
};
BENCHMARK_WRAPPER(VibratorPrimitivesBench, performComposedEffect, {
- auto capabilitiesResult = mController.getCapabilities();
+ auto result = mController.getCapabilities();
- if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::COMPOSE_EFFECTS)) {
+ if (!hasCapabilities(result, vibrator::Capabilities::COMPOSE_EFFECTS, state)) {
return;
}
hardware::vibrator::CompositeEffect effect;
effect.primitive = getPrimitive(state);
effect.scale = 1.0f;
- effect.delayMs = 0;
+ effect.delayMs = static_cast<int32_t>(0);
std::vector<hardware::vibrator::CompositeEffect> effects;
effects.push_back(effect);
@@ -389,9 +434,11 @@
for (auto _ : state) {
state.ResumeTiming();
- mController.performComposedEffect(effects, callback);
+ auto ret = mController.performComposedEffect(effects, callback);
state.PauseTiming();
- mController.off();
+ if (checkHalResult(ret, state)) {
+ checkHalResult(mController.off(), state);
+ }
}
});
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index f69de1f..1d29bab 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -21,7 +21,7 @@
}
llndk_library {
- name: "libvulkan",
+ name: "libvulkan.llndk",
symbol_file: "libvulkan.map.txt",
export_llndk_headers: [
"vulkan_headers_llndk",
@@ -30,6 +30,7 @@
cc_library_shared {
name: "libvulkan",
+ llndk_stubs: "libvulkan.llndk",
clang: true,
sanitize: {
misc_undefined: ["integer"],
@@ -89,7 +90,6 @@
"libhardware",
"libsync",
"libbase",
- "libdl_android",
"libhidlbase",
"liblog",
"libui",
@@ -100,6 +100,7 @@
"libnativebridge_lazy",
"libnativeloader_lazy",
"libnativewindow",
+ "libvndksupport",
"android.hardware.graphics.common@1.0",
"libSurfaceFlingerProp",
],
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index d9a9427..26052fb 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -226,6 +226,7 @@
INIT_PROC(true, dev, CreateQueryPool);
INIT_PROC(true, dev, DestroyQueryPool);
INIT_PROC(true, dev, GetQueryPoolResults);
+ INIT_PROC(false, dev, ResetQueryPool);
INIT_PROC(true, dev, CreateBuffer);
INIT_PROC(true, dev, DestroyBuffer);
INIT_PROC(true, dev, CreateBufferView);
@@ -337,8 +338,20 @@
INIT_PROC(false, dev, DestroySamplerYcbcrConversion);
INIT_PROC(false, dev, GetDeviceQueue2);
INIT_PROC(false, dev, GetDescriptorSetLayoutSupport);
+ INIT_PROC(false, dev, CreateRenderPass2);
+ INIT_PROC(false, dev, CmdBeginRenderPass2);
+ INIT_PROC(false, dev, CmdNextSubpass2);
+ INIT_PROC(false, dev, CmdEndRenderPass2);
+ INIT_PROC(false, dev, GetSemaphoreCounterValue);
+ INIT_PROC(false, dev, WaitSemaphores);
+ INIT_PROC(false, dev, SignalSemaphore);
INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetAndroidHardwareBufferPropertiesANDROID);
INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetMemoryAndroidHardwareBufferANDROID);
+ INIT_PROC(false, dev, CmdDrawIndirectCount);
+ INIT_PROC(false, dev, CmdDrawIndexedIndirectCount);
+ INIT_PROC(false, dev, GetBufferOpaqueCaptureAddress);
+ INIT_PROC(false, dev, GetBufferDeviceAddress);
+ INIT_PROC(false, dev, GetDeviceMemoryOpaqueCaptureAddress);
// clang-format on
return success;
@@ -391,6 +404,7 @@
VKAPI_ATTR VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
VKAPI_ATTR void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);
VKAPI_ATTR void DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView);
@@ -520,8 +534,20 @@
VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo);
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue);
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout);
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo);
VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties);
VKAPI_ATTR VkResult GetMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer);
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo);
VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) {
return GetData(instance).dispatch.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
@@ -551,6 +577,7 @@
"vkEnumerateInstanceVersion",
"vkEnumeratePhysicalDeviceGroups",
"vkEnumeratePhysicalDeviceGroupsKHR",
+ "vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR",
"vkEnumeratePhysicalDevices",
"vkGetDisplayModeProperties2KHR",
"vkGetDisplayPlaneCapabilities2KHR",
@@ -571,7 +598,7 @@
"vkGetPhysicalDeviceFormatProperties",
"vkGetPhysicalDeviceFormatProperties2",
"vkGetPhysicalDeviceFormatProperties2KHR",
- "vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX",
+ "vkGetPhysicalDeviceFragmentShadingRatesKHR",
"vkGetPhysicalDeviceImageFormatProperties",
"vkGetPhysicalDeviceImageFormatProperties2",
"vkGetPhysicalDeviceImageFormatProperties2KHR",
@@ -583,6 +610,7 @@
"vkGetPhysicalDeviceProperties",
"vkGetPhysicalDeviceProperties2",
"vkGetPhysicalDeviceProperties2KHR",
+ "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR",
"vkGetPhysicalDeviceQueueFamilyProperties",
"vkGetPhysicalDeviceQueueFamilyProperties2",
"vkGetPhysicalDeviceQueueFamilyProperties2KHR",
@@ -595,6 +623,7 @@
"vkGetPhysicalDeviceSurfaceFormatsKHR",
"vkGetPhysicalDeviceSurfacePresentModesKHR",
"vkGetPhysicalDeviceSurfaceSupportKHR",
+ "vkGetPhysicalDeviceToolPropertiesEXT",
"vkSubmitDebugUtilsMessageEXT",
};
// clang-format on
@@ -646,6 +675,7 @@
{ "vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2) },
{ "vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery) },
{ "vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass) },
+ { "vkCmdBeginRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass2) },
{ "vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets) },
{ "vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdBindIndexBuffer) },
{ "vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(CmdBindPipeline) },
@@ -665,12 +695,16 @@
{ "vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw) },
{ "vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed) },
{ "vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirect) },
+ { "vkCmdDrawIndexedIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirectCount) },
{ "vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirect) },
+ { "vkCmdDrawIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirectCount) },
{ "vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdEndQuery) },
{ "vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass) },
+ { "vkCmdEndRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass2) },
{ "vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(CmdExecuteCommands) },
{ "vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdFillBuffer) },
{ "vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass) },
+ { "vkCmdNextSubpass2", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass2) },
{ "vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier) },
{ "vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdPushConstants) },
{ "vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdResetEvent) },
@@ -709,6 +743,7 @@
{ "vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineLayout) },
{ "vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool) },
{ "vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass) },
+ { "vkCreateRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass2) },
{ "vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler) },
{ "vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(CreateSamplerYcbcrConversion) },
{ "vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore) },
@@ -749,13 +784,16 @@
{ "vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets) },
{ "vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory) },
{ "vkGetAndroidHardwareBufferPropertiesANDROID", reinterpret_cast<PFN_vkVoidFunction>(GetAndroidHardwareBufferPropertiesANDROID) },
+ { "vkGetBufferDeviceAddress", reinterpret_cast<PFN_vkVoidFunction>(GetBufferDeviceAddress) },
{ "vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements) },
{ "vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements2) },
+ { "vkGetBufferOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(GetBufferOpaqueCaptureAddress) },
{ "vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(GetDescriptorSetLayoutSupport) },
{ "vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPeerMemoryFeatures) },
{ "vkGetDeviceGroupPresentCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPresentCapabilitiesKHR) },
{ "vkGetDeviceGroupSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupSurfacePresentModesKHR) },
{ "vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryCommitment) },
+ { "vkGetDeviceMemoryOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryOpaqueCaptureAddress) },
{ "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) },
{ "vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue) },
{ "vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2) },
@@ -771,6 +809,7 @@
{ "vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData) },
{ "vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults) },
{ "vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(GetRenderAreaGranularity) },
+ { "vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(GetSemaphoreCounterValue) },
{ "vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR) },
{ "vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(InvalidateMappedMemoryRanges) },
{ "vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(MapMemory) },
@@ -784,12 +823,15 @@
{ "vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(ResetDescriptorPool) },
{ "vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(ResetEvent) },
{ "vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences) },
+ { "vkResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(ResetQueryPool) },
{ "vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent) },
+ { "vkSignalSemaphore", reinterpret_cast<PFN_vkVoidFunction>(SignalSemaphore) },
{ "vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(TrimCommandPool) },
{ "vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory) },
{ "vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSetWithTemplate) },
{ "vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets) },
{ "vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences) },
+ { "vkWaitSemaphores", reinterpret_cast<PFN_vkVoidFunction>(WaitSemaphores) },
};
// clang-format on
constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
@@ -965,6 +1007,10 @@
return GetData(device).dispatch.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
}
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+ GetData(device).dispatch.ResetQueryPool(device, queryPool, firstQuery, queryCount);
+}
+
VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer) {
return GetData(device).dispatch.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
}
@@ -1481,6 +1527,34 @@
GetData(device).dispatch.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
}
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) {
+ return GetData(device).dispatch.CreateRenderPass2(device, pCreateInfo, pAllocator, pRenderPass);
+}
+
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+ GetData(commandBuffer).dispatch.CmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
+}
+
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+ GetData(commandBuffer).dispatch.CmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
+}
+
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+ GetData(commandBuffer).dispatch.CmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
+}
+
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+ return GetData(device).dispatch.GetSemaphoreCounterValue(device, semaphore, pValue);
+}
+
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+ return GetData(device).dispatch.WaitSemaphores(device, pWaitInfo, timeout);
+}
+
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+ return GetData(device).dispatch.SignalSemaphore(device, pSignalInfo);
+}
+
VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
return GetData(device).dispatch.GetAndroidHardwareBufferPropertiesANDROID(device, buffer, pProperties);
}
@@ -1489,6 +1563,26 @@
return GetData(device).dispatch.GetMemoryAndroidHardwareBufferANDROID(device, pInfo, pBuffer);
}
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+ GetData(commandBuffer).dispatch.CmdDrawIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+ GetData(commandBuffer).dispatch.CmdDrawIndexedIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ return GetData(device).dispatch.GetBufferOpaqueCaptureAddress(device, pInfo);
+}
+
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ return GetData(device).dispatch.GetBufferDeviceAddress(device, pInfo);
+}
+
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+ return GetData(device).dispatch.GetDeviceMemoryOpaqueCaptureAddress(device, pInfo);
+}
+
} // anonymous namespace
@@ -1755,6 +1849,11 @@
}
__attribute__((visibility("default")))
+VKAPI_ATTR void vkResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+ vulkan::api::ResetQueryPool(device, queryPool, firstQuery, queryCount);
+}
+
+__attribute__((visibility("default")))
VKAPI_ATTR VkResult vkCreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer) {
return vulkan::api::CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
}
@@ -2400,6 +2499,41 @@
}
__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkCreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) {
+ return vulkan::api::CreateRenderPass2(device, pCreateInfo, pAllocator, pRenderPass);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+ vulkan::api::CmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+ vulkan::api::CmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+ vulkan::api::CmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+ return vulkan::api::GetSemaphoreCounterValue(device, semaphore, pValue);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+ return vulkan::api::WaitSemaphores(device, pWaitInfo, timeout);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+ return vulkan::api::SignalSemaphore(device, pSignalInfo);
+}
+
+__attribute__((visibility("default")))
VKAPI_ATTR VkResult vkGetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
return vulkan::api::GetAndroidHardwareBufferPropertiesANDROID(device, buffer, pProperties);
}
@@ -2409,4 +2543,29 @@
return vulkan::api::GetMemoryAndroidHardwareBufferANDROID(device, pInfo, pBuffer);
}
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+ vulkan::api::CmdDrawIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+ vulkan::api::CmdDrawIndexedIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR uint64_t vkGetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ return vulkan::api::GetBufferOpaqueCaptureAddress(device, pInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkDeviceAddress vkGetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ return vulkan::api::GetBufferDeviceAddress(device, pInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR uint64_t vkGetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+ return vulkan::api::GetDeviceMemoryOpaqueCaptureAddress(device, pInfo);
+}
+
// clang-format on
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 2195845..ad5cc34 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -99,6 +99,7 @@
PFN_vkCreateQueryPool CreateQueryPool;
PFN_vkDestroyQueryPool DestroyQueryPool;
PFN_vkGetQueryPoolResults GetQueryPoolResults;
+ PFN_vkResetQueryPool ResetQueryPool;
PFN_vkCreateBuffer CreateBuffer;
PFN_vkDestroyBuffer DestroyBuffer;
PFN_vkCreateBufferView CreateBufferView;
@@ -210,8 +211,20 @@
PFN_vkDestroySamplerYcbcrConversion DestroySamplerYcbcrConversion;
PFN_vkGetDeviceQueue2 GetDeviceQueue2;
PFN_vkGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupport;
+ PFN_vkCreateRenderPass2 CreateRenderPass2;
+ PFN_vkCmdBeginRenderPass2 CmdBeginRenderPass2;
+ PFN_vkCmdNextSubpass2 CmdNextSubpass2;
+ PFN_vkCmdEndRenderPass2 CmdEndRenderPass2;
+ PFN_vkGetSemaphoreCounterValue GetSemaphoreCounterValue;
+ PFN_vkWaitSemaphores WaitSemaphores;
+ PFN_vkSignalSemaphore SignalSemaphore;
PFN_vkGetAndroidHardwareBufferPropertiesANDROID GetAndroidHardwareBufferPropertiesANDROID;
PFN_vkGetMemoryAndroidHardwareBufferANDROID GetMemoryAndroidHardwareBufferANDROID;
+ PFN_vkCmdDrawIndirectCount CmdDrawIndirectCount;
+ PFN_vkCmdDrawIndexedIndirectCount CmdDrawIndexedIndirectCount;
+ PFN_vkGetBufferOpaqueCaptureAddress GetBufferOpaqueCaptureAddress;
+ PFN_vkGetBufferDeviceAddress GetBufferDeviceAddress;
+ PFN_vkGetDeviceMemoryOpaqueCaptureAddress GetDeviceMemoryOpaqueCaptureAddress;
// clang-format on
};
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 4068a16..6f09a8c 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -28,20 +28,17 @@
#include <android/dlext.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
-#include <cutils/properties.h>
#include <graphicsenv/GraphicsEnv.h>
#include <log/log.h>
-#include <nativeloader/dlext_namespaces.h>
#include <sys/prctl.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
+#include <vndksupport/linker.h>
#include <algorithm>
#include <array>
#include <climits>
#include <new>
-#include <string_view>
-#include <sstream>
#include <vector>
#include "stubhal.h"
@@ -157,19 +154,11 @@
Hal Hal::hal_;
-void* LoadLibrary(const android_dlextinfo& dlextinfo,
- const std::string_view subname) {
- ATRACE_CALL();
-
- std::stringstream ss;
- ss << "vulkan." << subname << ".so";
- return android_dlopen_ext(ss.str().c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
-}
-
const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
"ro.hardware.vulkan",
"ro.board.platform",
}};
+constexpr int LIB_DL_FLAGS = RTLD_LOCAL | RTLD_NOW;
// LoadDriver returns:
// * 0 when succeed, or
@@ -180,20 +169,26 @@
const hwvulkan_module_t** module) {
ATRACE_CALL();
- const android_dlextinfo dlextinfo = {
- .flags = ANDROID_DLEXT_USE_NAMESPACE,
- .library_namespace = library_namespace,
- };
void* so = nullptr;
- char prop[PROPERTY_VALUE_MAX];
for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
- int prop_len = property_get(key, prop, nullptr);
- if (prop_len > 0 && prop_len <= UINT_MAX) {
- std::string_view lib_name(prop, static_cast<unsigned int>(prop_len));
- so = LoadLibrary(dlextinfo, lib_name);
- if (so)
- break;
+ std::string lib_name = android::base::GetProperty(key, "");
+ if (lib_name.empty())
+ continue;
+
+ lib_name = "vulkan." + lib_name + ".so";
+ if (library_namespace) {
+ // load updated driver
+ const android_dlextinfo dlextinfo = {
+ .flags = ANDROID_DLEXT_USE_NAMESPACE,
+ .library_namespace = library_namespace,
+ };
+ so = android_dlopen_ext(lib_name.c_str(), LIB_DL_FLAGS, &dlextinfo);
+ } else {
+ // load built-in driver
+ so = android_load_sphal_library(lib_name.c_str(), LIB_DL_FLAGS);
}
+ if (so)
+ break;
}
if (!so)
return -ENOENT;
@@ -217,12 +212,9 @@
int LoadBuiltinDriver(const hwvulkan_module_t** module) {
ATRACE_CALL();
- auto ns = android_get_exported_namespace("sphal");
- if (!ns)
- return -ENOENT;
android::GraphicsEnv::getInstance().setDriverToLoad(
android::GpuStatsInfo::Driver::VULKAN);
- return LoadDriver(ns, module);
+ return LoadDriver(nullptr, module);
}
int LoadUpdatedDriver(const hwvulkan_module_t** module) {
@@ -323,7 +315,7 @@
"hw_device_t::close() failed.");
// Close the opened shared library in the hw_module_t
- dlclose(hal_.dev_->common.module->dso);
+ android_unload_sphal_library(hal_.dev_->common.module->dso);
hal_.dev_ = nullptr;
hal_.debug_report_index_ = -1;
@@ -658,6 +650,7 @@
case ProcHook::GOOGLE_display_timing:
case ProcHook::EXTENSION_CORE_1_0:
case ProcHook::EXTENSION_CORE_1_1:
+ case ProcHook::EXTENSION_CORE_1_2:
case ProcHook::EXTENSION_COUNT:
// Device and meta extensions. If we ever get here it's a bug in
// our code. But enumerating them lets us avoid having a default
@@ -711,6 +704,7 @@
case ProcHook::ANDROID_native_buffer:
case ProcHook::EXTENSION_CORE_1_0:
case ProcHook::EXTENSION_CORE_1_1:
+ case ProcHook::EXTENSION_CORE_1_2:
case ProcHook::EXTENSION_COUNT:
// Instance and meta extensions. If we ever get here it's a bug
// in our code. But enumerating them lets us avoid having a
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 1aba674..047e774 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -57,6 +57,7 @@
EXTENSION_CORE_1_0,
EXTENSION_CORE_1_1,
+ EXTENSION_CORE_1_2,
EXTENSION_COUNT,
EXTENSION_UNKNOWN,
};
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
index 0be66c9..df97d7f 100644
--- a/vulkan/libvulkan/libvulkan.map.txt
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -12,6 +12,7 @@
vkBindImageMemory2; # introduced=28
vkCmdBeginQuery;
vkCmdBeginRenderPass;
+ vkCmdBeginRenderPass2; # introduced=31
vkCmdBindDescriptorSets;
vkCmdBindIndexBuffer;
vkCmdBindPipeline;
@@ -31,12 +32,16 @@
vkCmdDraw;
vkCmdDrawIndexed;
vkCmdDrawIndexedIndirect;
+ vkCmdDrawIndexedIndirectCount; # introduced=31
vkCmdDrawIndirect;
+ vkCmdDrawIndirectCount; # introduced=31
vkCmdEndQuery;
vkCmdEndRenderPass;
+ vkCmdEndRenderPass2; # introduced=31
vkCmdExecuteCommands;
vkCmdFillBuffer;
vkCmdNextSubpass;
+ vkCmdNextSubpass2; # introduced=31
vkCmdPipelineBarrier;
vkCmdPushConstants;
vkCmdResetEvent;
@@ -76,6 +81,7 @@
vkCreatePipelineLayout;
vkCreateQueryPool;
vkCreateRenderPass;
+ vkCreateRenderPass2; # introduced=31
vkCreateSampler;
vkCreateSamplerYcbcrConversion; # introduced=28
vkCreateSemaphore;
@@ -119,13 +125,16 @@
vkFreeDescriptorSets;
vkFreeMemory;
vkGetAndroidHardwareBufferPropertiesANDROID; # introduced=28
+ vkGetBufferDeviceAddress; # introduced=31
vkGetBufferMemoryRequirements;
vkGetBufferMemoryRequirements2; # introduced=28
+ vkGetBufferOpaqueCaptureAddress; # introduced=31
vkGetDescriptorSetLayoutSupport; # introduced=28
vkGetDeviceGroupPeerMemoryFeatures; # introduced=28
vkGetDeviceGroupPresentCapabilitiesKHR; # introduced=28
vkGetDeviceGroupSurfacePresentModesKHR; # introduced=28
vkGetDeviceMemoryCommitment;
+ vkGetDeviceMemoryOpaqueCaptureAddress; # introduced=31
vkGetDeviceProcAddr;
vkGetDeviceQueue;
vkGetDeviceQueue2; # introduced=28
@@ -163,6 +172,7 @@
vkGetPipelineCacheData;
vkGetQueryPoolResults;
vkGetRenderAreaGranularity;
+ vkGetSemaphoreCounterValue; # introduced=31
vkGetSwapchainImagesKHR;
vkInvalidateMappedMemoryRanges;
vkMapMemory;
@@ -176,12 +186,15 @@
vkResetDescriptorPool;
vkResetEvent;
vkResetFences;
+ vkResetQueryPool; # introduced=31
vkSetEvent;
+ vkSignalSemaphore; # introduced=31
vkTrimCommandPool; # introduced=28
vkUnmapMemory;
vkUpdateDescriptorSets;
vkUpdateDescriptorSetWithTemplate; # introduced=28
vkWaitForFences;
+ vkWaitSemaphores; # introduced=31
local:
*;
};
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 4647a80..b94233b 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -1123,6 +1123,14 @@
return VK_SUCCESS;
}
+VkResult CreateRenderPass2(VkDevice device,
+ const VkRenderPassCreateInfo2*,
+ const VkAllocationCallbacks* /*allocator*/,
+ VkRenderPass* pRenderPass) {
+ *pRenderPass = AllocHandle<VkRenderPass>(device, HandleType::kRenderPass);
+ return VK_SUCCESS;
+}
+
// -----------------------------------------------------------------------------
// No-op entrypoints
@@ -1568,6 +1576,55 @@
void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
}
+void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+}
+
+void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+}
+
+void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+}
+
+void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+}
+
+VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return VK_SUCCESS;
+}
+
+VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return VK_SUCCESS;
+}
+
+VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return VK_SUCCESS;
+}
+
+void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+}
+
+void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+}
+
+uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return 0;
+}
+
+VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return (VkDeviceAddress)0;
+}
+
+uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return 0;
+}
+
#pragma clang diagnostic pop
// clang-format on
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index b8d7d2b..edda12c 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -67,6 +67,7 @@
{"vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindImageMemory2>(BindImageMemory2))},
{"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginQuery>(CmdBeginQuery))},
{"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginRenderPass>(CmdBeginRenderPass))},
+ {"vkCmdBeginRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginRenderPass2>(CmdBeginRenderPass2))},
{"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindDescriptorSets>(CmdBindDescriptorSets))},
{"vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindIndexBuffer>(CmdBindIndexBuffer))},
{"vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindPipeline>(CmdBindPipeline))},
@@ -86,12 +87,16 @@
{"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDraw>(CmdDraw))},
{"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexed>(CmdDrawIndexed))},
{"vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexedIndirect>(CmdDrawIndexedIndirect))},
+ {"vkCmdDrawIndexedIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexedIndirectCount>(CmdDrawIndexedIndirectCount))},
{"vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndirect>(CmdDrawIndirect))},
+ {"vkCmdDrawIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndirectCount>(CmdDrawIndirectCount))},
{"vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndQuery>(CmdEndQuery))},
{"vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndRenderPass>(CmdEndRenderPass))},
+ {"vkCmdEndRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndRenderPass2>(CmdEndRenderPass2))},
{"vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdExecuteCommands>(CmdExecuteCommands))},
{"vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdFillBuffer>(CmdFillBuffer))},
{"vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdNextSubpass>(CmdNextSubpass))},
+ {"vkCmdNextSubpass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdNextSubpass2>(CmdNextSubpass2))},
{"vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdPipelineBarrier>(CmdPipelineBarrier))},
{"vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdPushConstants>(CmdPushConstants))},
{"vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdResetEvent>(CmdResetEvent))},
@@ -131,6 +136,7 @@
{"vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreatePipelineLayout>(CreatePipelineLayout))},
{"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateQueryPool>(CreateQueryPool))},
{"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateRenderPass>(CreateRenderPass))},
+ {"vkCreateRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateRenderPass2>(CreateRenderPass2))},
{"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSampler>(CreateSampler))},
{"vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSamplerYcbcrConversion>(CreateSamplerYcbcrConversion))},
{"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSemaphore>(CreateSemaphore))},
@@ -172,11 +178,14 @@
{"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeCommandBuffers>(FreeCommandBuffers))},
{"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeDescriptorSets>(FreeDescriptorSets))},
{"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeMemory>(FreeMemory))},
+ {"vkGetBufferDeviceAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferDeviceAddress>(GetBufferDeviceAddress))},
{"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements>(GetBufferMemoryRequirements))},
{"vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements2>(GetBufferMemoryRequirements2))},
+ {"vkGetBufferOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferOpaqueCaptureAddress>(GetBufferOpaqueCaptureAddress))},
{"vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDescriptorSetLayoutSupport>(GetDescriptorSetLayoutSupport))},
{"vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceGroupPeerMemoryFeatures>(GetDeviceGroupPeerMemoryFeatures))},
{"vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceMemoryCommitment>(GetDeviceMemoryCommitment))},
+ {"vkGetDeviceMemoryOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceMemoryOpaqueCaptureAddress>(GetDeviceMemoryOpaqueCaptureAddress))},
{"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr))},
{"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue>(GetDeviceQueue))},
{"vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue2>(GetDeviceQueue2))},
@@ -215,6 +224,7 @@
{"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPipelineCacheData>(GetPipelineCacheData))},
{"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetQueryPoolResults>(GetQueryPoolResults))},
{"vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetRenderAreaGranularity>(GetRenderAreaGranularity))},
+ {"vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSemaphoreCounterValue>(GetSemaphoreCounterValue))},
{"vkGetSwapchainGrallocUsage2ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage2ANDROID>(GetSwapchainGrallocUsage2ANDROID))},
{"vkGetSwapchainGrallocUsageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID))},
{"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkInvalidateMappedMemoryRanges>(InvalidateMappedMemoryRanges))},
@@ -229,12 +239,15 @@
{"vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetDescriptorPool>(ResetDescriptorPool))},
{"vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetEvent>(ResetEvent))},
{"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetFences>(ResetFences))},
+ {"vkResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetQueryPool>(ResetQueryPool))},
{"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkSetEvent>(SetEvent))},
+ {"vkSignalSemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkSignalSemaphore>(SignalSemaphore))},
{"vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkTrimCommandPool>(TrimCommandPool))},
{"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUnmapMemory>(UnmapMemory))},
{"vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSetWithTemplate>(UpdateDescriptorSetWithTemplate))},
{"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSets>(UpdateDescriptorSets))},
{"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkWaitForFences>(WaitForFences))},
+ {"vkWaitSemaphores", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkWaitSemaphores>(WaitSemaphores))},
// clang-format on
};
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 0d3f688..e59cae9 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -79,6 +79,7 @@
VKAPI_ATTR VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
VKAPI_ATTR void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);
VKAPI_ATTR void DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView);
@@ -207,6 +208,18 @@
VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo);
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue);
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout);
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo);
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo);
// clang-format on
} // namespace null_driver
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index ef021f2..72fd4fb 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -25,6 +25,7 @@
_BLOCKED_EXTENSIONS = [
'VK_EXT_acquire_xlib_display',
'VK_EXT_direct_mode_display',
+ 'VK_EXT_directfb_surface',
'VK_EXT_display_control',
'VK_EXT_display_surface_counter',
'VK_EXT_full_screen_exclusive',
@@ -314,12 +315,12 @@
else:
f.write('INIT_PROC(')
- if name in version_dict and version_dict[name] == 'VK_VERSION_1_1':
+ if name in _OPTIONAL_COMMANDS:
f.write('false, ')
- elif name in _OPTIONAL_COMMANDS:
- f.write('false, ')
- else:
+ elif version_dict[name] == 'VK_VERSION_1_0':
f.write('true, ')
+ else:
+ f.write('false, ')
if is_instance_dispatched(name):
f.write('instance, ')
@@ -389,7 +390,7 @@
for exts in root.iter('extensions'):
for extension in exts:
- apiversion = ''
+ apiversion = 'VK_VERSION_1_0'
if extension.tag == 'extension':
extname = extension.get('name')
if (extension.get('type') == 'instance' and
@@ -404,8 +405,7 @@
cmd_name = commands.get('name')
if cmd_name not in extension_dict:
extension_dict[cmd_name] = extname
- if apiversion:
- version_dict[cmd_name] = apiversion
+ version_dict[cmd_name] = apiversion
for feature in root.iter('feature'):
apiversion = feature.get('name')
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index b0b466c..bfc240e 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -57,9 +57,17 @@
template <typename T> struct EnumTraits;
template <> struct EnumTraits<VkPhysicalDeviceType> {
- static uint32_t min() { return VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE; }
- static uint32_t max() { return VK_PHYSICAL_DEVICE_TYPE_END_RANGE; }
- static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+ static bool exist(uint32_t e) {
+ switch (e) {
+ case VK_PHYSICAL_DEVICE_TYPE_OTHER:
+ case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
+ case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
+ case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
+ case VK_PHYSICAL_DEVICE_TYPE_CPU:
+ return true;
+ }
+ return false;
+ }
};
template <> struct EnumTraits<VkFormat> {
@@ -250,6 +258,40 @@
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
+ case VK_FORMAT_G8B8G8R8_422_UNORM:
+ case VK_FORMAT_B8G8R8G8_422_UNORM:
+ case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
+ case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
+ case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
+ case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
+ case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
+ case VK_FORMAT_R10X6_UNORM_PACK16:
+ case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
+ case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
+ case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
+ case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
+ case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
+ case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
+ case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
+ case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
+ case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
+ case VK_FORMAT_R12X4_UNORM_PACK16:
+ case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
+ case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
+ case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
+ case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
+ case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
+ case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
+ case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
+ case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
+ case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
+ case VK_FORMAT_G16B16G16R16_422_UNORM:
+ case VK_FORMAT_B16G16R16G16_422_UNORM:
+ case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
+ case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
+ case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
+ case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
+ case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
@@ -258,40 +300,22 @@
case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
- case VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
- case VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
- case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
- case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
- case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
- case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
- case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR:
- case VK_FORMAT_R10X6_UNORM_PACK16_KHR:
- case VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR:
- case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR:
- case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
- case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
- case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
- case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
- case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
- case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
- case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR:
- case VK_FORMAT_R12X4_UNORM_PACK16_KHR:
- case VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR:
- case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR:
- case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
- case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
- case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
- case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
- case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
- case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
- case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR:
- case VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
- case VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
- case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
- case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
- case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
- case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
- case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR:
+ case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT:
+ case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT:
return true;
}
return false;
@@ -300,9 +324,14 @@
template <>
struct EnumTraits<VkPointClippingBehavior> {
- static uint32_t min() { return VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE; }
- static uint32_t max() { return VK_POINT_CLIPPING_BEHAVIOR_END_RANGE; }
- static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+ static bool exist(uint32_t e) {
+ switch (e) {
+ case VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES:
+ case VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY:
+ return true;
+ }
+ return false;
+ }
};
template <>
@@ -336,9 +365,26 @@
template <>
struct EnumTraits<VkDriverIdKHR> {
- static uint32_t min() { return VK_DRIVER_ID_BEGIN_RANGE_KHR; }
- static uint32_t max() { return VK_DRIVER_ID_END_RANGE_KHR; }
- static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+ static bool exist(uint32_t e) {
+ switch (e) {
+ case VK_DRIVER_ID_AMD_PROPRIETARY:
+ case VK_DRIVER_ID_AMD_OPEN_SOURCE:
+ case VK_DRIVER_ID_MESA_RADV:
+ case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
+ case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
+ case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA:
+ case VK_DRIVER_ID_IMAGINATION_PROPRIETARY:
+ case VK_DRIVER_ID_QUALCOMM_PROPRIETARY:
+ case VK_DRIVER_ID_ARM_PROPRIETARY:
+ case VK_DRIVER_ID_GOOGLE_SWIFTSHADER:
+ case VK_DRIVER_ID_GGP_PROPRIETARY:
+ case VK_DRIVER_ID_BROADCOM_PROPRIETARY:
+ case VK_DRIVER_ID_MESA_LLVMPIPE:
+ case VK_DRIVER_ID_MOLTENVK:
+ return true;
+ }
+ return false;
+ }
};
// VkSparseImageFormatProperties
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index ace713b..eb0fcc3 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -129,7 +129,9 @@
VkFormatProperties format_properties = {};
for (VkFormat format = VK_FORMAT_R4G4_UNORM_PACK8;
- format <= VK_FORMAT_END_RANGE;
+ // TODO(http://b/171403054): avoid hard-coding last value in the
+ // contiguous range
+ format <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK;
format = static_cast<VkFormat>(format + 1)) {
vkGetPhysicalDeviceFormatProperties(physical_device, format,
&format_properties);
@@ -142,6 +144,8 @@
if (device.properties.apiVersion >= VK_API_VERSION_1_1) {
for (VkFormat format = VK_FORMAT_G8B8G8R8_422_UNORM;
+ // TODO(http://b/171403054): avoid hard-coding last value in the
+ // contiguous range
format <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM;
format = static_cast<VkFormat>(format + 1)) {
vkGetPhysicalDeviceFormatProperties(physical_device, format,