Merge "Revert "Handle different scale and offset for pointers in InputTarget.""
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 5186ad3..cf75bba 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -854,7 +854,6 @@
tags |= c.tags;
}
}
- ok &= setTagsProperty(tags);
bool coreServicesTagEnabled = false;
for (size_t i = 0; i < arraysize(k_categories); i++) {
@@ -876,9 +875,11 @@
packageList += android::base::GetProperty(k_coreServicesProp, "");
}
ok &= setAppCmdlineProperty(&packageList[0]);
+ ok &= setTagsProperty(tags);
+#if !ATRACE_SHMEM
ok &= pokeBinderServices();
pokeHalServices();
-
+#endif
if (g_tracePdx) {
ok &= ServiceUtility::PokeServices();
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 6b14bee..e7b0d5d 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -108,6 +108,8 @@
* Property to control if app data isolation is enabled.
*/
static constexpr const char* kAppDataIsolationEnabledProperty = "persist.zygote.app_data_isolation";
+static constexpr const char* kMntSdcardfs = "/mnt/runtime/default/";
+static constexpr const char* kMntFuse = "/mnt/pass_through/0/";
static std::atomic<bool> sAppDataIsolationEnabled(false);
@@ -271,7 +273,7 @@
ps->startThreadPool();
ps->giveThreadPoolName();
sAppDataIsolationEnabled = android::base::GetBoolProperty(
- kAppDataIsolationEnabledProperty, false);
+ kAppDataIsolationEnabledProperty, true);
return android::OK;
}
@@ -2686,15 +2688,13 @@
std::getline(in, ignored);
if (android::base::GetBoolProperty(kFuseProp, false)) {
- // TODO(b/146139106): Use sdcardfs mounts on devices running sdcardfs so we don't bypass
- // it's VFS cache
- if (target.compare(0, 17, "/mnt/pass_through") == 0) {
+ if (target.find(kMntFuse) == 0) {
LOG(DEBUG) << "Found storage mount " << source << " at " << target;
mStorageMounts[source] = target;
}
} else {
#if !BYPASS_SDCARDFS
- if (target.compare(0, 21, "/mnt/runtime/default/") == 0) {
+ if (target.find(kMntSdcardfs) == 0) {
LOG(DEBUG) << "Found storage mount " << source << " at " << target;
mStorageMounts[source] = target;
}
@@ -2792,17 +2792,6 @@
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
auto path = StringPrintf("%s/media", create_data_path(uuid_).c_str());
- if (android::base::GetBoolProperty(kFuseProp, false)) {
- // TODO(b/146139106): This is only safe on devices not running sdcardfs where there is no
- // risk of bypassing the sdcardfs VFS cache
-
- // Always use the lower filesystem path on FUSE enabled devices not running sdcardfs
- // The upper filesystem path, /mnt/pass_through/<userid>/<vol>/ which was a bind mount
- // to the lower filesytem may have been unmounted already when a user is
- // removed and the path will now be pointing to a tmpfs without content
- return StringPrintf("%s/%u", path.c_str(), userid);
- }
-
auto resolved = mStorageMounts[path];
if (resolved.empty()) {
LOG(WARNING) << "Failed to find storage mount for " << path;
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 0d6c31e..675aad6 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -606,7 +606,7 @@
pc.viewport().bottom());
Rect frame = Rect(pc.frame().left(), pc.frame().top(), pc.frame().right(), pc.frame().bottom());
- t.setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame);
+ t.setDisplayProjection(mDisplays[id], ui::toRotation(pc.orientation()), viewport, frame);
}
status_t Replayer::createSurfaceControl(
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 01cf2f8..41718b2 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -100,6 +100,19 @@
int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
AndroidBitmapInfo* info);
+#if __ANDROID_API__ >= 30
+
+/**
+ * Given a java bitmap object, return its ADataSpace.
+ *
+ * Note that ADataSpace only exposes a few values. This may return
+ * ADATASPACE_UNKNOWN, even for Named ColorSpaces, if they have no
+ * corresponding ADataSpace.
+ */
+int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap) __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
/**
* Given a java bitmap object, attempt to lock the pixel address.
* Locking will ensure that the memory for the pixels will not move
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
new file mode 100644
index 0000000..50daaba
--- /dev/null
+++ b/include/android/imagedecoder.h
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup ImageDecoder
+ * @{
+ */
+
+/**
+ * @file imageDecoder.h
+ */
+
+#ifndef ANDROID_IMAGE_DECODER_H
+#define ANDROID_IMAGE_DECODER_H
+
+#include "bitmap.h"
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AAsset;
+struct ARect;
+
+#if __ANDROID_API__ >= 30
+
+/** AImageDecoder functions result code. */
+enum {
+ // Decoding was successful and complete.
+ ANDROID_IMAGE_DECODER_SUCCESS = 0,
+ // The input was incomplete. In decodeImage, this means a partial
+ // image was decoded. Undecoded lines are all zeroes.
+ // In AImageDecoder_create*, no AImageDecoder was created.
+ ANDROID_IMAGE_DECODER_INCOMPLETE = -1,
+ // The input contained an error after decoding some lines. Similar to
+ // INCOMPLETE, above.
+ ANDROID_IMAGE_DECODER_ERROR = -2,
+ // Could not convert, e.g. attempting to decode an image with
+ // alpha to an opaque format.
+ ANDROID_IMAGE_DECODER_INVALID_CONVERSION = -3,
+ // The scale is invalid. It may have overflowed, or it may be incompatible
+ // with the current alpha setting.
+ ANDROID_IMAGE_DECODER_INVALID_SCALE = -4,
+ // Some other parameter was bad (e.g. pixels)
+ ANDROID_IMAGE_DECODER_BAD_PARAMETER = -5,
+ // Input was invalid i.e. broken before decoding any pixels.
+ ANDROID_IMAGE_DECODER_INVALID_INPUT = -6,
+ // A seek was required, and failed.
+ ANDROID_IMAGE_DECODER_SEEK_ERROR = -7,
+ // Some other error (e.g. OOM)
+ ANDROID_IMAGE_DECODER_INTERNAL_ERROR = -8,
+ // We did not recognize the format
+ ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT = -9
+};
+
+struct AImageDecoder;
+
+/**
+ * Opaque handle for decoding images.
+ *
+ * Create using one of the following:
+ * - {@link AImageDecoder_createFromAAsset}
+ * - {@link AImageDecoder_createFromFd}
+ * - {@link AImageDecoder_createFromBuffer}
+ */
+typedef struct AImageDecoder AImageDecoder;
+
+/**
+ * Create a new AImageDecoder from an AAsset.
+ *
+ * @param asset {@link AAsset} containing encoded image data. Client is still
+ * responsible for calling {@link AAsset_close} on it.
+ * @param outDecoder On success (i.e. return value is
+ * {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
+ * a newly created {@link AImageDecoder}. Caller is
+ * responsible for calling {@link AImageDecoder_delete} on it.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating reason for the failure.
+ */
+int AImageDecoder_createFromAAsset(AAsset* asset, AImageDecoder** outDecoder) __INTRODUCED_IN(30);
+
+/**
+ * Create a new AImageDecoder from a file descriptor.
+ *
+ * @param fd Seekable, readable, open file descriptor for encoded data.
+ * Client is still responsible for closing it, which may be done
+ * *after* deleting the returned AImageDecoder.
+ * @param outDecoder On success (i.e. return value is
+ * {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
+ * a newly created {@link AImageDecoder}. Caller is
+ * responsible for calling {@link AImageDecoder_delete} on it.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating reason for the failure.
+ */
+int AImageDecoder_createFromFd(int fd, AImageDecoder** outDecoder) __INTRODUCED_IN(30);
+
+/**
+ * Create a new AImageDecoder from a buffer.
+ *
+ * @param buffer Pointer to encoded data. Must be valid for the entire time
+ * the AImageDecoder is used.
+ * @param length Byte length of buffer.
+ * @param outDecoder On success (i.e. return value is
+ * {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
+ * a newly created {@link AImageDecoder}. Caller is
+ * responsible for calling {@link AImageDecoder_delete} on it.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating reason for the failure.
+ */
+int AImageDecoder_createFromBuffer(const void* buffer, size_t length,
+ AImageDecoder** outDecoder) __INTRODUCED_IN(30);
+
+/**
+ * Delete the AImageDecoder.
+ */
+void AImageDecoder_delete(AImageDecoder* decoder) __INTRODUCED_IN(30);
+
+/**
+ * Choose the desired output format.
+ *
+ * @param format AndroidBitmapFormat to use
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} if the format is compatible
+ * with the image and {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION}
+ * otherwise. In the latter case, the AImageDecoder uses the
+ * format it was already planning to use (either its default
+ * or a previously successful setting from this function).
+ */
+int AImageDecoder_setAndroidBitmapFormat(AImageDecoder*,
+ int32_t format) __INTRODUCED_IN(30);
+
+/*
+ * Choose the desired output format.
+ *
+ * Must be one of:
+ * {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}
+ * {@link ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE}
+ * {@link ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL}
+ *
+ * Note: An OPAQUE image may be set to any of them.
+ * A non-OPAQUE image may not be set to OPAQUE
+ *
+ * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION} if the conversion
+ * is not possible
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for bad parameters
+ */
+int AImageDecoder_setAlphaFlags(AImageDecoder*, int alphaFlags) __INTRODUCED_IN(30);
+
+/**
+ * Specify the output size for a decoded image.
+ *
+ * Future calls to {@link AImageDecoder_decodeImage} will sample or scale the
+ * encoded image to reach the desired size. If a crop rect is set (via
+ * {@link AImageDecoder_setCrop}), it must be contained within the dimensions
+ * specified by width and height, and the output image will be the size of the
+ * crop rect.
+ *
+ * @param width Width of the output (prior to cropping).
+ * This will affect future calls to
+ * {@link AImageDecoder_getMinimumStride}, which will now return
+ * a value based on this width.
+ * @param height Height of the output (prior to cropping).
+ * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the AImageDecoder
+ * pointer is null, width or height is <= 0, or any existing crop is
+ * not contained by the image dimensions.
+ */
+int AImageDecoder_setTargetSize(AImageDecoder*, int width, int height) __INTRODUCED_IN(30);
+
+/**
+ * Specify how to crop the output after scaling (if any).
+ *
+ * Future calls to {@link AImageDecoder_decodeImage} will crop their output to
+ * the specified {@link ARect}. Clients will only need to allocate enough memory
+ * for the cropped ARect.
+ *
+ * @param crop Rectangle describing a crop of the decode. It must be contained inside of
+ * the (possibly scaled, by {@link AImageDecoder_setTargetSize})
+ * image dimensions. This will affect future calls to
+ * {@link AImageDecoder_getMinimumStride}, which will now return a
+ * value based on the width of the crop. An empty ARect -
+ * specifically { 0, 0, 0, 0 } - may be used to remove the cropping
+ * behavior. Any other empty or unsorted ARects will result in
+ * returning ANDROID_IMAGE_DECODER_BAD_PARAMETER.
+ * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the AImageDecoder
+ * pointer is null or the crop is not contained by the image
+ * dimensions.
+ */
+int AImageDecoder_setCrop(AImageDecoder*, ARect crop) __INTRODUCED_IN(30);
+
+/**
+ * Opaque handle for reading header info.
+ */
+struct AImageDecoderHeaderInfo;
+typedef struct AImageDecoderHeaderInfo AImageDecoderHeaderInfo;
+
+/**
+ * Return an opaque handle for reading header info.
+ *
+ * This is owned by the {@link AImageDecoder} and will be destroyed when the
+ * AImageDecoder is destroyed via {@link AImageDecoder_delete}.
+ */
+const AImageDecoderHeaderInfo* AImageDecoder_getHeaderInfo(
+ const AImageDecoder*) __INTRODUCED_IN(30);
+
+/**
+ * Report the native width of the encoded image.
+ */
+int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Report the native height of the encoded image.
+ */
+int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Report the mimeType of the encoded image.
+ *
+ * @return a string literal describing the mime type.
+ */
+const char* AImageDecoderHeaderInfo_getMimeType(
+ const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Report whether the encoded image represents an animation.
+ */
+bool AImageDecoderHeaderInfo_isAnimated(
+ const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Report the AndroidBitmapFormat the AImageDecoder will decode to
+ * by default. AImageDecoder will try to choose one that is sensible
+ * for the image and the system. Note that this does not indicate the
+ * encoded format of the image.
+ */
+AndroidBitmapFormat AImageDecoderHeaderInfo_getAndroidBitmapFormat(
+ const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Report how the AImageDecoder will handle alpha by default. If the image
+ * contains no alpha (according to its header), this will return
+ * {@link ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE}. If the image may contain alpha,
+ * this returns {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}.
+ *
+ * For animated images only the opacity of the first frame is reported.
+ */
+int AImageDecoderHeaderInfo_getAlphaFlags(
+ const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Return the minimum stride that can be used, taking the specified
+ * (or default) (possibly scaled) width, crop rect and
+ * {@link AndroidBitmapFormat} into account.
+ */
+size_t AImageDecoder_getMinimumStride(AImageDecoder*) __INTRODUCED_IN(30);
+
+/**
+ * Decode the image into pixels, using the settings of the AImageDecoder.
+ *
+ * @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 fit |size| bytes.
+ * @param stride Width in bytes of a single row. Must be at least
+ * {@link AImageDecoder_getMinimumStride}.
+ * @param size Size of the pixel buffer in bytes. Must be at least
+ * stride * (height - 1) +
+ * {@link AImageDecoder_getMinimumStride}.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success, or an error code
+ * from the same enum describing the failure.
+ */
+int AImageDecoder_decodeImage(AImageDecoder* decoder,
+ void* pixels, size_t stride,
+ size_t size) __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ANDROID_IMAGE_DECODER_H
+
+/** @} */
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index fa456bb..6100626 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -17,16 +17,23 @@
#ifndef _LIBINPUT_DISPLAY_VIEWPORT_H
#define _LIBINPUT_DISPLAY_VIEWPORT_H
-#include <android-base/stringprintf.h>
-#include <ui/DisplayInfo.h>
-#include <input/Input.h>
-#include <inttypes.h>
+#include <cinttypes>
#include <optional>
+#include <android-base/stringprintf.h>
+#include <input/Input.h>
+
using android::base::StringPrintf;
namespace android {
+enum {
+ DISPLAY_ORIENTATION_0 = 0,
+ DISPLAY_ORIENTATION_90 = 1,
+ DISPLAY_ORIENTATION_180 = 2,
+ DISPLAY_ORIENTATION_270 = 3
+};
+
/**
* Describes the different type of viewports supported by input flinger.
* Keep in sync with values in InputManagerService.java.
diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h
index b49c623..4fa2f86 100644
--- a/include/input/TouchVideoFrame.h
+++ b/include/input/TouchVideoFrame.h
@@ -19,7 +19,6 @@
#include <stdint.h>
#include <sys/time.h>
-#include <ui/DisplayInfo.h>
#include <vector>
namespace android {
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index a8f7d92..b1943a4 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -14,6 +14,7 @@
"-Wall",
"-Wextra",
],
+ export_include_dirs: ["."],
}
cc_test {
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 4ee9f55..ee44cf5 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -85,6 +85,16 @@
return policyN1 - policyN2;
}
+static int bpf_obj_get_wronly(const char *pathname) {
+ union bpf_attr attr;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.pathname = ptr_to_u64((void *)pathname);
+ attr.file_flags = BPF_F_WRONLY;
+
+ return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
+}
+
static bool initGlobals() {
std::lock_guard<std::mutex> guard(gInitializedMutex);
if (gInitialized) return true;
@@ -153,17 +163,17 @@
bool startTrackingUidTimes() {
if (!initGlobals()) return false;
- unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
- if (fd < 0) return false;
+ unique_fd cpuPolicyFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+ if (cpuPolicyFd < 0) return false;
for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
for (auto &cpu : gPolicyCpus[i]) {
- if (writeToMapEntry(fd, &cpu, &i, BPF_ANY)) return false;
+ if (writeToMapEntry(cpuPolicyFd, &cpu, &i, BPF_ANY)) return false;
}
}
- unique_fd fd2(bpf_obj_get(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
- if (fd2 < 0) return false;
+ unique_fd freqToIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+ if (freqToIdxFd < 0) return false;
freq_idx_key_t key;
for (uint32_t i = 0; i < gNPolicies; ++i) {
key.policy = i;
@@ -173,14 +183,41 @@
// The uid_times map still uses 0-based indexes, and the sched_switch program handles
// conversion between them, so this does not affect our map reading code.
uint32_t idx = j + 1;
- if (writeToMapEntry(fd2, &key, &idx, BPF_ANY)) return false;
+ if (writeToMapEntry(freqToIdxFd, &key, &idx, BPF_ANY)) return false;
}
}
+ unique_fd cpuLastUpdateFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_last_update_map"));
+ if (cpuLastUpdateFd < 0) return false;
+ std::vector<uint64_t> zeros(get_nprocs_conf(), 0);
+ uint32_t zero = 0;
+ if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false;
+
+ unique_fd nrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_nr_active_map"));
+ if (nrActiveFd < 0) return false;
+ if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false;
+
+ unique_fd policyNrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_nr_active_map"));
+ if (policyNrActiveFd < 0) return false;
+ for (uint32_t i = 0; i < gNPolicies; ++i) {
+ if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false;
+ }
+
+ unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
+ if (policyFreqIdxFd < 0) return false;
+ for (uint32_t i = 0; i < gNPolicies; ++i) {
+ if (writeToMapEntry(policyFreqIdxFd, &i, &zero, BPF_ANY)) return false;
+ }
+
return attachTracepointProgram("sched", "sched_switch") &&
attachTracepointProgram("power", "cpu_frequency");
}
+std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs() {
+ if (!gInitialized && !initGlobals()) return {};
+ return gPolicyFreqs;
+}
+
// Retrieve the times in ns that uid spent running at each CPU frequency.
// Return contains no value on error, otherwise it contains a vector of vectors using the format:
// [[t0_0, t0_1, ...],
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index f620715..49469d8 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -26,6 +26,7 @@
std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
getUidsCpuFreqTimes();
+std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs();
struct concurrent_time_t {
std::vector<uint64_t> active;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index c0cd3e0..23d87fd 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#include <bpf_timeinstate.h>
@@ -351,5 +367,16 @@
ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end());
}
+TEST(TimeInStateTest, GetCpuFreqs) {
+ auto freqs = getCpuFreqs();
+ ASSERT_TRUE(freqs.has_value());
+
+ auto times = getUidCpuFreqTimes(0);
+ ASSERT_TRUE(times.has_value());
+
+ ASSERT_EQ(freqs->size(), times->size());
+ for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size());
+}
+
} // namespace bpf
} // namespace android
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 0477801..875059c 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -34,7 +34,6 @@
"/system/bin/mediametrics", // media.metrics
"/system/bin/mediaserver",
"/system/bin/netd",
- "/system/bin/vold",
"/system/bin/sdcard",
"/system/bin/statsd",
"/system/bin/surfaceflinger",
@@ -44,6 +43,13 @@
NULL,
};
+
+// Native processes to dump on debuggable builds.
+static const char* debuggable_native_processes_to_dump[] = {
+ "/system/bin/vold",
+ NULL,
+};
+
/* list of hal interface to dump containing process during native dumps */
static const char* hal_interfaces_to_dump[] {
"android.hardware.audio@2.0::IDevicesFactory",
@@ -106,6 +112,15 @@
return true;
}
}
+
+ if (android::base::GetBoolProperty("ro.debuggable", false)) {
+ for (const char** p = debuggable_native_processes_to_dump; *p; p++) {
+ if (!strcmp(*p, path)) {
+ return true;
+ }
+ }
+ }
+
return false;
}
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index f07c231..befabee 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -611,6 +611,10 @@
return mDriverNamespace;
}
+std::string GraphicsEnv::getDriverPath() const {
+ return mDriverPath;
+}
+
android_namespace_t* GraphicsEnv::getAngleNamespace() {
std::lock_guard<std::mutex> lock(mNamespaceMutex);
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 2219074..22a2332 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -58,6 +58,7 @@
void setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries);
// Get the updatable driver namespace.
android_namespace_t* getDriverNamespace();
+ std::string getDriverPath() const;
/*
* Apis for GpuStats
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index a5e5693..f88ddf1 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -37,8 +37,6 @@
mHeight(height),
mNextTransaction(nullptr) {
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
- mConsumer->setMaxBufferCount(MAX_BUFFERS);
- mProducer->setMaxDequeuedBufferCount(MAX_BUFFERS - 1);
mConsumer->setMaxAcquiredBufferCount(MAX_ACQUIRED_BUFFERS);
mBufferItemConsumer =
new BufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index ab4d51e..d34fe3b 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -110,10 +110,10 @@
}
virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
- bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ bool& outCapturedSecureLayers, ui::Dataspace reqDataspace,
+ ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
- ISurfaceComposer::Rotation rotation, bool captureSecureLayers) {
+ ui::Rotation rotation, bool captureSecureLayers) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(display);
@@ -1214,8 +1214,7 @@
bool capturedSecureLayers = false;
status_t res = captureScreen(display, &outBuffer, capturedSecureLayers, reqDataspace,
reqPixelFormat, sourceCrop, reqWidth, reqHeight,
- useIdentityTransform,
- static_cast<ISurfaceComposer::Rotation>(rotation),
+ useIdentityTransform, ui::toRotation(rotation),
captureSecureLayers);
reply->writeInt32(res);
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index e033f93..a7c4f46 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -203,7 +203,6 @@
DisplayState::DisplayState() :
what(0),
layerStack(0),
- orientation(eOrientationDefault),
viewport(Rect::EMPTY_RECT),
frame(Rect::EMPTY_RECT),
width(0),
@@ -215,7 +214,7 @@
output.writeStrongBinder(IInterface::asBinder(surface));
output.writeUint32(what);
output.writeUint32(layerStack);
- output.writeUint32(orientation);
+ output.writeUint32(toRotationInt(orientation));
output.write(viewport);
output.write(frame);
output.writeUint32(width);
@@ -228,7 +227,7 @@
surface = interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
what = input.readUint32();
layerStack = input.readUint32();
- orientation = input.readUint32();
+ orientation = ui::toRotation(input.readUint32());
input.read(viewport);
input.read(frame);
width = input.readUint32();
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index f378fc5..5e259e2 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -225,9 +225,11 @@
.surfaceControls[surfaceStats.surfaceControl],
surfaceStats.acquireTime, surfaceStats.previousReleaseFence,
surfaceStats.transformHint);
- callbacksMap[callbackId]
- .surfaceControls[surfaceStats.surfaceControl]
- ->setTransformHint(surfaceStats.transformHint);
+ if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) {
+ callbacksMap[callbackId]
+ .surfaceControls[surfaceStats.surfaceControl]
+ ->setTransformHint(surfaceStats.transformHint);
+ }
}
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
@@ -1399,9 +1401,9 @@
}
void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token,
- uint32_t orientation,
- const Rect& layerStackRect,
- const Rect& displayRect) {
+ ui::Rotation orientation,
+ const Rect& layerStackRect,
+ const Rect& displayRect) {
DisplayState& s(getDisplayState(token));
s.orientation = orientation;
s.viewport = layerStackRect;
@@ -1773,28 +1775,26 @@
// ----------------------------------------------------------------------------
-status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+status_t ScreenshotClient::capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace,
+ ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
- uint32_t rotation, bool captureSecureLayers,
+ ui::Rotation rotation, bool captureSecureLayers,
sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- status_t ret =
- s->captureScreen(display, outBuffer, outCapturedSecureLayers, reqDataSpace,
- reqPixelFormat, sourceCrop, reqWidth, reqHeight, useIdentityTransform,
- static_cast<ISurfaceComposer::Rotation>(rotation),
- captureSecureLayers);
+ status_t ret = s->captureScreen(display, outBuffer, outCapturedSecureLayers, reqDataSpace,
+ reqPixelFormat, sourceCrop, reqWidth, reqHeight,
+ useIdentityTransform, rotation, captureSecureLayers);
if (ret != NO_ERROR) {
return ret;
}
return ret;
}
-status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+status_t ScreenshotClient::capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace,
+ ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
- uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
+ ui::Rotation rotation, sp<GraphicBuffer>* outBuffer) {
bool ignored;
return capture(display, reqDataSpace, reqPixelFormat, sourceCrop, reqWidth, reqHeight,
useIdentityTransform, rotation, false, outBuffer, ignored);
@@ -1807,9 +1807,8 @@
return s->captureScreen(displayOrLayerStack, outDataspace, outBuffer);
}
-status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
- const ui::Dataspace reqDataSpace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace,
+ ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
float frameScale, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
@@ -1819,8 +1818,8 @@
}
status_t ScreenshotClient::captureChildLayers(
- const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace, ui::PixelFormat reqPixelFormat,
+ const Rect& sourceCrop,
const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& excludeHandles,
float frameScale, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
@@ -1830,5 +1829,5 @@
excludeHandles, frameScale, true /* childrenOnly */);
return ret;
}
-// ----------------------------------------------------------------------------
-}; // namespace android
+
+} // namespace android
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 0a0a03c..be429fe 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -69,7 +69,6 @@
std::mutex mMutex;
std::condition_variable mCallbackCV;
- static const int MAX_BUFFERS = 3;
static const int MAX_ACQUIRED_BUFFERS = 2;
int32_t mNumFrameAvailable GUARDED_BY(mMutex);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 998973c..9804c92 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -34,6 +34,7 @@
#include <ui/GraphicTypes.h>
#include <ui/PhysicalDisplayId.h>
#include <ui/PixelFormat.h>
+#include <ui/Rotation.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -81,13 +82,6 @@
eEarlyWakeup = 0x04
};
- enum Rotation {
- eRotateNone = 0,
- eRotate90 = 1,
- eRotate180 = 2,
- eRotate270 = 3
- };
-
enum VsyncSource {
eVsyncSourceApp = 0,
eVsyncSourceSurfaceFlinger = 1
@@ -249,10 +243,10 @@
* it) around its center.
*/
virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
- bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ bool& outCapturedSecureLayers, ui::Dataspace reqDataspace,
+ ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
- Rotation rotation = eRotateNone,
+ ui::Rotation rotation = ui::ROTATION_0,
bool captureSecureLayers = false) = 0;
/**
* Capture the specified screen. This requires READ_FRAME_BUFFER
@@ -276,8 +270,9 @@
* it) around its center.
*/
virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- bool useIdentityTransform, Rotation rotation = eRotateNone) {
+ const Rect& sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ bool useIdentityTransform,
+ ui::Rotation rotation = ui::ROTATION_0) {
bool outIgnored;
return captureScreen(display, outBuffer, outIgnored, ui::Dataspace::V0_SRGB,
ui::PixelFormat::RGBA_8888, sourceCrop, reqWidth, reqHeight,
@@ -301,8 +296,7 @@
*/
virtual status_t captureLayers(
const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
- const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
- const Rect& sourceCrop,
+ ui::Dataspace reqDataspace, ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& excludeHandles,
float frameScale = 1.0, bool childrenOnly = false) = 0;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index c2b5119..fb18639 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -35,6 +35,7 @@
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/Rotation.h>
namespace android {
@@ -218,15 +219,6 @@
struct DisplayState {
enum {
- eOrientationDefault = 0,
- eOrientation90 = 1,
- eOrientation180 = 2,
- eOrientation270 = 3,
- eOrientationUnchanged = 4,
- eOrientationSwapMask = 0x01
- };
-
- enum {
eSurfaceChanged = 0x01,
eLayerStackChanged = 0x02,
eDisplayProjectionChanged = 0x04,
@@ -252,7 +244,7 @@
// 0, layers will be scaled by a factor of 2 and translated by (20, 10).
// When orientation is 1, layers will be additionally rotated by 90
// degrees around the origin clockwise and translated by (W, 0).
- uint32_t orientation;
+ ui::Rotation orientation = ui::ROTATION_0;
Rect viewport;
Rect frame;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 86468a4..44f29ea 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -35,6 +35,7 @@
#include <ui/FrameStats.h>
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
+#include <ui/Rotation.h>
#include <gui/CpuConsumer.h>
#include <gui/ISurfaceComposer.h>
@@ -531,10 +532,8 @@
* mapped to. displayRect is specified post-orientation, that is
* it uses the orientation seen by the end-user.
*/
- void setDisplayProjection(const sp<IBinder>& token,
- uint32_t orientation,
- const Rect& layerStackRect,
- const Rect& displayRect);
+ void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation,
+ const Rect& layerStackRect, const Rect& displayRect);
void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
void setAnimationTransaction();
void setEarlyWakeup();
@@ -548,10 +547,8 @@
static status_t getHdrCapabilities(const sp<IBinder>& display,
HdrCapabilities* outCapabilities);
- static void setDisplayProjection(const sp<IBinder>& token,
- uint32_t orientation,
- const Rect& layerStackRect,
- const Rect& displayRect);
+ static void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation,
+ const Rect& layerStackRect, const Rect& displayRect);
inline sp<ISurfaceComposerClient> getClient() { return mClient; }
@@ -583,23 +580,23 @@
public:
// if cropping isn't required, callers may pass in a default Rect, e.g.:
// capture(display, producer, Rect(), reqWidth, ...);
- static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ static status_t capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace,
+ ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
- uint32_t rotation, bool captureSecureLayers,
+ ui::Rotation rotation, bool captureSecureLayers,
sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers);
- static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ static status_t capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace,
+ ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
- uint32_t rotation, sp<GraphicBuffer>* outBuffer);
+ ui::Rotation rotation, sp<GraphicBuffer>* outBuffer);
static status_t capture(uint64_t displayOrLayerStack, ui::Dataspace* outDataspace,
sp<GraphicBuffer>* outBuffer);
- static status_t captureLayers(const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ static status_t captureLayers(const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace,
+ ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
float frameScale, sp<GraphicBuffer>* outBuffer);
static status_t captureChildLayers(
- const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace,
+ ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>&
excludeHandles,
float frameScale, sp<GraphicBuffer>* outBuffer);
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 0f618f1..8fca883 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -123,11 +123,12 @@
void setUpProducer(BLASTBufferQueueHelper adapter, sp<IGraphicBufferProducer>& producer) {
auto igbProducer = adapter.getIGraphicBufferProducer();
ASSERT_NE(nullptr, igbProducer.get());
+ ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2));
IGraphicBufferProducer::QueueBufferOutput qbOutput;
ASSERT_EQ(NO_ERROR,
igbProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
&qbOutput));
- ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+ ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
producer = igbProducer;
}
@@ -266,7 +267,7 @@
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
Fence::NO_FENCE);
igbProducer->queueBuffer(slot, input, &qbOutput);
- ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+ ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
adapter.waitForCallbacks();
@@ -349,7 +350,7 @@
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
Fence::NO_FENCE);
igbProducer->queueBuffer(slot, input, &qbOutput);
- ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+ ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
adapter.waitForCallbacks();
// capture screen and verify that it is red
@@ -410,7 +411,7 @@
NATIVE_WINDOW_SCALING_MODE_SCALE_CROP, 0,
Fence::NO_FENCE);
igbProducer->queueBuffer(slot, input, &qbOutput);
- ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+ ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
adapter.waitForCallbacks();
// capture screen and verify that it is red
@@ -456,7 +457,7 @@
NATIVE_WINDOW_SCALING_MODE_FREEZE, tr,
Fence::NO_FENCE);
igbProducer->queueBuffer(slot, input, &qbOutput);
- ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+ ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
adapter.waitForCallbacks();
bool capturedSecureLayers;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 8d36ba7..04749e6 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -112,22 +112,31 @@
if (consumed != OK) {
return nullptr;
}
- mInputConsumer->sendFinishedSignal(seqId, true);
+ status_t status = mInputConsumer->sendFinishedSignal(seqId, true);
+ EXPECT_EQ(OK, status) << "Could not send finished signal";
return ev;
}
+ void assertFocusChange(bool hasFocus) {
+ InputEvent *ev = consumeEvent();
+ ASSERT_NE(ev, nullptr);
+ ASSERT_EQ(AINPUT_EVENT_TYPE_FOCUS, ev->getType());
+ FocusEvent *focusEvent = static_cast<FocusEvent *>(ev);
+ EXPECT_EQ(hasFocus, focusEvent->getHasFocus());
+ }
+
void expectTap(int x, int y) {
InputEvent* ev = consumeEvent();
- EXPECT_TRUE(ev != nullptr);
- EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+ ASSERT_NE(ev, nullptr);
+ ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
MotionEvent* mev = static_cast<MotionEvent*>(ev);
EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction());
EXPECT_EQ(x, mev->getX(0));
EXPECT_EQ(y, mev->getY(0));
ev = consumeEvent();
- EXPECT_TRUE(ev != nullptr);
- EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+ ASSERT_NE(ev, nullptr);
+ ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
mev = static_cast<MotionEvent*>(ev);
EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
}
@@ -212,7 +221,7 @@
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
const auto display = mComposerClient->getInternalDisplayToken();
- ASSERT_FALSE(display == nullptr);
+ ASSERT_NE(display, nullptr);
DisplayInfo info;
ASSERT_EQ(NO_ERROR, mComposerClient->getDisplayInfo(display, &info));
@@ -259,18 +268,28 @@
TEST_F(InputSurfacesTest, can_receive_input) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->showAt(100, 100);
+ surface->assertFocusChange(true);
injectTap(101, 101);
- EXPECT_TRUE(surface->consumeEvent() != nullptr);
+ EXPECT_NE(surface->consumeEvent(), nullptr);
}
+/**
+ * Set up two surfaces side-by-side. Tap each surface.
+ * Next, swap the positions of the two surfaces. Inject tap into the two
+ * original locations. Ensure that the tap is received by the surfaces in the
+ * reverse order.
+ */
TEST_F(InputSurfacesTest, input_respects_positioning) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->showAt(100, 100);
+ surface->assertFocusChange(true);
std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
surface2->showAt(200, 200);
+ surface->assertFocusChange(false);
+ surface2->assertFocusChange(true);
injectTap(201, 201);
surface2->expectTap(1, 1);
@@ -297,11 +316,16 @@
std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
surface->showAt(10, 10);
+ surface->assertFocusChange(true);
surface2->showAt(10, 10);
+ surface->assertFocusChange(false);
+ surface2->assertFocusChange(true);
surface->doTransaction([](auto &t, auto &sc) {
t.setLayer(sc, LAYER_BASE + 1);
});
+ surface2->assertFocusChange(false);
+ surface->assertFocusChange(true);
injectTap(11, 11);
surface->expectTap(1, 1);
@@ -309,6 +333,8 @@
surface2->doTransaction([](auto &t, auto &sc) {
t.setLayer(sc, LAYER_BASE + 1);
});
+ surface2->assertFocusChange(true);
+ surface->assertFocusChange(false);
injectTap(11, 11);
surface2->expectTap(1, 1);
@@ -316,6 +342,8 @@
surface2->doTransaction([](auto &t, auto &sc) {
t.hide(sc);
});
+ surface2->assertFocusChange(false);
+ surface->assertFocusChange(true);
injectTap(11, 11);
surface->expectTap(1, 1);
@@ -328,9 +356,12 @@
std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
bgSurface->showAt(100, 100);
+ bgSurface->assertFocusChange(true);
fgSurface->mInputInfo.surfaceInset = 5;
fgSurface->showAt(100, 100);
+ fgSurface->assertFocusChange(true);
+ bgSurface->assertFocusChange(false);
injectTap(106, 106);
fgSurface->expectTap(1, 1);
@@ -344,9 +375,12 @@
std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> childSurface = makeSurface(100, 100);
parentSurface->showAt(100, 100);
+ parentSurface->assertFocusChange(true);
childSurface->mInputInfo.surfaceInset = 10;
childSurface->showAt(100, 100);
+ childSurface->assertFocusChange(true);
+ parentSurface->assertFocusChange(false);
childSurface->doTransaction([&](auto &t, auto &sc) {
t.setPosition(sc, -5, -5);
@@ -365,9 +399,12 @@
std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
bgSurface->showAt(100, 100);
+ bgSurface->assertFocusChange(true);
fgSurface->mInputInfo.surfaceInset = 5;
fgSurface->showAt(100, 100);
+ bgSurface->assertFocusChange(false);
+ fgSurface->assertFocusChange(true);
fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 4.0); });
@@ -384,6 +421,7 @@
// In case we pass the very big inset without any checking.
fgSurface->mInputInfo.surfaceInset = INT32_MAX;
fgSurface->showAt(100, 100);
+ fgSurface->assertFocusChange(true);
fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
@@ -400,6 +438,7 @@
t.setTransparentRegionHint(sc, transparentRegion);
});
surface->showAt(100, 100);
+ surface->assertFocusChange(true);
injectTap(101, 101);
surface->expectTap(1, 1);
}
@@ -414,7 +453,10 @@
InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
bgSurface->showAt(10, 10);
+ bgSurface->assertFocusChange(true);
bufferSurface->showAt(10, 10);
+ bgSurface->assertFocusChange(false);
+ bufferSurface->assertFocusChange(true);
injectTap(11, 11);
bufferSurface->expectTap(1, 1);
@@ -431,7 +473,10 @@
postBuffer(bufferSurface->mSurfaceControl);
bgSurface->showAt(10, 10);
+ bgSurface->assertFocusChange(true);
bufferSurface->showAt(10, 10);
+ bufferSurface->assertFocusChange(true);
+ bgSurface->assertFocusChange(false);
injectTap(11, 11);
bufferSurface->expectTap(1, 1);
@@ -447,7 +492,10 @@
std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
bgSurface->showAt(10, 10);
+ bgSurface->assertFocusChange(true);
fgSurface->showAt(10, 10);
+ bgSurface->assertFocusChange(false);
+ fgSurface->assertFocusChange(true);
injectTap(11, 11);
fgSurface->expectTap(1, 1);
@@ -464,12 +512,17 @@
InputSurface::makeContainerInputSurface(mComposerClient, 100, 100);
bgSurface->showAt(10, 10);
+ bgSurface->assertFocusChange(true);
containerSurface->showAt(10, 10);
+ bgSurface->assertFocusChange(false);
+ containerSurface->assertFocusChange(true);
injectTap(11, 11);
containerSurface->expectTap(1, 1);
containerSurface->doTransaction([](auto &t, auto &sc) { t.hide(sc); });
+ containerSurface->assertFocusChange(false);
+ bgSurface->assertFocusChange(true);
injectTap(11, 11);
bgSurface->expectTap(1, 1);
@@ -478,6 +531,7 @@
TEST_F(InputSurfacesTest, input_respects_outscreen) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->showAt(-1, -1);
+ surface->assertFocusChange(true);
injectTap(0, 0);
surface->expectTap(1, 1);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 0445755..f9540b2 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -742,11 +742,10 @@
status_t setActiveColorMode(const sp<IBinder>& /*display*/,
ColorMode /*colorMode*/) override { return NO_ERROR; }
status_t captureScreen(const sp<IBinder>& /*display*/, sp<GraphicBuffer>* /*outBuffer*/,
- bool& /* outCapturedSecureLayers */,
- const ui::Dataspace /*reqDataspace*/,
- const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/,
+ bool& /*outCapturedSecureLayers*/, ui::Dataspace /*reqDataspace*/,
+ ui::PixelFormat /*reqPixelFormat*/, const Rect& /*sourceCrop*/,
uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
- bool /*useIdentityTransform*/, Rotation /*rotation*/,
+ bool /*useIdentityTransform*/, ui::Rotation,
bool /*captureSecureLayers*/) override {
return NO_ERROR;
}
@@ -766,7 +765,7 @@
}
virtual status_t captureLayers(
const sp<IBinder>& /*parentHandle*/, sp<GraphicBuffer>* /*outBuffer*/,
- const ui::Dataspace /*reqDataspace*/, const ui::PixelFormat /*reqPixelFormat*/,
+ ui::Dataspace /*reqDataspace*/, ui::PixelFormat /*reqPixelFormat*/,
const Rect& /*sourceCrop*/,
const std::unordered_set<sp<IBinder>,
ISurfaceComposer::SpHash<IBinder>>& /*excludeHandles*/,
diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp
index 8a4298a..145b4ae 100644
--- a/libs/input/TouchVideoFrame.cpp
+++ b/libs/input/TouchVideoFrame.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <input/DisplayViewport.h>
#include <input/TouchVideoFrame.h>
namespace android {
diff --git a/libs/input/tests/TouchVideoFrame_test.cpp b/libs/input/tests/TouchVideoFrame_test.cpp
index 815424e..1ec9358 100644
--- a/libs/input/tests/TouchVideoFrame_test.cpp
+++ b/libs/input/tests/TouchVideoFrame_test.cpp
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
+#include <input/DisplayViewport.h>
#include <input/TouchVideoFrame.h>
namespace android {
diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp
index 6566538..1e25049 100644
--- a/libs/nativedisplay/ADisplay.cpp
+++ b/libs/nativedisplay/ADisplay.cpp
@@ -129,6 +129,8 @@
}
} // namespace
+namespace android {
+
int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) {
const std::vector<PhysicalDisplayId> ids = SurfaceComposerClient::getPhysicalDisplayIds();
const size_t size = ids.size();
@@ -298,3 +300,5 @@
return reinterpret_cast<DisplayConfigImpl*>(config)->appOffset;
}
+
+} // namespace android
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index d37b9a1..bcc99fc 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -40,6 +40,8 @@
"-Wno-unused-function",
],
+ version_script: "libnativedisplay.map.txt",
+
srcs: [
"AChoreographer.cpp",
"ADisplay.cpp",
diff --git a/libs/nativedisplay/include/apex/display.h b/libs/nativedisplay/include/apex/display.h
index 9be401e..a7eaf87 100644
--- a/libs/nativedisplay/include/apex/display.h
+++ b/libs/nativedisplay/include/apex/display.h
@@ -20,7 +20,12 @@
#include <android/hardware_buffer.h>
#include <inttypes.h>
-__BEGIN_DECLS
+// TODO: the intention of these apis is to be stable - hence they are defined in
+// an apex directory. But because they don't yet need to be stable, hold off on
+// making them stable until a Mainline module needs them.
+// __BEGIN_DECLS
+
+namespace android {
/**
* Opaque handle for a native display
@@ -130,4 +135,5 @@
*/
int64_t ADisplayConfig_getAppVsyncOffsetNanos(ADisplayConfig* config);
-__END_DECLS
+} // namespace android
+// __END_DECLS
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 3b6a241..650bdf1 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -7,6 +7,28 @@
AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30
AChoreographer_registerRefreshRateCallback; # apex # introduced=30
AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30
+ AChoreographer_create; # apex # introduced=30
+ AChoreographer_destroy; # apex # introduced=30
+ AChoreographer_getFd; # apex # introduced=30
+ AChoreographer_handlePendingEvents; # apex # introduced=30
local:
*;
};
+
+LIBNATIVEDISPLAY_PLATFORM {
+ global:
+ extern "C++" {
+ android::ADisplay_acquirePhysicalDisplays*;
+ android::ADisplay_release*;
+ android::ADisplay_getMaxSupportedFps*;
+ android::ADisplay_getDisplayType*;
+ android::ADisplay_getPreferredWideColorFormat*;
+ android::ADisplay_getCurrentConfig*;
+ android::ADisplayConfig_getDensity*;
+ android::ADisplayConfig_getWidth*;
+ android::ADisplayConfig_getHeight*;
+ android::ADisplayConfig_getFps*;
+ android::ADisplayConfig_getCompositorOffsetNanos*;
+ android::ADisplayConfig_getAppVsyncOffsetNanos*;
+ };
+} LIBNATIVEDISPLAY;
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 0772210..38f8d6b 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <ui/Rotation.h>
#include <utils/Timers.h>
namespace android {
@@ -33,7 +34,7 @@
float ydpi{0};
float fps{0};
float density{0};
- uint8_t orientation{0};
+ ui::Rotation orientation{ui::ROTATION_0};
bool secure{false};
nsecs_t appVsyncOffset{0};
nsecs_t presentationDeadline{0};
@@ -42,14 +43,6 @@
uint32_t layerStack{NO_LAYER_STACK};
};
-/* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
-enum {
- DISPLAY_ORIENTATION_0 = 0,
- DISPLAY_ORIENTATION_90 = 1,
- DISPLAY_ORIENTATION_180 = 2,
- DISPLAY_ORIENTATION_270 = 3
-};
-
} // namespace android
#endif // ANDROID_COMPOSER_DISPLAY_INFO_H
diff --git a/libs/ui/include/ui/Rotation.h b/libs/ui/include/ui/Rotation.h
new file mode 100644
index 0000000..89008f6
--- /dev/null
+++ b/libs/ui/include/ui/Rotation.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <type_traits>
+
+namespace android::ui {
+
+enum class Rotation { Rotation0 = 0, Rotation90 = 1, Rotation180 = 2, Rotation270 = 3 };
+
+// Equivalent to Surface.java constants.
+constexpr auto ROTATION_0 = Rotation::Rotation0;
+constexpr auto ROTATION_90 = Rotation::Rotation90;
+constexpr auto ROTATION_180 = Rotation::Rotation180;
+constexpr auto ROTATION_270 = Rotation::Rotation270;
+
+constexpr auto toRotation(std::underlying_type_t<Rotation> rotation) {
+ return static_cast<Rotation>(rotation);
+}
+
+constexpr auto toRotationInt(Rotation rotation) {
+ return static_cast<std::underlying_type_t<Rotation>>(rotation);
+}
+
+constexpr Rotation operator+(Rotation lhs, Rotation rhs) {
+ constexpr auto N = toRotationInt(ROTATION_270) + 1;
+ return toRotation((toRotationInt(lhs) + toRotationInt(rhs)) % N);
+}
+
+constexpr const char* toCString(Rotation rotation) {
+ switch (rotation) {
+ case ROTATION_0:
+ return "ROTATION_0";
+ case ROTATION_90:
+ return "ROTATION_90";
+ case ROTATION_180:
+ return "ROTATION_180";
+ case ROTATION_270:
+ return "ROTATION_270";
+ }
+}
+
+} // namespace android::ui
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index de07684..c6bb598 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_TRANSFORM_H
-#define ANDROID_TRANSFORM_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -28,6 +27,7 @@
#include <math/vec3.h>
#include <ui/Point.h>
#include <ui/Rect.h>
+#include <ui/Rotation.h>
namespace android {
@@ -42,13 +42,13 @@
explicit Transform(uint32_t orientation, int w = 0, int h = 0);
~Transform();
- enum orientation_flags {
- ROT_0 = 0x00000000,
- FLIP_H = HAL_TRANSFORM_FLIP_H,
- FLIP_V = HAL_TRANSFORM_FLIP_V,
- ROT_90 = HAL_TRANSFORM_ROT_90,
- ROT_180 = FLIP_H|FLIP_V,
- ROT_270 = ROT_180|ROT_90,
+ enum RotationFlags : uint32_t {
+ ROT_0 = 0,
+ FLIP_H = HAL_TRANSFORM_FLIP_H,
+ FLIP_V = HAL_TRANSFORM_FLIP_V,
+ ROT_90 = HAL_TRANSFORM_ROT_90,
+ ROT_180 = FLIP_H | FLIP_V,
+ ROT_270 = ROT_180 | ROT_90,
ROT_INVALID = 0x80
};
@@ -100,6 +100,8 @@
void dump(std::string& result, const char* name) const;
void dump(const char* name) const;
+ static RotationFlags toRotationFlags(Rotation);
+
private:
struct mat33 {
vec3 v[3];
@@ -117,13 +119,26 @@
mutable uint32_t mType;
};
-static inline void PrintTo(const Transform& t, ::std::ostream* os) {
+inline void PrintTo(const Transform& t, ::std::ostream* os) {
std::string out;
t.dump(out, "ui::Transform");
*os << out;
}
+inline Transform::RotationFlags Transform::toRotationFlags(Rotation rotation) {
+ switch (rotation) {
+ case ROTATION_0:
+ return ROT_0;
+ case ROTATION_90:
+ return ROT_90;
+ case ROTATION_180:
+ return ROT_180;
+ case ROTATION_270:
+ return ROT_270;
+ default:
+ return ROT_INVALID;
+ }
+}
+
} // namespace ui
} // namespace android
-
-#endif /* ANDROID_TRANSFORM_H */
diff --git a/libs/ui/include_vndk/ui/Rotation.h b/libs/ui/include_vndk/ui/Rotation.h
new file mode 120000
index 0000000..d84fb4b
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Rotation.h
@@ -0,0 +1 @@
+../../include/ui/Rotation.h
\ No newline at end of file
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 188ac6b..b771538 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -1215,6 +1215,12 @@
return Void();
}
+Return<void> HardwareComposer::ComposerCallback::onSeamlessPossible(
+ Hwc2::Display /*display*/) {
+ LOG_ALWAYS_FATAL("Unexpected onSeamlessPossible callback");
+ return Void();
+}
+
void HardwareComposer::ComposerCallback::SetVsyncService(
const sp<VsyncService>& vsync_service) {
std::lock_guard<std::mutex> lock(mutex_);
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 8698814..bfce10b 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -381,6 +381,7 @@
hardware::Return<void> onVsyncPeriodTimingChanged(
Hwc2::Display display,
const Hwc2::VsyncPeriodChangeTimeline& updatedTimeline) override;
+ hardware::Return<void> onSeamlessPossible(Hwc2::Display display) override;
bool GotFirstHotplug() { return got_first_hotplug_; }
void SetVsyncService(const sp<VsyncService>& vsync_service);
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index e143260..51878e9 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -25,7 +25,6 @@
#include <dlfcn.h>
#include <android/dlext.h>
-#include <cutils/properties.h>
#include <log/log.h>
#include <utils/Timers.h>
@@ -206,6 +205,7 @@
}
cnx->systemDriverUnloaded = true;
+ cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
}
void* Loader::open(egl_connection_t* cnx)
@@ -228,6 +228,7 @@
} else {
cnx->shouldUseAngle = false;
}
+ cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
// Firstly, try to load ANGLE driver.
driver_t* hnd = attempt_to_load_angle(cnx);
@@ -237,22 +238,31 @@
}
bool failToLoadFromDriverSuffixProperty = false;
+ cnx->systemDriverUseExactName = true;
if (!hnd) {
+ // If updated driver apk is set but fail to load, abort here.
+ if (android::GraphicsEnv::getInstance().getDriverNamespace()) {
+ LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s",
+ android::GraphicsEnv::getInstance().getDriverPath().c_str());
+ }
// Finally, try to load system driver, start by searching for the library name appended by
// the system properties of the GLES userspace driver in both locations.
// i.e.:
// libGLES_${prop}.so, or:
// libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so
- char prop[PROPERTY_VALUE_MAX + 1];
for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
- if (property_get(key, prop, nullptr) <= 0) {
+ if (property_get(key, cnx->systemDriverProperty, nullptr) <= 0) {
continue;
}
- hnd = attempt_to_load_system_driver(cnx, prop, true);
+ hnd = attempt_to_load_system_driver(cnx, cnx->systemDriverProperty,
+ cnx->systemDriverUseExactName);
if (hnd) {
+ cnx->systemDriverUseProperty = true;
break;
- } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
- failToLoadFromDriverSuffixProperty = true;
+ } else {
+ if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
+ failToLoadFromDriverSuffixProperty = true;
+ }
}
}
}
@@ -263,11 +273,12 @@
// i.e.:
// libGLES.so, or:
// libEGL.so, libGLESv1_CM.so, libGLESv2.so
- hnd = attempt_to_load_system_driver(cnx, nullptr, true);
+ hnd = attempt_to_load_system_driver(cnx, nullptr, cnx->systemDriverUseExactName);
}
if (!hnd && !failToLoadFromDriverSuffixProperty) {
- hnd = attempt_to_load_system_driver(cnx, nullptr, false);
+ cnx->systemDriverUseExactName = false;
+ hnd = attempt_to_load_system_driver(cnx, nullptr, cnx->systemDriverUseExactName);
}
if (!hnd) {
@@ -282,14 +293,11 @@
if (!cnx->libEgl) {
cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
}
- if (!cnx->libGles1) {
- cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
- }
if (!cnx->libGles2) {
cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
}
- if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) {
+ if (!cnx->libEgl || !cnx->libGles2) {
android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL,
false, systemTime() - openTime);
}
@@ -297,8 +305,7 @@
LOG_ALWAYS_FATAL_IF(!cnx->libEgl,
"couldn't load system EGL wrapper libraries");
- LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,
- "couldn't load system OpenGL ES wrapper libraries");
+ LOG_ALWAYS_FATAL_IF(!cnx->libGles2, "couldn't load system OpenGL ESv2+ wrapper libraries");
android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, true,
systemTime() - openTime);
@@ -314,7 +321,7 @@
cnx->shouldUseAngle = false;
cnx->angleDecided = false;
- cnx->useAngle = false;
+ cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
if (cnx->vendorEGL) {
dlclose(cnx->vendorEGL);
@@ -519,7 +526,6 @@
if (so) {
ALOGV("Loaded ANGLE %s library for '%s' (instead of native)", kind,
android::GraphicsEnv::getInstance().getAngleAppName().c_str());
- cnx->useAngle = true;
char prop[PROPERTY_VALUE_MAX];
@@ -562,7 +568,6 @@
} else {
ALOGV("Loaded native %s library for '%s' (instead of ANGLE)", kind,
android::GraphicsEnv::getInstance().getAngleAppName().c_str());
- cnx->useAngle = false;
}
cnx->angleDecided = true;
@@ -592,6 +597,7 @@
Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) {
ATRACE_CALL();
+ assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
if (!ns) {
return nullptr;
@@ -606,19 +612,17 @@
initialize_api(dso, cnx, EGL);
hnd = new driver_t(dso);
- dso = load_angle("GLESv1_CM", ns, cnx);
- initialize_api(dso, cnx, GLESv1_CM);
- hnd->set(dso, GLESv1_CM);
-
dso = load_angle("GLESv2", ns, cnx);
initialize_api(dso, cnx, GLESv2);
hnd->set(dso, GLESv2);
+ cnx->loadedDriverType = egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER;
}
return hnd;
}
Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) {
ATRACE_CALL();
+ assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
#ifndef __ANDROID_VNDK__
android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
if (!ns) {
@@ -630,8 +634,9 @@
driver_t* hnd = nullptr;
void* dso = load_updated_driver("GLES", ns);
if (dso) {
- initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
+ initialize_api(dso, cnx, EGL | GLESv2);
hnd = new driver_t(dso);
+ if (hnd) cnx->loadedDriverType = egl_connection_t::GLES_UPDATED_COMBO_DRIVER;
return hnd;
}
@@ -640,13 +645,10 @@
initialize_api(dso, cnx, EGL);
hnd = new driver_t(dso);
- dso = load_updated_driver("GLESv1_CM", ns);
- initialize_api(dso, cnx, GLESv1_CM);
- hnd->set(dso, GLESv1_CM);
-
dso = load_updated_driver("GLESv2", ns);
initialize_api(dso, cnx, GLESv2);
hnd->set(dso, GLESv2);
+ cnx->loadedDriverType = egl_connection_t::GLES_UPDATED_STANDALONE_DRIVER;
}
return hnd;
#else
@@ -657,30 +659,94 @@
Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix,
const bool exact) {
ATRACE_CALL();
+ assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL);
driver_t* hnd = nullptr;
void* dso = load_system_driver("GLES", suffix, exact);
if (dso) {
- initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
+ initialize_api(dso, cnx, EGL | GLESv2);
hnd = new driver_t(dso);
+ if (hnd) cnx->loadedDriverType = egl_connection_t::GLES_SYSTEM_COMBO_DRIVER;
return hnd;
}
+
dso = load_system_driver("EGL", suffix, exact);
if (dso) {
initialize_api(dso, cnx, EGL);
hnd = new driver_t(dso);
- dso = load_system_driver("GLESv1_CM", suffix, exact);
- initialize_api(dso, cnx, GLESv1_CM);
- hnd->set(dso, GLESv1_CM);
-
dso = load_system_driver("GLESv2", suffix, exact);
initialize_api(dso, cnx, GLESv2);
hnd->set(dso, GLESv2);
+ cnx->loadedDriverType = egl_connection_t::GLES_SYSTEM_STANDALONE_DRIVER;
}
return hnd;
}
+bool Loader::load_glesv1_driver(egl_connection_t* cnx) {
+ ATRACE_CALL();
+ void* dso = nullptr;
+
+ driver_t* hnd = (driver_t*)cnx->dso;
+ // EGL driver must have been loaded. if not, something went wrong.
+ if (!hnd || cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER) {
+ return false;
+ }
+
+ if (cnx->libGles1) return EGL_TRUE;
+
+ // If there is a GLES driver, use that first
+ switch (cnx->loadedDriverType) {
+ case egl_connection_t::GLES_SYSTEM_COMBO_DRIVER:
+ case egl_connection_t::GLES_UPDATED_COMBO_DRIVER: {
+ dso = hnd->dso[0];
+ initialize_api(dso, cnx, GLESv1_CM);
+ break;
+ }
+ case egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER: {
+ android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
+ dso = load_angle("GLESv1_CM", ns, cnx);
+ if (dso) {
+ initialize_api(dso, cnx, GLESv1_CM);
+ hnd->set(dso, GLESv1_CM);
+ }
+ break;
+ }
+ case egl_connection_t::GLES_UPDATED_STANDALONE_DRIVER: {
+ android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
+ void* dso = load_updated_driver("GLESv1_CM", ns);
+ if (dso) {
+ initialize_api(dso, cnx, GLESv1_CM);
+ hnd->set(dso, GLESv1_CM);
+ }
+ break;
+ }
+ case egl_connection_t::GLES_SYSTEM_STANDALONE_DRIVER: {
+ dso = load_system_driver("GLESv1_CM",
+ cnx->systemDriverUseProperty ? cnx->systemDriverProperty
+ : nullptr,
+ cnx->systemDriverUseExactName);
+ if (dso) {
+ initialize_api(dso, cnx, GLESv1_CM);
+ hnd->set(dso, GLESv1_CM);
+ }
+ break;
+ }
+ default: {
+ ALOGE("Bad loadedDriverType (%d)", cnx->loadedDriverType);
+ break;
+ }
+ }
+
+ if (!cnx->libGles1) {
+ cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
+ }
+
+ LOG_ALWAYS_FATAL_IF(!cnx->libGles1, "couldn't load system OpenGL ES V1 wrapper libraries");
+
+ return dso ? true : false;
+}
+
void Loader::initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask) {
if (mask & EGL) {
getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 6f31ab4..4199753 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -53,6 +53,8 @@
void* open(egl_connection_t* cnx);
void close(egl_connection_t* cnx);
+ bool load_glesv1_driver(egl_connection_t* cnx);
+
private:
Loader();
driver_t* attempt_to_load_angle(egl_connection_t* cnx);
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 25b1009..2e183b3 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -172,10 +172,6 @@
// ----------------------------------------------------------------------------
-// this mutex protects:
-// d->disp[]
-// egl_init_drivers_locked()
-//
static EGLBoolean egl_init_drivers_locked() {
if (sEarlyInitState) {
// initialized by static ctor. should be set here.
@@ -202,6 +198,17 @@
return cnx->dso ? EGL_TRUE : EGL_FALSE;
}
+static EGLBoolean egl_init_glesv1_drivers_locked() {
+ // get our driver loader
+ Loader& loader(Loader::getInstance());
+
+ // dynamically load our GLESV1 implementation
+ egl_connection_t* cnx = &gEGLImpl;
+ return loader.load_glesv1_driver(cnx);
+}
+
+// this mutex protects driver load logic as a critical section since it accesses to global variable
+// like gEGLImpl
static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
EGLBoolean egl_init_drivers() {
@@ -212,6 +219,14 @@
return res;
}
+EGLBoolean egl_init_glesv1_drivers() {
+ EGLBoolean res;
+ pthread_mutex_lock(&sInitDriverMutex);
+ res = egl_init_glesv1_drivers_locked();
+ pthread_mutex_unlock(&sInitDriverMutex);
+ return res;
+}
+
static pthread_mutex_t sLogPrintMutex = PTHREAD_MUTEX_INITIALIZER;
static std::chrono::steady_clock::time_point sLogPrintTime;
static constexpr std::chrono::seconds DURATION(1);
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 67d69b4..3b19b32 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -220,7 +220,7 @@
if (cnx->dso) {
EGLDisplay dpy = EGL_NO_DISPLAY;
- if (cnx->useAngle) {
+ if (cnx->loadedDriverType == egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER) {
EGLint error;
dpy = getPlatformDisplayAngle(display, cnx, attrib_list, &error);
if (error != EGL_NONE) {
@@ -464,7 +464,7 @@
egl_connection_t* const cnx = &gEGLImpl;
if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
// If we're using ANGLE reset any custom DisplayPlatform
- if (cnx->useAngle) {
+ if (cnx->loadedDriverType == egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER) {
angle::resetAnglePlatform(disp.dpy);
}
if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 5162ba4..e2bc5c6 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -277,6 +277,7 @@
extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
extern EGLBoolean egl_init_drivers();
+extern EGLBoolean egl_init_glesv1_drivers();
extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
extern gl_hooks_t gHooksTrace;
@@ -956,44 +957,42 @@
egl_context_t* const c = get_context(share_list);
share_list = c->context;
}
- // b/111083885 - If we are presenting EGL 1.4 interface to apps
- // error out on robust access attributes that are invalid
- // in EGL 1.4 as the driver may be fine with them but dEQP expects
- // tests to fail according to spec.
- if (attrib_list && (cnx->driverVersion < EGL_MAKE_VERSION(1, 5, 0))) {
- const EGLint* attrib_ptr = attrib_list;
- while (*attrib_ptr != EGL_NONE) {
- GLint attr = *attrib_ptr++;
- GLint value = *attrib_ptr++;
- if (attr == EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR) {
- // We are GL ES context with EGL 1.4, this is an invalid
- // attribute
+
+ // figure out if it's a GLESv1 or GLESv2
+ int gles_version_idx = egl_connection_t::GLESv1_INDEX;
+ if (attrib_list) {
+ const EGLint* ptr = attrib_list; // so that we don't modify attrib_list
+ while (*ptr != EGL_NONE) {
+ GLint attr = *ptr++;
+ GLint value = *ptr++;
+ if (attr == EGL_CONTEXT_CLIENT_VERSION) {
+ if (value == 1) {
+ gles_version_idx = egl_connection_t::GLESv1_INDEX;
+ } else if (value == 2 || value == 3) {
+ gles_version_idx = egl_connection_t::GLESv2_INDEX;
+ }
+ } else if (attr == EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR &&
+ cnx->driverVersion < EGL_MAKE_VERSION(1, 5, 0)) {
+ // b/111083885 - If we are presenting EGL 1.4 interface to apps
+ // error out on robust access attributes that are invalid
+ // in EGL 1.4 as the driver may be fine with them but dEQP expects
+ // tests to fail according to spec.
return setError(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
}
- };
+ }
}
+
+ // GLESV1 driver is lazily loaded and initialized
+ if (gles_version_idx == egl_connection_t::GLESv1_INDEX) {
+ android::GraphicsEnv::getInstance().setTargetStats(
+ android::GpuStatsInfo::Stats::GLES_1_IN_USE);
+ if (!egl_init_glesv1_drivers()) return EGL_NO_CONTEXT;
+ }
+
EGLContext context = cnx->egl.eglCreateContext(
dp->disp.dpy, config, share_list, attrib_list);
if (context != EGL_NO_CONTEXT) {
- // figure out if it's a GLESv1 or GLESv2
- int version = 0;
- if (attrib_list) {
- while (*attrib_list != EGL_NONE) {
- GLint attr = *attrib_list++;
- GLint value = *attrib_list++;
- if (attr == EGL_CONTEXT_CLIENT_VERSION) {
- if (value == 1) {
- version = egl_connection_t::GLESv1_INDEX;
- android::GraphicsEnv::getInstance().setTargetStats(
- android::GpuStatsInfo::Stats::GLES_1_IN_USE);
- } else if (value == 2 || value == 3) {
- version = egl_connection_t::GLESv2_INDEX;
- }
- }
- };
- }
- egl_context_t* c = new egl_context_t(dpy, context, config, cnx,
- version);
+ egl_context_t* c = new egl_context_t(dpy, context, config, cnx, gles_version_idx);
return c;
}
}
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 7bb9b59..4e9d7d0 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -17,11 +17,12 @@
#ifndef ANDROID_EGLDEFS_H
#define ANDROID_EGLDEFS_H
+#include <cutils/properties.h>
+#include <log/log.h>
+
#include "../hooks.h"
#include "egl_platform_entries.h"
-#include <log/log.h>
-
#define VERSION_MAJOR 1
#define VERSION_MINOR 4
#define EGL_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch))
@@ -44,6 +45,15 @@
GLESv2_INDEX = 1
};
+ enum {
+ GLES_NO_DRIVER = 0, // no driver is loaded
+ GLES_SYSTEM_COMBO_DRIVER = 1, // GLES combo driver in system folder is loaded
+ GLES_SYSTEM_STANDALONE_DRIVER = 2, // standalone system drivers are loaded
+ GLES_ANGLE_STANDALONE_DRIVER = 3, // ANGLE (always standalone) drivers are loaded.
+ GLES_UPDATED_COMBO_DRIVER = 4, // GLES combo driver in updated driver folder is loaded
+ GLES_UPDATED_STANDALONE_DRIVER = 5, // standalone drivers in updated driver folder are loaded
+ };
+
inline egl_connection_t() : dso(nullptr),
libEgl(nullptr),
libGles1(nullptr),
@@ -83,9 +93,12 @@
bool systemDriverUnloaded;
bool shouldUseAngle; // Should we attempt to load ANGLE
bool angleDecided; // Have we tried to load ANGLE
- bool useAngle; // Was ANGLE successfully loaded
EGLint angleBackend;
+ int loadedDriverType;
void* vendorEGL;
+ bool systemDriverUseExactName;
+ bool systemDriverUseProperty;
+ char systemDriverProperty[PROPERTY_VALUE_MAX + 1];
};
// clang-format on
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index a0bd4e2..4dcc1ca 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -48,8 +48,7 @@
}
uint32_t width, height;
- if (mainDpyInfo.orientation != DISPLAY_ORIENTATION_0 &&
- mainDpyInfo.orientation != DISPLAY_ORIENTATION_180) {
+ if (mainDpyInfo.orientation != ui::ROTATION_0 && mainDpyInfo.orientation != ui::ROTATION_180) {
// rotated
width = mainDpyInfo.h;
height = mainDpyInfo.w;
diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp
new file mode 100644
index 0000000..5a5dc89
--- /dev/null
+++ b/services/automotive/display/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+ name: "android.frameworks.automotive.display@1.0-service",
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "main_automotivedisplay.cpp",
+ "CarWindowService.cpp",
+ ],
+ init_rc: ["android.frameworks.automotive.display@1.0-service.rc"],
+
+ shared_libs: [
+ "android.frameworks.automotive.display@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
+ "libgui",
+ "libhidlbase",
+ "liblog",
+ "libui",
+ "libutils",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+}
diff --git a/services/automotive/display/CarWindowService.cpp b/services/automotive/display/CarWindowService.cpp
new file mode 100644
index 0000000..e95c9e1
--- /dev/null
+++ b/services/automotive/display/CarWindowService.cpp
@@ -0,0 +1,121 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#include <ui/DisplayInfo.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+
+#include "CarWindowService.h"
+
+namespace android {
+namespace frameworks {
+namespace automotive {
+namespace display {
+namespace V1_0 {
+namespace implementation {
+
+Return<sp<IGraphicBufferProducer>>
+ CarWindowService::getIGraphicBufferProducer() {
+ if (mSurface == nullptr) {
+ status_t err;
+ mSurfaceComposerClient = new SurfaceComposerClient();
+
+ err = mSurfaceComposerClient->initCheck();
+ if (err != NO_ERROR) {
+ ALOGE("SurfaceComposerClient::initCheck error: %#x", err);
+ mSurfaceComposerClient = nullptr;
+ return nullptr;
+ }
+
+ // Get main display parameters.
+ sp<IBinder> mainDpy = SurfaceComposerClient::getInternalDisplayToken();
+ if (mainDpy == nullptr) {
+ ALOGE("Failed to get internal display ");
+ return nullptr;
+ }
+ DisplayInfo mainDpyInfo;
+ err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+ if (err != NO_ERROR) {
+ ALOGE("Failed to get display characteristics");
+ return nullptr;
+ }
+ unsigned int mWidth, mHeight;
+ if (mainDpyInfo.orientation != ui::ROTATION_0 &&
+ mainDpyInfo.orientation != ui::ROTATION_180) {
+ // rotated
+ mWidth = mainDpyInfo.h;
+ mHeight = mainDpyInfo.w;
+ } else {
+ mWidth = mainDpyInfo.w;
+ mHeight = mainDpyInfo.h;
+ }
+
+ mSurfaceControl = mSurfaceComposerClient->createSurface(
+ String8("Automotive Display"), mWidth, mHeight,
+ PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
+ if (mSurfaceControl == nullptr || !mSurfaceControl->isValid()) {
+ ALOGE("Failed to create SurfaceControl");
+ mSurfaceComposerClient = nullptr;
+ mSurfaceControl = nullptr;
+ return nullptr;
+ }
+
+ // SurfaceControl::getSurface is guaranteed to be not null.
+ mSurface = mSurfaceControl->getSurface();
+ }
+
+ return new ::android::hardware::graphics::bufferqueue::V2_0::utils::
+ B2HGraphicBufferProducer(
+ mSurface->getIGraphicBufferProducer());
+}
+
+Return<bool> CarWindowService::showWindow() {
+ status_t status = NO_ERROR;
+
+ if (mSurfaceControl != nullptr) {
+ status = SurfaceComposerClient::Transaction{}
+ .setLayer(
+ mSurfaceControl, 0x7FFFFFFF) // always on top
+ .show(mSurfaceControl)
+ .apply();
+ } else {
+ ALOGE("showWindow: Failed to get a valid SurfaceControl!");
+ return false;
+ }
+
+ return status == NO_ERROR;
+}
+
+Return<bool> CarWindowService::hideWindow() {
+ status_t status = NO_ERROR;
+
+ if (mSurfaceControl != nullptr) {
+ status = SurfaceComposerClient::Transaction{}
+ .hide(mSurfaceControl)
+ .apply();
+ } else {
+ ALOGE("hideWindow: Failed to get a valid SurfaceControl!");
+ return false;
+ }
+
+ return status == NO_ERROR;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace display
+} // namespace automotive
+} // namespace frameworks
+} // namespace android
+
diff --git a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
new file mode 100644
index 0000000..ffb7b5e
--- /dev/null
+++ b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
@@ -0,0 +1,5 @@
+service automotive_display /system/bin/android.frameworks.automotive.display@1.0-service
+ class hal
+ user graphics
+ group automotive_evs
+ disabled # will not automatically start with its class; must be explicitly started.
diff --git a/services/automotive/display/include/CarWindowService.h b/services/automotive/display/include/CarWindowService.h
new file mode 100644
index 0000000..3290cc7
--- /dev/null
+++ b/services/automotive/display/include/CarWindowService.h
@@ -0,0 +1,52 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#pragma once
+
+#include <android/frameworks/automotive/display/1.0/ICarWindowService.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+namespace android {
+namespace frameworks {
+namespace automotive {
+namespace display {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::sp;
+using ::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer;
+
+class CarWindowService : public ICarWindowService {
+public:
+ Return<sp<IGraphicBufferProducer>> getIGraphicBufferProducer() override;
+ Return<bool> showWindow() override;
+ Return<bool> hideWindow() override;
+
+private:
+ sp<android::Surface> mSurface;
+ sp<android::SurfaceComposerClient> mSurfaceComposerClient;
+ sp<android::SurfaceControl> mSurfaceControl;
+};
+} // namespace implementation
+} // namespace V1_0
+} // namespace display
+} // namespace automotive
+} // namespace frameworks
+} // namespace android
+
diff --git a/services/automotive/display/main_automotivedisplay.cpp b/services/automotive/display/main_automotivedisplay.cpp
new file mode 100644
index 0000000..69f0a13
--- /dev/null
+++ b/services/automotive/display/main_automotivedisplay.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AutomotiveDisplayService"
+
+#include <unistd.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "CarWindowService.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::frameworks::automotive::display::V1_0::ICarWindowService;
+
+// The namespace in which all our implementation code lives
+using namespace android::frameworks::automotive::display::V1_0::implementation;
+using namespace android;
+
+const static char kServiceName[] = "default";
+
+int main() {
+ ALOGI("Car Window Service is starting");
+
+ android::sp<ICarWindowService> service = new CarWindowService();
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ // Register our service -- if somebody is already registered by our name,
+ // they will be killed (their thread pool will throw an exception).
+ status_t status = service->registerAsService(kServiceName);
+ if (status == OK) {
+ ALOGD("%s is ready.", kServiceName);
+ joinRpcThreadpool();
+ } else {
+ ALOGE("Could not register service %s (%d).", kServiceName, status);
+ }
+
+ // In normal operation, we don't expect the thread pool to exit
+ ALOGE("Car Window Service is shutting down");
+
+ return 1;
+}
+
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index e925f5b..b723654 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -111,6 +111,21 @@
msg += StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", deviceId, policyFlags);
}
+// --- FocusEntry ---
+
+// Focus notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER for all entries
+FocusEntry::FocusEntry(uint32_t sequenceNum, nsecs_t eventTime, sp<IBinder> connectionToken,
+ bool hasFocus)
+ : EventEntry(sequenceNum, Type::FOCUS, eventTime, POLICY_FLAG_PASS_TO_USER),
+ connectionToken(connectionToken),
+ hasFocus(hasFocus) {}
+
+FocusEntry::~FocusEntry() {}
+
+void FocusEntry::appendDescription(std::string& msg) const {
+ msg += StringPrintf("FocusEvent(hasFocus=%s)", hasFocus ? "true" : "false");
+}
+
// --- KeyEntry ---
KeyEntry::KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 9dcaadc..e8c37f0 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -33,7 +33,13 @@
constexpr uint32_t SYNTHESIZED_EVENT_SEQUENCE_NUM = 0;
struct EventEntry {
- enum class Type { CONFIGURATION_CHANGED, DEVICE_RESET, KEY, MOTION };
+ enum class Type {
+ CONFIGURATION_CHANGED,
+ DEVICE_RESET,
+ FOCUS,
+ KEY,
+ MOTION,
+ };
static const char* typeToString(Type type) {
switch (type) {
@@ -41,6 +47,8 @@
return "CONFIGURATION_CHANGED";
case Type::DEVICE_RESET:
return "DEVICE_RESET";
+ case Type::FOCUS:
+ return "FOCUS";
case Type::KEY:
return "KEY";
case Type::MOTION:
@@ -102,6 +110,17 @@
virtual ~DeviceResetEntry();
};
+struct FocusEntry : EventEntry {
+ sp<IBinder> connectionToken;
+ bool hasFocus;
+
+ FocusEntry(uint32_t sequenceNum, nsecs_t eventTime, sp<IBinder> connectionToken, bool hasFocus);
+ virtual void appendDescription(std::string& msg) const;
+
+protected:
+ virtual ~FocusEntry();
+};
+
struct KeyEntry : EventEntry {
int32_t deviceId;
uint32_t source;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index a3cb4f8..ce7399e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -469,6 +469,14 @@
break;
}
+ case EventEntry::Type::FOCUS: {
+ FocusEntry* typedEntry = static_cast<FocusEntry*>(mPendingEvent);
+ dispatchFocusLocked(currentTime, typedEntry);
+ done = true;
+ dropReason = DropReason::NOT_DROPPED; // focus events are never dropped
+ break;
+ }
+
case EventEntry::Type::KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
if (isAppSwitchDue) {
@@ -573,7 +581,8 @@
break;
}
case EventEntry::Type::CONFIGURATION_CHANGED:
- case EventEntry::Type::DEVICE_RESET: {
+ case EventEntry::Type::DEVICE_RESET:
+ case EventEntry::Type::FOCUS: {
// nothing to do
break;
}
@@ -712,6 +721,7 @@
}
break;
}
+ case EventEntry::Type::FOCUS:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("Should not drop %s events", EventEntry::typeToString(entry.type));
@@ -872,6 +882,25 @@
return true;
}
+void InputDispatcher::enqueueFocusEventLocked(const InputWindowHandle& window, bool hasFocus) {
+ FocusEntry* focusEntry =
+ new FocusEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, now(), window.getToken(), hasFocus);
+ enqueueInboundEventLocked(focusEntry);
+}
+
+void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, FocusEntry* entry) {
+ sp<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
+ if (channel == nullptr) {
+ return; // Window has gone away
+ }
+ InputTarget target;
+ target.inputChannel = channel;
+ target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ entry->dispatchInProgress = true;
+
+ dispatchEventLocked(currentTime, entry, {target});
+}
+
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
@@ -1254,6 +1283,7 @@
displayId = motionEntry.displayId;
break;
}
+ case EventEntry::Type::FOCUS:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
ALOGE("%s events do not have a target display", EventEntry::typeToString(entry.type));
@@ -1993,6 +2023,10 @@
}
void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) {
+ if (eventEntry.type == EventEntry::Type::FOCUS) {
+ // Focus events are passed to apps, but do not represent user activity.
+ return;
+ }
int32_t displayId = getTargetDisplayId(eventEntry);
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
@@ -2027,6 +2061,7 @@
eventType = USER_ACTIVITY_EVENT_BUTTON;
break;
}
+ case EventEntry::Type::FOCUS:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("%s events are not user activity",
@@ -2224,6 +2259,9 @@
break;
}
+ case EventEntry::Type::FOCUS: {
+ break;
+ }
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("%s events should not go to apps",
@@ -2359,6 +2397,14 @@
reportTouchEventForStatistics(*motionEntry);
break;
}
+ case EventEntry::Type::FOCUS: {
+ FocusEntry* focusEntry = static_cast<FocusEntry*>(eventEntry);
+ status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq,
+ focusEntry->hasFocus,
+ mInTouchMode);
+ break;
+ }
+
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events",
@@ -2598,6 +2644,10 @@
*cancelationEventEntry));
break;
}
+ case EventEntry::Type::FOCUS: {
+ LOG_ALWAYS_FATAL("Canceling focus events is not supported");
+ break;
+ }
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue",
@@ -3394,6 +3444,7 @@
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options);
+ enqueueFocusEventLocked(*oldFocusedWindowHandle, false /*hasFocus*/);
}
mFocusedWindowHandlesByDisplay.erase(displayId);
}
@@ -3403,6 +3454,7 @@
newFocusedWindowHandle->getName().c_str(), displayId);
}
mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
+ enqueueFocusEventLocked(*newFocusedWindowHandle, true /*hasFocus*/);
}
if (mFocusedDisplayId == displayId) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 50b5250..a4ba0de 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -157,6 +157,9 @@
// Cleans up input state when dropping an inbound event.
void dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) REQUIRES(mLock);
+ // Enqueues a focus event.
+ void enqueueFocusEventLocked(const InputWindowHandle& window, bool hasFocus) REQUIRES(mLock);
+
// Adds an event to a queue of recent events for debugging purposes.
void addRecentEventLocked(EventEntry* entry) REQUIRES(mLock);
@@ -299,6 +302,7 @@
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,
const std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 5ffc89d..c262abb 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -482,12 +482,31 @@
EXPECT_EQ(expectedFlags, motionEvent.getFlags());
break;
}
+ case AINPUT_EVENT_TYPE_FOCUS: {
+ FAIL() << "Use 'consumeFocusEvent' for FOCUS events";
+ }
default: {
FAIL() << mName.c_str() << ": invalid event type: " << expectedEventType;
}
}
}
+ void consumeFocusEvent(bool hasFocus, bool inTouchMode) {
+ InputEvent* event = consume();
+ ASSERT_NE(nullptr, event) << mName.c_str()
+ << ": consumer should have returned non-NULL event.";
+ ASSERT_EQ(AINPUT_EVENT_TYPE_FOCUS, event->getType())
+ << "Got " << inputEventTypeToString(event->getType())
+ << " event instead of FOCUS event";
+
+ ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
+ << mName.c_str() << ": event displayId should always be NONE.";
+
+ FocusEvent* focusEvent = static_cast<FocusEvent*>(event);
+ EXPECT_EQ(hasFocus, focusEvent->getHasFocus());
+ EXPECT_EQ(inTouchMode, focusEvent->getInTouchMode());
+ }
+
void assertNoEvents() {
InputEvent* event = consume();
ASSERT_EQ(nullptr, event)
@@ -508,7 +527,6 @@
public:
static const int32_t WIDTH = 600;
static const int32_t HEIGHT = 800;
- const std::string mName;
FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<InputDispatcher>& dispatcher, const std::string name,
@@ -551,7 +569,7 @@
virtual bool updateInfo() { return true; }
- void setFocus() { mInfo.hasFocus = true; }
+ void setFocus(bool hasFocus) { mInfo.hasFocus = hasFocus; }
void setFrame(const Rect& frame) {
mInfo.frameLeft = frame.left;
@@ -586,6 +604,12 @@
expectedFlags);
}
+ void consumeFocusEvent(bool hasFocus, bool inTouchMode = true) {
+ ASSERT_NE(mInputReceiver, nullptr)
+ << "Cannot consume events from a window with no receiver";
+ mInputReceiver->consumeFocusEvent(hasFocus, inTouchMode);
+ }
+
void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId,
int32_t expectedFlags) {
ASSERT_NE(mInputReceiver, nullptr) << "Invalid consume event on window with no receiver";
@@ -608,7 +632,10 @@
sp<IBinder> getToken() { return mInfo.token; }
+ const std::string& getName() { return mName; }
+
private:
+ const std::string mName;
std::unique_ptr<FakeInputReceiver> mInputReceiver;
};
@@ -759,10 +786,11 @@
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
- // Expect one focus window exist in display.
- windowSecond->setFocus();
-
+ // Display should have only one focused window
+ windowSecond->setFocus(true);
mDispatcher->setInputWindows({windowTop, windowSecond}, ADISPLAY_ID_DEFAULT);
+
+ windowSecond->consumeFocusEvent(true);
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
<< "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
@@ -782,10 +810,11 @@
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
// Display has two focused windows. Add them to inputWindowsHandles in z-order (top most first)
- windowTop->setFocus();
- windowSecond->setFocus();
+ windowTop->setFocus(true);
+ windowSecond->setFocus(true);
mDispatcher->setInputWindows({windowTop, windowSecond}, ADISPLAY_ID_DEFAULT);
+ windowTop->consumeFocusEvent(true);
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
<< "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
@@ -805,11 +834,12 @@
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
- windowTop->setFocus();
- windowSecond->setFocus();
+ windowTop->setFocus(true);
+ windowSecond->setFocus(true);
// Release channel for window is no longer valid.
windowTop->releaseChannel();
mDispatcher->setInputWindows({windowTop, windowSecond}, ADISPLAY_ID_DEFAULT);
+ windowSecond->consumeFocusEvent(true);
// Test inject a key down, should dispatch to a valid window.
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
@@ -849,9 +879,10 @@
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
- window->setFocus();
+ window->setFocus(true);
mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+ window->consumeFocusEvent(true);
NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
mDispatcher->notifyKey(&keyArgs);
@@ -890,6 +921,59 @@
0 /*expectedFlags*/);
}
+TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+
+ window->setFocus(true);
+ mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+
+ window->consumeFocusEvent(true);
+
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+
+ // Window should receive key down event.
+ window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+}
+
+TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+
+ mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ mDispatcher->waitForIdle();
+
+ window->assertNoEvents();
+}
+
+// If a window is touchable, but does not have focus, it should receive motion events, but not keys
+TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+
+ mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+
+ // Send key
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ // Send motion
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+
+ // Window should receive only the motion event
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents(); // Key event or focus event will not be received
+}
+
class FakeMonitorReceiver {
public:
FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
@@ -946,9 +1030,10 @@
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
- window->setFocus();
+ window->setFocus(true);
mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+ window->consumeFocusEvent(true);
FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
true /*isGestureMonitor*/);
@@ -1010,6 +1095,49 @@
0 /*expectedFlags*/);
}
+/**
+ * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
+ * the device default right away. In the test scenario, we check both the default value,
+ * and the action of enabling / disabling.
+ */
+TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+
+ // Set focused application.
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ window->setFocus(true);
+
+ SCOPED_TRACE("Check default value of touch mode");
+ mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+ window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+ SCOPED_TRACE("Remove the window to trigger focus loss");
+ window->setFocus(false);
+ mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+ window->consumeFocusEvent(false /*hasFocus*/, true /*inTouchMode*/);
+
+ SCOPED_TRACE("Disable touch mode");
+ mDispatcher->setInTouchMode(false);
+ window->setFocus(true);
+ mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+ window->consumeFocusEvent(true /*hasFocus*/, false /*inTouchMode*/);
+
+ SCOPED_TRACE("Remove the window to trigger focus loss");
+ window->setFocus(false);
+ mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+ window->consumeFocusEvent(false /*hasFocus*/, false /*inTouchMode*/);
+
+ SCOPED_TRACE("Enable touch mode again");
+ mDispatcher->setInTouchMode(true);
+ window->setFocus(true);
+ mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+ window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+ window->assertNoEvents();
+}
+
/* Test InputDispatcher for MultiDisplay */
class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
public:
@@ -1023,8 +1151,9 @@
// Set focus window for primary display, but focused display would be second one.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
- windowInPrimary->setFocus();
+ windowInPrimary->setFocus(true);
mDispatcher->setInputWindows({windowInPrimary}, ADISPLAY_ID_DEFAULT);
+ windowInPrimary->consumeFocusEvent(true);
application2 = new FakeApplicationHandle();
windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2",
@@ -1034,8 +1163,9 @@
mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
// Set focus window for second display.
mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
- windowInSecondary->setFocus();
+ windowInSecondary->setFocus(true);
mDispatcher->setInputWindows({windowInSecondary}, SECOND_DISPLAY_ID);
+ windowInSecondary->consumeFocusEvent(true);
}
virtual void TearDown() override {
@@ -1094,6 +1224,7 @@
ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
<< "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
windowInPrimary->assertNoEvents();
+ windowInSecondary->consumeFocusEvent(false);
windowInSecondary->assertNoEvents();
}
@@ -1244,10 +1375,11 @@
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
- mFocusedWindow->setFocus();
+ mFocusedWindow->setFocus(true);
// Expect one focus window exist in display.
mDispatcher->setInputWindows({mUnfocusedWindow, mFocusedWindow}, ADISPLAY_ID_DEFAULT);
+ mFocusedWindow->consumeFocusEvent(true);
}
virtual void TearDown() override {
@@ -1350,7 +1482,7 @@
void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
const std::vector<PointF>& points) {
- std::string name = window->mName;
+ const std::string name = window->getName();
InputEvent* event = window->consume();
ASSERT_NE(nullptr, event) << name.c_str()
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index d476f7b4..4c5e5da 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -51,7 +51,7 @@
"libprocessgroup",
"libprotobuf-cpp-lite",
"libsync",
- "libtimestats_proto",
+ "libtimestats",
"libui",
"libinput",
"libutils",
@@ -70,7 +70,6 @@
"libperfetto_client_experimental",
"librenderengine",
"libserviceutils",
- "libtimestats",
"libtrace_proto",
"libvr_manager",
"libvrflinger",
@@ -84,7 +83,6 @@
"libcompositionengine",
"librenderengine",
"libserviceutils",
- "libtimestats",
],
export_shared_lib_headers: [
"android.hardware.graphics.allocator@2.0",
@@ -96,6 +94,7 @@
"android.hardware.graphics.composer@2.4",
"android.hardware.power@1.3",
"libhidlbase",
+ "libtimestats",
],
// TODO (marissaw): this library is not used by surfaceflinger. This is here so
// the library compiled in a way that is accessible to system partition when running
@@ -231,7 +230,6 @@
"liblog",
"libprocessgroup",
"libsync",
- "libtimestats_proto",
"libutils",
],
static_libs: [
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index bdecdb7..3b1b796 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -207,7 +207,7 @@
* the code below applies the primary display's inverse transform to
* the texture transform
*/
- uint32_t transform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
mat4 tr = inverseOrientation(transform);
/**
@@ -622,7 +622,7 @@
}
if (getTransformToDisplayInverse()) {
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
if (invTransform & ui::Transform::ROT_90) {
std::swap(bufWidth, bufHeight);
}
@@ -658,7 +658,7 @@
}
if (getTransformToDisplayInverse()) {
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
if (invTransform & ui::Transform::ROT_90) {
std::swap(bufWidth, bufHeight);
}
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 1e471e5..067aa46 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -344,6 +344,11 @@
return willPresent;
}
+void BufferStateLayer::forceSendCallbacks() {
+ mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
+ mCurrentState.callbackHandles);
+}
+
bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
mCurrentState.transparentRegionHint = transparent;
mCurrentState.modified = true;
@@ -468,7 +473,7 @@
}
if (s.transformToDisplayInverse) {
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
if (invTransform & ui::Transform::ROT_90) {
std::swap(bufferWidth, bufferHeight);
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 8e6a70c..574bc51 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -77,6 +77,7 @@
bool setApi(int32_t api) override;
bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
+ void forceSendCallbacks() override;
// Override to ignore legacy layer state properties that are not used by BufferStateLayer
bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; }
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 78f8104..18477bb 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -22,14 +22,13 @@
"libnativewindow",
"libprotobuf-cpp-lite",
"libsync",
- "libtimestats_proto",
+ "libtimestats",
"libui",
"libutils",
],
static_libs: [
"libmath",
"librenderengine",
- "libtimestats",
"libtrace_proto",
],
header_libs: [
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 28d2653..6e28167 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -788,6 +788,7 @@
outputState.usesClientComposition};
base::unique_fd readyFence;
if (!hasClientComposition) {
+ setExpensiveRenderingExpected(false);
return readyFence;
}
@@ -871,10 +872,6 @@
new Fence(dup(readyFence.get()))));
}
- if (expensiveRenderingExpected) {
- setExpensiveRenderingExpected(false);
- }
-
return readyFence;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 3a4df74..ae93969 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -700,6 +700,9 @@
// We expect no calls to queueBuffer if composition was skipped.
EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
+ // Expect a call to signal no expensive rendering since there is no client composition.
+ EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, false));
+
mDisplay->editState().isEnabled = true;
mDisplay->editState().usesClientComposition = false;
mDisplay->editState().viewport = Rect(0, 0, 1, 1);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index cb6c50c..80528e3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -2842,9 +2842,11 @@
OutputComposeSurfacesTest::kDefaultAvgLuminance,
OutputComposeSurfacesTest::kDefaultMinLuminance};
-TEST_F(OutputComposeSurfacesTest, doesNothingIfNoClientComposition) {
+TEST_F(OutputComposeSurfacesTest, doesNothingButSignalNoExpensiveRenderingIfNoClientComposition) {
mOutput.mState.usesClientComposition = false;
+ EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
+
verify().execute().expectAFenceWasReturned();
}
@@ -3163,7 +3165,6 @@
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _)).WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
mOutput.composeSurfaces(kDebugRegion);
}
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 84ec597..e0dc3e7 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -41,12 +41,7 @@
using android::base::StringAppendF;
-/*
- * Initialize the display to the specified values.
- *
- */
-
-uint32_t DisplayDevice::sPrimaryDisplayOrientation = 0;
+ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0;
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
const wp<IBinder>& displayToken,
@@ -57,13 +52,11 @@
: mFlinger(args.flinger),
mDisplayToken(args.displayToken),
mSequenceId(args.sequenceId),
- mDisplayInstallOrientation(args.displayInstallOrientation),
+ mIsVirtual(args.isVirtual),
mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
compositionengine::DisplayCreationArgs{args.isVirtual, args.displayId,
args.powerAdvisor})},
- mIsVirtual(args.isVirtual),
- mOrientation(),
- mActiveConfig(0),
+ mPhysicalOrientation(args.physicalOrientation),
mIsPrimary(args.isPrimary) {
mCompositionDisplay->editState().isSecure = args.isSecure;
mCompositionDisplay->createRenderSurface(
@@ -88,7 +81,7 @@
setPowerMode(args.initialPowerMode);
// initialize the display orientation transform.
- setProjection(DisplayState::eOrientationDefault, Rect::INVALID_RECT, Rect::INVALID_RECT);
+ setProjection(ui::ROTATION_0, Rect::INVALID_RECT, Rect::INVALID_RECT);
}
DisplayDevice::~DisplayDevice() = default;
@@ -131,7 +124,6 @@
return mPowerMode != HWC_POWER_MODE_OFF;
}
-// ----------------------------------------------------------------------------
void DisplayDevice::setActiveConfig(HwcConfigIndexType mode) {
mActiveConfig = mode;
}
@@ -140,53 +132,19 @@
return mActiveConfig;
}
-// ----------------------------------------------------------------------------
-
ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
return mCompositionDisplay->getState().dataspace;
}
-// ----------------------------------------------------------------------------
-
void DisplayDevice::setLayerStack(uint32_t stack) {
mCompositionDisplay->setLayerStackFilter(stack, isPrimary());
}
-// ----------------------------------------------------------------------------
-
-uint32_t DisplayDevice::displayStateOrientationToTransformOrientation(int orientation) {
- switch (orientation) {
- case DisplayState::eOrientationDefault:
- return ui::Transform::ROT_0;
- case DisplayState::eOrientation90:
- return ui::Transform::ROT_90;
- case DisplayState::eOrientation180:
- return ui::Transform::ROT_180;
- case DisplayState::eOrientation270:
- return ui::Transform::ROT_270;
- default:
- return ui::Transform::ROT_INVALID;
- }
-}
-
-status_t DisplayDevice::orientationToTransfrom(int orientation, int w, int h, ui::Transform* tr) {
- uint32_t flags = displayStateOrientationToTransformOrientation(orientation);
- if (flags == ui::Transform::ROT_INVALID) {
- return BAD_VALUE;
- }
- tr->set(flags, w, h);
- return NO_ERROR;
-}
-
void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
mCompositionDisplay->setBounds(ui::Size(newWidth, newHeight));
}
-void DisplayDevice::setProjection(int orientation,
- const Rect& newViewport, const Rect& newFrame) {
- Rect viewport(newViewport);
- Rect frame(newFrame);
-
+void DisplayDevice::setProjection(ui::Rotation orientation, Rect viewport, Rect frame) {
mOrientation = orientation;
const Rect& displayBounds = getCompositionDisplay()->getState().bounds;
@@ -194,7 +152,10 @@
const int h = displayBounds.height();
ui::Transform R;
- DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
+ if (const auto flags = ui::Transform::toRotationFlags(orientation);
+ flags != ui::Transform::ROT_INVALID) {
+ R.set(flags, w, h);
+ }
if (!frame.isValid()) {
// the destination frame can be invalid if it has never been set,
@@ -236,9 +197,10 @@
// need to take care of primary display rotation for globalTransform
// for case if the panel is not installed aligned with device orientation
if (isPrimary()) {
- DisplayDevice::orientationToTransfrom(
- (orientation + mDisplayInstallOrientation) % (DisplayState::eOrientation270 + 1),
- w, h, &R);
+ if (const auto flags = ui::Transform::toRotationFlags(orientation + mPhysicalOrientation);
+ flags != ui::Transform::ROT_INVALID) {
+ R.set(flags, w, h);
+ }
}
// The viewport and frame are both in the logical orientation.
@@ -258,19 +220,18 @@
uint32_t transformOrientation;
if (isPrimary()) {
- sPrimaryDisplayOrientation = displayStateOrientationToTransformOrientation(orientation);
- transformOrientation = displayStateOrientationToTransformOrientation(
- (orientation + mDisplayInstallOrientation) % (DisplayState::eOrientation270 + 1));
+ sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation);
+ transformOrientation = ui::Transform::toRotationFlags(orientation + mPhysicalOrientation);
} else {
- transformOrientation = displayStateOrientationToTransformOrientation(orientation);
+ transformOrientation = ui::Transform::toRotationFlags(orientation);
}
getCompositionDisplay()->setProjection(globalTransform, transformOrientation,
frame, viewport, scissor, needsFiltering);
}
-uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() {
- return sPrimaryDisplayOrientation;
+ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
+ return sPrimaryDisplayRotationFlags;
}
std::string DisplayDevice::getDebugName() const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 79a1185..605e7c8 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DISPLAY_DEVICE_H
-#define ANDROID_DISPLAY_DEVICE_H
+#pragma once
#include <stdlib.h>
@@ -83,14 +82,17 @@
int getWidth() const;
int getHeight() const;
- int getInstallOrientation() const { return mDisplayInstallOrientation; }
void setLayerStack(uint32_t stack);
void setDisplaySize(const int newWidth, const int newHeight);
- void setProjection(int orientation, const Rect& viewport, const Rect& frame);
- int getOrientation() const { return mOrientation; }
- static uint32_t getPrimaryDisplayOrientationTransform();
+ void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
+
+ ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
+ ui::Rotation getOrientation() const { return mOrientation; }
+
+ static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
+
const ui::Transform& getTransform() const;
const Rect& getViewport() const;
const Rect& getFrame() const;
@@ -156,37 +158,21 @@
void dump(std::string& result) const;
private:
- /*
- * Constants, set during initialization
- */
const sp<SurfaceFlinger> mFlinger;
const wp<IBinder> mDisplayToken;
const int32_t mSequenceId;
+ const bool mIsVirtual;
- const int mDisplayInstallOrientation;
const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
std::string mDisplayName;
- const bool mIsVirtual;
- /*
- * Can only accessed from the main thread, these members
- * don't need synchronization.
- */
+ const ui::Rotation mPhysicalOrientation;
+ ui::Rotation mOrientation = ui::ROTATION_0;
- /*
- * Transaction state
- */
- static uint32_t displayStateOrientationToTransformOrientation(int orientation);
- static status_t orientationToTransfrom(int orientation,
- int w, int h, ui::Transform* tr);
+ static ui::Transform::RotationFlags sPrimaryDisplayRotationFlags;
- int mOrientation;
- static uint32_t sPrimaryDisplayOrientation;
-
- // Current power mode
- int mPowerMode;
- // Current active config
+ int mPowerMode = HWC_POWER_MODE_OFF;
HwcConfigIndexType mActiveConfig;
// TODO(b/74619554): Remove special cases for primary display.
@@ -202,7 +188,7 @@
uint32_t layerStack = NO_LAYER_STACK;
Rect viewport;
Rect frame;
- uint8_t orientation = 0;
+ ui::Rotation orientation = ui::ROTATION_0;
uint32_t width = 0;
uint32_t height = 0;
std::string displayName;
@@ -227,7 +213,7 @@
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
sp<compositionengine::DisplaySurface> displaySurface;
- int displayInstallOrientation{DisplayState::eOrientationDefault};
+ ui::Rotation physicalOrientation{ui::ROTATION_0};
bool hasWideColorGamut{false};
HdrCapabilities hdrCapabilities;
int32_t supportedPerFrameMetadata{0};
@@ -239,31 +225,33 @@
class DisplayRenderArea : public RenderArea {
public:
- DisplayRenderArea(const sp<const DisplayDevice> device,
- ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
- : DisplayRenderArea(device, device->getBounds(), device->getWidth(), device->getHeight(),
- device->getCompositionDataSpace(), rotation) {}
- DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqWidth,
- uint32_t reqHeight, ui::Dataspace reqDataSpace,
- ui::Transform::orientation_flags rotation, bool allowSecureLayers = true)
+ DisplayRenderArea(const sp<const DisplayDevice>& display,
+ RotationFlags rotation = ui::Transform::ROT_0)
+ : DisplayRenderArea(display, display->getBounds(), display->getWidth(),
+ display->getHeight(), display->getCompositionDataSpace(), rotation) {}
+
+ DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop, uint32_t reqWidth,
+ uint32_t reqHeight, ui::Dataspace reqDataSpace, RotationFlags rotation,
+ bool allowSecureLayers = true)
: RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace,
- device->getViewport(),
- getDisplayRotation(rotation, device->getInstallOrientation())),
- mDevice(device),
+ display->getViewport(),
+ applyInversePhysicalOrientation(rotation,
+ display->getPhysicalOrientation())),
+ mDisplay(std::move(display)),
mSourceCrop(sourceCrop),
mAllowSecureLayers(allowSecureLayers) {}
- const ui::Transform& getTransform() const override { return mDevice->getTransform(); }
- Rect getBounds() const override { return mDevice->getBounds(); }
- int getHeight() const override { return mDevice->getHeight(); }
- int getWidth() const override { return mDevice->getWidth(); }
- bool isSecure() const override { return mAllowSecureLayers && mDevice->isSecure(); }
- const sp<const DisplayDevice> getDisplayDevice() const override { return mDevice; }
+ const ui::Transform& getTransform() const override { return mDisplay->getTransform(); }
+ Rect getBounds() const override { return mDisplay->getBounds(); }
+ int getHeight() const override { return mDisplay->getHeight(); }
+ int getWidth() const override { return mDisplay->getWidth(); }
+ bool isSecure() const override { return mAllowSecureLayers && mDisplay->isSecure(); }
+ sp<const DisplayDevice> getDisplayDevice() const override { return mDisplay; }
bool needsFiltering() const override {
// check if the projection from the logical display to the physical
// display needs filtering
- if (mDevice->needsFiltering()) {
+ if (mDisplay->needsFiltering()) {
return true;
}
@@ -281,7 +269,7 @@
Rect getSourceCrop() const override {
// use the projected display viewport by default.
if (mSourceCrop.isEmpty()) {
- return mDevice->getScissor();
+ return mDisplay->getScissor();
}
// Recompute the device transformation for the source crop.
@@ -289,27 +277,13 @@
ui::Transform translatePhysical;
ui::Transform translateLogical;
ui::Transform scale;
- const Rect& viewport = mDevice->getViewport();
- const Rect& scissor = mDevice->getScissor();
- const Rect& frame = mDevice->getFrame();
+ const Rect& viewport = mDisplay->getViewport();
+ const Rect& scissor = mDisplay->getScissor();
+ const Rect& frame = mDisplay->getFrame();
- const int orientation = mDevice->getInstallOrientation();
- // Install orientation is transparent to the callers. Apply it now.
- uint32_t flags = 0x00;
- switch (orientation) {
- case DisplayState::eOrientation90:
- flags = ui::Transform::ROT_90;
- break;
- case DisplayState::eOrientation180:
- flags = ui::Transform::ROT_180;
- break;
- case DisplayState::eOrientation270:
- flags = ui::Transform::ROT_270;
- break;
- default:
- break;
- }
+ const auto flags = ui::Transform::toRotationFlags(mDisplay->getPhysicalOrientation());
rotation.set(flags, getWidth(), getHeight());
+
translateLogical.set(-viewport.left, -viewport.top);
translatePhysical.set(scissor.left, scissor.top);
scale.set(frame.getWidth() / float(viewport.getWidth()), 0, 0,
@@ -320,49 +294,44 @@
}
private:
- // Install orientation is transparent to the callers. We need to cancel
- // it out by modifying rotation flags.
- static ui::Transform::orientation_flags getDisplayRotation(
- ui::Transform::orientation_flags rotation, int orientation) {
- if (orientation == DisplayState::eOrientationDefault) {
- return rotation;
- }
+ static RotationFlags applyInversePhysicalOrientation(RotationFlags orientation,
+ ui::Rotation physicalOrientation) {
+ uint32_t inverseRotate90 = 0;
+ uint32_t inverseReflect = 0;
- // convert hw orientation into flag presentation
- // here inverse transform needed
- uint8_t hw_rot_90 = 0x00;
- uint8_t hw_flip_hv = 0x00;
- switch (orientation) {
- case DisplayState::eOrientation90:
- hw_rot_90 = ui::Transform::ROT_90;
- hw_flip_hv = ui::Transform::ROT_180;
+ switch (physicalOrientation) {
+ case ui::ROTATION_0:
+ return orientation;
+
+ case ui::ROTATION_90:
+ inverseRotate90 = ui::Transform::ROT_90;
+ inverseReflect = ui::Transform::ROT_180;
break;
- case DisplayState::eOrientation180:
- hw_flip_hv = ui::Transform::ROT_180;
+
+ case ui::ROTATION_180:
+ inverseReflect = ui::Transform::ROT_180;
break;
- case DisplayState::eOrientation270:
- hw_rot_90 = ui::Transform::ROT_90;
+
+ case ui::ROTATION_270:
+ inverseRotate90 = ui::Transform::ROT_90;
break;
}
- // transform flags operation
- // 1) flip H V if both have ROT_90 flag
- // 2) XOR these flags
- uint8_t rotation_rot_90 = rotation & ui::Transform::ROT_90;
- uint8_t rotation_flip_hv = rotation & ui::Transform::ROT_180;
- if (rotation_rot_90 & hw_rot_90) {
- rotation_flip_hv = (~rotation_flip_hv) & ui::Transform::ROT_180;
+ const uint32_t rotate90 = orientation & ui::Transform::ROT_90;
+ uint32_t reflect = orientation & ui::Transform::ROT_180;
+
+ // Apply reflection for double rotation.
+ if (rotate90 & inverseRotate90) {
+ reflect = ~reflect & ui::Transform::ROT_180;
}
- return static_cast<ui::Transform::orientation_flags>(
- (rotation_rot_90 ^ hw_rot_90) | (rotation_flip_hv ^ hw_flip_hv));
+ return static_cast<RotationFlags>((rotate90 ^ inverseRotate90) |
+ (reflect ^ inverseReflect));
}
- const sp<const DisplayDevice> mDevice;
+ const sp<const DisplayDevice> mDisplay;
const Rect mSourceCrop;
const bool mAllowSecureLayers;
};
-}; // namespace android
-
-#endif // ANDROID_DISPLAY_DEVICE_H
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 8b532e3..e7cf5ff 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -76,6 +76,7 @@
virtual void onVsyncPeriodTimingChangedReceived(
int32_t sequenceId, hwc2_display_t display,
const hwc_vsync_period_change_timeline_t& updatedTimeline) = 0;
+ virtual void onSeamlessPossible(int32_t sequenceId, hwc2_display_t display) = 0;
virtual ~ComposerCallback() = default;
};
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 0a7009b..1960f43 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -125,6 +125,11 @@
return android::hardware::Void();
}
+ android::hardware::Return<void> onSeamlessPossible(android::Hwc2::Display display) override {
+ mCallback->onSeamlessPossible(mSequenceId, display);
+ return android::hardware::Void();
+ }
+
private:
HWC2::ComposerCallback* mCallback;
const int32_t mSequenceId;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6fd1629..2593681 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -848,7 +848,7 @@
// inevitably waiting on a buffer to return. We recreate this semantic for BufferQueue
// even though it is a little consistent. detachChildren is shortly slated for removal
// by the hierarchy mirroring work so we don't need to worry about it too much.
- mDrawingState.callbackHandles = mCurrentState.callbackHandles;
+ forceSendCallbacks();
mCurrentState.callbackHandles = {};
return flags;
}
@@ -1893,6 +1893,18 @@
setTransactionFlags(eTransactionNeeded);
}
+LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) const {
+ LayerProto* layerProto = layersProto.add_layers();
+ writeToProtoDrawingState(layerProto, traceFlags);
+ writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
+
+ for (const sp<Layer>& layer : mDrawingChildren) {
+ layer->writeToProto(layersProto, traceFlags);
+ }
+
+ return layerProto;
+}
+
void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) const {
ui::Transform transform = getTransform();
@@ -2014,6 +2026,8 @@
} else {
layerInfo->set_z_order_relative_of(-1);
}
+
+ layerInfo->set_is_relative_of(state.isRelativeOf);
}
if (traceFlags & SurfaceTracing::TRACE_INPUT) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d697a6a..174ac8d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -333,6 +333,7 @@
const std::vector<sp<CallbackHandle>>& /*handles*/) {
return false;
};
+ virtual void forceSendCallbacks() {}
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
virtual bool setColorSpaceAgnostic(const bool agnostic);
bool setShadowRadius(float shadowRadius);
@@ -453,6 +454,9 @@
bool isRemovedFromCurrentState() const;
+ LayerProto* writeToProto(LayersProto& layersProto,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+
// Write states that are modified by the main thread. This includes drawing
// state as well as buffer data. This should be called in the main or tracing
// thread.
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 1a60f1e..412f977 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -49,7 +49,7 @@
}
if (mTransformToDisplayInverse) {
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
if (invTransform & ui::Transform::ROT_90) {
std::swap(bufWidth, bufHeight);
}
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index 69d8c89..f2bc65d 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -5,4 +5,6 @@
lpy@google.com
marissaw@google.com
racarr@google.com
-stoza@google.com
\ No newline at end of file
+steventhomas@google.com
+stoza@google.com
+vhau@google.com
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index a484373..73de4f8 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -337,19 +337,7 @@
}
const auto device = mFlinger.getDefaultDisplayDevice();
- const auto orientation = [](uint32_t orientation) {
- switch (orientation) {
- default:
- case DisplayState::eOrientationDefault:
- return ui::Transform::ROT_0;
- case DisplayState::eOrientation90:
- return ui::Transform::ROT_90;
- case DisplayState::eOrientation180:
- return ui::Transform::ROT_180;
- case DisplayState::eOrientation270:
- return ui::Transform::ROT_270;
- }
- }(device->getOrientation());
+ const auto orientation = ui::Transform::toRotationFlags(device->getOrientation());
std::vector<RegionSamplingThread::Descriptor> descriptors;
Region sampleRegion;
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 532572f..a7a6dd5 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -17,13 +17,15 @@
// physical render area.
class RenderArea {
public:
+ using RotationFlags = ui::Transform::RotationFlags;
+
enum class CaptureFill {CLEAR, OPAQUE};
static float getCaptureFillValue(CaptureFill captureFill);
RenderArea(uint32_t reqWidth, uint32_t reqHeight, CaptureFill captureFill,
ui::Dataspace reqDataSpace, const Rect& displayViewport,
- ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
+ RotationFlags rotation = ui::Transform::ROT_0)
: mReqWidth(reqWidth),
mReqHeight(reqHeight),
mReqDataSpace(reqDataSpace),
@@ -66,20 +68,20 @@
virtual Rect getSourceCrop() const = 0;
// Returns the rotation of the source crop and the layers.
- ui::Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
+ RotationFlags getRotationFlags() const { return mRotationFlags; }
// Returns the size of the physical render area.
- int getReqWidth() const { return mReqWidth; };
- int getReqHeight() const { return mReqHeight; };
+ int getReqWidth() const { return mReqWidth; }
+ int getReqHeight() const { return mReqHeight; }
// Returns the composition data space of the render area.
ui::Dataspace getReqDataSpace() const { return mReqDataSpace; }
// Returns the fill color of the physical render area. Regions not
// covered by any rendered layer should be filled with this color.
- CaptureFill getCaptureFill() const { return mCaptureFill; };
+ CaptureFill getCaptureFill() const { return mCaptureFill; }
- virtual const sp<const DisplayDevice> getDisplayDevice() const = 0;
+ virtual sp<const DisplayDevice> getDisplayDevice() const = 0;
// Returns the source display viewport.
const Rect& getDisplayViewport() const { return mDisplayViewport; }
@@ -89,7 +91,7 @@
const uint32_t mReqHeight;
const ui::Dataspace mReqDataSpace;
const CaptureFill mCaptureFill;
- const ui::Transform::orientation_flags mRotationFlags;
+ const RotationFlags mRotationFlags;
const Rect mDisplayViewport;
};
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 146ec1b..cf79d9f 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -34,7 +34,7 @@
#include "LayerInfo.h"
#include "SchedulerUtils.h"
-namespace android::scheduler {
+namespace android::scheduler::impl {
namespace {
@@ -157,4 +157,4 @@
mActiveLayersEnd = 0;
}
-} // namespace android::scheduler
+} // namespace android::scheduler::impl
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 745c4c1..d92e5c3 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -32,33 +32,51 @@
namespace scheduler {
+class LayerHistoryTest;
class LayerInfo;
-// Records per-layer history of scheduling-related information (primarily present time),
-// heuristically categorizes layers as active or inactive, and summarizes stats about
-// active layers (primarily maximum refresh rate). See go/content-fps-detection-in-scheduler.
class LayerHistory {
public:
- LayerHistory();
- ~LayerHistory();
+ virtual ~LayerHistory() = default;
// Layers are unregistered when the weak reference expires.
- void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate);
+ virtual void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate) = 0;
// Marks the layer as active, and records the given state to its history.
- void record(Layer*, nsecs_t presentTime, nsecs_t now);
+ virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0;
struct Summary {
float maxRefreshRate; // Maximum refresh rate among recently active layers.
};
// Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
- Summary summarize(nsecs_t now);
+ virtual Summary summarize(nsecs_t now) = 0;
- void clear();
+ virtual void clear() = 0;
+};
+
+namespace impl {
+// Records per-layer history of scheduling-related information (primarily present time),
+// heuristically categorizes layers as active or inactive, and summarizes stats about
+// active layers (primarily maximum refresh rate). See go/content-fps-detection-in-scheduler.
+class LayerHistory : public android::scheduler::LayerHistory {
+public:
+ LayerHistory();
+ virtual ~LayerHistory();
+
+ // Layers are unregistered when the weak reference expires.
+ void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate) override;
+
+ // Marks the layer as active, and records the given state to its history.
+ void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
+
+ // Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
+ android::scheduler::LayerHistory::Summary summarize(nsecs_t now) override;
+
+ void clear() override;
private:
- friend class LayerHistoryTest;
+ friend class android::scheduler::LayerHistoryTest;
friend TestableScheduler;
using LayerPair = std::pair<wp<Layer>, std::unique_ptr<LayerInfo>>;
@@ -90,5 +108,6 @@
const bool mTraceEnabled;
};
+} // namespace impl
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index ff9cf86..73dc753 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -108,7 +108,7 @@
using namespace sysprop;
if (property_get_bool("debug.sf.use_smart_90_for_video", 0) || use_smart_90_for_video(false)) {
- mLayerHistory.emplace();
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
}
const int setIdleTimerMs = property_get_int32("debug.sf.set_idle_timer_ms", 0);
@@ -493,7 +493,7 @@
const bool supported = mRefreshRateConfigs.refreshRateSwitchingSupported();
StringAppendF(&result, "+ Refresh rate switching: %s\n", states[supported]);
- StringAppendF(&result, "+ Content detection: %s\n", states[mLayerHistory.has_value()]);
+ StringAppendF(&result, "+ Content detection: %s\n", states[mLayerHistory != nullptr]);
StringAppendF(&result, "+ Idle timer: %s\n",
mIdleTimer ? mIdleTimer->dump().c_str() : states[0]);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 2cdb757..c6430c3 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -193,7 +193,7 @@
std::unique_ptr<EventControlThread> mEventControlThread;
// Used to choose refresh rate if content detection is enabled.
- std::optional<scheduler::LayerHistory> mLayerHistory;
+ std::unique_ptr<scheduler::LayerHistory> mLayerHistory;
// Whether to use idle timer callbacks that support the kernel timer.
const bool mSupportKernelTimer;
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index 56b3252..a6fb3a4 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -39,6 +39,14 @@
virtual ~VSyncDispatch();
/*
+ * A callback that can be registered to be awoken at a given time relative to a vsync event.
+ * \param [in] vsyncTime The timestamp of the vsync the callback is for.
+ * \param [in] targetWakeupTime The timestamp of intended wakeup time of the cb.
+ *
+ */
+ using Callback = std::function<void(nsecs_t vsyncTime, nsecs_t targetWakeupTime)>;
+
+ /*
* Registers a callback that will be called at designated points on the vsync timeline.
* The callback can be scheduled, rescheduled targeting vsync times, or cancelled.
* The token returned must be cleaned up via unregisterCallback.
@@ -51,7 +59,7 @@
* invocation of callbackFn.
*
*/
- virtual CallbackToken registerCallback(std::function<void(nsecs_t)> const& callbackFn,
+ virtual CallbackToken registerCallback(Callback const& callbackFn,
std::string callbackName) = 0;
/*
@@ -112,7 +120,7 @@
*/
class VSyncCallbackRegistration {
public:
- VSyncCallbackRegistration(VSyncDispatch&, std::function<void(nsecs_t)> const& callbackFn,
+ VSyncCallbackRegistration(VSyncDispatch&, VSyncDispatch::Callback const& callbackFn,
std::string const& callbackName);
VSyncCallbackRegistration(VSyncCallbackRegistration&&);
VSyncCallbackRegistration& operator=(VSyncCallbackRegistration&&);
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 48f2abb..2e5b6e9 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -29,7 +29,7 @@
TimeKeeper::~TimeKeeper() = default;
VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string const& name,
- std::function<void(nsecs_t)> const& cb,
+ VSyncDispatch::Callback const& cb,
nsecs_t minVsyncDistance)
: mName(name),
mCallback(cb),
@@ -97,13 +97,13 @@
return *mLastDispatchTime;
}
-void VSyncDispatchTimerQueueEntry::callback(nsecs_t t) {
+void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp) {
{
std::lock_guard<std::mutex> lk(mRunningMutex);
mRunning = true;
}
- mCallback(t);
+ mCallback(vsyncTimestamp, wakeupTimestamp);
std::lock_guard<std::mutex> lk(mRunningMutex);
mRunning = false;
@@ -171,7 +171,8 @@
void VSyncDispatchTimerQueue::timerCallback() {
struct Invocation {
std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
- nsecs_t timestamp;
+ nsecs_t vsyncTimestamp;
+ nsecs_t wakeupTimestamp;
};
std::vector<Invocation> invocations;
{
@@ -186,7 +187,7 @@
if (*wakeupTime < mIntendedWakeupTime + mTimerSlack) {
callback->executing();
invocations.emplace_back(
- Invocation{callback, *callback->lastExecutedVsyncTarget()});
+ Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime});
}
}
@@ -195,12 +196,12 @@
}
for (auto const& invocation : invocations) {
- invocation.callback->callback(invocation.timestamp);
+ invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp);
}
}
VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
- std::function<void(nsecs_t)> const& callbackFn, std::string callbackName) {
+ Callback const& callbackFn, std::string callbackName) {
std::lock_guard<decltype(mMutex)> lk(mMutex);
return CallbackToken{
mCallbacks
@@ -271,7 +272,7 @@
}
VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
- std::function<void(nsecs_t)> const& callbackFn,
+ VSyncDispatch::Callback const& callbackFn,
std::string const& callbackName)
: mDispatch(dispatch),
mToken(dispatch.registerCallback(callbackFn, callbackName)),
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 0c9b4fe..087acc7 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -36,7 +36,7 @@
// Valid transition: disarmed -> armed ( when scheduled )
// Valid transition: armed -> running -> disarmed ( when timer is called)
// Valid transition: armed -> disarmed ( when cancelled )
- VSyncDispatchTimerQueueEntry(std::string const& name, std::function<void(nsecs_t)> const& fn,
+ VSyncDispatchTimerQueueEntry(std::string const& name, VSyncDispatch::Callback const& fn,
nsecs_t minVsyncDistance);
std::string_view name() const;
@@ -62,14 +62,14 @@
nsecs_t executing();
// End: functions that are not threadsafe.
- // Invoke the callback with the timestamp, moving the state from running->disarmed.
- void callback(nsecs_t timestamp);
+ // Invoke the callback with the two given timestamps, moving the state from running->disarmed.
+ void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp);
// Block calling thread while the callback is executing.
void ensureNotRunning();
private:
std::string const mName;
- std::function<void(nsecs_t)> const mCallback;
+ VSyncDispatch::Callback const mCallback;
nsecs_t mWorkDuration;
nsecs_t mEarliestVsync;
@@ -104,8 +104,7 @@
nsecs_t timerSlack, nsecs_t minVsyncDistance);
~VSyncDispatchTimerQueue();
- CallbackToken registerCallback(std::function<void(nsecs_t)> const& callbackFn,
- std::string callbackName) final;
+ CallbackToken registerCallback(Callback const& callbackFn, std::string callbackName) final;
void unregisterCallback(CallbackToken token) final;
ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final;
CancelResult cancel(CallbackToken token) final;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index a652053..20b6238 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -48,7 +48,8 @@
nsecs_t period, nsecs_t offset, nsecs_t notBefore)
: mCallback(cb),
mRegistration(dispatch,
- std::bind(&CallbackRepeater::callback, this, std::placeholders::_1),
+ std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
+ std::placeholders::_2),
std::string(name)),
mPeriod(period),
mOffset(offset),
@@ -85,15 +86,13 @@
}
private:
- void callback(nsecs_t vsynctime) {
- nsecs_t period = 0;
+ void callback(nsecs_t vsynctime, nsecs_t wakeupTime) {
{
std::lock_guard<std::mutex> lk(mMutex);
- period = mPeriod;
mLastCallTime = vsynctime;
}
- mCallback->onDispSyncEvent(vsynctime - period);
+ mCallback->onDispSyncEvent(wakeupTime);
{
std::lock_guard<std::mutex> lk(mMutex);
@@ -175,10 +174,25 @@
return mTracker->nextAnticipatedVSyncTimeFrom(mClock->now());
}
+void VSyncReactor::startPeriodTransition(nsecs_t newPeriod) {
+ mPeriodTransitioningTo = newPeriod;
+ mMoreSamplesNeeded = true;
+}
+
+void VSyncReactor::endPeriodTransition() {
+ mPeriodTransitioningTo.reset();
+ mLastHwVsync.reset();
+ mMoreSamplesNeeded = false;
+}
+
void VSyncReactor::setPeriod(nsecs_t period) {
std::lock_guard lk(mMutex);
mLastHwVsync.reset();
- mPeriodTransitioningTo = period;
+ if (period == getPeriod()) {
+ endPeriodTransition();
+ } else {
+ startPeriodTransition(period);
+ }
}
nsecs_t VSyncReactor::getPeriod() {
@@ -202,16 +216,13 @@
std::lock_guard<std::mutex> lk(mMutex);
if (periodChangeDetected(timestamp)) {
- mMoreSamplesNeeded = false;
- *periodFlushed = true;
-
mTracker->setPeriod(*mPeriodTransitioningTo);
for (auto& entry : mCallbacks) {
entry.second->setPeriod(*mPeriodTransitioningTo);
}
- mPeriodTransitioningTo.reset();
- mLastHwVsync.reset();
+ endPeriodTransition();
+ *periodFlushed = true;
} else if (mPeriodTransitioningTo) {
mLastHwVsync = timestamp;
mMoreSamplesNeeded = true;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 73a5e37..f318dcb 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -61,6 +61,8 @@
void reset() final;
private:
+ void startPeriodTransition(nsecs_t newPeriod) REQUIRES(mMutex);
+ void endPeriodTransition() REQUIRES(mMutex);
bool periodChangeDetected(nsecs_t vsync_timestamp) REQUIRES(mMutex);
std::unique_ptr<Clock> const mClock;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8c1d168..97bed34 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -163,21 +163,6 @@
return false;
}
-ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
- switch (rotation) {
- case ISurfaceComposer::eRotateNone:
- return ui::Transform::ROT_0;
- case ISurfaceComposer::eRotate90:
- return ui::Transform::ROT_90;
- case ISurfaceComposer::eRotate180:
- return ui::Transform::ROT_180;
- case ISurfaceComposer::eRotate270:
- return ui::Transform::ROT_270;
- }
- ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
- return ui::Transform::ROT_0;
-}
-
#pragma clang diagnostic pop
class ConditionalLock {
@@ -215,7 +200,7 @@
bool SurfaceFlinger::useVrFlinger;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
bool SurfaceFlinger::hasWideColorDisplay;
-int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
+ui::Rotation SurfaceFlinger::internalDisplayOrientation = ui::ROTATION_0;
bool SurfaceFlinger::useColorManagement;
bool SurfaceFlinger::useContextPriority;
Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
@@ -298,23 +283,21 @@
useContextPriority = use_context_priority(true);
- auto tmpPrimaryDisplayOrientation = primary_display_orientation(
- SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_0);
- switch (tmpPrimaryDisplayOrientation) {
- case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_90:
- SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation90;
+ using Values = SurfaceFlingerProperties::primary_display_orientation_values;
+ switch (primary_display_orientation(Values::ORIENTATION_0)) {
+ case Values::ORIENTATION_0:
break;
- case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_180:
- SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation180;
+ case Values::ORIENTATION_90:
+ internalDisplayOrientation = ui::ROTATION_90;
break;
- case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_270:
- SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation270;
+ case Values::ORIENTATION_180:
+ internalDisplayOrientation = ui::ROTATION_180;
break;
- default:
- SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
+ case Values::ORIENTATION_270:
+ internalDisplayOrientation = ui::ROTATION_270;
break;
}
- ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
+ ALOGV("Internal Display Orientation: %s", toCString(internalDisplayOrientation));
mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries();
@@ -507,6 +490,7 @@
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mFrameTracer->initialize();
+ mTimeStats->onBootFinished();
// wait patiently for the window manager death
const String16 name("window");
@@ -789,9 +773,8 @@
}
info.density = density;
- // TODO: this needs to go away (currently needed only by webkit)
const auto display = getDefaultDisplayDeviceLocked();
- info.orientation = display ? display->getOrientation() : 0;
+ info.orientation = display->getOrientation();
// This is for screenrecord
const Rect viewport = display->getViewport();
@@ -804,7 +787,6 @@
// TODO: where should this value come from?
static const int TV_DENSITY = 213;
info.density = TV_DENSITY / 160.0f;
- info.orientation = 0;
const auto display = getDisplayDeviceLocked(displayToken);
info.layerStack = display->getLayerStack();
@@ -835,7 +817,8 @@
info.secure = true;
if (displayId == getInternalDisplayIdLocked() &&
- primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
+ (internalDisplayOrientation == ui::ROTATION_90 ||
+ internalDisplayOrientation == ui::ROTATION_270)) {
std::swap(info.w, info.h);
}
@@ -1570,6 +1553,11 @@
mScheduler->onNewVsyncPeriodChangeTimeline(updatedTimeline);
}
+void SurfaceFlinger::onSeamlessPossible(int32_t /*sequenceId*/, hwc2_display_t /*display*/) {
+ // TODO(b/142753666): use constraints when calling to setActiveConfigWithConstrains and
+ // use this callback to know when to retry in case of SEAMLESS_NOT_POSSIBLE.
+}
+
void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDisplayId*/) {
Mutex::Autolock lock(mStateLock);
if (sequenceId != getBE().mComposerSequenceId) {
@@ -2279,8 +2267,8 @@
nativeWindow->setSwapInterval(nativeWindow.get(), 0);
}
- creationArgs.displayInstallOrientation =
- isInternalDisplay ? primaryDisplayOrientation : DisplayState::eOrientationDefault;
+ creationArgs.physicalOrientation =
+ isInternalDisplay ? internalDisplayOrientation : ui::ROTATION_0;
// virtual displays are always considered enabled
creationArgs.initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
@@ -3817,7 +3805,7 @@
DisplayState::eLayerStackChanged;
d.token = token;
d.layerStack = 0;
- d.orientation = DisplayState::eOrientationDefault;
+ d.orientation = ui::ROTATION_0;
d.frame.makeInvalid();
d.viewport.makeInvalid();
d.width = 0;
@@ -4270,12 +4258,9 @@
LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
LayersProto layersProto;
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProtoDrawingState(layerProto, traceFlags);
- layer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
- });
-
+ for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
+ layer->writeToProto(layersProto, traceFlags);
+ }
return layersProto;
}
@@ -4293,21 +4278,8 @@
rootProto->add_children(offscreenLayer->sequence);
// Add layer
- LayerProto* layerProto = layersProto.add_layers();
- offscreenLayer->writeToProtoDrawingState(layerProto, traceFlags);
- offscreenLayer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing,
- traceFlags);
+ LayerProto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags);
layerProto->set_parent(offscreenRootLayerId);
-
- // Add children
- offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- if (layer == offscreenLayer) {
- return;
- }
- LayerProto* childProto = layersProto.add_layers();
- layer->writeToProtoDrawingState(childProto, traceFlags);
- layer->writeToProtoCommonState(childProto, LayerVector::StateSet::Drawing, traceFlags);
- });
}
}
@@ -4426,8 +4398,8 @@
if (const auto display = getDefaultDisplayDeviceLocked()) {
display->getCompositionDisplay()->getState().undefinedRegion.dump(result,
"undefinedRegion");
- StringAppendF(&result, " orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
- display->isPoweredOn());
+ StringAppendF(&result, " orientation=%s, isPoweredOn=%d\n",
+ toCString(display->getOrientation()), display->isPoweredOn());
}
StringAppendF(&result,
" transaction-flags : %08x\n"
@@ -5004,17 +4976,19 @@
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken,
sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers,
- const Dataspace reqDataspace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
- uint32_t reqWidth, uint32_t reqHeight,
- bool useIdentityTransform,
- ISurfaceComposer::Rotation rotation,
- bool captureSecureLayers) {
+ Dataspace reqDataspace, ui::PixelFormat reqPixelFormat,
+ const Rect& sourceCrop, uint32_t reqWidth,
+ uint32_t reqHeight, bool useIdentityTransform,
+ ui::Rotation rotation, bool captureSecureLayers) {
ATRACE_CALL();
if (!displayToken) return BAD_VALUE;
- auto renderAreaRotation = fromSurfaceComposerRotation(rotation);
+ auto renderAreaRotation = ui::Transform::toRotationFlags(rotation);
+ if (renderAreaRotation == ui::Transform::ROT_INVALID) {
+ ALOGE("%s: Invalid rotation: %s", __FUNCTION__, toCString(rotation));
+ renderAreaRotation = ui::Transform::ROT_0;
+ }
sp<DisplayDevice> display;
{
@@ -5076,7 +5050,7 @@
sp<DisplayDevice> display;
uint32_t width;
uint32_t height;
- ui::Transform::orientation_flags captureOrientation;
+ ui::Transform::RotationFlags captureOrientation;
{
Mutex::Autolock _l(mStateLock);
display = getDisplayByIdOrLayerStack(displayOrLayerStack);
@@ -5087,12 +5061,25 @@
width = uint32_t(display->getViewport().width());
height = uint32_t(display->getViewport().height());
- captureOrientation = fromSurfaceComposerRotation(
- static_cast<ISurfaceComposer::Rotation>(display->getOrientation()));
- if (captureOrientation == ui::Transform::orientation_flags::ROT_90) {
- captureOrientation = ui::Transform::orientation_flags::ROT_270;
- } else if (captureOrientation == ui::Transform::orientation_flags::ROT_270) {
- captureOrientation = ui::Transform::orientation_flags::ROT_90;
+ const auto orientation = display->getOrientation();
+ captureOrientation = ui::Transform::toRotationFlags(orientation);
+
+ switch (captureOrientation) {
+ case ui::Transform::ROT_90:
+ captureOrientation = ui::Transform::ROT_270;
+ break;
+
+ case ui::Transform::ROT_270:
+ captureOrientation = ui::Transform::ROT_90;
+ break;
+
+ case ui::Transform::ROT_INVALID:
+ ALOGE("%s: Invalid orientation: %s", __FUNCTION__, toCString(orientation));
+ captureOrientation = ui::Transform::ROT_0;
+ break;
+
+ default:
+ break;
}
*outDataspace =
pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode);
@@ -5140,7 +5127,7 @@
}
bool isSecure() const override { return false; }
bool needsFiltering() const override { return mNeedsFiltering; }
- const sp<const DisplayDevice> getDisplayDevice() const override { return nullptr; }
+ sp<const DisplayDevice> getDisplayDevice() const override { return nullptr; }
Rect getSourceCrop() const override {
if (mCrop.isEmpty()) {
return getBounds();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 2f84b13..723e332 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -229,7 +229,7 @@
// found on devices with wide color gamut (e.g. Display-P3) display.
static bool hasWideColorDisplay;
- static int primaryDisplayOrientation;
+ static ui::Rotation internalDisplayOrientation;
// Indicate if device wants color management on its display.
static bool useColorManagement;
@@ -415,10 +415,10 @@
ISurfaceComposer::ConfigChanged configChanged =
ISurfaceComposer::eConfigChangedSuppress) override;
status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
- bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
- const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
- uint32_t reqWidth, uint32_t reqHeight,
- bool useIdentityTransform, ISurfaceComposer::Rotation rotation, bool captureSecureLayers) override;
+ bool& outCapturedSecureLayers, ui::Dataspace reqDataspace,
+ ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ ui::Rotation rotation, bool captureSecureLayers) override;
status_t captureScreen(uint64_t displayOrLayerStack, ui::Dataspace* outDataspace,
sp<GraphicBuffer>* outBuffer) override;
status_t captureLayers(
@@ -505,6 +505,7 @@
void onVsyncPeriodTimingChangedReceived(
int32_t sequenceId, hwc2_display_t display,
const hwc_vsync_period_change_timeline_t& updatedTimeline) override;
+ void onSeamlessPossible(int32_t sequenceId, hwc2_display_t display) override;
/* ------------------------------------------------------------------------
* ISchedulerCallback
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 5e8910a..8e0462a 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -137,8 +137,8 @@
addDisplaySurfaceLocked(transaction, display.sequenceId, display.surface);
addDisplayLayerStackLocked(transaction, display.sequenceId, display.layerStack);
addDisplaySizeLocked(transaction, display.sequenceId, display.width, display.height);
- addDisplayProjectionLocked(transaction, display.sequenceId, display.orientation,
- display.viewport, display.frame);
+ addDisplayProjectionLocked(transaction, display.sequenceId, toRotationInt(display.orientation),
+ display.viewport, display.frame);
}
status_t SurfaceInterceptor::writeProtoFileLocked() {
@@ -467,8 +467,8 @@
addDisplaySizeLocked(transaction, sequenceId, state.width, state.height);
}
if (state.what & DisplayState::eDisplayProjectionChanged) {
- addDisplayProjectionLocked(transaction, sequenceId, state.orientation, state.viewport,
- state.frame);
+ addDisplayProjectionLocked(transaction, sequenceId, toRotationInt(state.orientation),
+ state.viewport, state.frame);
}
}
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index 2080a38..ed0fe9e 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -1,12 +1,35 @@
-cc_library_static {
+cc_library_shared {
name: "libtimestats",
- defaults: ["surfaceflinger_defaults"],
srcs: [
- "TimeStats.cpp",
+ "TimeStats.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "libprotobuf-cpp-lite",
+ "libstatslog",
+ "libstatspull",
+ "libstatssocket",
+ "libtimestats_proto",
+ "libui",
+ "libutils",
],
export_include_dirs: ["."],
- shared_libs: [
- "libtimestats_proto",
- "libui",
+ export_shared_lib_headers: [
+ "libbinder",
+ "libstatslog",
+ "libstatspull",
+ "libstatssocket",
+ "libtimestats_proto",
+ ],
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
],
}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 1895777..6520d01 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -32,14 +32,54 @@
namespace impl {
+bool TimeStats::pullGlobalAtomCallback(int32_t atom_tag, pulled_stats_event_list* data,
+ const void* cookie) {
+ impl::TimeStats* timeStats =
+ const_cast<impl::TimeStats*>(reinterpret_cast<const impl::TimeStats*>(cookie));
+ if (atom_tag != android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) {
+ return false;
+ }
+
+ std::lock_guard<std::mutex> lock(timeStats->mMutex);
+
+ const auto& stats = timeStats->mTimeStats;
+ if (stats.statsStart == 0) {
+ return false;
+ }
+ timeStats->flushPowerTimeLocked();
+
+ struct stats_event* event = timeStats->mStatsDelegate->addStatsEventToPullData(data);
+ timeStats->mStatsDelegate->statsEventSetAtomId(event,
+ android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+ timeStats->mStatsDelegate->statsEventWriteInt64(event, stats.totalFrames);
+ timeStats->mStatsDelegate->statsEventWriteInt64(event, stats.missedFrames);
+ timeStats->mStatsDelegate->statsEventWriteInt64(event, stats.clientCompositionFrames);
+ timeStats->mStatsDelegate->statsEventWriteInt64(event, stats.displayOnTime);
+ timeStats->mStatsDelegate->statsEventWriteInt64(event, stats.presentToPresent.totalTime());
+ timeStats->mStatsDelegate->statsEventBuild(event);
+ timeStats->clearGlobalLocked();
+
+ return true;
+}
+
TimeStats::TimeStats() {
// Temporarily enable TimeStats by default. Telemetry is disabled while
// we move onto statsd, so TimeStats is currently not exercised at all
- // during testing.
- // TODO: remove this.
+ // during testing without enabling by default.
+ // TODO: remove this, as we should only be paying this overhead on devices
+ // where statsd exists.
enable();
}
+TimeStats::TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate) : TimeStats() {
+ mStatsDelegate = std::move(statsDelegate);
+}
+
+void TimeStats::onBootFinished() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mRegisteredCallback = false;
+}
+
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
ATRACE_CALL();
@@ -65,7 +105,7 @@
}
if (argsMap.count("-clear")) {
- clear();
+ clearAll();
}
if (argsMap.count("-enable")) {
@@ -549,6 +589,30 @@
mGlobalRecord.renderEngineDurations.pop_front();
}
+ // Try to register to statsd at the end of every global flush, if we haven't
+ // yet.
+ registerToStatsdIfNeededLocked();
+}
+
+bool TimeStats::StatsEventDelegate::checkStatsService() {
+ ATRACE_CALL();
+ bool ret =
+ android::defaultServiceManager()->checkService(android::String16("stats")) != nullptr;
+ return ret;
+}
+
+void TimeStats::registerToStatsdIfNeededLocked() {
+ if (!mRegisteredCallback && mStatsDelegate->checkStatsService()) {
+ // Note that this assumes that statsd will never crash. To be absolutely
+ // correct we would need to register a DeathRecipient ourselves, but to
+ // minimize the cost on the rendering path let's only register once as
+ // soon as we know that statd has booted up.
+ ALOGD("Registering statsd callback");
+ mStatsDelegate
+ ->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ TimeStats::pullGlobalAtomCallback, nullptr, this);
+ mRegisteredCallback = true;
+ }
}
void TimeStats::setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) {
@@ -605,12 +669,15 @@
ALOGD("Disabled");
}
-void TimeStats::clear() {
+void TimeStats::clearAll() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ clearGlobalLocked();
+ clearLayersLocked();
+}
+
+void TimeStats::clearGlobalLocked() {
ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mMutex);
- mTimeStatsTracker.clear();
- mTimeStats.stats.clear();
mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
mTimeStats.statsEnd = 0;
mTimeStats.totalFrames = 0;
@@ -618,11 +685,21 @@
mTimeStats.clientCompositionFrames = 0;
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
+ mTimeStats.frameDuration.hist.clear();
+ mTimeStats.renderEngineTiming.hist.clear();
mTimeStats.refreshRateStats.clear();
mPowerTime.prevTime = systemTime();
mGlobalRecord.prevPresentTime = 0;
mGlobalRecord.presentFences.clear();
- ALOGD("Cleared");
+ ALOGD("Cleared global stats");
+}
+
+void TimeStats::clearLayersLocked() {
+ ATRACE_CALL();
+
+ mTimeStatsTracker.clear();
+ mTimeStats.stats.clear();
+ ALOGD("Cleared layer stats");
}
bool TimeStats::isEnabled() {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 65e5cf4..94c24ea 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -16,7 +16,11 @@
#pragma once
+#include <binder/IServiceManager.h>
#include <hardware/hwcomposer_defs.h>
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
+#include <statslog.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
#include <ui/FenceTime.h>
@@ -37,6 +41,10 @@
public:
virtual ~TimeStats() = default;
+ // Called once boot has been finished to perform additional capabilities,
+ // e.g. registration to statsd.
+ virtual void onBootFinished() = 0;
+
virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
virtual bool isEnabled() = 0;
virtual std::string miniDump() = 0;
@@ -131,6 +139,40 @@
public:
TimeStats();
+ // Delegate to the statsd service and associated APIs.
+ // Production code may use this class directly, whereas unit test may define
+ // a subclass for ease of testing.
+ class StatsEventDelegate {
+ public:
+ virtual ~StatsEventDelegate() = default;
+ virtual struct stats_event* addStatsEventToPullData(pulled_stats_event_list* data) {
+ return add_stats_event_to_pull_data(data);
+ }
+ virtual void registerStatsPullAtomCallback(int32_t atom_tag,
+ stats_pull_atom_callback_t callback,
+ pull_atom_metadata* metadata, void* cookie) {
+ return register_stats_pull_atom_callback(atom_tag, callback, metadata, cookie);
+ }
+
+ // Check if the statsd daemon exists, as otherwise callback registration
+ // will silently fail.
+ virtual bool checkStatsService();
+
+ virtual void statsEventSetAtomId(struct stats_event* event, int32_t atom_id) {
+ return stats_event_set_atom_id(event, atom_id);
+ }
+
+ virtual void statsEventWriteInt64(struct stats_event* event, int64_t field) {
+ return stats_event_write_int64(event, field);
+ }
+
+ virtual void statsEventBuild(struct stats_event* event) { return stats_event_build(event); }
+ };
+ // For testing only for injecting custom dependencies.
+ TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate);
+
+ void onBootFinished() override;
+
void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
bool isEnabled() override;
std::string miniDump() override;
@@ -167,14 +209,19 @@
static const size_t MAX_NUM_TIME_RECORDS = 64;
private:
+ static bool pullGlobalAtomCallback(int32_t atom_tag, pulled_stats_event_list* data,
+ const void* cookie);
bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
void flushAvailableRecordsToStatsLocked(int32_t layerId);
void flushPowerTimeLocked();
void flushAvailableGlobalRecordsToStatsLocked();
+ void registerToStatsdIfNeededLocked();
void enable();
void disable();
- void clear();
+ void clearAll();
+ void clearGlobalLocked();
+ void clearLayersLocked();
void dump(bool asProto, std::optional<uint32_t> maxLayers, std::string& result);
std::atomic<bool> mEnabled = false;
@@ -187,6 +234,10 @@
static const size_t MAX_NUM_LAYER_RECORDS = 200;
static const size_t MAX_NUM_LAYER_STATS = 200;
+ // Default is true, so that registration doesn't happen until the device has
+ // been booted.
+ bool mRegisteredCallback = true;
+ std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>();
};
} // namespace impl
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 4c1baaf..1475889 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -310,8 +310,8 @@
// we get pointers that compare unequal in the SF process.
interface_cast<ITransactionCompletedListener>(listenerStats.listener)
->onTransactionCompleted(listenerStats);
- listener->unlinkToDeath(mDeathRecipient);
if (transactionStatsDeque.empty()) {
+ listener->unlinkToDeath(mDeathRecipient);
completedTransactionsItr =
mCompletedTransactions.erase(completedTransactionsItr);
} else {
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 23df1bb..41ecafa 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -102,6 +102,8 @@
// layer or set by a parent layer.
float shadow_radius = 49;
ColorTransformProto color_transform = 50;
+
+ bool is_relative_of = 51;
}
message PositionProto {
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 0403237..1c8199a 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -55,7 +55,6 @@
"liblog",
"libnativewindow",
"libprotobuf-cpp-full",
- "libtimestats_proto",
"libui",
"libutils",
],
@@ -68,7 +67,7 @@
name: "ipc_defaults",
cflags: [
"-Wall",
- "-Werror",
+ "-Werror",
],
}
@@ -82,11 +81,11 @@
],
cppflags: [
"-Wall",
- "-Werror",
- "-Wformat",
- "-Wthread-safety",
- "-Wunused",
- "-Wunreachable-code",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
],
shared_libs: [
"libandroid",
@@ -98,7 +97,6 @@
"liblayers_proto",
"liblog",
"libprotobuf-cpp-full",
- "libtimestats_proto",
"libui",
"libutils",
],
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index b1bb7fd..f618873 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -23,7 +23,6 @@
namespace {
const String8 DISPLAY_NAME("Credentials Display Test");
const String8 SURFACE_NAME("Test Surface Name");
-const uint32_t ROTATION = 0;
const float FRAME_SCALE = 1.0f;
} // namespace
@@ -262,7 +261,7 @@
sp<GraphicBuffer> outBuffer;
return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB,
ui::PixelFormat::RGBA_8888, Rect(), 0 /*reqWidth*/,
- 0 /*reqHeight*/, false, ROTATION, &outBuffer);
+ 0 /*reqHeight*/, false, ui::ROTATION_0, &outBuffer);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 627de7a..92698f0 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -189,12 +189,12 @@
}
TEST_P(LayerRenderTypeTransactionTest, CreateLayer_BufferState) {
- uint32_t transformHint = ui::Transform::orientation_flags::ROT_INVALID;
+ uint32_t transformHint = ui::Transform::ROT_INVALID;
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32,
ISurfaceComposerClient::eFXSurfaceBufferState,
/*parent*/ nullptr, &transformHint));
- ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, transformHint);
+ ASSERT_NE(ui::Transform::ROT_INVALID, transformHint);
}
void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
index 35c51e1..7816c66 100644
--- a/services/surfaceflinger/tests/LayerTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -53,7 +53,7 @@
ASSERT_EQ(NO_ERROR,
composer->captureScreen(mDisplay, &outBuffer, outCapturedSecureLayers,
ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0,
- 0, false, ISurfaceComposer::eRotateNone, true));
+ 0, false, ui::ROTATION_0, true));
ASSERT_EQ(true, outCapturedSecureLayers);
ScreenCapture sc(outBuffer);
sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 31837a9..ff403f6 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -29,7 +29,7 @@
"liblog",
"libnativewindow",
"libsync",
- "libtimestats_proto",
+ "libtimestats",
"libui",
"libutils",
],
@@ -38,7 +38,6 @@
"libgmock",
"libperfetto_client_experimental",
"librenderengine",
- "libtimestats",
"libtrace_proto",
],
header_libs: [
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 68adbfc..b43e939 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -79,11 +79,13 @@
"libgui_mocks",
"libperfetto_client_experimental",
"librenderengine_mocks",
- "libtimestats",
"perfetto_trace_protos",
],
shared_libs: [
+ "libstatssocket",
"libsurfaceflinger",
+ "libtimestats",
+ "libtimestats_proto",
],
header_libs: [
"libsurfaceflinger_headers",
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 76e8171..55c3ab8 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -2040,8 +2040,8 @@
TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
using Case = NonHwcVirtualDisplayCase;
- constexpr int oldTransform = 0;
- constexpr int newTransform = 2;
+ constexpr ui::Rotation oldTransform = ui::ROTATION_0;
+ constexpr ui::Rotation newTransform = ui::ROTATION_180;
// --------------------------------------------------------------------
// Preconditions
@@ -2414,7 +2414,7 @@
TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) {
using Case = SimplePrimaryDisplayCase;
- constexpr int initialOrientation = 180;
+ constexpr ui::Rotation initialOrientation = ui::ROTATION_180;
const Rect initialFrame = {1, 2, 3, 4};
const Rect initialViewport = {5, 6, 7, 8};
@@ -2458,8 +2458,8 @@
TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfOrientationChanged) {
using Case = SimplePrimaryDisplayCase;
- constexpr int initialOrientation = 90;
- constexpr int desiredOrientation = 180;
+ constexpr ui::Rotation initialOrientation = ui::ROTATION_90;
+ constexpr ui::Rotation desiredOrientation = ui::ROTATION_180;
// --------------------------------------------------------------------
// Preconditions
@@ -2721,7 +2721,7 @@
// The layer stack state should be set to zero
EXPECT_EQ(0u, primaryDisplayState.layerStack);
// The orientation state should be set to zero
- EXPECT_EQ(0, primaryDisplayState.orientation);
+ EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation);
// The frame state should be set to INVALID
EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.frame);
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index d95252b..f055fe7 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -29,8 +29,8 @@
LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); }
- LayerHistory& history() { return *mScheduler->mutableLayerHistory(); }
- const LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); }
+ impl::LayerHistory& history() { return *mScheduler->mutableLayerHistory(); }
+ const impl::LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); }
size_t layerCount() const { return mScheduler->layerHistorySize(); }
size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index fa095aa..a67c24c 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -30,14 +30,14 @@
public:
explicit TestableScheduler(const scheduler::RefreshRateConfigs& configs)
: Scheduler([](bool) {}, configs, *this) {
- mLayerHistory.emplace();
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
}
TestableScheduler(std::unique_ptr<DispSync> primaryDispSync,
std::unique_ptr<EventControlThread> eventControlThread,
const scheduler::RefreshRateConfigs& configs)
: Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs, *this) {
- mLayerHistory.emplace();
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
}
// Used to inject mock event thread.
@@ -46,7 +46,7 @@
}
size_t layerHistorySize() const NO_THREAD_SAFETY_ANALYSIS {
- return mLayerHistory->mLayerInfos.size();
+ return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get())->mLayerInfos.size();
}
/* ------------------------------------------------------------------------
@@ -57,7 +57,9 @@
auto& mutableEventControlThread() { return mEventControlThread; }
auto& mutablePrimaryDispSync() { return mPrimaryDispSync; }
auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
- auto& mutableLayerHistory() { return mLayerHistory; }
+ auto mutableLayerHistory() {
+ return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get());
+ }
~TestableScheduler() {
// All these pointer and container clears help ensure that GMock does
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b5245e2..9728c80 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -371,7 +371,6 @@
*/
auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
- auto& mutablePrimaryDisplayOrientation() { return SurfaceFlinger::primaryDisplayOrientation; }
auto& mutableUseColorManagement() { return SurfaceFlinger::useColorManagement; }
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 68e4c58..ec27201 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -36,7 +36,9 @@
namespace android {
namespace {
+using testing::_;
using testing::Contains;
+using testing::InSequence;
using testing::SizeIs;
using testing::UnorderedElementsAre;
@@ -132,7 +134,41 @@
}
std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
- std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
+
+ class FakeStatsEventDelegate : public impl::TimeStats::StatsEventDelegate {
+ public:
+ FakeStatsEventDelegate() = default;
+ ~FakeStatsEventDelegate() override = default;
+
+ struct stats_event* addStatsEventToPullData(pulled_stats_event_list*) override {
+ return mEvent;
+ }
+ void registerStatsPullAtomCallback(int32_t atom_tag, stats_pull_atom_callback_t callback,
+ pull_atom_metadata*, void* cookie) override {
+ mAtomTag = atom_tag;
+ mCallback = callback;
+ mCookie = cookie;
+ }
+
+ bool checkStatsService() override { return true; }
+
+ bool makePullAtomCallback(int32_t atom_tag, const void* cookie) {
+ return (*mCallback)(atom_tag, nullptr, cookie);
+ }
+
+ MOCK_METHOD2(statsEventSetAtomId, void(struct stats_event*, int32_t));
+ MOCK_METHOD2(statsEventWriteInt64, void(struct stats_event*, int64_t));
+ MOCK_METHOD1(statsEventBuild, void(struct stats_event*));
+
+ struct stats_event* mEvent = stats_event_obtain();
+ int32_t mAtomTag = 0;
+ stats_pull_atom_callback_t mCallback = nullptr;
+ void* mCookie = nullptr;
+ };
+
+ FakeStatsEventDelegate* mDelegate = new FakeStatsEventDelegate;
+ std::unique_ptr<TimeStats> mTimeStats =
+ std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate));
};
std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -562,6 +598,16 @@
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
+
+ using namespace std::chrono_literals;
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+ .count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
ASSERT_NO_FATAL_FAILURE(
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
ASSERT_NO_FATAL_FAILURE(
@@ -578,6 +624,8 @@
EXPECT_EQ(0, globalProto.missed_frames());
EXPECT_EQ(0, globalProto.client_composition_frames());
EXPECT_EQ(0, globalProto.present_to_present_size());
+ EXPECT_EQ(0, globalProto.frame_duration_size());
+ EXPECT_EQ(0, globalProto.render_engine_timing_size());
EXPECT_EQ(0, globalProto.stats_size());
}
@@ -615,6 +663,66 @@
ASSERT_EQ(0, globalProto.stats_size());
}
+TEST_F(TimeStatsTest, globalStatsCallback_disabledBeforeBoot) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+
+ // Callback should not be registered after flushing global stats
+ EXPECT_EQ(nullptr, mDelegate->mCallback);
+}
+
+TEST_F(TimeStatsTest, globalStatsCallback_worksAfterBoot) {
+ constexpr size_t TOTAL_FRAMES = 5;
+ constexpr size_t MISSED_FRAMES = 4;
+ constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ mTimeStats->onBootFinished();
+
+ for (size_t i = 0; i < TOTAL_FRAMES; i++) {
+ mTimeStats->incrementTotalFrames();
+ }
+ for (size_t i = 0; i < MISSED_FRAMES; i++) {
+ mTimeStats->incrementMissedFrames();
+ }
+ for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
+ mTimeStats->incrementClientCompositionFrames();
+ }
+
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+
+ EXPECT_EQ(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, mDelegate->mAtomTag);
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ {
+ InSequence seq;
+ EXPECT_CALL(*mDelegate,
+ statsEventSetAtomId(mDelegate->mEvent,
+ android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
+ EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+ }
+ mDelegate->makePullAtomCallback(mDelegate->mAtomTag, mDelegate->mCookie);
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ EXPECT_EQ(0, globalProto.total_frames());
+ EXPECT_EQ(0, globalProto.missed_frames());
+ EXPECT_EQ(0, globalProto.client_composition_frames());
+ EXPECT_EQ(0, globalProto.present_to_present_size());
+}
+
TEST_F(TimeStatsTest, canSurviveMonkey) {
if (g_noSlowTests) {
GTEST_SKIP();
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index 5846c77..b51a025 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -101,7 +101,7 @@
RepeatingCallbackReceiver(VSyncDispatch& dispatch, nsecs_t wl)
: mWorkload(wl),
mCallback(
- dispatch, [&](auto time) { callback_called(time); }, "repeat0") {}
+ dispatch, [&](auto time, auto) { callback_called(time); }, "repeat0") {}
void repeatedly_schedule(size_t iterations, std::function<void(nsecs_t)> const& onEachFrame) {
mCallbackTimes.reserve(iterations);
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 5aff429..6fcb1af 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -97,13 +97,14 @@
CountingCallback(VSyncDispatch& dispatch)
: mDispatch(dispatch),
mToken(dispatch.registerCallback(std::bind(&CountingCallback::counter, this,
- std::placeholders::_1),
+ std::placeholders::_1,
+ std::placeholders::_2),
"test")) {}
~CountingCallback() { mDispatch.unregisterCallback(mToken); }
operator VSyncDispatch::CallbackToken() const { return mToken; }
- void counter(nsecs_t time) { mCalls.push_back(time); }
+ void counter(nsecs_t time, nsecs_t) { mCalls.push_back(time); }
VSyncDispatch& mDispatch;
VSyncDispatch::CallbackToken mToken;
@@ -115,7 +116,8 @@
PausingCallback(VSyncDispatch& dispatch, std::chrono::milliseconds pauseAmount)
: mDispatch(dispatch),
mToken(dispatch.registerCallback(std::bind(&PausingCallback::pause, this,
- std::placeholders::_1),
+ std::placeholders::_1,
+ std::placeholders::_2),
"test")),
mRegistered(true),
mPauseAmount(pauseAmount) {}
@@ -123,7 +125,7 @@
operator VSyncDispatch::CallbackToken() const { return mToken; }
- void pause(nsecs_t) {
+ void pause(nsecs_t, nsecs_t) {
std::unique_lock<std::mutex> lk(mMutex);
mPause = true;
mCv.notify_all();
@@ -462,7 +464,8 @@
EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
VSyncDispatch::CallbackToken tmp;
- tmp = mDispatch.registerCallback([&](auto) { mDispatch.schedule(tmp, 100, 2000); }, "o.o");
+ tmp = mDispatch.registerCallback([&](auto, auto) { mDispatch.schedule(tmp, 100, 2000); },
+ "o.o");
mDispatch.schedule(tmp, 100, 1000);
advanceToNextCallback();
@@ -472,7 +475,7 @@
VSyncDispatch::CallbackToken tmp;
std::optional<nsecs_t> lastTarget;
tmp = mDispatch.registerCallback(
- [&](auto timestamp) {
+ [&](auto timestamp, auto) {
EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp - mVsyncMoveThreshold),
ScheduleResult::Scheduled);
EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp), ScheduleResult::Scheduled);
@@ -621,7 +624,7 @@
EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
VSyncCallbackRegistration cb(
- mDispatch, [](auto) {}, "");
+ mDispatch, [](auto, auto) {}, "");
VSyncCallbackRegistration cb1(std::move(cb));
cb.schedule(100, 1000);
cb.cancel();
@@ -635,9 +638,9 @@
EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
VSyncCallbackRegistration cb(
- mDispatch, [](auto) {}, "");
+ mDispatch, [](auto, auto) {}, "");
VSyncCallbackRegistration cb1(
- mDispatch, [](auto) {}, "");
+ mDispatch, [](auto, auto) {}, "");
cb1 = std::move(cb);
cb.schedule(100, 1000);
cb.cancel();
@@ -656,7 +659,7 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) {
std::string name("basicname");
VSyncDispatchTimerQueueEntry entry(
- name, [](auto) {}, mVsyncMoveThreshold);
+ name, [](auto, auto) {}, mVsyncMoveThreshold);
EXPECT_THAT(entry.name(), Eq(name));
EXPECT_FALSE(entry.lastExecutedVsyncTarget());
EXPECT_FALSE(entry.wakeupTime());
@@ -664,7 +667,7 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) {
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
@@ -684,7 +687,7 @@
.Times(1)
.WillOnce(Return(10000));
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled));
@@ -695,12 +698,14 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) {
auto callCount = 0;
- auto calledTime = 0;
+ auto vsyncCalledTime = 0;
+ auto wakeupCalledTime = 0;
VSyncDispatchTimerQueueEntry entry(
"test",
- [&](auto time) {
+ [&](auto vsyncTime, auto wakeupTime) {
callCount++;
- calledTime = time;
+ vsyncCalledTime = vsyncTime;
+ wakeupCalledTime = wakeupTime;
},
mVsyncMoveThreshold);
@@ -709,10 +714,11 @@
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(900));
- entry.callback(entry.executing());
+ entry.callback(entry.executing(), *wakeup);
EXPECT_THAT(callCount, Eq(1));
- EXPECT_THAT(calledTime, Eq(mPeriod));
+ EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
+ EXPECT_THAT(wakeupCalledTime, Eq(*wakeup));
EXPECT_FALSE(entry.wakeupTime());
auto lastCalledTarget = entry.lastExecutedVsyncTarget();
ASSERT_TRUE(lastCalledTarget);
@@ -726,7 +732,7 @@
.WillOnce(Return(1020));
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
entry.update(mStubTracker, 0);
@@ -745,7 +751,7 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) {
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
entry.update(mStubTracker, 0);
@@ -756,7 +762,7 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
entry.executing(); // 1000 is executing
// had 1000 not been executing, this could have been scheduled for time 800.
@@ -773,7 +779,7 @@
TEST_F(VSyncDispatchTimerQueueEntryTest,
willRequestNextEstimateWhenSnappingToNextTargettableVSync) {
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
Sequence seq;
EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
@@ -795,7 +801,7 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 72f8bb9..188adea 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -73,7 +73,8 @@
class MockVSyncDispatch : public VSyncDispatch {
public:
- MOCK_METHOD2(registerCallback, CallbackToken(std::function<void(nsecs_t)> const&, std::string));
+ MOCK_METHOD2(registerCallback,
+ CallbackToken(std::function<void(nsecs_t, nsecs_t)> const&, std::string));
MOCK_METHOD1(unregisterCallback, void(CallbackToken));
MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t));
MOCK_METHOD1(cancel, CancelResult(CallbackToken token));
@@ -82,7 +83,7 @@
class VSyncDispatchWrapper : public VSyncDispatch {
public:
VSyncDispatchWrapper(std::shared_ptr<VSyncDispatch> const& dispatch) : mDispatch(dispatch) {}
- CallbackToken registerCallback(std::function<void(nsecs_t)> const& callbackFn,
+ CallbackToken registerCallback(std::function<void(nsecs_t, nsecs_t)> const& callbackFn,
std::string callbackName) final {
return mDispatch->registerCallback(callbackFn, callbackName);
}
@@ -159,14 +160,15 @@
static constexpr nsecs_t mPhase = 3000;
static constexpr nsecs_t mAnotherPhase = 5200;
static constexpr nsecs_t period = 10000;
- static constexpr nsecs_t mFakeCbTime = 2093;
+ static constexpr nsecs_t mFakeVSyncTime = 2093;
+ static constexpr nsecs_t mFakeWakeupTime = 1892;
static constexpr nsecs_t mFakeNow = 2214;
static constexpr const char mName[] = "callbacky";
VSyncDispatch::CallbackToken const mFakeToken{2398};
nsecs_t lastCallbackTime = 0;
StubCallback outerCb;
- std::function<void(nsecs_t)> innerCb;
+ std::function<void(nsecs_t, nsecs_t)> innerCb;
VSyncReactor mReactor;
};
@@ -292,6 +294,46 @@
EXPECT_TRUE(periodFlushed);
}
+TEST_F(VSyncReactorTest, changingPeriodBackAbortsConfirmationProcess) {
+ nsecs_t sampleTime = 0;
+ nsecs_t const newPeriod = 5000;
+ mReactor.setPeriod(newPeriod);
+ bool periodFlushed = true;
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+
+ mReactor.setPeriod(period);
+ EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, changingToAThirdPeriodWillWaitForLastPeriod) {
+ nsecs_t sampleTime = 0;
+ nsecs_t const secondPeriod = 5000;
+ nsecs_t const thirdPeriod = 2000;
+
+ mReactor.setPeriod(secondPeriod);
+ bool periodFlushed = true;
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ mReactor.setPeriod(thirdPeriod);
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += secondPeriod, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_FALSE(mReactor.addResyncSample(sampleTime += thirdPeriod, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, presentFenceAdditionDoesNotInterruptConfirmationProcess) {
+ nsecs_t const newPeriod = 5000;
+ mReactor.setPeriod(newPeriod);
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
TEST_F(VSyncReactorTest, setPeriodCalledFirstTwoEventsNewPeriod) {
nsecs_t const newPeriod = 5000;
EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0);
@@ -399,7 +441,8 @@
.WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
.InSequence(seq);
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeCbTime))
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
.Times(2)
.InSequence(seq);
EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
@@ -407,24 +450,25 @@
mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
ASSERT_TRUE(innerCb);
- innerCb(mFakeCbTime);
- innerCb(mFakeCbTime);
+ innerCb(mFakeVSyncTime, mFakeWakeupTime);
+ innerCb(mFakeVSyncTime, mFakeWakeupTime);
}
-TEST_F(VSyncReactorTest, callbackTimestampReadapted) {
+TEST_F(VSyncReactorTest, callbackTimestampDistributedIsWakeupTime) {
Sequence seq;
EXPECT_CALL(*mMockDispatch, registerCallback(_, _))
.InSequence(seq)
.WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
.InSequence(seq);
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeCbTime))
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
.InSequence(seq);
mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
ASSERT_TRUE(innerCb);
- innerCb(mFakeCbTime);
- EXPECT_THAT(outerCb.lastCallTime(), Optional(mFakeCbTime - period));
+ innerCb(mFakeVSyncTime, mFakeWakeupTime);
+ EXPECT_THAT(outerCb.lastCallTime(), Optional(mFakeWakeupTime));
}
TEST_F(VSyncReactorTest, eventListenersRemovedOnDestruction) {
@@ -500,7 +544,7 @@
mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
mReactor.changePhaseOffset(&outerCb, mAnotherPhase);
ASSERT_TRUE(innerCb);
- innerCb(mFakeCbTime);
+ innerCb(mFakeVSyncTime, mFakeWakeupTime);
}
TEST_F(VSyncReactorTest, negativeOffsetsApplied) {
@@ -550,7 +594,7 @@
ON_CALL(*mMockDispatch, schedule(_, _, _))
.WillByDefault(Return(ScheduleResult::CannotSchedule));
- EXPECT_DEATH(innerCb(mFakeCbTime), ".*");
+ EXPECT_DEATH(innerCb(mFakeVSyncTime, mFakeWakeupTime), ".*");
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index ec74a42..9ada5ef 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -28,6 +28,7 @@
TimeStats();
~TimeStats() override;
+ MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
MOCK_METHOD0(isEnabled, bool());
MOCK_METHOD0(miniDump, std::string());
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index 36f6b32..dd1603d 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -73,7 +73,7 @@
auto err = mVrHal.setLayerInfo(mCurrentDisplay, mCurrentLayer, read(), read());
if (err != Error::NONE) {
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
}
return true;
@@ -86,7 +86,7 @@
auto err = mVrHal.setClientTargetMetadata(mCurrentDisplay, readBufferMetadata());
if (err != Error::NONE)
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
return true;
}
@@ -99,7 +99,7 @@
auto err = mVrHal.setLayerBufferMetadata(mCurrentDisplay, mCurrentLayer,
readBufferMetadata());
if (err != Error::NONE)
- mWriter.setError(getCommandLoc(), err);
+ mWriter->setError(getCommandLoc(), err);
return true;
}