summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/atrace/atrace.rc2
-rw-r--r--cmds/dumpstate/Android.bp3
-rw-r--r--cmds/dumpstate/README.md6
-rw-r--r--cmds/dumpstate/dumpstate.cpp20
-rw-r--r--cmds/dumpstate/dumpstate.h3
-rw-r--r--cmds/dumpstate/dumpstate_test.xml29
-rw-r--r--cmds/dumpstate/tests/dumpstate_test.cpp5
-rw-r--r--cmds/dumpstate/utils.cpp5
-rw-r--r--cmds/installd/Android.bp2
-rw-r--r--cmds/installd/InstalldNativeService.cpp9
-rw-r--r--cmds/installd/OWNERS2
-rw-r--r--cmds/installd/art_helper/Android.bp12
-rw-r--r--cmds/installd/art_helper/art_image_values.cpp37
-rw-r--r--cmds/installd/art_helper/art_image_values.h34
-rw-r--r--cmds/installd/binder/android/os/IInstalld.aidl2
-rw-r--r--cmds/installd/otapreopt.cpp10
-rw-r--r--cmds/installd/otapreopt_chroot.cpp10
-rw-r--r--cmds/installd/tests/installd_dexopt_test.cpp22
-rw-r--r--cmds/lshal/Android.bp11
-rw-r--r--cmds/lshal/Command.h5
-rw-r--r--cmds/lshal/DebugCommand.cpp3
-rw-r--r--cmds/lshal/DebugCommand.h5
-rw-r--r--cmds/lshal/HelpCommand.h5
-rw-r--r--cmds/lshal/ListCommand.h5
-rw-r--r--cmds/lshal/Lshal.h5
-rw-r--r--cmds/lshal/NullableOStream.h5
-rw-r--r--cmds/lshal/PipeRelay.h7
-rw-r--r--cmds/lshal/TableEntry.h5
-rw-r--r--cmds/lshal/TextTable.h5
-rw-r--r--cmds/lshal/Timeout.h2
-rw-r--r--cmds/lshal/libprocpartition/include/procpartition/procpartition.h5
-rw-r--r--cmds/lshal/utils.h5
-rw-r--r--cmds/servicemanager/Access.cpp140
-rw-r--r--cmds/servicemanager/Access.h59
-rw-r--r--cmds/servicemanager/Android.bp54
-rw-r--r--cmds/servicemanager/ServiceManager.cpp144
-rw-r--r--cmds/servicemanager/ServiceManager.h47
-rw-r--r--cmds/servicemanager/TEST_MAPPING7
-rw-r--r--cmds/servicemanager/bctest.c107
-rw-r--r--cmds/servicemanager/binder.c682
-rw-r--r--cmds/servicemanager/binder.h94
-rw-r--r--cmds/servicemanager/main.cpp54
-rw-r--r--cmds/servicemanager/service_manager.c442
-rw-r--r--cmds/servicemanager/test_sm.cpp261
-rw-r--r--include/android/font.h2
-rw-r--r--include/android/font_matcher.h2
-rw-r--r--include/android/system_fonts.h2
-rw-r--r--libs/binder/Android.bp4
-rw-r--r--libs/binder/IPCThreadState.cpp2
-rw-r--r--libs/binder/IServiceManager.cpp58
-rw-r--r--libs/binder/aidl/android/os/IServiceManager.aidl80
-rw-r--r--libs/binder/include/binder/IPCThreadState.h2
-rw-r--r--libs/cputimeinstate/cputimeinstate.cpp69
-rw-r--r--libs/cputimeinstate/cputimeinstate.h5
-rw-r--r--libs/cputimeinstate/testtimeinstate.cpp37
-rw-r--r--libs/dumputils/dump_utils.cpp1
-rw-r--r--libs/graphicsenv/GraphicsEnv.cpp26
-rw-r--r--libs/gui/BufferQueueCore.cpp12
-rw-r--r--libs/gui/BufferQueueProducer.cpp35
-rw-r--r--libs/gui/DisplayEventReceiver.cpp5
-rw-r--r--libs/gui/IGraphicBufferProducer.cpp39
-rw-r--r--libs/gui/ISurfaceComposer.cpp12
-rw-r--r--libs/gui/Surface.cpp45
-rw-r--r--libs/gui/SurfaceComposerClient.cpp109
-rw-r--r--libs/gui/SurfaceControl.cpp11
-rw-r--r--libs/gui/include/gui/BufferQueueCore.h8
-rw-r--r--libs/gui/include/gui/BufferQueueProducer.h3
-rw-r--r--libs/gui/include/gui/DisplayEventReceiver.h5
-rw-r--r--libs/gui/include/gui/IGraphicBufferProducer.h9
-rw-r--r--libs/gui/include/gui/ISurfaceComposer.h5
-rw-r--r--libs/gui/include/gui/Surface.h7
-rw-r--r--libs/gui/include/gui/SurfaceComposerClient.h11
-rw-r--r--libs/gui/include/gui/SurfaceControl.h4
-rw-r--r--libs/gui/tests/BufferQueue_test.cpp12
-rw-r--r--libs/gui/tests/Surface_test.cpp74
-rw-r--r--libs/input/Keyboard.cpp18
-rw-r--r--libs/nativewindow/ANativeWindow.cpp4
-rw-r--r--libs/nativewindow/include/system/window.h83
-rw-r--r--libs/nativewindow/include/vndk/window.h9
-rw-r--r--libs/nativewindow/libnativewindow.map.txt1
-rw-r--r--libs/renderengine/gl/GLESRenderEngine.cpp40
-rw-r--r--libs/renderengine/gl/GLESRenderEngine.h61
-rw-r--r--libs/renderengine/include/renderengine/RenderEngine.h56
-rw-r--r--libs/renderengine/include/renderengine/mock/RenderEngine.h24
-rw-r--r--libs/sensor/SensorManager.cpp2
-rw-r--r--libs/ui/BufferHubBuffer.cpp1
-rw-r--r--libs/ui/GraphicBuffer.cpp2
-rw-r--r--libs/ui/tests/Android.bp18
-rw-r--r--libs/ui/tests/GraphicBufferOverBinder_test.cpp170
-rw-r--r--services/bufferhub/Android.bp1
-rw-r--r--services/gpuservice/OWNERS3
-rw-r--r--services/inputflinger/InputClassifier.cpp2
-rw-r--r--services/surfaceflinger/Android.bp5
-rw-r--r--services/surfaceflinger/BufferLayer.cpp14
-rw-r--r--services/surfaceflinger/BufferLayerConsumer.cpp24
-rw-r--r--services/surfaceflinger/BufferLayerConsumer.h5
-rw-r--r--services/surfaceflinger/BufferQueueLayer.cpp4
-rw-r--r--services/surfaceflinger/Client.cpp7
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h4
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp7
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp14
-rw-r--r--services/surfaceflinger/DisplayHardware/ComposerHal.cpp2
-rw-r--r--services/surfaceflinger/Layer.cpp50
-rw-r--r--services/surfaceflinger/Layer.h2
-rw-r--r--services/surfaceflinger/MonitoredProducer.cpp4
-rw-r--r--services/surfaceflinger/MonitoredProducer.h1
-rw-r--r--services/surfaceflinger/RegionSamplingThread.cpp26
-rw-r--r--services/surfaceflinger/RegionSamplingThread.h4
-rw-r--r--services/surfaceflinger/Scheduler/DispSync.cpp35
-rw-r--r--services/surfaceflinger/Scheduler/DispSyncSource.cpp46
-rw-r--r--services/surfaceflinger/Scheduler/DispSyncSource.h10
-rw-r--r--services/surfaceflinger/Scheduler/EventThread.cpp18
-rw-r--r--services/surfaceflinger/Scheduler/EventThread.h10
-rw-r--r--services/surfaceflinger/Scheduler/LayerHistory.cpp17
-rw-r--r--services/surfaceflinger/Scheduler/LayerHistory.h6
-rw-r--r--services/surfaceflinger/Scheduler/LayerInfo.cpp11
-rw-r--r--services/surfaceflinger/Scheduler/LayerInfo.h49
-rw-r--r--services/surfaceflinger/Scheduler/MessageQueue.cpp3
-rw-r--r--services/surfaceflinger/Scheduler/OneShotTimer.cpp (renamed from services/surfaceflinger/Scheduler/IdleTimer.cpp)18
-rw-r--r--services/surfaceflinger/Scheduler/OneShotTimer.h (renamed from services/surfaceflinger/Scheduler/IdleTimer.h)8
-rw-r--r--services/surfaceflinger/Scheduler/PhaseOffsets.cpp53
-rw-r--r--services/surfaceflinger/Scheduler/PhaseOffsets.h7
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.cpp68
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.h23
-rw-r--r--services/surfaceflinger/Scheduler/SchedulerUtils.h15
-rw-r--r--services/surfaceflinger/Scheduler/VSyncModulator.cpp177
-rw-r--r--services/surfaceflinger/Scheduler/VSyncModulator.h158
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp96
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h11
-rw-r--r--services/surfaceflinger/SurfaceFlingerProperties.cpp8
-rw-r--r--services/surfaceflinger/SurfaceTracing.h2
-rw-r--r--services/surfaceflinger/layerproto/Android.bp2
-rw-r--r--services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop54
-rw-r--r--services/surfaceflinger/test.pngbin0 -> 3058273 bytes
-rw-r--r--services/surfaceflinger/tests/unittests/Android.bp2
-rw-r--r--services/surfaceflinger/tests/unittests/CompositionTest.cpp5
-rw-r--r--services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp4
-rw-r--r--services/surfaceflinger/tests/unittests/EventThreadTest.cpp44
-rw-r--r--services/surfaceflinger/tests/unittests/FakePhaseOffsets.h14
-rw-r--r--services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp17
-rw-r--r--services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp (renamed from services/surfaceflinger/tests/unittests/IdleTimerTest.cpp)65
-rw-r--r--services/surfaceflinger/tests/unittests/SchedulerTest.cpp22
-rw-r--r--services/surfaceflinger/tests/unittests/TestableScheduler.h4
-rw-r--r--services/surfaceflinger/tests/unittests/mock/MockEventThread.h3
-rw-r--r--services/vr/hardware_composer/Android.bp1
-rw-r--r--vulkan/api/templates/asciidoc.tmpl151
-rw-r--r--vulkan/api/templates/vk_xml.tmpl435
-rw-r--r--vulkan/api/templates/vulkan_h.tmpl295
-rw-r--r--vulkan/libvulkan/driver.cpp40
-rw-r--r--vulkan/libvulkan/swapchain.cpp24
152 files changed, 2465 insertions, 3309 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 032d0726e0..f1426b6bd0 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -47,6 +47,8 @@ on late-init
chmod 0666 /sys/kernel/tracing/events/power/clock_set_rate/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable
+ chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable
chmod 0666 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
chmod 0666 /sys/kernel/tracing/events/cpufreq_interactive/enable
chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index ee32cb4495..4020480479 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -123,7 +123,6 @@ cc_binary {
"lsmod",
"lsof",
"netstat",
- "parse_radio_log",
"printenv",
"procrank",
"screencap",
@@ -146,6 +145,8 @@ cc_test {
"tests/dumpstate_test.cpp",
],
static_libs: ["libgmock"],
+ test_config: "dumpstate_test.xml",
+ data: [":dumpstate_test_fixture", "tests/testdata/**/*"]
}
cc_test {
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index c818c05117..26dabbbcef 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -92,6 +92,12 @@ Then to restore the default version:
adb shell setprop dumpstate.version default
```
+## To set Bugreport API workflow for bugreport
+
+```
+adb shell setprop settings_call_bugreport_api true
+```
+
## Code style and formatting
Use the style defined at the
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8ba95266b6..cc745708c8 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1316,8 +1316,6 @@ static Dumpstate::RunStatus dumpstate() {
RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
- RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"});
-
/* Binder state is expensive to look at as it uses a lot of memory. */
DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
@@ -1796,22 +1794,21 @@ void Dumpstate::DumpstateBoard() {
static void ShowUsage() {
fprintf(stderr,
- "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
+ "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
"[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
" -h: display this help message\n"
" -b: play sound file instead of vibrate, at beginning of job\n"
" -e: play sound file instead of vibrate, at end of job\n"
- " -o: write to file (instead of stdout)\n"
- " -d: append date to filename (requires -o)\n"
- " -p: capture screenshot to filename.png (requires -o)\n"
- " -z: generate zipped file (requires -o)\n"
+ " -d: append date to filename\n"
+ " -p: capture screenshot to filename.png\n"
+ " -z: generate zipped file\n"
" -s: write output to control socket (for init)\n"
- " -S: write file location to control socket (for init; requires -o and -z)\n"
+ " -S: write file location to control socket (for init; requires -z)\n"
" -q: disable vibrate\n"
- " -B: send broadcast when finished (requires -o)\n"
+ " -B: send broadcast when finished\n"
" -P: send broadcast when started and update system properties on "
- "progress (requires -o and -B)\n"
- " -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
+ "progress (requires -B)\n"
+ " -R: take bugreport in remote mode (requires -z, -d and -B, "
"shouldn't be used with -P)\n"
" -w: start binder service and make it wait for a call to startBugreport\n"
" -v: prints the dumpstate header and exit\n");
@@ -2295,7 +2292,6 @@ Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[])
}
}
- // TODO: use helper function to convert argv into a string
for (int i = 0; i < argc; i++) {
args += argv[i];
if (i < argc - 1) {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index d02ec759a7..ae6a72171a 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -441,8 +441,7 @@ class Dumpstate {
// Full path of the bugreport file, be it zip or text, inside bugreport_internal_dir_.
std::string path_;
- // TODO: If temporary this should be removed at the end.
- // Full path of the temporary file containing the screenshot (when requested).
+ // Full path of the file containing the screenshot (when requested).
std::string screenshot_path_;
// Pointer to the zipped file.
diff --git a/cmds/dumpstate/dumpstate_test.xml b/cmds/dumpstate/dumpstate_test.xml
new file mode 100644
index 0000000000..e4e4a30a1e
--- /dev/null
+++ b/cmds/dumpstate/dumpstate_test.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for dumpstate_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="dumpstate_test->/data/local/tmp/dumpstate_test" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="file-exclusion-filter-regex" value=".*/dumpstate_test_fixture" />
+ <option name="file-exclusion-filter-regex" value=".*/tests/.*" />
+ <option name="module-name" value="dumpstate_test" />
+ </test>
+</configuration>
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index c5d01fdf25..0e88e43258 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -105,9 +105,8 @@ class DumpstateBaseTest : public Test {
protected:
const std::string kTestPath = dirname(android::base::GetExecutablePath().c_str());
- const std::string kFixturesPath = kTestPath + "/../dumpstate_test_fixture/";
- const std::string kTestDataPath = kFixturesPath + "tests/testdata/";
- const std::string kSimpleCommand = kFixturesPath + "dumpstate_test_fixture";
+ const std::string kTestDataPath = kTestPath + "/tests/testdata/";
+ const std::string kSimpleCommand = kTestPath + "/dumpstate_test_fixture";
const std::string kEchoCommand = "/system/bin/echo";
/*
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 0bb80dcfba..4cbf5776d3 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -733,6 +733,11 @@ int open_socket(const char *service) {
struct sockaddr addr;
socklen_t alen = sizeof(addr);
int fd = accept(s, &addr, &alen);
+
+ // Close socket just after accept(), to make sure that connect() by client will get error
+ // when the socket is used by the other services.
+ close(s);
+
if (fd < 0) {
MYLOGE("accept(control socket): %s\n", strerror(errno));
return -1;
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 654213f5e0..064a268d2e 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -151,6 +151,7 @@ cc_binary {
shared_libs: [
"libbase",
"libbinder",
+ "libcrypto",
"liblog",
"libprotobuf-cpp-full",
"libselinux",
@@ -163,6 +164,7 @@ cc_binary {
"lib_apex_manifest_proto",
"libavb",
"libdm",
+ "libverity_tree",
"libvold_binder",
],
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index caac2e89a7..dd51898422 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -2107,10 +2107,15 @@ binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t
CHECK_ARGUMENT_PATH(dexMetadataPath);
std::lock_guard<std::recursive_mutex> lock(mLock);
+ const char* oat_dir = getCStr(outputPath);
+ const char* instruction_set = instructionSet.c_str();
+ if (oat_dir != nullptr && !createOatDir(oat_dir, instruction_set).isOk()) {
+ // Can't create oat dir - let dexopt use cache dir.
+ oat_dir = nullptr;
+ }
+
const char* apk_path = apkPath.c_str();
const char* pkgname = getCStr(packageName, "*");
- const char* instruction_set = instructionSet.c_str();
- const char* oat_dir = getCStr(outputPath);
const char* compiler_filter = compilerFilter.c_str();
const char* volume_uuid = getCStr(uuid);
const char* class_loader_context = getCStr(classLoaderContext);
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
index 56739181bb..9a21104131 100644
--- a/cmds/installd/OWNERS
+++ b/cmds/installd/OWNERS
@@ -4,7 +4,9 @@ agampe@google.com
calin@google.com
jsharkey@android.com
maco@google.com
+mast@google.com
mathieuc@google.com
narayan@google.com
ngeoffray@google.com
+rpl@google.com
toddke@google.com
diff --git a/cmds/installd/art_helper/Android.bp b/cmds/installd/art_helper/Android.bp
deleted file mode 100644
index c47dd722f9..0000000000
--- a/cmds/installd/art_helper/Android.bp
+++ /dev/null
@@ -1,12 +0,0 @@
-// Inherit image values.
-art_global_defaults {
- name: "libartimagevalues_defaults",
-}
-
-cc_library_static {
- name: "libartimagevalues",
- defaults: ["libartimagevalues_defaults"],
- srcs: ["art_image_values.cpp"],
- export_include_dirs: ["."],
- cflags: ["-Wconversion"],
-}
diff --git a/cmds/installd/art_helper/art_image_values.cpp b/cmds/installd/art_helper/art_image_values.cpp
deleted file mode 100644
index a139049d9f..0000000000
--- a/cmds/installd/art_helper/art_image_values.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 "art_image_values.h"
-
-namespace android {
-namespace installd {
-namespace art {
-
-uint32_t GetImageBaseAddress() {
- return ART_BASE_ADDRESS;
-}
-int32_t GetImageMinBaseAddressDelta() {
- return ART_BASE_ADDRESS_MIN_DELTA;
-}
-int32_t GetImageMaxBaseAddressDelta() {
- return ART_BASE_ADDRESS_MAX_DELTA;
-}
-
-static_assert(ART_BASE_ADDRESS_MIN_DELTA < ART_BASE_ADDRESS_MAX_DELTA, "Inconsistent setup");
-
-} // namespace art
-} // namespace installd
-} // namespace android
diff --git a/cmds/installd/art_helper/art_image_values.h b/cmds/installd/art_helper/art_image_values.h
deleted file mode 100644
index 20c44c953f..0000000000
--- a/cmds/installd/art_helper/art_image_values.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H
-#define FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H
-
-#include <cstdint>
-
-namespace android {
-namespace installd {
-namespace art {
-
-uint32_t GetImageBaseAddress();
-int32_t GetImageMinBaseAddressDelta();
-int32_t GetImageMaxBaseAddressDelta();
-
-} // namespace art
-} // namespace installd
-} // namespace android
-
-#endif // FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 26e9984f11..d99bcc8d13 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -127,4 +127,6 @@ interface IInstalld {
const int FLAG_USE_QUOTA = 0x1000;
const int FLAG_FORCE = 0x2000;
+
+ const int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES = 0x20000;
}
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index de7b2499b8..db36ce3c9e 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -445,9 +445,11 @@ private:
}
cmd.push_back(StringPrintf("--oat-file=%s", oat_path.c_str()));
- int32_t base_offset = ChooseRelocationOffsetDelta(art::GetImageMinBaseAddressDelta(),
- art::GetImageMaxBaseAddressDelta());
- cmd.push_back(StringPrintf("--base=0x%x", art::GetImageBaseAddress() + base_offset));
+ int32_t base_offset = ChooseRelocationOffsetDelta(
+ art::imagevalues::GetImageMinBaseAddressDelta(),
+ art::imagevalues::GetImageMaxBaseAddressDelta());
+ cmd.push_back(StringPrintf("--base=0x%x",
+ art::imagevalues::GetImageBaseAddress() + base_offset));
cmd.push_back(StringPrintf("--instruction-set=%s", isa));
@@ -464,7 +466,7 @@ private:
"--compiler-filter=",
false,
cmd);
- cmd.push_back("--image-classes=/system/etc/preloaded-classes");
+ cmd.push_back("--profile-file=/system/etc/boot-image.prof");
// TODO: Compiled-classes.
const std::string* extra_opts =
system_properties_.GetProperty("dalvik.vm.image-dex2oat-flags");
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 2e2cc182ec..0c4badf489 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -64,16 +64,18 @@ static std::vector<apex::ApexFile> ActivateApexPackages() {
// system/apex/apexd/apexd_main.cpp.
//
// Only scan the APEX directory under /system (within the chroot dir).
- apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir);
+ // Cast call to void to suppress warn_unused_result.
+ static_cast<void>(apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir));
return apex::getActivePackages();
}
static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) {
for (const apex::ApexFile& apex_file : active_packages) {
const std::string& package_path = apex_file.GetPath();
- apex::Status status = apex::deactivatePackage(package_path);
- if (!status.Ok()) {
- LOG(ERROR) << "Failed to deactivate " << package_path << ": " << status.ErrorMessage();
+ base::Result<void> status = apex::deactivatePackage(package_path);
+ if (!status) {
+ LOG(ERROR) << "Failed to deactivate " << package_path << ": "
+ << status.error();
}
}
}
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 13fd0677e5..73780eccbf 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -241,18 +241,14 @@ protected:
}
::testing::AssertionResult create_mock_app() {
- // Create the oat dir.
- app_oat_dir_ = app_apk_dir_ + "/oat";
// For debug mode, the directory might already exist. Avoid erroring out.
if (mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755) != 0 && !kDebug) {
return ::testing::AssertionFailure() << "Could not create app dir " << app_apk_dir_
<< " : " << strerror(errno);
}
- binder::Status status = service_->createOatDir(app_oat_dir_, kRuntimeIsa);
- if (!status.isOk()) {
- return ::testing::AssertionFailure() << "Could not create oat dir: "
- << status.toString8().c_str();
- }
+
+ // Initialize the oat dir path.
+ app_oat_dir_ = app_apk_dir_ + "/oat";
// Copy the primary apk.
apk_path_ = app_apk_dir_ + "/base.jar";
@@ -283,7 +279,7 @@ protected:
}
// Create the app user data.
- status = service_->createAppData(
+ binder::Status status = service_->createAppData(
volume_uuid_,
package_name_,
kTestUserId,
@@ -647,6 +643,16 @@ TEST_F(DexoptTest, DexoptPrimaryPublic) {
DEX2OAT_FROM_SCRATCH);
}
+TEST_F(DexoptTest, DexoptPrimaryPublicCreateOatDir) {
+ LOG(INFO) << "DexoptPrimaryPublic";
+ ASSERT_BINDER_SUCCESS(service_->createOatDir(app_oat_dir_, kRuntimeIsa));
+ CompilePrimaryDexOk("verify",
+ DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
+ app_oat_dir_.c_str(),
+ kTestAppGid,
+ DEX2OAT_FROM_SCRATCH);
+}
+
TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) {
LOG(INFO) << "DexoptPrimaryFailedInvalidFilter";
binder::Status status;
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 93d878b607..f7dd8c82c3 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-cc_library_shared {
+cc_library_static {
name: "liblshal",
shared_libs: [
"libbase",
@@ -47,13 +47,16 @@ cc_defaults {
name: "lshal_defaults",
shared_libs: [
"libbase",
+ "libcutils",
+ "libutils",
"libhidlbase",
- "libhidl-gen-utils",
"libhidltransport",
- "liblshal",
- "libutils",
+ "libhidl-gen-hash",
+ "libhidl-gen-utils",
+ "libvintf",
],
static_libs: [
+ "liblshal",
"libprocpartition",
],
cflags: ["-Wall", "-Werror"],
diff --git a/cmds/lshal/Command.h b/cmds/lshal/Command.h
index e19e3f7fc2..84809d9a5d 100644
--- a/cmds/lshal/Command.h
+++ b/cmds/lshal/Command.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_COMMAND_H_
-#define FRAMEWORK_NATIVE_CMDS_LSHAL_COMMAND_H_
+#pragma once
#include "utils.h"
@@ -48,5 +47,3 @@ protected:
} // namespace lshal
} // namespace android
-
-#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
index 0952db6e72..af22ac9b3d 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -79,7 +79,7 @@ void DebugCommand::usage() const {
" lshal debug [-E] <interface> [options [options [...]]] \n"
" Print debug information of a specified interface.\n"
" -E: excludes debug output if HAL is actually a subclass.\n"
- " <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
+ " <interface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
" If instance name is missing `default` is used.\n"
" options: space separated options to IBase::debug.\n";
@@ -88,4 +88,3 @@ void DebugCommand::usage() const {
} // namespace lshal
} // namespace android
-
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
index 3c3f56fde5..cd57e31bfc 100644
--- a/cmds/lshal/DebugCommand.h
+++ b/cmds/lshal/DebugCommand.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
-#define FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
+#pragma once
#include <string>
@@ -53,5 +52,3 @@ private:
} // namespace lshal
} // namespace android
-
-#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
diff --git a/cmds/lshal/HelpCommand.h b/cmds/lshal/HelpCommand.h
index da0cba6f42..bfa850075d 100644
--- a/cmds/lshal/HelpCommand.h
+++ b/cmds/lshal/HelpCommand.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_
-#define FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_
+#pragma once
#include <string>
@@ -44,5 +43,3 @@ public:
} // namespace lshal
} // namespace android
-
-#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 85195fcc54..b3ed23d1fc 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
-#define FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
+#pragma once
#include <getopt.h>
#include <stdint.h>
@@ -206,5 +205,3 @@ private:
} // namespace lshal
} // namespace android
-
-#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
index 9457f1e563..2679650611 100644
--- a/cmds/lshal/Lshal.h
+++ b/cmds/lshal/Lshal.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
-#define FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
+#pragma once
#include <iostream>
#include <string>
@@ -76,5 +75,3 @@ private:
} // namespace lshal
} // namespace android
-
-#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
diff --git a/cmds/lshal/NullableOStream.h b/cmds/lshal/NullableOStream.h
index 737d3a2963..7cffcf8193 100644
--- a/cmds/lshal/NullableOStream.h
+++ b/cmds/lshal/NullableOStream.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_
-#define FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_
+#pragma once
#include <iostream>
@@ -69,5 +68,3 @@ private:
} // namespace lshal
} // namespace android
-
-#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
index 8dc3093742..8350160419 100644
--- a/cmds/lshal/PipeRelay.h
+++ b/cmds/lshal/PipeRelay.h
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-#ifndef FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
-
-#define FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+#pragma once
#include <android-base/macros.h>
#include <ostream>
@@ -53,6 +51,3 @@ private:
} // namespace lshal
} // namespace android
-
-#endif // FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
-
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 601b7e25f9..0ff0c96d38 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
-#define FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
+#pragma once
#include <stdint.h>
@@ -157,5 +156,3 @@ private:
} // namespace lshal
} // namespace android
-
-#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
diff --git a/cmds/lshal/TextTable.h b/cmds/lshal/TextTable.h
index 301b4bd969..be41a08251 100644
--- a/cmds/lshal/TextTable.h
+++ b/cmds/lshal/TextTable.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_
-#define FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_
+#pragma once
#include <iostream>
#include <string>
@@ -80,5 +79,3 @@ private:
} // namespace lshal
} // namespace android
-
-#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index 46d817759d..e8d22d9b58 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#pragma once
+
#include <condition_variable>
#include <chrono>
#include <functional>
diff --git a/cmds/lshal/libprocpartition/include/procpartition/procpartition.h b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h
index 7e864327af..ca1e690694 100644
--- a/cmds/lshal/libprocpartition/include/procpartition/procpartition.h
+++ b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
-#define FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
+#pragma once
#include <sys/types.h>
@@ -44,5 +43,3 @@ Partition getPartition(pid_t pid);
} // namespace procpartition
} // namespace android
-
-#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h
index 240155e4d0..04f52726e3 100644
--- a/cmds/lshal/utils.h
+++ b/cmds/lshal/utils.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_
-#define FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_
+#pragma once
#include <iomanip>
#include <iostream>
@@ -88,5 +87,3 @@ void replaceAll(std::string *s, char from, char to);
} // namespace lshal
} // namespace android
-
-#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
new file mode 100644
index 0000000000..f4005c4dee
--- /dev/null
+++ b/cmds/servicemanager/Access.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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 "Access.h"
+
+#include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
+#include <log/log_safetynet.h>
+#include <selinux/android.h>
+#include <selinux/avc.h>
+
+namespace android {
+
+#ifdef VENDORSERVICEMANAGER
+constexpr bool kIsVendor = true;
+#else
+constexpr bool kIsVendor = false;
+#endif
+
+static std::string getPidcon(pid_t pid) {
+ android_errorWriteLog(0x534e4554, "121035042");
+
+ char* lookup = nullptr;
+ if (getpidcon(pid, &lookup) < 0) {
+ LOG(ERROR) << "SELinux: getpidcon(pid=" << pid << ") failed to retrieve pid context";
+ return "";
+ }
+ std::string result = lookup;
+ freecon(lookup);
+ return result;
+}
+
+static struct selabel_handle* getSehandle() {
+ static struct selabel_handle* gSehandle = nullptr;
+
+ if (gSehandle != nullptr && selinux_status_updated()) {
+ selabel_close(gSehandle);
+ gSehandle = nullptr;
+ }
+
+ if (gSehandle == nullptr) {
+ gSehandle = kIsVendor
+ ? selinux_android_vendor_service_context_handle()
+ : selinux_android_service_context_handle();
+ }
+
+ CHECK(gSehandle != nullptr);
+ return gSehandle;
+}
+
+static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
+ const Access::CallingContext* ad = reinterpret_cast<Access::CallingContext*>(data);
+
+ if (!ad) {
+ LOG(ERROR) << "No service manager audit data";
+ return 0;
+ }
+
+ snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name.c_str(), ad->debugPid, ad->uid);
+ return 0;
+}
+
+Access::Access() {
+ union selinux_callback cb;
+
+ cb.func_audit = auditCallback;
+ selinux_set_callback(SELINUX_CB_AUDIT, cb);
+
+ cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback;
+ selinux_set_callback(SELINUX_CB_LOG, cb);
+
+ CHECK(selinux_status_open(true /*fallback*/) >= 0);
+
+ CHECK(getcon(&mThisProcessContext) == 0);
+}
+
+Access::~Access() {
+ freecon(mThisProcessContext);
+}
+
+Access::CallingContext Access::getCallingContext(const std::string& name) {
+ IPCThreadState* ipc = IPCThreadState::self();
+
+ const char* callingSid = ipc->getCallingSid();
+ pid_t callingPid = ipc->getCallingPid();
+
+ return CallingContext {
+ .debugPid = callingPid,
+ .uid = ipc->getCallingUid(),
+ .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid),
+ .name = name,
+ };
+}
+
+bool Access::canFind(const CallingContext& ctx) {
+ return actionAllowedFromLookup(ctx, "find");
+}
+
+bool Access::canAdd(const CallingContext& ctx) {
+ return actionAllowedFromLookup(ctx, "add");
+}
+
+bool Access::canList(const CallingContext& ctx) {
+ CHECK(ctx.name == "");
+
+ return actionAllowed(ctx, mThisProcessContext, "list");
+}
+
+bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm) {
+ const char* tclass = "service_manager";
+
+ return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, reinterpret_cast<void*>(const_cast<CallingContext*>((&sctx))));
+}
+
+bool Access::actionAllowedFromLookup(const CallingContext& sctx, const char *perm) {
+ char *tctx = nullptr;
+ if (selabel_lookup(getSehandle(), &tctx, sctx.name.c_str(), 0) != 0) {
+ LOG(ERROR) << "SELinux: No match for " << sctx.name << " in service_contexts.\n";
+ return false;
+ }
+
+ bool allowed = actionAllowed(sctx, tctx, perm);
+ freecon(tctx);
+ return allowed;
+}
+
+} // android
diff --git a/cmds/servicemanager/Access.h b/cmds/servicemanager/Access.h
new file mode 100644
index 0000000000..b2c78cc34d
--- /dev/null
+++ b/cmds/servicemanager/Access.h
@@ -0,0 +1,59 @@
+/*
+ * 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 <string>
+#include <sys/types.h>
+
+namespace android {
+
+// singleton
+class Access {
+public:
+ Access();
+ virtual ~Access();
+
+ Access(const Access&) = delete;
+ Access& operator=(const Access&) = delete;
+ Access(Access&&) = delete;
+ Access& operator=(Access&&) = delete;
+
+ struct CallingContext {
+ pid_t debugPid;
+ uid_t uid;
+ std::string sid;
+
+ // name of the service
+ //
+ // empty if call is unrelated to service (e.g. list)
+ std::string name;
+ };
+
+ virtual CallingContext getCallingContext(const std::string& name);
+
+ virtual bool canFind(const CallingContext& ctx);
+ virtual bool canAdd(const CallingContext& ctx);
+ virtual bool canList(const CallingContext& ctx);
+
+private:
+ bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm);
+ bool actionAllowedFromLookup(const CallingContext& sctx, const char *perm);
+
+ char* mThisProcessContext = nullptr;
+};
+
+};
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 428561bc8a..9cf3c5c134 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -1,51 +1,51 @@
cc_defaults {
- name: "servicemanager_flags",
+ name: "servicemanager_defaults",
cflags: [
"-Wall",
"-Wextra",
"-Werror",
],
- product_variables: {
- binder32bit: {
- cflags: ["-DBINDER_IPC_32BIT=1"],
- },
- },
- shared_libs: ["liblog"],
-}
-
-cc_binary {
- name: "bctest",
- defaults: ["servicemanager_flags"],
srcs: [
- "bctest.c",
- "binder.c",
+ "Access.cpp",
+ "ServiceManager.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libbinder", // also contains servicemanager_interface
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libselinux",
],
}
cc_binary {
name: "servicemanager",
- defaults: ["servicemanager_flags"],
- srcs: [
- "service_manager.c",
- "binder.c",
- ],
- shared_libs: ["libcutils", "libselinux"],
+ defaults: ["servicemanager_defaults"],
init_rc: ["servicemanager.rc"],
+ srcs: ["main.cpp"],
}
cc_binary {
name: "vndservicemanager",
- defaults: ["servicemanager_flags"],
+ defaults: ["servicemanager_defaults"],
+ init_rc: ["vndservicemanager.rc"],
vendor: true,
- srcs: [
- "service_manager.c",
- "binder.c",
- ],
cflags: [
"-DVENDORSERVICEMANAGER=1",
],
- shared_libs: ["libcutils", "libselinux"],
- init_rc: ["vndservicemanager.rc"],
+ srcs: ["main.cpp"],
+}
+
+cc_test {
+ name: "servicemanager_test",
+ test_suites: ["device-tests"],
+ defaults: ["servicemanager_defaults"],
+ srcs: [
+ "test_sm.cpp",
+ ],
+ static_libs: ["libgmock"],
}
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
new file mode 100644
index 0000000000..b88b67d138
--- /dev/null
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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 "ServiceManager.h"
+
+#include <android-base/logging.h>
+#include <cutils/android_filesystem_config.h>
+#include <cutils/multiuser.h>
+
+using ::android::binder::Status;
+
+namespace android {
+
+ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {}
+
+Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) {
+ // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons.
+ return checkService(name, outBinder);
+}
+
+Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) {
+ auto ctx = mAccess->getCallingContext(name);
+
+ auto it = mNameToService.find(name);
+ if (it == mNameToService.end()) {
+ *outBinder = nullptr;
+ return Status::ok();
+ }
+
+ const Service& service = it->second;
+
+ if (!service.allowIsolated) {
+ uid_t appid = multiuser_get_app_id(ctx.uid);
+ bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END;
+
+ if (isIsolated) {
+ *outBinder = nullptr;
+ return Status::ok();
+ }
+ }
+
+ // TODO(b/136023468): move this check to be first
+ if (!mAccess->canFind(ctx)) {
+ // returns ok and null for legacy reasons
+ *outBinder = nullptr;
+ return Status::ok();
+ }
+
+ *outBinder = service.binder;
+ return Status::ok();
+}
+
+Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
+ auto ctx = mAccess->getCallingContext(name);
+
+ // apps cannot add services
+ if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ if (!mAccess->canAdd(ctx)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ if (binder == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ }
+
+ // match legacy rules
+ if (name.size() == 0 || name.size() > 127) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (OK != binder->linkToDeath(this)) {
+ LOG(ERROR) << "Could not linkToDeath when adding " << name;
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+
+ auto it = mNameToService.find(name);
+ if (it != mNameToService.end()) {
+ if (OK != it->second.binder->unlinkToDeath(this)) {
+ LOG(WARNING) << "Could not unlinkToDeath when adding " << name;
+ }
+ }
+
+ mNameToService[name] = Service {
+ .binder = binder,
+ .allowIsolated = allowIsolated,
+ .dumpPriority = dumpPriority,
+ };
+
+ return Status::ok();
+}
+
+Status ServiceManager::listServices(int32_t dumpPriority, std::vector<std::string>* outList) {
+ if (!mAccess->canList(mAccess->getCallingContext(""))) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ size_t toReserve = 0;
+ for (auto const& [name, service] : mNameToService) {
+ (void) name;
+
+ if (service.dumpPriority & dumpPriority) ++toReserve;
+ }
+
+ CHECK(outList->empty());
+
+ outList->reserve(toReserve);
+ for (auto const& [name, service] : mNameToService) {
+ (void) service;
+
+ if (service.dumpPriority & dumpPriority) {
+ outList->push_back(name);
+ }
+ }
+
+ return Status::ok();
+}
+
+void ServiceManager::binderDied(const wp<IBinder>& who) {
+ for (auto it = mNameToService.begin(); it != mNameToService.end();) {
+ if (who == it->second.binder) {
+ it = mNameToService.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+} // namespace android
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
new file mode 100644
index 0000000000..78e48052b8
--- /dev/null
+++ b/cmds/servicemanager/ServiceManager.h
@@ -0,0 +1,47 @@
+/*
+ * 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/os/BnServiceManager.h>
+
+#include "Access.h"
+
+namespace android {
+
+class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
+public:
+ ServiceManager(std::unique_ptr<Access>&& access);
+
+ binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override;
+ binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override;
+ binder::Status addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) override;
+ binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override;
+
+ void binderDied(const wp<IBinder>& who) override;
+
+private:
+ struct Service {
+ sp<IBinder> binder;
+ bool allowIsolated;
+ int32_t dumpPriority;
+ };
+
+ std::map<std::string, Service> mNameToService;
+ std::unique_ptr<Access> mAccess;
+};
+
+} // namespace android
diff --git a/cmds/servicemanager/TEST_MAPPING b/cmds/servicemanager/TEST_MAPPING
new file mode 100644
index 0000000000..3e47269fe0
--- /dev/null
+++ b/cmds/servicemanager/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "servicemanager_test"
+ }
+ ]
+}
diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c
deleted file mode 100644
index 354df670e5..0000000000
--- a/cmds/servicemanager/bctest.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* Copyright 2008 The Android Open Source Project
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include "binder.h"
-
-uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name)
-{
- uint32_t handle;
- unsigned iodata[512/4];
- struct binder_io msg, reply;
-
- bio_init(&msg, iodata, sizeof(iodata), 4);
- bio_put_uint32(&msg, 0); // strict mode header
- bio_put_string16_x(&msg, SVC_MGR_NAME);
- bio_put_string16_x(&msg, name);
-
- if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))
- return 0;
-
- handle = bio_get_ref(&reply);
-
- if (handle)
- binder_acquire(bs, handle);
-
- binder_done(bs, &msg, &reply);
-
- return handle;
-}
-
-int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr)
-{
- int status;
- unsigned iodata[512/4];
- struct binder_io msg, reply;
-
- bio_init(&msg, iodata, sizeof(iodata), 4);
- bio_put_uint32(&msg, 0); // strict mode header
- bio_put_string16_x(&msg, SVC_MGR_NAME);
- bio_put_string16_x(&msg, name);
- bio_put_obj(&msg, ptr);
-
- if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
- return -1;
-
- status = bio_get_uint32(&reply);
-
- binder_done(bs, &msg, &reply);
-
- return status;
-}
-
-unsigned token;
-
-int main(int argc, char **argv)
-{
- struct binder_state *bs;
- uint32_t svcmgr = BINDER_SERVICE_MANAGER;
- uint32_t handle;
-
- bs = binder_open("/dev/binder", 128*1024);
- if (!bs) {
- fprintf(stderr, "failed to open binder driver\n");
- return -1;
- }
-
- argc--;
- argv++;
- while (argc > 0) {
- if (!strcmp(argv[0],"alt")) {
- handle = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr");
- if (!handle) {
- fprintf(stderr,"cannot find alt_svc_mgr\n");
- return -1;
- }
- svcmgr = handle;
- fprintf(stderr,"svcmgr is via %x\n", handle);
- } else if (!strcmp(argv[0],"lookup")) {
- if (argc < 2) {
- fprintf(stderr,"argument required\n");
- return -1;
- }
- handle = svcmgr_lookup(bs, svcmgr, argv[1]);
- fprintf(stderr,"lookup(%s) = %x\n", argv[1], handle);
- argc--;
- argv++;
- } else if (!strcmp(argv[0],"publish")) {
- if (argc < 2) {
- fprintf(stderr,"argument required\n");
- return -1;
- }
- svcmgr_publish(bs, svcmgr, argv[1], &token);
- argc--;
- argv++;
- } else {
- fprintf(stderr,"unknown command %s\n", argv[0]);
- return -1;
- }
- argc--;
- argv++;
- }
- return 0;
-}
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
deleted file mode 100644
index cf3b1728b6..0000000000
--- a/cmds/servicemanager/binder.c
+++ /dev/null
@@ -1,682 +0,0 @@
-/* Copyright 2008 The Android Open Source Project
- */
-
-#define LOG_TAG "Binder"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "binder.h"
-
-#define MAX_BIO_SIZE (1 << 30)
-
-#define TRACE 0
-
-void bio_init_from_txn(struct binder_io *io, struct binder_transaction_data *txn);
-
-#if TRACE
-void hexdump(void *_data, size_t len)
-{
- unsigned char *data = _data;
- size_t count;
-
- for (count = 0; count < len; count++) {
- if ((count & 15) == 0)
- fprintf(stderr,"%04zu:", count);
- fprintf(stderr," %02x %c", *data,
- (*data < 32) || (*data > 126) ? '.' : *data);
- data++;
- if ((count & 15) == 15)
- fprintf(stderr,"\n");
- }
- if ((count & 15) != 0)
- fprintf(stderr,"\n");
-}
-
-void binder_dump_txn(struct binder_transaction_data *txn)
-{
- struct flat_binder_object *obj;
- binder_size_t *offs = (binder_size_t *)(uintptr_t)txn->data.ptr.offsets;
- size_t count = txn->offsets_size / sizeof(binder_size_t);
-
- fprintf(stderr," target %016"PRIx64" cookie %016"PRIx64" code %08x flags %08x\n",
- (uint64_t)txn->target.ptr, (uint64_t)txn->cookie, txn->code, txn->flags);
- fprintf(stderr," pid %8d uid %8d data %"PRIu64" offs %"PRIu64"\n",
- txn->sender_pid, txn->sender_euid, (uint64_t)txn->data_size, (uint64_t)txn->offsets_size);
- hexdump((void *)(uintptr_t)txn->data.ptr.buffer, txn->data_size);
- while (count--) {
- obj = (struct flat_binder_object *) (((char*)(uintptr_t)txn->data.ptr.buffer) + *offs++);
- fprintf(stderr," - type %08x flags %08x ptr %016"PRIx64" cookie %016"PRIx64"\n",
- obj->type, obj->flags, (uint64_t)obj->binder, (uint64_t)obj->cookie);
- }
-}
-
-#define NAME(n) case n: return #n
-const char *cmd_name(uint32_t cmd)
-{
- switch(cmd) {
- NAME(BR_NOOP);
- NAME(BR_TRANSACTION_COMPLETE);
- NAME(BR_INCREFS);
- NAME(BR_ACQUIRE);
- NAME(BR_RELEASE);
- NAME(BR_DECREFS);
- NAME(BR_TRANSACTION);
- NAME(BR_REPLY);
- NAME(BR_FAILED_REPLY);
- NAME(BR_DEAD_REPLY);
- NAME(BR_DEAD_BINDER);
- default: return "???";
- }
-}
-#else
-#define hexdump(a,b) do{} while (0)
-#define binder_dump_txn(txn) do{} while (0)
-#endif
-
-#define BIO_F_SHARED 0x01 /* needs to be buffer freed */
-#define BIO_F_OVERFLOW 0x02 /* ran out of space */
-#define BIO_F_IOERROR 0x04
-#define BIO_F_MALLOCED 0x08 /* needs to be free()'d */
-
-struct binder_state
-{
- int fd;
- void *mapped;
- size_t mapsize;
-};
-
-struct binder_state *binder_open(const char* driver, size_t mapsize)
-{
- struct binder_state *bs;
- struct binder_version vers;
-
- bs = malloc(sizeof(*bs));
- if (!bs) {
- errno = ENOMEM;
- return NULL;
- }
-
- bs->fd = open(driver, O_RDWR | O_CLOEXEC);
- if (bs->fd < 0) {
- fprintf(stderr,"binder: cannot open %s (%s)\n",
- driver, strerror(errno));
- goto fail_open;
- }
-
- if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
- (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
- fprintf(stderr,
- "binder: kernel driver version (%d) differs from user space version (%d)\n",
- vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
- goto fail_open;
- }
-
- bs->mapsize = mapsize;
- bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
- if (bs->mapped == MAP_FAILED) {
- fprintf(stderr,"binder: cannot map device (%s)\n",
- strerror(errno));
- goto fail_map;
- }
-
- return bs;
-
-fail_map:
- close(bs->fd);
-fail_open:
- free(bs);
- return NULL;
-}
-
-void binder_close(struct binder_state *bs)
-{
- munmap(bs->mapped, bs->mapsize);
- close(bs->fd);
- free(bs);
-}
-
-int binder_become_context_manager(struct binder_state *bs)
-{
- struct flat_binder_object obj;
- memset(&obj, 0, sizeof(obj));
- obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
-
- int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj);
-
- // fallback to original method
- if (result != 0) {
- android_errorWriteLog(0x534e4554, "121035042");
-
- result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
- }
- return result;
-}
-
-int binder_write(struct binder_state *bs, void *data, size_t len)
-{
- struct binder_write_read bwr;
- int res;
-
- bwr.write_size = len;
- bwr.write_consumed = 0;
- bwr.write_buffer = (uintptr_t) data;
- bwr.read_size = 0;
- bwr.read_consumed = 0;
- bwr.read_buffer = 0;
- res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
- if (res < 0) {
- fprintf(stderr,"binder_write: ioctl failed (%s)\n",
- strerror(errno));
- }
- return res;
-}
-
-void binder_free_buffer(struct binder_state *bs,
- binder_uintptr_t buffer_to_free)
-{
- struct {
- uint32_t cmd_free;
- binder_uintptr_t buffer;
- } __attribute__((packed)) data;
- data.cmd_free = BC_FREE_BUFFER;
- data.buffer = buffer_to_free;
- binder_write(bs, &data, sizeof(data));
-}
-
-void binder_send_reply(struct binder_state *bs,
- struct binder_io *reply,
- binder_uintptr_t buffer_to_free,
- int status)
-{
- struct {
- uint32_t cmd_free;
- binder_uintptr_t buffer;
- uint32_t cmd_reply;
- struct binder_transaction_data txn;
- } __attribute__((packed)) data;
-
- data.cmd_free = BC_FREE_BUFFER;
- data.buffer = buffer_to_free;
- data.cmd_reply = BC_REPLY;
- data.txn.target.ptr = 0;
- data.txn.cookie = 0;
- data.txn.code = 0;
- if (status) {
- data.txn.flags = TF_STATUS_CODE;
- data.txn.data_size = sizeof(int);
- data.txn.offsets_size = 0;
- data.txn.data.ptr.buffer = (uintptr_t)&status;
- data.txn.data.ptr.offsets = 0;
- } else {
- data.txn.flags = 0;
- data.txn.data_size = reply->data - reply->data0;
- data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
- data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
- data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
- }
- binder_write(bs, &data, sizeof(data));
-}
-
-int binder_parse(struct binder_state *bs, struct binder_io *bio,
- uintptr_t ptr, size_t size, binder_handler func)
-{
- int r = 1;
- uintptr_t end = ptr + (uintptr_t) size;
-
- while (ptr < end) {
- uint32_t cmd = *(uint32_t *) ptr;
- ptr += sizeof(uint32_t);
-#if TRACE
- fprintf(stderr,"%s:\n", cmd_name(cmd));
-#endif
- switch(cmd) {
- case BR_NOOP:
- break;
- case BR_TRANSACTION_COMPLETE:
- break;
- case BR_INCREFS:
- case BR_ACQUIRE:
- case BR_RELEASE:
- case BR_DECREFS:
-#if TRACE
- fprintf(stderr," %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *)));
-#endif
- ptr += sizeof(struct binder_ptr_cookie);
- break;
- case BR_TRANSACTION_SEC_CTX:
- case BR_TRANSACTION: {
- struct binder_transaction_data_secctx txn;
- if (cmd == BR_TRANSACTION_SEC_CTX) {
- if ((end - ptr) < sizeof(struct binder_transaction_data_secctx)) {
- ALOGE("parse: txn too small (binder_transaction_data_secctx)!\n");
- return -1;
- }
- memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx));
- ptr += sizeof(struct binder_transaction_data_secctx);
- } else /* BR_TRANSACTION */ {
- if ((end - ptr) < sizeof(struct binder_transaction_data)) {
- ALOGE("parse: txn too small (binder_transaction_data)!\n");
- return -1;
- }
- memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data));
- ptr += sizeof(struct binder_transaction_data);
-
- txn.secctx = 0;
- }
-
- binder_dump_txn(&txn.transaction_data);
- if (func) {
- unsigned rdata[256/4];
- struct binder_io msg;
- struct binder_io reply;
- int res;
-
- bio_init(&reply, rdata, sizeof(rdata), 4);
- bio_init_from_txn(&msg, &txn.transaction_data);
- res = func(bs, &txn, &msg, &reply);
- if (txn.transaction_data.flags & TF_ONE_WAY) {
- binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer);
- } else {
- binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res);
- }
- }
- break;
- }
- case BR_REPLY: {
- struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
- if ((end - ptr) < sizeof(*txn)) {
- ALOGE("parse: reply too small!\n");
- return -1;
- }
- binder_dump_txn(txn);
- if (bio) {
- bio_init_from_txn(bio, txn);
- bio = 0;
- } else {
- /* todo FREE BUFFER */
- }
- ptr += sizeof(*txn);
- r = 0;
- break;
- }
- case BR_DEAD_BINDER: {
- struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;
- ptr += sizeof(binder_uintptr_t);
- death->func(bs, death->ptr);
- break;
- }
- case BR_FAILED_REPLY:
- r = -1;
- break;
- case BR_DEAD_REPLY:
- r = -1;
- break;
- default:
- ALOGE("parse: OOPS %d\n", cmd);
- return -1;
- }
- }
-
- return r;
-}
-
-void binder_acquire(struct binder_state *bs, uint32_t target)
-{
- uint32_t cmd[2];
- cmd[0] = BC_ACQUIRE;
- cmd[1] = target;
- binder_write(bs, cmd, sizeof(cmd));
-}
-
-void binder_release(struct binder_state *bs, uint32_t target)
-{
- uint32_t cmd[2];
- cmd[0] = BC_RELEASE;
- cmd[1] = target;
- binder_write(bs, cmd, sizeof(cmd));
-}
-
-void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death)
-{
- struct {
- uint32_t cmd;
- struct binder_handle_cookie payload;
- } __attribute__((packed)) data;
-
- data.cmd = BC_REQUEST_DEATH_NOTIFICATION;
- data.payload.handle = target;
- data.payload.cookie = (uintptr_t) death;
- binder_write(bs, &data, sizeof(data));
-}
-
-int binder_call(struct binder_state *bs,
- struct binder_io *msg, struct binder_io *reply,
- uint32_t target, uint32_t code)
-{
- int res;
- struct binder_write_read bwr;
- struct {
- uint32_t cmd;
- struct binder_transaction_data txn;
- } __attribute__((packed)) writebuf;
- unsigned readbuf[32];
-
- if (msg->flags & BIO_F_OVERFLOW) {
- fprintf(stderr,"binder: txn buffer overflow\n");
- goto fail;
- }
-
- writebuf.cmd = BC_TRANSACTION;
- writebuf.txn.target.handle = target;
- writebuf.txn.code = code;
- writebuf.txn.flags = 0;
- writebuf.txn.data_size = msg->data - msg->data0;
- writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0);
- writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0;
- writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0;
-
- bwr.write_size = sizeof(writebuf);
- bwr.write_consumed = 0;
- bwr.write_buffer = (uintptr_t) &writebuf;
-
- hexdump(msg->data0, msg->data - msg->data0);
- for (;;) {
- bwr.read_size = sizeof(readbuf);
- bwr.read_consumed = 0;
- bwr.read_buffer = (uintptr_t) readbuf;
-
- res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
-
- if (res < 0) {
- fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno));
- goto fail;
- }
-
- res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0);
- if (res == 0) return 0;
- if (res < 0) goto fail;
- }
-
-fail:
- memset(reply, 0, sizeof(*reply));
- reply->flags |= BIO_F_IOERROR;
- return -1;
-}
-
-void binder_loop(struct binder_state *bs, binder_handler func)
-{
- int res;
- struct binder_write_read bwr;
- uint32_t readbuf[32];
-
- bwr.write_size = 0;
- bwr.write_consumed = 0;
- bwr.write_buffer = 0;
-
- readbuf[0] = BC_ENTER_LOOPER;
- binder_write(bs, readbuf, sizeof(uint32_t));
-
- for (;;) {
- bwr.read_size = sizeof(readbuf);
- bwr.read_consumed = 0;
- bwr.read_buffer = (uintptr_t) readbuf;
-
- res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
-
- if (res < 0) {
- ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
- break;
- }
-
- res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
- if (res == 0) {
- ALOGE("binder_loop: unexpected reply?!\n");
- break;
- }
- if (res < 0) {
- ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
- break;
- }
- }
-}
-
-void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn)
-{
- bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer;
- bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets;
- bio->data_avail = txn->data_size;
- bio->offs_avail = txn->offsets_size / sizeof(size_t);
- bio->flags = BIO_F_SHARED;
-}
-
-void bio_init(struct binder_io *bio, void *data,
- size_t maxdata, size_t maxoffs)
-{
- size_t n = maxoffs * sizeof(size_t);
-
- if (n > maxdata) {
- bio->flags = BIO_F_OVERFLOW;
- bio->data_avail = 0;
- bio->offs_avail = 0;
- return;
- }
-
- bio->data = bio->data0 = (char *) data + n;
- bio->offs = bio->offs0 = data;
- bio->data_avail = maxdata - n;
- bio->offs_avail = maxoffs;
- bio->flags = 0;
-}
-
-static void *bio_alloc(struct binder_io *bio, size_t size)
-{
- size = (size + 3) & (~3);
- if (size > bio->data_avail) {
- bio->flags |= BIO_F_OVERFLOW;
- return NULL;
- } else {
- void *ptr = bio->data;
- bio->data += size;
- bio->data_avail -= size;
- return ptr;
- }
-}
-
-void binder_done(struct binder_state *bs,
- __unused struct binder_io *msg,
- struct binder_io *reply)
-{
- struct {
- uint32_t cmd;
- uintptr_t buffer;
- } __attribute__((packed)) data;
-
- if (reply->flags & BIO_F_SHARED) {
- data.cmd = BC_FREE_BUFFER;
- data.buffer = (uintptr_t) reply->data0;
- binder_write(bs, &data, sizeof(data));
- reply->flags = 0;
- }
-}
-
-static struct flat_binder_object *bio_alloc_obj(struct binder_io *bio)
-{
- struct flat_binder_object *obj;
-
- obj = bio_alloc(bio, sizeof(*obj));
-
- if (obj && bio->offs_avail) {
- bio->offs_avail--;
- *bio->offs++ = ((char*) obj) - ((char*) bio->data0);
- return obj;
- }
-
- bio->flags |= BIO_F_OVERFLOW;
- return NULL;
-}
-
-void bio_put_uint32(struct binder_io *bio, uint32_t n)
-{
- uint32_t *ptr = bio_alloc(bio, sizeof(n));
- if (ptr)
- *ptr = n;
-}
-
-void bio_put_obj(struct binder_io *bio, void *ptr)
-{
- struct flat_binder_object *obj;
-
- obj = bio_alloc_obj(bio);
- if (!obj)
- return;
-
- obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- obj->hdr.type = BINDER_TYPE_BINDER;
- obj->binder = (uintptr_t)ptr;
- obj->cookie = 0;
-}
-
-void bio_put_ref(struct binder_io *bio, uint32_t handle)
-{
- struct flat_binder_object *obj;
-
- if (handle)
- obj = bio_alloc_obj(bio);
- else
- obj = bio_alloc(bio, sizeof(*obj));
-
- if (!obj)
- return;
-
- obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- obj->hdr.type = BINDER_TYPE_HANDLE;
- obj->handle = handle;
- obj->cookie = 0;
-}
-
-void bio_put_string16(struct binder_io *bio, const uint16_t *str)
-{
- size_t len;
- uint16_t *ptr;
-
- if (!str) {
- bio_put_uint32(bio, 0xffffffff);
- return;
- }
-
- len = 0;
- while (str[len]) len++;
-
- if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) {
- bio_put_uint32(bio, 0xffffffff);
- return;
- }
-
- /* Note: The payload will carry 32bit size instead of size_t */
- bio_put_uint32(bio, (uint32_t) len);
- len = (len + 1) * sizeof(uint16_t);
- ptr = bio_alloc(bio, len);
- if (ptr)
- memcpy(ptr, str, len);
-}
-
-void bio_put_string16_x(struct binder_io *bio, const char *_str)
-{
- unsigned char *str = (unsigned char*) _str;
- size_t len;
- uint16_t *ptr;
-
- if (!str) {
- bio_put_uint32(bio, 0xffffffff);
- return;
- }
-
- len = strlen(_str);
-
- if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) {
- bio_put_uint32(bio, 0xffffffff);
- return;
- }
-
- /* Note: The payload will carry 32bit size instead of size_t */
- bio_put_uint32(bio, len);
- ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t));
- if (!ptr)
- return;
-
- while (*str)
- *ptr++ = *str++;
- *ptr++ = 0;
-}
-
-static void *bio_get(struct binder_io *bio, size_t size)
-{
- size = (size + 3) & (~3);
-
- if (bio->data_avail < size){
- bio->data_avail = 0;
- bio->flags |= BIO_F_OVERFLOW;
- return NULL;
- } else {
- void *ptr = bio->data;
- bio->data += size;
- bio->data_avail -= size;
- return ptr;
- }
-}
-
-uint32_t bio_get_uint32(struct binder_io *bio)
-{
- uint32_t *ptr = bio_get(bio, sizeof(*ptr));
- return ptr ? *ptr : 0;
-}
-
-uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz)
-{
- size_t len;
-
- /* Note: The payload will carry 32bit size instead of size_t */
- len = (size_t) bio_get_uint32(bio);
- if (sz)
- *sz = len;
- return bio_get(bio, (len + 1) * sizeof(uint16_t));
-}
-
-static struct flat_binder_object *_bio_get_obj(struct binder_io *bio)
-{
- size_t n;
- size_t off = bio->data - bio->data0;
-
- /* TODO: be smarter about this? */
- for (n = 0; n < bio->offs_avail; n++) {
- if (bio->offs[n] == off)
- return bio_get(bio, sizeof(struct flat_binder_object));
- }
-
- bio->data_avail = 0;
- bio->flags |= BIO_F_OVERFLOW;
- return NULL;
-}
-
-uint32_t bio_get_ref(struct binder_io *bio)
-{
- struct flat_binder_object *obj;
-
- obj = _bio_get_obj(bio);
- if (!obj)
- return 0;
-
- if (obj->hdr.type == BINDER_TYPE_HANDLE)
- return obj->handle;
-
- return 0;
-}
diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h
deleted file mode 100644
index a9ccc74130..0000000000
--- a/cmds/servicemanager/binder.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* Copyright 2008 The Android Open Source Project
- */
-
-#ifndef _BINDER_H_
-#define _BINDER_H_
-
-#include <linux/android/binder.h>
-#include <sys/ioctl.h>
-
-struct binder_state;
-
-struct binder_io
-{
- char *data; /* pointer to read/write from */
- binder_size_t *offs; /* array of offsets */
- size_t data_avail; /* bytes available in data buffer */
- size_t offs_avail; /* entries available in offsets array */
-
- char *data0; /* start of data buffer */
- binder_size_t *offs0; /* start of offsets buffer */
- uint32_t flags;
- uint32_t unused;
-};
-
-struct binder_death {
- void (*func)(struct binder_state *bs, void *ptr);
- void *ptr;
-};
-
-/* the one magic handle */
-#define BINDER_SERVICE_MANAGER 0U
-
-#define SVC_MGR_NAME "android.os.IServiceManager"
-
-enum {
- /* Must match definitions in IBinder.h and IServiceManager.h */
- PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'),
- SVC_MGR_GET_SERVICE = 1,
- SVC_MGR_CHECK_SERVICE,
- SVC_MGR_ADD_SERVICE,
- SVC_MGR_LIST_SERVICES,
-};
-
-typedef int (*binder_handler)(struct binder_state *bs,
- struct binder_transaction_data_secctx *txn,
- struct binder_io *msg,
- struct binder_io *reply);
-
-struct binder_state *binder_open(const char* driver, size_t mapsize);
-void binder_close(struct binder_state *bs);
-
-/* initiate a blocking binder call
- * - returns zero on success
- */
-int binder_call(struct binder_state *bs,
- struct binder_io *msg, struct binder_io *reply,
- uint32_t target, uint32_t code);
-
-/* release any state associate with the binder_io
- * - call once any necessary data has been extracted from the
- * binder_io after binder_call() returns
- * - can safely be called even if binder_call() fails
- */
-void binder_done(struct binder_state *bs,
- struct binder_io *msg, struct binder_io *reply);
-
-/* manipulate strong references */
-void binder_acquire(struct binder_state *bs, uint32_t target);
-void binder_release(struct binder_state *bs, uint32_t target);
-
-void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death);
-
-void binder_loop(struct binder_state *bs, binder_handler func);
-
-int binder_become_context_manager(struct binder_state *bs);
-
-/* allocate a binder_io, providing a stack-allocated working
- * buffer, size of the working buffer, and how many object
- * offset entries to reserve from the buffer
- */
-void bio_init(struct binder_io *bio, void *data,
- size_t maxdata, size_t maxobjects);
-
-void bio_put_obj(struct binder_io *bio, void *ptr);
-void bio_put_ref(struct binder_io *bio, uint32_t handle);
-void bio_put_uint32(struct binder_io *bio, uint32_t n);
-void bio_put_string16(struct binder_io *bio, const uint16_t *str);
-void bio_put_string16_x(struct binder_io *bio, const char *_str);
-
-uint32_t bio_get_uint32(struct binder_io *bio);
-uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz);
-uint32_t bio_get_ref(struct binder_io *bio);
-
-#endif
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
new file mode 100644
index 0000000000..c8ceb42ac8
--- /dev/null
+++ b/cmds/servicemanager/main.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 <android-base/logging.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/Status.h>
+#include <utils/StrongPointer.h>
+
+#include "Access.h"
+#include "ServiceManager.h"
+
+using ::android::sp;
+using ::android::ProcessState;
+using ::android::IPCThreadState;
+using ::android::ServiceManager;
+using ::android::Access;
+
+int main(int argc, char** argv) {
+ if (argc > 2) {
+ LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
+ }
+
+ const char* driver = argc == 2 ? argv[1] : "/dev/binder";
+
+ android::base::InitLogging(nullptr, &android::base::KernelLogger);
+
+ ProcessState::self()->initWithDriver(driver);
+ ProcessState::self()->setThreadPoolMaxThreadCount(0);
+ ProcessState::self()->setCallRestriction(
+ ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
+
+ sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>());
+ IPCThreadState::self()->setTheContextObject(manager);
+ ProcessState::self()->becomeContextManager(nullptr, nullptr);
+
+ IPCThreadState::self()->joinThreadPool();
+
+ // should not be reached
+ return EXIT_FAILURE;
+}
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
deleted file mode 100644
index ec3fac538d..0000000000
--- a/cmds/servicemanager/service_manager.c
+++ /dev/null
@@ -1,442 +0,0 @@
-/* Copyright 2008 The Android Open Source Project
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <cutils/android_filesystem_config.h>
-#include <cutils/multiuser.h>
-
-#include <selinux/android.h>
-#include <selinux/avc.h>
-
-#include "binder.h"
-
-#ifdef VENDORSERVICEMANAGER
-#define LOG_TAG "VendorServiceManager"
-#else
-#define LOG_TAG "ServiceManager"
-#endif
-#include <log/log.h>
-
-struct audit_data {
- pid_t pid;
- uid_t uid;
- const char *name;
-};
-
-const char *str8(const uint16_t *x, size_t x_len)
-{
- static char buf[128];
- size_t max = 127;
- char *p = buf;
-
- if (x_len < max) {
- max = x_len;
- }
-
- if (x) {
- while ((max > 0) && (*x != '\0')) {
- *p++ = *x++;
- max--;
- }
- }
- *p++ = 0;
- return buf;
-}
-
-int str16eq(const uint16_t *a, const char *b)
-{
- while (*a && *b)
- if (*a++ != *b++) return 0;
- if (*a || *b)
- return 0;
- return 1;
-}
-
-static char *service_manager_context;
-static struct selabel_handle* sehandle;
-
-static bool check_mac_perms(pid_t spid, const char* sid, uid_t uid, const char *tctx, const char *perm, const char *name)
-{
- char *lookup_sid = NULL;
- const char *class = "service_manager";
- bool allowed;
- struct audit_data ad;
-
- if (sid == NULL && getpidcon(spid, &lookup_sid) < 0) {
- ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);
- return false;
- }
-
- ad.pid = spid;
- ad.uid = uid;
- ad.name = name;
-
- if (sid == NULL) {
- android_errorWriteLog(0x534e4554, "121035042");
- }
-
- int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad);
- allowed = (result == 0);
-
- freecon(lookup_sid);
- return allowed;
-}
-
-static bool check_mac_perms_from_getcon(pid_t spid, const char* sid, uid_t uid, const char *perm)
-{
- return check_mac_perms(spid, sid, uid, service_manager_context, perm, NULL);
-}
-
-static bool check_mac_perms_from_lookup(pid_t spid, const char* sid, uid_t uid, const char *perm, const char *name)
-{
- bool allowed;
- char *tctx = NULL;
-
- if (!sehandle) {
- ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n");
- abort();
- }
-
- if (selabel_lookup(sehandle, &tctx, name, 0) != 0) {
- ALOGE("SELinux: No match for %s in service_contexts.\n", name);
- return false;
- }
-
- allowed = check_mac_perms(spid, sid, uid, tctx, perm, name);
- freecon(tctx);
- return allowed;
-}
-
-static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid)
-{
- const char *perm = "add";
-
- if (multiuser_get_app_id(uid) >= AID_APP) {
- return 0; /* Don't allow apps to register services */
- }
-
- return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0;
-}
-
-static int svc_can_list(pid_t spid, const char* sid, uid_t uid)
-{
- const char *perm = "list";
- return check_mac_perms_from_getcon(spid, sid, uid, perm) ? 1 : 0;
-}
-
-static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid)
-{
- const char *perm = "find";
- return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0;
-}
-
-struct svcinfo
-{
- struct svcinfo *next;
- uint32_t handle;
- struct binder_death death;
- int allow_isolated;
- uint32_t dumpsys_priority;
- size_t len;
- uint16_t name[0];
-};
-
-struct svcinfo *svclist = NULL;
-
-struct svcinfo *find_svc(const uint16_t *s16, size_t len)
-{
- struct svcinfo *si;
-
- for (si = svclist; si; si = si->next) {
- if ((len == si->len) &&
- !memcmp(s16, si->name, len * sizeof(uint16_t))) {
- return si;
- }
- }
- return NULL;
-}
-
-void svcinfo_death(struct binder_state *bs, void *ptr)
-{
- struct svcinfo *si = (struct svcinfo* ) ptr;
-
- ALOGI("service '%s' died\n", str8(si->name, si->len));
- if (si->handle) {
- binder_release(bs, si->handle);
- si->handle = 0;
- }
-}
-
-uint16_t svcmgr_id[] = {
- 'a','n','d','r','o','i','d','.','o','s','.',
- 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r'
-};
-
-
-uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid)
-{
- struct svcinfo *si = find_svc(s, len);
-
- if (!si || !si->handle) {
- return 0;
- }
-
- if (!si->allow_isolated) {
- // If this service doesn't allow access from isolated processes,
- // then check the uid to see if it is isolated.
- uid_t appid = uid % AID_USER;
- if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
- return 0;
- }
- }
-
- if (!svc_can_find(s, len, spid, sid, uid)) {
- return 0;
- }
-
- return si->handle;
-}
-
-int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,
- uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid, const char* sid) {
- struct svcinfo *si;
-
- //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
- // allow_isolated ? "allow_isolated" : "!allow_isolated", uid);
-
- if (!handle || (len == 0) || (len > 127))
- return -1;
-
- if (!svc_can_register(s, len, spid, sid, uid)) {
- ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
- str8(s, len), handle, uid);
- return -1;
- }
-
- si = find_svc(s, len);
- if (si) {
- if (si->handle) {
- ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
- str8(s, len), handle, uid);
- svcinfo_death(bs, si);
- }
- si->handle = handle;
- } else {
- si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
- if (!si) {
- ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
- str8(s, len), handle, uid);
- return -1;
- }
- si->handle = handle;
- si->len = len;
- memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
- si->name[len] = '\0';
- si->death.func = (void*) svcinfo_death;
- si->death.ptr = si;
- si->allow_isolated = allow_isolated;
- si->dumpsys_priority = dumpsys_priority;
- si->next = svclist;
- svclist = si;
- }
-
- binder_acquire(bs, handle);
- binder_link_to_death(bs, handle, &si->death);
- return 0;
-}
-
-int svcmgr_handler(struct binder_state *bs,
- struct binder_transaction_data_secctx *txn_secctx,
- struct binder_io *msg,
- struct binder_io *reply)
-{
- struct svcinfo *si;
- uint16_t *s;
- size_t len;
- uint32_t handle;
- uint32_t strict_policy;
- int allow_isolated;
- uint32_t dumpsys_priority;
-
- struct binder_transaction_data *txn = &txn_secctx->transaction_data;
-
- //ALOGI("target=%p code=%d pid=%d uid=%d\n",
- // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
-
- if (txn->target.ptr != BINDER_SERVICE_MANAGER)
- return -1;
-
- if (txn->code == PING_TRANSACTION)
- return 0;
-
- // Equivalent to Parcel::enforceInterface(), reading the RPC
- // header with the strict mode policy mask and the interface name.
- // Note that we ignore the strict_policy and don't propagate it
- // further (since we do no outbound RPCs anyway).
- strict_policy = bio_get_uint32(msg);
- bio_get_uint32(msg); // Ignore worksource header.
- s = bio_get_string16(msg, &len);
- if (s == NULL) {
- return -1;
- }
-
- if ((len != (sizeof(svcmgr_id) / 2)) ||
- memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
- fprintf(stderr,"invalid id %s\n", str8(s, len));
- return -1;
- }
-
- if (sehandle && selinux_status_updated() > 0) {
-#ifdef VENDORSERVICEMANAGER
- struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle();
-#else
- struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
-#endif
- if (tmp_sehandle) {
- selabel_close(sehandle);
- sehandle = tmp_sehandle;
- }
- }
-
- switch(txn->code) {
- case SVC_MGR_GET_SERVICE:
- case SVC_MGR_CHECK_SERVICE:
- s = bio_get_string16(msg, &len);
- if (s == NULL) {
- return -1;
- }
- handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid,
- (const char*) txn_secctx->secctx);
- if (!handle)
- break;
- bio_put_ref(reply, handle);
- return 0;
-
- case SVC_MGR_ADD_SERVICE:
- s = bio_get_string16(msg, &len);
- if (s == NULL) {
- return -1;
- }
- handle = bio_get_ref(msg);
- allow_isolated = bio_get_uint32(msg) ? 1 : 0;
- dumpsys_priority = bio_get_uint32(msg);
- if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
- txn->sender_pid, (const char*) txn_secctx->secctx))
- return -1;
- break;
-
- case SVC_MGR_LIST_SERVICES: {
- uint32_t n = bio_get_uint32(msg);
- uint32_t req_dumpsys_priority = bio_get_uint32(msg);
-
- if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) {
- ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
- txn->sender_euid);
- return -1;
- }
- si = svclist;
- // walk through the list of services n times skipping services that
- // do not support the requested priority
- while (si) {
- if (si->dumpsys_priority & req_dumpsys_priority) {
- if (n == 0) break;
- n--;
- }
- si = si->next;
- }
- if (si) {
- bio_put_string16(reply, si->name);
- return 0;
- }
- return -1;
- }
- default:
- ALOGE("unknown code %d\n", txn->code);
- return -1;
- }
-
- bio_put_uint32(reply, 0);
- return 0;
-}
-
-
-static int audit_callback(void *data, __unused security_class_t cls, char *buf, size_t len)
-{
- struct audit_data *ad = (struct audit_data *)data;
-
- if (!ad || !ad->name) {
- ALOGE("No service manager audit data");
- return 0;
- }
-
- snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name, ad->pid, ad->uid);
- return 0;
-}
-
-int main(int argc, char** argv)
-{
- struct binder_state *bs;
- union selinux_callback cb;
- char *driver;
-
- if (argc > 1) {
- driver = argv[1];
- } else {
- driver = "/dev/binder";
- }
-
- bs = binder_open(driver, 128*1024);
- if (!bs) {
-#ifdef VENDORSERVICEMANAGER
- ALOGW("failed to open binder driver %s\n", driver);
- while (true) {
- sleep(UINT_MAX);
- }
-#else
- ALOGE("failed to open binder driver %s\n", driver);
-#endif
- return -1;
- }
-
- if (binder_become_context_manager(bs)) {
- ALOGE("cannot become context manager (%s)\n", strerror(errno));
- return -1;
- }
-
- cb.func_audit = audit_callback;
- selinux_set_callback(SELINUX_CB_AUDIT, cb);
-#ifdef VENDORSERVICEMANAGER
- cb.func_log = selinux_vendor_log_callback;
-#else
- cb.func_log = selinux_log_callback;
-#endif
- selinux_set_callback(SELINUX_CB_LOG, cb);
-
-#ifdef VENDORSERVICEMANAGER
- sehandle = selinux_android_vendor_service_context_handle();
-#else
- sehandle = selinux_android_service_context_handle();
-#endif
- selinux_status_open(true);
-
- if (sehandle == NULL) {
- ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
- abort();
- }
-
- if (getcon(&service_manager_context) != 0) {
- ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
- abort();
- }
-
-
- binder_loop(bs, svcmgr_handler);
-
- return 0;
-}
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
new file mode 100644
index 0000000000..812d5cacd5
--- /dev/null
+++ b/cmds/servicemanager/test_sm.cpp
@@ -0,0 +1,261 @@
+/*
+ * 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 <binder/ProcessState.h>
+#include <cutils/android_filesystem_config.h>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "Access.h"
+#include "ServiceManager.h"
+
+using android::sp;
+using android::Access;
+using android::IBinder;
+using android::ServiceManager;
+using android::os::IServiceManager;
+using testing::_;
+using testing::ElementsAre;
+using testing::NiceMock;
+using testing::Return;
+
+static sp<IBinder> getBinder() {
+ // It doesn't matter what remote binder it is, we just need one so that linkToDeath will work.
+ // The context manager (servicemanager) is easy to get and is in another process.
+ return android::ProcessState::self()->getContextObject(nullptr);
+}
+
+class MockAccess : public Access {
+public:
+ MOCK_METHOD1(getCallingContext, CallingContext(const std::string& name));
+ MOCK_METHOD1(canAdd, bool(const CallingContext&));
+ MOCK_METHOD1(canFind, bool(const CallingContext&));
+ MOCK_METHOD1(canList, bool(const CallingContext&));
+};
+
+static sp<ServiceManager> getPermissiveServiceManager() {
+ std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
+
+ ON_CALL(*access, getCallingContext(_)).WillByDefault(Return(Access::CallingContext{}));
+ ON_CALL(*access, canAdd(_)).WillByDefault(Return(true));
+ ON_CALL(*access, canFind(_)).WillByDefault(Return(true));
+ ON_CALL(*access, canList(_)).WillByDefault(Return(true));
+
+ sp<ServiceManager> sm = new ServiceManager(std::move(access));
+ return sm;
+}
+
+TEST(AddService, HappyHappy) {
+ auto sm = getPermissiveServiceManager();
+ EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+}
+
+TEST(AddService, EmptyNameDisallowed) {
+ auto sm = getPermissiveServiceManager();
+ EXPECT_FALSE(sm->addService("", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+}
+
+TEST(AddService, JustShortEnoughServiceNameHappy) {
+ auto sm = getPermissiveServiceManager();
+ EXPECT_TRUE(sm->addService(std::string(127, 'a'), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+}
+
+TEST(AddService, TooLongNameDisallowed) {
+ auto sm = getPermissiveServiceManager();
+ EXPECT_FALSE(sm->addService(std::string(128, 'a'), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+}
+
+TEST(AddService, AddNullServiceDisallowed) {
+ auto sm = getPermissiveServiceManager();
+ EXPECT_FALSE(sm->addService("foo", nullptr, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+}
+
+TEST(AddService, AddDisallowedFromApp) {
+ for (uid_t uid : { AID_APP_START, AID_APP_START + 1, AID_APP_END }) {
+ std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
+ EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{
+ .debugPid = 1337,
+ .uid = uid,
+ }));
+ EXPECT_CALL(*access, canAdd(_)).Times(0);
+ sp<ServiceManager> sm = new ServiceManager(std::move(access));
+
+ EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+ }
+
+}
+
+TEST(AddService, HappyOverExistingService) {
+ auto sm = getPermissiveServiceManager();
+ EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+ EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+}
+
+TEST(AddService, NoPermissions) {
+ std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
+
+ EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{}));
+ EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(false));
+
+ sp<ServiceManager> sm = new ServiceManager(std::move(access));
+
+ EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+}
+
+TEST(GetService, HappyHappy) {
+ auto sm = getPermissiveServiceManager();
+ EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ sp<IBinder> out;
+ EXPECT_TRUE(sm->getService("foo", &out).isOk());
+ EXPECT_EQ(getBinder(), out);
+}
+
+TEST(GetService, NonExistant) {
+ auto sm = getPermissiveServiceManager();
+
+ sp<IBinder> out;
+ EXPECT_TRUE(sm->getService("foo", &out).isOk());
+ EXPECT_EQ(nullptr, out.get());
+}
+
+TEST(GetService, NoPermissionsForGettingService) {
+ std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
+
+ EXPECT_CALL(*access, getCallingContext(_)).WillRepeatedly(Return(Access::CallingContext{}));
+ EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true));
+ EXPECT_CALL(*access, canFind(_)).WillOnce(Return(false));
+
+ sp<ServiceManager> sm = new ServiceManager(std::move(access));
+
+ EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ sp<IBinder> out;
+ // returns nullptr but has OK status for legacy compatibility
+ EXPECT_TRUE(sm->getService("foo", &out).isOk());
+ EXPECT_EQ(nullptr, out.get());
+}
+
+TEST(GetService, AllowedFromIsolated) {
+ std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
+
+ EXPECT_CALL(*access, getCallingContext(_))
+ // something adds it
+ .WillOnce(Return(Access::CallingContext{}))
+ // next call is from isolated app
+ .WillOnce(Return(Access::CallingContext{
+ .uid = AID_ISOLATED_START,
+ }));
+ EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true));
+ EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true));
+
+ sp<ServiceManager> sm = new ServiceManager(std::move(access));
+
+ EXPECT_TRUE(sm->addService("foo", getBinder(), true /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ sp<IBinder> out;
+ EXPECT_TRUE(sm->getService("foo", &out).isOk());
+ EXPECT_EQ(getBinder(), out.get());
+}
+
+TEST(GetService, NotAllowedFromIsolated) {
+ std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
+
+ EXPECT_CALL(*access, getCallingContext(_))
+ // something adds it
+ .WillOnce(Return(Access::CallingContext{}))
+ // next call is from isolated app
+ .WillOnce(Return(Access::CallingContext{
+ .uid = AID_ISOLATED_START,
+ }));
+ EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true));
+
+ // TODO(b/136023468): when security check is first, this should be called first
+ // EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true));
+
+ sp<ServiceManager> sm = new ServiceManager(std::move(access));
+
+ EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ sp<IBinder> out;
+ // returns nullptr but has OK status for legacy compatibility
+ EXPECT_TRUE(sm->getService("foo", &out).isOk());
+ EXPECT_EQ(nullptr, out.get());
+}
+
+TEST(ListServices, NoPermissions) {
+ std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>();
+
+ EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{}));
+ EXPECT_CALL(*access, canList(_)).WillOnce(Return(false));
+
+ sp<ServiceManager> sm = new ServiceManager(std::move(access));
+
+ std::vector<std::string> out;
+ EXPECT_FALSE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk());
+ EXPECT_TRUE(out.empty());
+}
+
+TEST(ListServices, AllServices) {
+ auto sm = getPermissiveServiceManager();
+
+ EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+ EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk());
+ EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk());
+ EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk());
+
+ std::vector<std::string> out;
+ EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk());
+
+ // all there and in the right order
+ EXPECT_THAT(out, ElementsAre("sa", "sb", "sc", "sd"));
+}
+
+TEST(ListServices, CriticalServices) {
+ auto sm = getPermissiveServiceManager();
+
+ EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+ EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk());
+ EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk());
+ EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk());
+
+ std::vector<std::string> out;
+ EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, &out).isOk());
+
+ // all there and in the right order
+ EXPECT_THAT(out, ElementsAre("sa"));
+}
diff --git a/include/android/font.h b/include/android/font.h
index 435a573f51..8001ee1938 100644
--- a/include/android/font.h
+++ b/include/android/font.h
@@ -16,7 +16,7 @@
/**
* @addtogroup Font
- * {
+ * @{
*/
/**
diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h
index e286a4c812..0b8f892b9b 100644
--- a/include/android/font_matcher.h
+++ b/include/android/font_matcher.h
@@ -16,7 +16,7 @@
/**
* @addtogroup Font
- * {
+ * @{
*/
/**
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
index dde9055c7a..f0485a1871 100644
--- a/include/android/system_fonts.h
+++ b/include/android/system_fonts.h
@@ -16,7 +16,7 @@
/**
* @addtogroup Font
- * {
+ * @{
*/
/**
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 905b25f397..760d55b751 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -94,7 +94,6 @@ cc_library_shared {
"PermissionController.cpp",
"ProcessInfoService.cpp",
"IpPrefix.cpp",
- ":libbinder_aidl",
],
},
},
@@ -142,8 +141,7 @@ filegroup {
name: "libbinder_aidl",
srcs: [
"aidl/android/content/pm/IPackageManagerNative.aidl",
+ "aidl/android/os/IServiceManager.aidl",
],
path: "aidl",
}
-
-subdirs = ["tests"]
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index a2d10ab0ab..3424c28883 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1062,7 +1062,7 @@ status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
sp<BBinder> the_context_object;
-void setTheContextObject(sp<BBinder> obj)
+void IPCThreadState::setTheContextObject(sp<BBinder> obj)
{
the_context_object = obj;
}
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 0203d41992..07550fb571 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -18,6 +18,7 @@
#include <binder/IServiceManager.h>
+#include <android/os/IServiceManager.h>
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#ifndef __ANDROID_VNDK__
@@ -34,6 +35,9 @@
namespace android {
+using AidlServiceManager = android::os::IServiceManager;
+using android::binder::Status;
+
sp<IServiceManager> defaultServiceManager()
{
static Mutex gDefaultServiceManagerLock;
@@ -142,11 +146,12 @@ class BpServiceManager : public BpInterface<IServiceManager>
{
public:
explicit BpServiceManager(const sp<IBinder>& impl)
- : BpInterface<IServiceManager>(impl)
+ : BpInterface<IServiceManager>(impl),
+ mTheRealServiceManager(interface_cast<AidlServiceManager>(impl))
{
}
- virtual sp<IBinder> getService(const String16& name) const
+ sp<IBinder> getService(const String16& name) const override
{
static bool gSystemBootCompleted = false;
@@ -179,43 +184,36 @@ public:
return nullptr;
}
- virtual sp<IBinder> checkService( const String16& name) const
- {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
- return reply.readStrongBinder();
+ sp<IBinder> checkService(const String16& name) const override {
+ sp<IBinder> ret;
+ if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
+ return nullptr;
+ }
+ return ret;
}
- virtual status_t addService(const String16& name, const sp<IBinder>& service,
- bool allowIsolated, int dumpsysPriority) {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- data.writeStrongBinder(service);
- data.writeInt32(allowIsolated ? 1 : 0);
- data.writeInt32(dumpsysPriority);
- status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
- return err == NO_ERROR ? reply.readExceptionCode() : err;
+ status_t addService(const String16& name, const sp<IBinder>& service,
+ bool allowIsolated, int dumpsysPriority) override {
+ Status status = mTheRealServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority);
+ return status.exceptionCode();
}
virtual Vector<String16> listServices(int dumpsysPriority) {
- Vector<String16> res;
- int n = 0;
+ std::vector<std::string> ret;
+ if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
+ return {};
+ }
- for (;;) {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeInt32(n++);
- data.writeInt32(dumpsysPriority);
- status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
- if (err != NO_ERROR)
- break;
- res.add(reply.readString16());
+ Vector<String16> res;
+ res.setCapacity(ret.size());
+ for (const std::string& name : ret) {
+ res.push(String16(name.c_str()));
}
return res;
}
+
+private:
+ sp<AidlServiceManager> mTheRealServiceManager;
};
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
new file mode 100644
index 0000000000..50a72aa9e4
--- /dev/null
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Basic interface for finding and publishing system services.
+ *
+ * You likely want to use android.os.ServiceManager in Java or
+ * android::IServiceManager in C++ in order to use this interface.
+ *
+ * @hide
+ */
+interface IServiceManager {
+ /*
+ * Must update values in IServiceManager.h
+ */
+ /* Allows services to dump sections according to priorities. */
+ const int DUMP_FLAG_PRIORITY_CRITICAL = 1; // 1 << 0
+ const int DUMP_FLAG_PRIORITY_HIGH = 2; // 1 << 1
+ const int DUMP_FLAG_PRIORITY_NORMAL = 4; // 1 << 2
+ /**
+ * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the
+ * same priority as NORMAL priority but the services are not called with dump priority
+ * arguments.
+ */
+ const int DUMP_FLAG_PRIORITY_DEFAULT = 8; // 1 << 3
+
+ const int DUMP_FLAG_PRIORITY_ALL = 15;
+ // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
+ // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
+
+ /* Allows services to dump sections in protobuf format. */
+ const int DUMP_FLAG_PROTO = 16; // 1 << 4
+
+ /**
+ * Retrieve an existing service called @a name from the
+ * service manager.
+ *
+ * This is the same as checkService (returns immediately) but
+ * exists for legacy purposes.
+ *
+ * Returns null if the service does not exist.
+ */
+ @UnsupportedAppUsage
+ IBinder getService(@utf8InCpp String name);
+
+ /**
+ * Retrieve an existing service called @a name from the service
+ * manager. Non-blocking. Returns null if the service does not
+ * exist.
+ */
+ @UnsupportedAppUsage
+ IBinder checkService(@utf8InCpp String name);
+
+ /**
+ * Place a new @a service called @a name into the service
+ * manager.
+ */
+ void addService(@utf8InCpp String name, IBinder service,
+ boolean allowIsolated, int dumpPriority);
+
+ /**
+ * Return a list of all currently running services.
+ */
+ @utf8InCpp String[] listServices(int dumpPriority);
+}
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 614b0b33dd..b810f7e8ee 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -110,6 +110,8 @@ public:
// the maximum number of binder threads threads allowed for this process.
void blockUntilThreadAvailable();
+ // Service manager registration
+ void setTheContextObject(sp<BBinder> obj);
// Is this thread currently serving a binder call. This method
// returns true if while traversing backwards from the function call
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 5fd4a95d7b..41cbde1c18 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <mutex>
+#include <optional>
#include <set>
#include <string>
#include <unordered_map>
@@ -62,19 +63,20 @@ static std::vector<std::vector<uint32_t>> gPolicyCpus;
static std::set<uint32_t> gAllFreqs;
static unique_fd gMapFd;
-static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) {
+static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) {
std::string data;
- if (!android::base::ReadFileToString(path, &data)) return false;
+ if (!android::base::ReadFileToString(path, &data)) return {};
auto strings = android::base::Split(data, " \n");
+ std::vector<uint32_t> ret;
for (const auto &s : strings) {
if (s.empty()) continue;
uint32_t n;
- if (!android::base::ParseUint(s, &n)) return false;
- out->emplace_back(n);
+ if (!android::base::ParseUint(s, &n)) return {};
+ ret.emplace_back(n);
}
- return true;
+ return ret;
}
static int isPolicyFile(const struct dirent *d) {
@@ -111,20 +113,22 @@ static bool initGlobals() {
for (const auto &name : {"available", "boost"}) {
std::string path =
StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name);
- if (!readNumbersFromFile(path, &freqs)) return false;
+ auto nums = readNumbersFromFile(path);
+ if (!nums) return false;
+ freqs.insert(freqs.end(), nums->begin(), nums->end());
}
std::sort(freqs.begin(), freqs.end());
gPolicyFreqs.emplace_back(freqs);
for (auto freq : freqs) gAllFreqs.insert(freq);
- std::vector<uint32_t> cpus;
std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus");
- if (!readNumbersFromFile(path, &cpus)) return false;
- gPolicyCpus.emplace_back(cpus);
+ auto cpus = readNumbersFromFile(path);
+ if (!cpus) return false;
+ gPolicyCpus.emplace_back(*cpus);
}
- gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")};
+ gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")};
if (gMapFd < 0) return false;
gInitialized = true;
@@ -151,17 +155,15 @@ bool startTrackingUidCpuFreqTimes() {
}
// Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes.
-// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors
-// using the format:
+// Return contains no value on error, otherwise it contains a vector of vectors using the format:
// [[t0_0, t0_1, ...],
// [t1_0, t1_1, ...], ...]
// where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq.
-bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTimes) {
- if (!gInitialized && !initGlobals()) return false;
+std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid) {
+ if (!gInitialized && !initGlobals()) return {};
time_key_t key = {.uid = uid, .freq = 0};
- freqTimes->clear();
- freqTimes->resize(gNPolicies);
+ std::vector<std::vector<uint64_t>> out(gNPolicies);
std::vector<uint32_t> idxs(gNPolicies, 0);
val_t value;
@@ -172,32 +174,32 @@ bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTi
if (errno == ENOENT)
memset(&value.ar, 0, sizeof(value.ar));
else
- return false;
+ return {};
}
for (uint32_t i = 0; i < gNPolicies; ++i) {
if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue;
uint64_t time = 0;
for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu];
idxs[i] += 1;
- (*freqTimes)[i].emplace_back(time);
+ out[i].emplace_back(time);
}
}
- return true;
+ return out;
}
// Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap.
-// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to
-// vectors of vectors using the format:
+// Return contains no value on error, otherwise it contains a map from uids to vectors of vectors
+// using the format:
// { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
// uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
// where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq.
-bool getUidsCpuFreqTimes(
- std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *freqTimeMap) {
- if (!gInitialized && !initGlobals()) return false;
+std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
+getUidsCpuFreqTimes() {
+ if (!gInitialized && !initGlobals()) return {};
- int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times");
- if (fd < 0) return false;
+ int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map");
+ if (fd < 0) return {};
BpfMap<time_key_t, val_t> m(fd);
std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs;
@@ -206,25 +208,26 @@ bool getUidsCpuFreqTimes(
for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j;
policyFreqIdxs.emplace_back(freqIdxs);
}
-
- auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val,
+ std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map;
+ auto fn = [&map, &policyFreqIdxs](const time_key_t &key, const val_t &val,
const BpfMap<time_key_t, val_t> &) {
- if (freqTimeMap->find(key.uid) == freqTimeMap->end()) {
- (*freqTimeMap)[key.uid].resize(gNPolicies);
+ if (map.find(key.uid) == map.end()) {
+ map[key.uid].resize(gNPolicies);
for (uint32_t i = 0; i < gNPolicies; ++i) {
- (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0);
+ map[key.uid][i].resize(gPolicyFreqs[i].size(), 0);
}
}
for (size_t policy = 0; policy < gNPolicies; ++policy) {
for (const auto &cpu : gPolicyCpus[policy]) {
auto freqIdx = policyFreqIdxs[policy][key.freq];
- (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu];
+ map[key.uid][policy][freqIdx] += val.ar[cpu];
}
}
return android::netdutils::status::ok;
};
- return isOk(m.iterateWithValue(fn));
+ if (isOk(m.iterateWithValue(fn))) return map;
+ return {};
}
// Clear all time in state data for a given uid. Returns false on error, true otherwise.
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index 9f6103ed9b..d7b45870ac 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -23,8 +23,9 @@ namespace android {
namespace bpf {
bool startTrackingUidCpuFreqTimes();
-bool getUidCpuFreqTimes(unsigned int uid, std::vector<std::vector<uint64_t>> *freqTimes);
-bool getUidsCpuFreqTimes(std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *tisMap);
+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();
bool clearUidCpuFreqTimes(unsigned int uid);
} // namespace bpf
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 9837865dfb..d4b87386e0 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -12,45 +12,46 @@ namespace bpf {
using std::vector;
TEST(TimeInStateTest, SingleUid) {
- vector<vector<uint64_t>> times;
- ASSERT_TRUE(getUidCpuFreqTimes(0, &times));
- EXPECT_FALSE(times.empty());
+ auto times = getUidCpuFreqTimes(0);
+ ASSERT_TRUE(times.has_value());
+ EXPECT_FALSE(times->empty());
}
TEST(TimeInStateTest, AllUid) {
vector<size_t> sizes;
- std::unordered_map<uint32_t, vector<vector<uint64_t>>> map;
- ASSERT_TRUE(getUidsCpuFreqTimes(&map));
+ auto map = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map.has_value());
- ASSERT_FALSE(map.empty());
+ ASSERT_FALSE(map->empty());
- auto firstEntry = map.begin()->second;
+ auto firstEntry = map->begin()->second;
for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());
- for (const auto &vec : map) {
+ for (const auto &vec : *map) {
ASSERT_EQ(vec.second.size(), sizes.size());
for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
}
}
TEST(TimeInStateTest, RemoveUid) {
- vector<vector<uint64_t>> times, times2;
- ASSERT_TRUE(getUidCpuFreqTimes(0, &times));
- ASSERT_FALSE(times.empty());
+ auto times = getUidCpuFreqTimes(0);
+ ASSERT_TRUE(times.has_value());
+ ASSERT_FALSE(times->empty());
uint64_t sum = 0;
- for (size_t i = 0; i < times.size(); ++i) {
- for (auto x : times[i]) sum += x;
+ for (size_t i = 0; i < times->size(); ++i) {
+ for (auto x : (*times)[i]) sum += x;
}
ASSERT_GT(sum, (uint64_t)0);
ASSERT_TRUE(clearUidCpuFreqTimes(0));
- ASSERT_TRUE(getUidCpuFreqTimes(0, &times2));
- ASSERT_EQ(times2.size(), times.size());
- for (size_t i = 0; i < times.size(); ++i) {
- ASSERT_EQ(times2[i].size(), times[i].size());
- for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]);
+ auto times2 = getUidCpuFreqTimes(0);
+ ASSERT_TRUE(times2.has_value());
+ ASSERT_EQ(times2->size(), times->size());
+ for (size_t i = 0; i < times->size(); ++i) {
+ ASSERT_EQ((*times2)[i].size(), (*times)[i].size());
+ for (size_t j = 0; j < (*times)[i].size(); ++j) ASSERT_LE((*times2)[i][j], (*times)[i][j]);
}
}
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 40f6b43802..8e762f193f 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -46,6 +46,7 @@ static const char* native_processes_to_dump[] = {
static const char* hal_interfaces_to_dump[] {
"android.hardware.audio@2.0::IDevicesFactory",
"android.hardware.audio@4.0::IDevicesFactory",
+ "android.hardware.biometrics.face@1.0::IBiometricsFace",
"android.hardware.bluetooth@1.0::IBluetoothHci",
"android.hardware.camera.provider@2.4::ICameraProvider",
"android.hardware.drm@1.0::IDrmFactory",
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 1c5fa52855..24b6c2d6de 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -37,6 +37,7 @@
#include <memory>
#include <string>
+#include <thread>
// TODO(b/37049319) Get this from a header once one exists
extern "C" {
@@ -163,17 +164,20 @@ void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path,
void GraphicsEnv::hintActivityLaunch() {
ATRACE_CALL();
- // If there's already graphics driver preloaded in the process, just send
- // the stats info to GpuStats directly through async binder.
- std::lock_guard<std::mutex> lock(mStatsLock);
- if (mGpuStats.glDriverToSend) {
- mGpuStats.glDriverToSend = false;
- sendGpuStatsLocked(GraphicsEnv::Api::API_GL, true, mGpuStats.glDriverLoadingTime);
- }
- if (mGpuStats.vkDriverToSend) {
- mGpuStats.vkDriverToSend = false;
- sendGpuStatsLocked(GraphicsEnv::Api::API_VK, true, mGpuStats.vkDriverLoadingTime);
- }
+ std::thread trySendGpuStatsThread([this]() {
+ // If there's already graphics driver preloaded in the process, just send
+ // the stats info to GpuStats directly through async binder.
+ std::lock_guard<std::mutex> lock(mStatsLock);
+ if (mGpuStats.glDriverToSend) {
+ mGpuStats.glDriverToSend = false;
+ sendGpuStatsLocked(GraphicsEnv::Api::API_GL, true, mGpuStats.glDriverLoadingTime);
+ }
+ if (mGpuStats.vkDriverToSend) {
+ mGpuStats.vkDriverToSend = false;
+ sendGpuStatsLocked(GraphicsEnv::Api::API_VK, true, mGpuStats.vkDriverLoadingTime);
+ }
+ });
+ trySendGpuStatsThread.detach();
}
void GraphicsEnv::setGpuStats(const std::string& driverPackageName,
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index e0e3431ca5..b429d387ad 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -97,7 +97,9 @@ BufferQueueCore::BufferQueueCore() :
mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
HAL_DATASPACE_UNKNOWN),
mLastQueuedSlot(INVALID_BUFFER_SLOT),
- mUniqueId(getUniqueId())
+ mUniqueId(getUniqueId()),
+ mAutoPrerotation(false),
+ mTransformHintInUse(0)
{
int numStartingBuffers = getMaxBufferCountLocked();
for (int s = 0; s < numStartingBuffers; s++) {
@@ -123,10 +125,12 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const
mQueueBufferCanDrop, mLegacyBufferDrop);
outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(),
mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
- outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint,
- mFrameCounter);
+ outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.string(),
+ mTransformHint, mFrameCounter);
+ outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.string(),
+ mTransformHintInUse, mAutoPrerotation);
- outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size());
+ outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size());
Fifo::const_iterator current(mQueue.begin());
while (current != mQueue.end()) {
double timestamp = current->mTimestamp / 1e9;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9c311a314f..da091cc61f 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -408,6 +408,10 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou
if (useDefaultSize) {
width = mCore->mDefaultWidth;
height = mCore->mDefaultHeight;
+ if (mCore->mAutoPrerotation &&
+ (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) {
+ std::swap(width, height);
+ }
}
int found = BufferItem::INVALID_BUFFER_SLOT;
@@ -951,7 +955,7 @@ status_t BufferQueueProducer::queueBuffer(int slot,
output->width = mCore->mDefaultWidth;
output->height = mCore->mDefaultHeight;
- output->transformHint = mCore->mTransformHint;
+ output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint;
output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size());
output->nextFrameNumber = mCore->mFrameCounter + 1;
@@ -1132,9 +1136,6 @@ int BufferQueueProducer::query(int what, int *outValue) {
case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
value = static_cast<int32_t>(mCore->mConsumerIsProtected);
break;
- case NATIVE_WINDOW_MAX_BUFFER_COUNT:
- value = static_cast<int32_t>(mCore->mMaxBufferCount);
- break;
default:
return BAD_VALUE;
}
@@ -1194,11 +1195,12 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
output->width = mCore->mDefaultWidth;
output->height = mCore->mDefaultHeight;
- output->transformHint = mCore->mTransformHint;
+ output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint;
output->numPendingBuffers =
static_cast<uint32_t>(mCore->mQueue.size());
output->nextFrameNumber = mCore->mFrameCounter + 1;
output->bufferReplaced = false;
+ output->maxBufferCount = mCore->mMaxBufferCount;
if (listener != nullptr) {
// Set up a death notification so that we can disconnect
@@ -1298,6 +1300,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) {
mCore->mConnectedPid = -1;
mCore->mSidebandStream.clear();
mCore->mDequeueCondition.notify_all();
+ mCore->mAutoPrerotation = false;
listener = mCore->mConsumerListener;
} else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
BQ_LOGE("disconnect: not connected (req=%d)", api);
@@ -1341,6 +1344,8 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream)
void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
PixelFormat format, uint64_t usage) {
ATRACE_CALL();
+
+ const bool useDefaultSize = !width && !height;
while (true) {
size_t newBufferCount = 0;
uint32_t allocWidth = 0;
@@ -1367,6 +1372,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
allocWidth = width > 0 ? width : mCore->mDefaultWidth;
allocHeight = height > 0 ? height : mCore->mDefaultHeight;
+ if (useDefaultSize && mCore->mAutoPrerotation &&
+ (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) {
+ std::swap(allocWidth, allocHeight);
+ }
+
allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
allocUsage = usage | mCore->mConsumerUsageBits;
allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size());
@@ -1397,6 +1407,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
std::unique_lock<std::mutex> lock(mCore->mMutex);
uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth;
uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
+ if (useDefaultSize && mCore->mAutoPrerotation &&
+ (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) {
+ std::swap(checkWidth, checkHeight);
+ }
+
PixelFormat checkFormat = format != 0 ?
format : mCore->mDefaultBufferFormat;
uint64_t checkUsage = usage | mCore->mConsumerUsageBits;
@@ -1599,4 +1614,14 @@ status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const {
return NO_ERROR;
}
+status_t BufferQueueProducer::setAutoPrerotation(bool autoPrerotation) {
+ ATRACE_CALL();
+ BQ_LOGV("setAutoPrerotation: %d", autoPrerotation);
+
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
+
+ mCore->mAutoPrerotation = autoPrerotation;
+ return NO_ERROR;
+}
+
} // namespace android
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index f5cf1c4d5a..b8faa2df4c 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -32,10 +32,11 @@ namespace android {
// ---------------------------------------------------------------------------
-DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
+DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource,
+ ISurfaceComposer::ConfigChanged configChanged) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != nullptr) {
- mEventConnection = sf->createDisplayEventConnection(vsyncSource);
+ mEventConnection = sf->createDisplayEventConnection(vsyncSource, configChanged);
if (mEventConnection != nullptr) {
mDataChannel = std::make_unique<gui::BitTube>();
mEventConnection->stealReceiveChannel(mDataChannel.get());
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 0e03b7d393..0009a57653 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -73,6 +73,7 @@ enum {
GET_UNIQUE_ID,
GET_CONSUMER_USAGE,
SET_LEGACY_BUFFER_DROP,
+ SET_AUTO_PREROTATION,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -547,6 +548,17 @@ public:
}
return actualResult;
}
+
+ virtual status_t setAutoPrerotation(bool autoPrerotation) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeBool(autoPrerotation);
+ status_t result = remote()->transact(SET_AUTO_PREROTATION, data, &reply);
+ if (result == NO_ERROR) {
+ result = reply.readInt32();
+ }
+ return result;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -675,6 +687,10 @@ public:
status_t getConsumerUsage(uint64_t* outUsage) const override {
return mBase->getConsumerUsage(outUsage);
}
+
+ status_t setAutoPrerotation(bool autoPrerotation) override {
+ return mBase->setAutoPrerotation(autoPrerotation);
+ }
};
IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer,
@@ -688,6 +704,12 @@ status_t IGraphicBufferProducer::setLegacyBufferDrop(bool drop) {
return INVALID_OPERATION;
}
+status_t IGraphicBufferProducer::setAutoPrerotation(bool autoPrerotation) {
+ // No-op for IGBP other than BufferQueue.
+ (void)autoPrerotation;
+ return INVALID_OPERATION;
+}
+
status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
status_t res = OK;
res = parcel->writeUint32(USE_BUFFER_QUEUE);
@@ -1050,6 +1072,13 @@ status_t BnGraphicBufferProducer::onTransact(
reply->writeInt32(result);
return NO_ERROR;
}
+ case SET_AUTO_PREROTATION: {
+ CHECK_INTERFACE(IGraphicBuffer, data, reply);
+ bool autoPrerotation = data.readBool();
+ status_t result = setAutoPrerotation(autoPrerotation);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
@@ -1141,12 +1170,8 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten(
// ----------------------------------------------------------------------------
constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() {
- return sizeof(width) +
- sizeof(height) +
- sizeof(transformHint) +
- sizeof(numPendingBuffers) +
- sizeof(nextFrameNumber) +
- sizeof(bufferReplaced);
+ return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) +
+ sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount);
}
size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const {
@@ -1170,6 +1195,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::flatten(
FlattenableUtils::write(buffer, size, numPendingBuffers);
FlattenableUtils::write(buffer, size, nextFrameNumber);
FlattenableUtils::write(buffer, size, bufferReplaced);
+ FlattenableUtils::write(buffer, size, maxBufferCount);
return frameTimestamps.flatten(buffer, size, fds, count);
}
@@ -1187,6 +1213,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::unflatten(
FlattenableUtils::read(buffer, size, numPendingBuffers);
FlattenableUtils::read(buffer, size, nextFrameNumber);
FlattenableUtils::read(buffer, size, bufferReplaced);
+ FlattenableUtils::read(buffer, size, maxBufferCount);
return frameTimestamps.unflatten(buffer, size, fds, count);
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 6c9d81ab57..e487792c87 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -278,8 +278,8 @@ public:
return NO_ERROR;
}
- virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource)
- {
+ virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource,
+ ConfigChanged configChanged) {
Parcel data, reply;
sp<IDisplayEventConnection> result;
int err = data.writeInterfaceToken(
@@ -288,6 +288,7 @@ public:
return result;
}
data.writeInt32(static_cast<int32_t>(vsyncSource));
+ data.writeInt32(static_cast<int32_t>(configChanged));
err = remote()->transact(
BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
data, &reply);
@@ -1155,8 +1156,11 @@ status_t BnSurfaceComposer::onTransact(
}
case CREATE_DISPLAY_EVENT_CONNECTION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IDisplayEventConnection> connection(createDisplayEventConnection(
- static_cast<ISurfaceComposer::VsyncSource>(data.readInt32())));
+ auto vsyncSource = static_cast<ISurfaceComposer::VsyncSource>(data.readInt32());
+ auto configChanged = static_cast<ISurfaceComposer::ConfigChanged>(data.readInt32());
+
+ sp<IDisplayEventConnection> connection(
+ createDisplayEventConnection(vsyncSource, configChanged));
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index e6eb327c6f..4e6a4e7b4c 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -96,6 +96,7 @@ Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controll
mConnectedToCpu = false;
mProducerControlledByApp = controlledByApp;
mSwapIntervalZero = false;
+ mMaxBufferCount = 0;
}
Surface::~Surface() {
@@ -961,6 +962,10 @@ int Surface::query(int what, int* value) const {
*value = static_cast<int>(mDataSpace);
return NO_ERROR;
}
+ case NATIVE_WINDOW_MAX_BUFFER_COUNT: {
+ *value = mMaxBufferCount;
+ return NO_ERROR;
+ }
}
}
return mGraphicBufferProducer->query(what, value);
@@ -1072,6 +1077,9 @@ int Surface::perform(int operation, va_list args)
case NATIVE_WINDOW_GET_CONSUMER_USAGE64:
res = dispatchGetConsumerUsage64(args);
break;
+ case NATIVE_WINDOW_SET_AUTO_PREROTATION:
+ res = dispatchSetAutoPrerotation(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1272,6 +1280,11 @@ int Surface::dispatchGetConsumerUsage64(va_list args) {
return getConsumerUsage(usage);
}
+int Surface::dispatchSetAutoPrerotation(va_list args) {
+ bool autoPrerotation = va_arg(args, int);
+ return setAutoPrerotation(autoPrerotation);
+}
+
bool Surface::transformToDisplayInverse() {
return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
@@ -1298,6 +1311,7 @@ int Surface::connect(
mDefaultWidth = output.width;
mDefaultHeight = output.height;
mNextFrameNumber = output.nextFrameNumber;
+ mMaxBufferCount = output.maxBufferCount;
// Ignore transform hint if sticky transform is set or transform to display inverse flag is
// set. Transform hint should be ignored if the client is expected to always submit buffers
@@ -1339,6 +1353,7 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) {
mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
mTransform = 0;
mStickyTransform = 0;
+ mAutoPrerotation = false;
if (api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = false;
@@ -1920,7 +1935,8 @@ status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out)
return OK;
}
-status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer) {
+status_t Surface::attachAndQueueBufferWithDataspace(Surface* surface, sp<GraphicBuffer> buffer,
+ Dataspace dataspace) {
if (buffer == nullptr) {
return BAD_VALUE;
}
@@ -1929,6 +1945,11 @@ status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffe
if (err != OK) {
return err;
}
+ ui::Dataspace tmpDataspace = surface->getBuffersDataSpace();
+ err = surface->setBuffersDataSpace(dataspace);
+ if (err != OK) {
+ return err;
+ }
err = surface->attachBuffer(buffer->getNativeBuffer());
if (err != OK) {
return err;
@@ -1937,8 +1958,30 @@ status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffe
if (err != OK) {
return err;
}
+ err = surface->setBuffersDataSpace(tmpDataspace);
+ if (err != OK) {
+ return err;
+ }
err = surface->disconnect(NATIVE_WINDOW_API_CPU);
return err;
}
+int Surface::setAutoPrerotation(bool autoPrerotation) {
+ ATRACE_CALL();
+ ALOGV("Surface::setAutoPrerotation (%d)", autoPrerotation);
+ Mutex::Autolock lock(mMutex);
+
+ if (mAutoPrerotation == autoPrerotation) {
+ return OK;
+ }
+
+ status_t err = mGraphicBufferProducer->setAutoPrerotation(autoPrerotation);
+ if (err == NO_ERROR) {
+ mAutoPrerotation = autoPrerotation;
+ }
+ ALOGE_IF(err, "IGraphicBufferProducer::setAutoPrerotation(%d) returned %s", autoPrerotation,
+ strerror(-err));
+ return err;
+}
+
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index cc9e468e16..c59fddfb9d 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -322,10 +322,99 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
mTransactionNestCount(other.mTransactionNestCount),
mAnimation(other.mAnimation),
mEarlyWakeup(other.mEarlyWakeup),
+ mContainsBuffer(other.mContainsBuffer),
mDesiredPresentTime(other.mDesiredPresentTime) {
mDisplayStates = other.mDisplayStates;
mComposerStates = other.mComposerStates;
mInputWindowCommands = other.mInputWindowCommands;
+ mListenerCallbacks = other.mListenerCallbacks;
+}
+
+std::unique_ptr<SurfaceComposerClient::Transaction>
+SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) {
+ auto transaction = std::make_unique<Transaction>();
+ if (transaction->readFromParcel(parcel) == NO_ERROR) {
+ return transaction;
+ }
+ return nullptr;
+}
+
+status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) {
+ const uint32_t forceSynchronous = parcel->readUint32();
+ const uint32_t transactionNestCount = parcel->readUint32();
+ const bool animation = parcel->readBool();
+ const bool earlyWakeup = parcel->readBool();
+ const bool containsBuffer = parcel->readBool();
+ const int64_t desiredPresentTime = parcel->readInt64();
+
+ size_t count = static_cast<size_t>(parcel->readUint32());
+ if (count > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
+ SortedVector<DisplayState> displayStates;
+ displayStates.setCapacity(count);
+ for (size_t i = 0; i < count; i++) {
+ DisplayState displayState;
+ if (displayState.read(*parcel) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+ displayStates.add(displayState);
+ }
+
+ count = static_cast<size_t>(parcel->readUint32());
+ if (count > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
+ std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> composerStates;
+ composerStates.reserve(count);
+ for (size_t i = 0; i < count; i++) {
+ sp<SurfaceControl> surfaceControl = SurfaceControl::readFromParcel(parcel);
+
+ ComposerState composerState;
+ if (composerState.read(*parcel) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+ composerStates[surfaceControl] = composerState;
+ }
+
+ InputWindowCommands inputWindowCommands;
+ inputWindowCommands.read(*parcel);
+
+ // Parsing was successful. Update the object.
+ mForceSynchronous = forceSynchronous;
+ mTransactionNestCount = transactionNestCount;
+ mAnimation = animation;
+ mEarlyWakeup = earlyWakeup;
+ mContainsBuffer = containsBuffer;
+ mDesiredPresentTime = desiredPresentTime;
+ mDisplayStates = displayStates;
+ mComposerStates = composerStates;
+ mInputWindowCommands = inputWindowCommands;
+ // listener callbacks contain function pointer addresses and may not be safe to parcel.
+ mListenerCallbacks.clear();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const {
+ parcel->writeUint32(mForceSynchronous);
+ parcel->writeUint32(mTransactionNestCount);
+ parcel->writeBool(mAnimation);
+ parcel->writeBool(mEarlyWakeup);
+ parcel->writeBool(mContainsBuffer);
+ parcel->writeInt64(mDesiredPresentTime);
+ parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
+ for (auto const& displayState : mDisplayStates) {
+ displayState.write(*parcel);
+ }
+
+ parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size()));
+ for (auto const& [surfaceControl, composerState] : mComposerStates) {
+ surfaceControl->writeToParcel(parcel);
+ composerState.write(*parcel);
+ }
+
+ mInputWindowCommands.write(*parcel);
+ return NO_ERROR;
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
@@ -336,7 +425,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr
mComposerStates[kv.first].state.merge(kv.second.state);
}
}
- other.mComposerStates.clear();
for (auto const& state : other.mDisplayStates) {
ssize_t index = mDisplayStates.indexOf(state);
@@ -346,7 +434,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr
mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state);
}
}
- other.mDisplayStates.clear();
for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) {
auto& [callbackIds, surfaceControls] = callbackInfo;
@@ -357,17 +444,27 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr
.surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()),
std::make_move_iterator(surfaceControls.end()));
}
- other.mListenerCallbacks.clear();
mInputWindowCommands.merge(other.mInputWindowCommands);
- other.mInputWindowCommands.clear();
mContainsBuffer = other.mContainsBuffer;
- other.mContainsBuffer = false;
-
+ other.clear();
return *this;
}
+void SurfaceComposerClient::Transaction::clear() {
+ mComposerStates.clear();
+ mDisplayStates.clear();
+ mListenerCallbacks.clear();
+ mInputWindowCommands.clear();
+ mContainsBuffer = false;
+ mForceSynchronous = 0;
+ mTransactionNestCount = 0;
+ mAnimation = false;
+ mEarlyWakeup = false;
+ mDesiredPresentTime = -1;
+}
+
void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle,
const sp<ISurfaceComposerClient>& client) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 55488dad0b..b9defdd120 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -71,14 +71,6 @@ SurfaceControl::~SurfaceControl()
release();
}
-void SurfaceControl::destroy()
-{
- if (isValid()) {
- SurfaceComposerClient::Transaction().reparent(this, nullptr).apply();
- }
- release();
-}
-
void SurfaceControl::release()
{
// Trigger an IPC now, to make sure things
@@ -186,8 +178,7 @@ void SurfaceControl::writeToParcel(Parcel* parcel)
parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer));
}
-sp<SurfaceControl> SurfaceControl::readFromParcel(Parcel* parcel)
-{
+sp<SurfaceControl> SurfaceControl::readFromParcel(const Parcel* parcel) {
sp<IBinder> client = parcel->readStrongBinder();
sp<IBinder> handle = parcel->readStrongBinder();
if (client == nullptr || handle == nullptr)
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 690a85f395..205e79c879 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -348,6 +348,14 @@ private:
const uint64_t mUniqueId;
+ // When buffer size is driven by the consumer and mTransformHint specifies
+ // a 90 or 270 degree rotation, this indicates whether the width and height
+ // used by dequeueBuffer will be additionally swapped.
+ bool mAutoPrerotation;
+
+ // mTransformHintInUse is to cache the mTransformHint used by the producer.
+ uint32_t mTransformHintInUse;
+
}; // class BufferQueueCore
} // namespace android
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index d2a47a6aa8..9ad92a6e78 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -190,6 +190,9 @@ public:
// See IGraphicBufferProducer::getConsumerUsage
virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+ // See IGraphicBufferProducer::setAutoPrerotation
+ virtual status_t setAutoPrerotation(bool autoPrerotation);
+
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 22de751498..a558cf9e18 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -88,10 +88,13 @@ public:
* DisplayEventReceiver creates and registers an event connection with
* SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate
* or requestNextVsync to receive them.
+ * To receive Config Changed events specify this in the constructor.
* Other events start being delivered immediately.
*/
explicit DisplayEventReceiver(
- ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
+ ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
+ ISurfaceComposer::ConfigChanged configChanged =
+ ISurfaceComposer::eConfigChangedSuppress);
/*
* ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 3dde8c8c80..abe1e3f6e6 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -412,6 +412,7 @@ public:
uint64_t nextFrameNumber{0};
FrameEventHistoryDelta frameTimestamps;
bool bufferReplaced{false};
+ int maxBufferCount{0};
};
virtual status_t queueBuffer(int slot, const QueueBufferInput& input,
@@ -629,6 +630,14 @@ public:
// NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute.
virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0;
+ // Enable/disable the auto prerotation at buffer allocation when the buffer
+ // size is driven by the consumer.
+ //
+ // When buffer size is driven by the consumer and the transform hint
+ // specifies a 90 or 270 degree rotation, if auto prerotation is enabled,
+ // the width and height used for dequeueBuffer will be additionally swapped.
+ virtual status_t setAutoPrerotation(bool autoPrerotation);
+
// Static method exports any IGraphicBufferProducer object to a parcel. It
// handles null producer as well.
static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e2f77365b3..c84910b6ec 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -90,6 +90,8 @@ public:
eVsyncSourceSurfaceFlinger = 1
};
+ enum ConfigChanged { eConfigChangedSuppress = 0, eConfigChangedDispatch = 1 };
+
/*
* Create a connection with SurfaceFlinger.
*/
@@ -97,7 +99,8 @@ public:
/* return an IDisplayEventConnection */
virtual sp<IDisplayEventConnection> createDisplayEventConnection(
- VsyncSource vsyncSource = eVsyncSourceApp) = 0;
+ VsyncSource vsyncSource = eVsyncSourceApp,
+ ConfigChanged configChanged = eConfigChangedSuppress) = 0;
/* create a virtual display
* requires ACCESS_SURFACE_FLINGER permission.
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 0c471bb701..fe528b3711 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -230,6 +230,7 @@ private:
int dispatchGetWideColorSupport(va_list args);
int dispatchGetHdrSupport(va_list args);
int dispatchGetConsumerUsage64(va_list args);
+ int dispatchSetAutoPrerotation(va_list args);
bool transformToDisplayInverse();
protected:
@@ -265,6 +266,7 @@ public:
virtual int setAsyncMode(bool async);
virtual int setSharedBufferMode(bool sharedBufferMode);
virtual int setAutoRefresh(bool autoRefresh);
+ virtual int setAutoPrerotation(bool autoPrerotation);
virtual int setBuffersDimensions(uint32_t width, uint32_t height);
virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
virtual int unlockAndPost();
@@ -292,7 +294,8 @@ public:
ui::Dataspace getBuffersDataSpace();
- static status_t attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer);
+ static status_t attachAndQueueBufferWithDataspace(Surface* surface, sp<GraphicBuffer> buffer,
+ ui::Dataspace dataspace);
protected:
enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
@@ -433,6 +436,7 @@ protected:
// Caches the values that have been passed to the producer.
bool mSharedBufferMode;
bool mAutoRefresh;
+ bool mAutoPrerotation;
// If in shared buffer mode and auto refresh is enabled, store the shared
// buffer slot and return it for all calls to queue/dequeue without going
@@ -465,6 +469,7 @@ protected:
bool mReportRemovedBuffers = false;
std::vector<sp<GraphicBuffer>> mRemovedBuffers;
+ int mMaxBufferCount;
};
} // namespace android
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0e17c7b015..4dda97f5e1 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -285,7 +285,7 @@ public:
std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls;
};
- class Transaction {
+ class Transaction : Parcelable {
std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
SortedVector<DisplayState > mDisplayStates;
std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
@@ -325,6 +325,15 @@ public:
virtual ~Transaction() = default;
Transaction(Transaction const& other);
+ // Factory method that creates a new Transaction instance from the parcel.
+ static std::unique_ptr<Transaction> createFromParcel(const Parcel* parcel);
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ // Clears the contents of the transaction without applying it.
+ void clear();
+
status_t apply(bool synchronous = false);
// Merge another transaction in to this one, clearing other
// as if it had been applied.
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 23bfc0256b..ae4a14690f 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -44,7 +44,7 @@ class SurfaceComposerClient;
class SurfaceControl : public RefBase
{
public:
- static sp<SurfaceControl> readFromParcel(Parcel* parcel);
+ static sp<SurfaceControl> readFromParcel(const Parcel* parcel);
void writeToParcel(Parcel* parcel);
static bool isValid(const sp<SurfaceControl>& surface) {
@@ -81,7 +81,7 @@ public:
status_t getLayerFrameStats(FrameStats* outStats) const;
sp<SurfaceComposerClient> getClient() const;
-
+
explicit SurfaceControl(const sp<SurfaceControl>& other);
SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 119e888edb..98dc1e6337 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -169,6 +169,18 @@ TEST_F(BufferQueueTest, DISABLED_BufferQueueInAnotherProcess) {
ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
}
+TEST_F(BufferQueueTest, GetMaxBufferCountInQueueBufferOutput_Succeeds) {
+ createBufferQueue();
+ sp<DummyConsumer> dc(new DummyConsumer);
+ mConsumer->consumerConnect(dc, false);
+ int bufferCount = 50;
+ mConsumer->setMaxBufferCount(bufferCount);
+
+ IGraphicBufferProducer::QueueBufferOutput output;
+ mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output);
+ ASSERT_EQ(output.maxBufferCount, bufferCount);
+}
+
TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 960cf1846e..7718bc1b8e 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -548,8 +548,8 @@ public:
}
sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
- sp<IDisplayEventConnection> createDisplayEventConnection(ISurfaceComposer::VsyncSource)
- override {
+ sp<IDisplayEventConnection> createDisplayEventConnection(
+ ISurfaceComposer::VsyncSource, ISurfaceComposer::ConfigChanged) override {
return nullptr;
}
sp<IBinder> createDisplay(const String8& /*displayName*/,
@@ -1746,4 +1746,74 @@ TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) {
EXPECT_EQ(-1, outDisplayPresentTime);
}
+TEST_F(SurfaceTest, DequeueWithConsumerDrivenSize) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+ consumer->consumerConnect(dummyConsumer, false);
+ consumer->setDefaultBufferSize(10, 10);
+
+ sp<Surface> surface = new Surface(producer);
+ sp<ANativeWindow> window(surface);
+ native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+ native_window_set_buffers_dimensions(window.get(), 0, 0);
+
+ int fence;
+ ANativeWindowBuffer* buffer;
+
+ // Buffer size is driven by the consumer
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(10, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+
+ // Buffer size is driven by the consumer
+ consumer->setDefaultBufferSize(10, 20);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(20, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+
+ // Transform hint isn't synced to producer before queueBuffer or connect
+ consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(20, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence));
+
+ // Transform hint is synced to producer but no auto prerotation
+ consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(20, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+
+ // Prerotation is driven by the consumer with the transform hint used by producer
+ native_window_set_auto_prerotation(window.get(), true);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(20, buffer->width);
+ EXPECT_EQ(10, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+
+ // Turn off auto prerotaton
+ native_window_set_auto_prerotation(window.get(), false);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(20, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+
+ // Test auto prerotation bit is disabled after disconnect
+ native_window_set_auto_prerotation(window.get(), true);
+ native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_CPU);
+ native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+ consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270);
+ native_window_set_buffers_dimensions(window.get(), 0, 0);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(20, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+}
+
} // namespace android
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 0c22bfefed..56900c129e 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -38,29 +38,29 @@ KeyMap::KeyMap() {
KeyMap::~KeyMap() {
}
-status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
+status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier,
const PropertyMap* deviceConfiguration) {
// Use the configured key layout if available.
if (deviceConfiguration) {
String8 keyLayoutName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
keyLayoutName)) {
- status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str());
+ status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
"it was not found.",
- deviceIdenfifier.name.c_str(), keyLayoutName.string());
+ deviceIdentifier.name.c_str(), keyLayoutName.string());
}
}
String8 keyCharacterMapName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
keyCharacterMapName)) {
- status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str());
+ status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard character "
"map '%s' but it was not found.",
- deviceIdenfifier.name.c_str(), keyLayoutName.string());
+ deviceIdentifier.name.c_str(), keyCharacterMapName.string());
}
}
@@ -70,25 +70,25 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
}
// Try searching by device identifier.
- if (probeKeyMap(deviceIdenfifier, "")) {
+ if (probeKeyMap(deviceIdentifier, "")) {
return OK;
}
// Fall back on the Generic key map.
// TODO Apply some additional heuristics here to figure out what kind of
// generic key map to use (US English, etc.) for typical external keyboards.
- if (probeKeyMap(deviceIdenfifier, "Generic")) {
+ if (probeKeyMap(deviceIdentifier, "Generic")) {
return OK;
}
// Try the Virtual key map as a last resort.
- if (probeKeyMap(deviceIdenfifier, "Virtual")) {
+ if (probeKeyMap(deviceIdentifier, "Virtual")) {
return OK;
}
// Give up!
ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
- deviceIdenfifier.name.c_str());
+ deviceIdentifier.name.c_str());
return NAME_NOT_FOUND;
}
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 8435dac636..1751443419 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -262,3 +262,7 @@ int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMo
int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh) {
return native_window_set_auto_refresh(window, autoRefresh);
}
+
+int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation) {
+ return native_window_set_auto_prerotation(window, autoPrerotation);
+}
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 61590e0196..8cbf0a4244 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -203,41 +203,42 @@ enum {
*/
enum {
// clang-format off
- NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */
- NATIVE_WINDOW_CONNECT = 1, /* deprecated */
- NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
- NATIVE_WINDOW_SET_CROP = 3, /* private */
- NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
- NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
- NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
- NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
- NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
- NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
- NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
- NATIVE_WINDOW_LOCK = 11, /* private */
- NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
- NATIVE_WINDOW_API_CONNECT = 13, /* private */
- NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
- NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
- NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */
- NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */
- NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
- NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
- NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
- NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
- NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
- NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23,
- NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
- NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
- NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
- NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
- NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
- NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
- NATIVE_WINDOW_SET_USAGE64 = 30,
- NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
- NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
- NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
+ NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */
+ NATIVE_WINDOW_CONNECT = 1, /* deprecated */
+ NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
+ NATIVE_WINDOW_SET_CROP = 3, /* private */
+ NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
+ NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
+ NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
+ NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
+ NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
+ NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
+ NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
+ NATIVE_WINDOW_LOCK = 11, /* private */
+ NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
+ NATIVE_WINDOW_API_CONNECT = 13, /* private */
+ NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
+ NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
+ NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */
+ NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */
+ NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
+ NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
+ NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
+ NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
+ NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
+ NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23,
+ NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
+ NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
+ NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
+ NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
+ NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
+ NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
+ NATIVE_WINDOW_SET_USAGE64 = 30,
+ NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
+ NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
+ NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34,
+ NATIVE_WINDOW_SET_AUTO_PREROTATION = 35,
// clang-format on
};
@@ -985,4 +986,18 @@ static inline int native_window_get_consumer_usage(struct ANativeWindow* window,
return window->perform(window, NATIVE_WINDOW_GET_CONSUMER_USAGE64, outUsage);
}
+/*
+ * native_window_set_auto_prerotation(..., autoPrerotation)
+ * Enable/disable the auto prerotation at buffer allocation when the buffer size
+ * is driven by the consumer.
+ *
+ * When buffer size is driven by the consumer and the transform hint specifies
+ * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and
+ * height used for dequeueBuffer will be additionally swapped.
+ */
+static inline int native_window_set_auto_prerotation(struct ANativeWindow* window,
+ bool autoPrerotation) {
+ return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation);
+}
+
__END_DECLS
diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h
index 995ba44d20..500052c936 100644
--- a/libs/nativewindow/include/vndk/window.h
+++ b/libs/nativewindow/include/vndk/window.h
@@ -316,6 +316,15 @@ int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMo
*/
int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh);
+/*
+ * Enable/disable the auto prerotation at buffer allocation when the buffer size
+ * is driven by the consumer.
+ *
+ * When buffer size is driven by the consumer and the transform hint specifies
+ * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and
+ * height used for dequeueBuffer will be additionally swapped.
+ */
+int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation);
/*****************************************************************************/
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index bad8b11540..119a07dad7 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -28,6 +28,7 @@ LIBNATIVEWINDOW {
ANativeWindow_queryf; # vndk
ANativeWindow_queueBuffer; # vndk
ANativeWindow_release;
+ ANativeWindow_setAutoPrerotation; # vndk
ANativeWindow_setAutoRefresh; # vndk
ANativeWindow_setBufferCount; # vndk
ANativeWindow_setBuffersDataSpace; # introduced=28
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 46a8e9eecf..6e7ec336e9 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -456,10 +456,6 @@ void GLESRenderEngine::primeCache() const {
mFeatureFlags & USE_COLOR_MANAGEMENT);
}
-bool GLESRenderEngine::isCurrent() const {
- return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
-}
-
base::unique_fd GLESRenderEngine::flush() {
ATRACE_CALL();
if (!GLExtensions::getInstance().hasNativeFenceSync()) {
@@ -795,7 +791,6 @@ status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0);
uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-
ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
glStatus);
@@ -1013,33 +1008,6 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
return NO_ERROR;
}
-void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
- ui::Transform::orientation_flags rotation) {
- setViewportAndProjection(Rect(vpw, vph), sourceCrop);
-
- if (rotation == ui::Transform::ROT_0) {
- return;
- }
-
- // Apply custom rotation to the projection.
- float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
- mat4 m = mState.projectionMatrix;
- switch (rotation) {
- case ui::Transform::ROT_90:
- m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m;
- break;
- case ui::Transform::ROT_180:
- m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m;
- break;
- case ui::Transform::ROT_270:
- m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m;
- break;
- default:
- break;
- }
- mState.projectionMatrix = m;
-}
-
void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) {
ATRACE_CALL();
mVpWidth = viewport.getWidth();
@@ -1103,14 +1071,6 @@ void GLESRenderEngine::setupLayerTexturing(const Texture& texture) {
mState.textureEnabled = true;
}
-void GLESRenderEngine::setupLayerBlackedOut() {
- glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
- Texture texture(Texture::TEXTURE_2D, mProtectedTexName);
- texture.setDimensions(1, 1); // FIXME: we should get that from somewhere
- mState.texture = texture;
- mState.textureEnabled = true;
-}
-
void GLESRenderEngine::setColorTransform(const mat4& colorTransform) {
mState.colorMatrix = colorTransform;
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index de793c2142..70b704abce 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -50,7 +50,6 @@ class GLESRenderEngine : public impl::RenderEngine {
public:
static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags,
uint32_t imageCacheSize);
- static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy,
@@ -58,17 +57,7 @@ public:
uint32_t imageCacheSize);
~GLESRenderEngine() override EXCLUDES(mRenderingMutex);
- std::unique_ptr<Framebuffer> createFramebuffer() override;
- std::unique_ptr<Image> createImage() override;
-
void primeCache() const override;
- bool isCurrent() const override;
- base::unique_fd flush() override;
- bool finish() override;
- bool waitFence(base::unique_fd fenceFd) override;
- void clearWithColor(float red, float green, float blue, float alpha) override;
- void fillRegionWithColor(const Region& region, float red, float green, float blue,
- float alpha) override;
void genTextures(size_t count, uint32_t* names) override;
void deleteTextures(size_t count, uint32_t const* names) override;
void bindExternalTextureImage(uint32_t texName, const Image& image) override;
@@ -78,7 +67,6 @@ public:
void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex);
status_t bindFrameBuffer(Framebuffer* framebuffer) override;
void unbindFrameBuffer(Framebuffer* framebuffer) override;
- void checkErrors() const override;
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
@@ -88,9 +76,7 @@ public:
base::unique_fd&& bufferFence, base::unique_fd* drawFence)
EXCLUDES(mRenderingMutex) override;
- // internal to RenderEngine
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
- EGLConfig getEGLConfig() const { return mEGLConfig; }
// Creates an output image for rendering to
EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected,
bool useFramebufferCache);
@@ -104,27 +90,6 @@ public:
protected:
Framebuffer* getFramebufferForDrawing() override;
void dump(std::string& result) override;
- void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
- ui::Transform::orientation_flags rotation) override;
- void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
- const half4& color, float cornerRadius) override;
- void setupLayerTexturing(const Texture& texture) override;
- void setupLayerBlackedOut() override;
- void setupFillWithColor(float r, float g, float b, float a) override;
- void setColorTransform(const mat4& colorTransform) override;
- void disableTexturing() override;
- void disableBlending() override;
- void setupCornerRadiusCropSize(float width, float height) override;
-
- // HDR and color management related functions and state
- void setSourceY410BT2020(bool enable) override;
- void setSourceDataSpace(ui::Dataspace source) override;
- void setOutputDataSpace(ui::Dataspace dataspace) override;
- void setDisplayMaxLuminance(const float maxLuminance) override;
-
- // drawing
- void drawMesh(const Mesh& mesh) override;
-
size_t getMaxTextureSize() const override;
size_t getMaxViewportDims() const override;
@@ -136,12 +101,16 @@ private:
GLES_VERSION_3_0 = 0x30000,
};
+ static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
static GlesVersion parseGlesVersion(const char* str);
static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
EGLContext shareContext, bool useContextPriority,
Protection protection);
static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
int hwcFormat, Protection protection);
+ std::unique_ptr<Framebuffer> createFramebuffer();
+ std::unique_ptr<Image> createImage();
+ void checkErrors() const;
void setScissor(const Rect& region);
void disableScissor();
bool waitSync(EGLSyncKHR sync, EGLint flags);
@@ -165,6 +134,28 @@ private:
// blending is an expensive operation, we want to turn off blending when it's not necessary.
void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer,
const Mesh& mesh);
+ base::unique_fd flush();
+ bool finish();
+ bool waitFence(base::unique_fd fenceFd);
+ void clearWithColor(float red, float green, float blue, float alpha);
+ void fillRegionWithColor(const Region& region, float red, float green, float blue, float alpha);
+ void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+ const half4& color, float cornerRadius);
+ void setupLayerTexturing(const Texture& texture);
+ void setupFillWithColor(float r, float g, float b, float a);
+ void setColorTransform(const mat4& colorTransform);
+ void disableTexturing();
+ void disableBlending();
+ void setupCornerRadiusCropSize(float width, float height);
+
+ // HDR and color management related functions and state
+ void setSourceY410BT2020(bool enable);
+ void setSourceDataSpace(ui::Dataspace source);
+ void setOutputDataSpace(ui::Dataspace dataspace);
+ void setDisplayMaxLuminance(const float maxLuminance);
+
+ // drawing
+ void drawMesh(const Mesh& mesh);
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index e7070041f2..8a798eefd1 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -77,10 +77,6 @@ public:
// This interface, while still in use until a suitable replacement is built,
// should be considered deprecated, minus some methods which still may be
// used to support legacy behavior.
-
- virtual std::unique_ptr<Framebuffer> createFramebuffer() = 0;
- virtual std::unique_ptr<Image> createImage() = 0;
-
virtual void primeCache() const = 0;
// dump the extension strings. always call the base class.
@@ -88,24 +84,6 @@ public:
virtual bool useNativeFenceSync() const = 0;
virtual bool useWaitSync() const = 0;
-
- virtual bool isCurrent() const = 0;
-
- // helpers
- // flush submits RenderEngine command stream for execution and returns a
- // native fence fd that is signaled when the execution has completed. It
- // returns -1 on errors.
- virtual base::unique_fd flush() = 0;
- // finish waits until RenderEngine command stream has been executed. It
- // returns false on errors.
- virtual bool finish() = 0;
- // waitFence inserts a wait on an external fence fd to RenderEngine
- // command stream. It returns false on errors.
- virtual bool waitFence(base::unique_fd fenceFd) = 0;
-
- virtual void clearWithColor(float red, float green, float blue, float alpha) = 0;
- virtual void fillRegionWithColor(const Region& region, float red, float green, float blue,
- float alpha) = 0;
virtual void genTextures(size_t count, uint32_t* names) = 0;
virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
@@ -126,40 +104,6 @@ public:
virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0;
- // set-up
- virtual void checkErrors() const = 0;
- virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
- ui::Transform::orientation_flags rotation) = 0;
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
- const half4& color, float cornerRadius) = 0;
- virtual void setupLayerTexturing(const Texture& texture) = 0;
- virtual void setupLayerBlackedOut() = 0;
- virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
- // Sets up the crop size for corner radius clipping.
- //
- // Having corner radius will force GPU composition on the layer and its children, drawing it
- // with a special shader. The shader will receive the radius and the crop rectangle as input,
- // modifying the opacity of the destination texture, multiplying it by a number between 0 and 1.
- // We query Layer#getRoundedCornerState() to retrieve the radius as well as the rounded crop
- // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be
- // in local layer coordinate space, so we have to take the layer transform into account when
- // walking up the tree.
- virtual void setupCornerRadiusCropSize(float width, float height) = 0;
-
- // Set a color transform matrix that is applied in linear space right before OETF.
- virtual void setColorTransform(const mat4& /* colorTransform */) = 0;
- virtual void disableTexturing() = 0;
- virtual void disableBlending() = 0;
-
- // HDR and color management support
- virtual void setSourceY410BT2020(bool enable) = 0;
- virtual void setSourceDataSpace(ui::Dataspace source) = 0;
- virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0;
- virtual void setDisplayMaxLuminance(const float maxLuminance) = 0;
-
- // drawing
- virtual void drawMesh(const Mesh& mesh) = 0;
-
// queries
virtual size_t getMaxTextureSize() const = 0;
virtual size_t getMaxViewportDims() const = 0;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index e33bcfd994..f099cd2455 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -34,20 +34,12 @@ public:
RenderEngine();
~RenderEngine() override;
- MOCK_METHOD0(createFramebuffer, std::unique_ptr<renderengine::Framebuffer>());
- MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>());
MOCK_METHOD0(getFramebufferForDrawing, Framebuffer*());
MOCK_CONST_METHOD0(primeCache, void());
MOCK_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(useNativeFenceSync, bool());
MOCK_CONST_METHOD0(useWaitSync, bool());
MOCK_CONST_METHOD0(isCurrent, bool());
- MOCK_METHOD0(flush, base::unique_fd());
- MOCK_METHOD0(finish, bool());
- MOCK_METHOD1(waitFence, bool(base::unique_fd*));
- bool waitFence(base::unique_fd fd) override { return waitFence(&fd); };
- MOCK_METHOD4(clearWithColor, void(float, float, float, float));
- MOCK_METHOD5(fillRegionWithColor, void(const Region&, float, float, float, float));
MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
@@ -55,22 +47,6 @@ public:
MOCK_METHOD3(bindExternalTextureBuffer,
status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&));
MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
- MOCK_CONST_METHOD0(checkErrors, void());
- MOCK_METHOD4(setViewportAndProjection,
- void(size_t, size_t, Rect, ui::Transform::orientation_flags));
- MOCK_METHOD5(setupLayerBlending, void(bool, bool, bool, const half4&, float));
- MOCK_METHOD1(setupLayerTexturing, void(const Texture&));
- MOCK_METHOD0(setupLayerBlackedOut, void());
- MOCK_METHOD4(setupFillWithColor, void(float, float, float, float));
- MOCK_METHOD2(setupCornerRadiusCropSize, void(float, float));
- MOCK_METHOD1(setColorTransform, void(const mat4&));
- MOCK_METHOD1(setSaturationMatrix, void(const mat4&));
- MOCK_METHOD0(disableTexturing, void());
- MOCK_METHOD0(disableBlending, void());
- MOCK_METHOD1(setSourceY410BT2020, void(bool));
- MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace));
- MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace));
- MOCK_METHOD1(setDisplayMaxLuminance, void(const float));
MOCK_METHOD1(bindFrameBuffer, status_t(renderengine::Framebuffer*));
MOCK_METHOD1(unbindFrameBuffer, void(renderengine::Framebuffer*));
MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&));
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 5840d51079..96d5eb9d1f 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -94,7 +94,7 @@ SensorManager& SensorManager::getInstanceForPackage(const String16& packageName)
SensorManager::SensorManager(const String16& opPackageName)
: mSensorList(nullptr), mOpPackageName(opPackageName), mDirectConnectionHandle(1) {
- // okay we're not locked here, but it's not needed during construction
+ Mutex::Autolock _l(mLock);
assertStateLocked();
}
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index da91a979fe..1dfc1e9e88 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#define LOG_TAG "BufferHubBuffer"
#include <poll.h>
#include <android-base/unique_fd.h>
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 3fc6a2d34a..579e68e917 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -626,7 +626,7 @@ status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& si
bufferHubBuffer->desc().layers, bufferHubBuffer->desc().usage,
bufferHubBuffer->desc().stride);
mBufferId = bufferHubBuffer->id();
- mBufferHubBuffer.reset(std::move(bufferHubBuffer.get()));
+ mBufferHubBuffer = std::move(bufferHubBuffer);
return NO_ERROR;
}
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 373fa4f221..c5170d091c 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -46,6 +46,24 @@ cc_test {
cflags: ["-Wall", "-Werror"],
}
+// This test has a main method, and requires a separate binary to be built.
+cc_test {
+ name: "GraphicBufferOverBinder_test",
+ srcs: ["GraphicBufferOverBinder_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+ header_libs: [
+ "libdvr_headers",
+ ],
+ shared_libs: [
+ "android.frameworks.bufferhub@1.0",
+ "libbinder",
+ "libgui",
+ "liblog",
+ "libui",
+ "libutils",
+ ],
+}
+
cc_test {
name: "BufferHub_test",
header_libs: [
diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
new file mode 100644
index 0000000000..7c0a44a64f
--- /dev/null
+++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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 "GraphicBufferOverBinder_test"
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <gui/BufferQueue.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <ui/BufferHubBuffer.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Log.h>
+
+namespace android {
+
+constexpr uint32_t kTestWidth = 1024;
+constexpr uint32_t kTestHeight = 1;
+constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB;
+constexpr uint32_t kTestLayerCount = 1;
+constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN;
+static const String16 kTestServiceName = String16("GraphicBufferOverBinderTestService");
+enum GraphicBufferOverBinderTestServiceCode {
+ GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+ GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER,
+};
+
+class GraphicBufferOverBinderTestService : public BBinder {
+public:
+ GraphicBufferOverBinderTestService() {
+ // GraphicBuffer
+ mGraphicBuffer = new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount,
+ kTestUsage);
+ ALOGI("mGraphicBuffer id %" PRIi32, mGraphicBuffer->getBufferId());
+
+ // BufferHub-backed GraphicBuffer
+ std::unique_ptr<BufferHubBuffer> bufferHubBuffer =
+ BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
+ kTestUsage, /*userMetadataSize=*/0);
+ mBufferhubBackedGraphicBuffer = new GraphicBuffer(std::move(bufferHubBuffer));
+ if (!mBufferhubBackedGraphicBuffer->isBufferHubBuffer()) {
+ ALOGE("Failed to back GraphicBuffer with BufferHub.");
+ }
+ if (bufferHubBuffer != nullptr) {
+ ALOGE("Failed to move BufferHubBuffer to GraphicBuffer");
+ }
+ ALOGI("mBufferhubBackedGraphicBuffer id %" PRIi32,
+ mBufferhubBackedGraphicBuffer->getBufferId());
+ }
+
+ ~GraphicBufferOverBinderTestService() = default;
+
+ virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply,
+ uint32_t /*flags*/ = 0) {
+ switch (code) {
+ case GRAPHIC_BUFFER: {
+ return reply->write(*mGraphicBuffer);
+ }
+ case GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER: {
+ return reply->write(*mBufferhubBackedGraphicBuffer);
+ }
+ default:
+ return UNKNOWN_TRANSACTION;
+ };
+ }
+
+protected:
+ sp<GraphicBuffer> mGraphicBuffer;
+ sp<GraphicBuffer> mBufferhubBackedGraphicBuffer;
+};
+
+static int runBinderServer() {
+ ProcessState::self()->startThreadPool();
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<GraphicBufferOverBinderTestService> service = new GraphicBufferOverBinderTestService;
+ sm->addService(kTestServiceName, service, false);
+
+ ALOGI("Binder server running...");
+
+ while (true) {
+ int stat, retval;
+ retval = wait(&stat);
+ if (retval == -1 && errno == ECHILD) {
+ break;
+ }
+ }
+
+ ALOGI("Binder server exiting...");
+ return 0;
+}
+
+class GraphicBufferOverBinderTest : public ::testing::TestWithParam<uint32_t> {
+protected:
+ virtual void SetUp() {
+ mService = defaultServiceManager()->getService(kTestServiceName);
+ if (mService == nullptr) {
+ ALOGE("Failed to connect to the test service.");
+ return;
+ }
+
+ ALOGI("Binder service is ready for client.");
+ }
+
+ status_t GetGraphicBuffer(sp<GraphicBuffer>* outBuf, uint32_t opCode) {
+ Parcel data;
+ Parcel reply;
+ status_t error = mService->transact(opCode, data, &reply);
+ if (error != NO_ERROR) {
+ ALOGE("Failed to get graphic buffer over binder, error=%d.", error);
+ return error;
+ }
+
+ *outBuf = new GraphicBuffer();
+ return reply.read(**outBuf);
+ }
+
+private:
+ sp<IBinder> mService;
+};
+
+TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferOverBinder) {
+ sp<GraphicBuffer> gb;
+ EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER), OK);
+ EXPECT_NE(gb, nullptr);
+ EXPECT_FALSE(gb->isBufferHubBuffer());
+ void* vaddr;
+ EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK);
+ EXPECT_EQ(gb->unlock(), OK);
+}
+
+TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferFromBufferHubBufferOverBinder) {
+ sp<GraphicBuffer> gb;
+ EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER), NO_ERROR);
+ EXPECT_NE(gb, nullptr);
+ EXPECT_TRUE(gb->isBufferHubBuffer());
+ void* vaddr;
+ EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK);
+ EXPECT_EQ(gb->unlock(), OK);
+}
+
+} // namespace android
+
+int main(int argc, char** argv) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ android::ProcessState::self()->startThreadPool();
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+
+ } else {
+ ALOGI("Test process pid: %d.", pid);
+ return android::runBinderServer();
+ }
+}
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
index a4b81feffc..cd03bc2be7 100644
--- a/services/bufferhub/Android.bp
+++ b/services/bufferhub/Android.bp
@@ -63,6 +63,7 @@ cc_binary {
"libbufferhubservice",
"libcrypto",
"libcutils",
+ "libhidlbase",
"libhidltransport",
"libhwbinder",
"liblog",
diff --git a/services/gpuservice/OWNERS b/services/gpuservice/OWNERS
new file mode 100644
index 0000000000..5d028393f6
--- /dev/null
+++ b/services/gpuservice/OWNERS
@@ -0,0 +1,3 @@
+chrisforbes@google.com
+lpy@google.com
+zzyiwei@google.com
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 6a7f2797f4..7c061c5857 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -276,7 +276,7 @@ void MotionClassifier::enqueueEvent(ClassifierEvent&& event) {
bool eventAdded = mEvents.push(std::move(event));
if (!eventAdded) {
// If the queue is full, suspect the HAL is slow in processing the events.
- ALOGE("Dropped event with eventTime %" PRId64, event.args->eventTime);
+ ALOGE("Could not add the event to the queue. Resetting");
reset();
}
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 9aa4e85e2f..6e953f4af6 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -149,13 +149,14 @@ filegroup {
"Scheduler/DispSyncSource.cpp",
"Scheduler/EventControlThread.cpp",
"Scheduler/EventThread.cpp",
- "Scheduler/IdleTimer.cpp",
+ "Scheduler/OneShotTimer.cpp",
"Scheduler/LayerHistory.cpp",
"Scheduler/LayerInfo.cpp",
"Scheduler/MessageQueue.cpp",
+ "Scheduler/PhaseOffsets.cpp",
"Scheduler/Scheduler.cpp",
"Scheduler/SchedulerUtils.cpp",
- "Scheduler/PhaseOffsets.cpp",
+ "Scheduler/VSyncModulator.cpp",
"StartPropertySetThread.cpp",
"SurfaceFlinger.cpp",
"SurfaceInterceptor.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 9d723998c4..f51fbb45f6 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -19,9 +19,7 @@
#define LOG_TAG "BufferLayer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <cmath>
-#include <cstdlib>
-#include <mutex>
+#include "BufferLayer.h"
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
@@ -45,11 +43,14 @@
#include <utils/StopWatch.h>
#include <utils/Trace.h>
-#include "BufferLayer.h"
+#include <cmath>
+#include <cstdlib>
+#include <mutex>
+#include <sstream>
+
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "LayerRejecter.h"
-
#include "TimeStats/TimeStats.h"
namespace android {
@@ -525,6 +526,9 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime)
}
if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
+ std::stringstream ss;
+ ss << "Dropping sync point " << (*point)->getFrameNumber();
+ ATRACE_NAME(ss.str().c_str());
point = mLocalSyncPoints.erase(point);
} else {
++point;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 6709fb4b48..096cd1a9cc 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -419,30 +419,6 @@ std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const {
return mCurrentFenceTime;
}
-status_t BufferLayerConsumer::doFenceWaitLocked() const {
- if (mCurrentFence->isValid()) {
- if (mRE.useWaitSync()) {
- base::unique_fd fenceFd(mCurrentFence->dup());
- if (fenceFd == -1) {
- BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno);
- return -errno;
- }
- if (!mRE.waitFence(std::move(fenceFd))) {
- BLC_LOGE("doFenceWait: failed to wait on fence fd");
- return UNKNOWN_ERROR;
- }
- } else {
- status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doFenceWaitLocked");
- if (err != NO_ERROR) {
- BLC_LOGE("doFenceWait: error waiting for fence: %d", err);
- return err;
- }
- }
- }
-
- return NO_ERROR;
-}
-
void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
std::lock_guard<std::mutex> lock(mImagesMutex);
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index e3f6100c35..144686c83d 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -252,11 +252,6 @@ private:
// mCurrentTextureImage must not be nullptr.
void computeCurrentTransformMatrixLocked();
- // doFenceWaitLocked inserts a wait command into the RenderEngine command
- // stream to ensure that it is safe for future RenderEngine commands to
- // access the current texture buffer.
- status_t doFenceWaitLocked() const;
-
// getCurrentCropLocked returns the cropping rectangle of the current buffer.
Rect getCurrentCropLocked() const;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 57f1008e85..d6853661a5 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -201,7 +201,7 @@ uint64_t BufferQueueLayer::getFrameNumber() const {
uint64_t frameNumber = mQueueItems[0].mFrameNumber;
// The head of the queue will be dropped if there are signaled and timely frames behind it
- nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime();
+ nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
@@ -279,7 +279,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
getTransformToDisplayInverse(), mFreezeGeometryUpdates);
- nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime();
+ nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 482c723a15..6bfd302b5c 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -87,11 +87,18 @@ status_t Client::createWithSurfaceParent(const String8& name, uint32_t w, uint32
LayerMetadata metadata, sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp) {
if (mFlinger->authenticateSurfaceTexture(parent) == false) {
+ ALOGE("failed to authenticate surface texture");
+ // The extra parent layer check below before returning is to help with debugging
+ // b/134888387. Once the bug is fixed the check can be deleted.
+ if ((static_cast<MonitoredProducer*>(parent.get()))->getLayer() == nullptr) {
+ ALOGE("failed to find parent layer");
+ }
return BAD_VALUE;
}
const auto& layer = (static_cast<MonitoredProducer*>(parent.get()))->getLayer();
if (layer == nullptr) {
+ ALOGE("failed to find parent layer");
return BAD_VALUE;
}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index e21128ca81..9bff73e950 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -83,10 +83,6 @@ public:
// Called after the HWC calls are made to present the display
virtual void onPresentDisplayCompleted() = 0;
- // Called to set the viewport and projection state for rendering into this
- // surface
- virtual void setViewportAndProjection() = 0;
-
// Called after the surface has been rendering to signal the surface should
// be made ready for displaying
virtual void flip() = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 0f57315eb6..e4c9c80429 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -56,7 +56,6 @@ public:
sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override;
void queueBuffer(base::unique_fd&& readyFence) override;
void onPresentDisplayCompleted() override;
- void setViewportAndProjection() override;
void flip() override;
// Debugging
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index ca2299aa26..146a2eae64 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -41,7 +41,6 @@ public:
MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
MOCK_METHOD0(onPresentDisplayCompleted, void());
- MOCK_METHOD0(setViewportAndProjection, void());
MOCK_METHOD0(flip, void());
MOCK_CONST_METHOD1(dump, void(std::string& result));
MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 3fcd9d155d..8a91316e65 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -215,13 +215,6 @@ void RenderSurface::onPresentDisplayCompleted() {
mDisplaySurface->onFrameCommitted();
}
-void RenderSurface::setViewportAndProjection() {
- auto& renderEngine = mCompositionEngine.getRenderEngine();
- Rect sourceCrop = Rect(mSize);
- renderEngine.setViewportAndProjection(mSize.width, mSize.height, sourceCrop,
- ui::Transform::ROT_0);
-}
-
void RenderSurface::flip() {
mPageFlipCount++;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index f75a4dcb85..87419ea6a8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -364,20 +364,6 @@ TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) {
}
/* ------------------------------------------------------------------------
- * RenderSurface::setViewportAndProjection()
- */
-
-TEST_F(RenderSurfaceTest, setViewportAndProjectionAppliesChang) {
- mSurface.setSizeForTest(ui::Size(100, 200));
-
- EXPECT_CALL(mRenderEngine,
- setViewportAndProjection(100, 200, Rect(100, 200), ui::Transform::ROT_0))
- .Times(1);
-
- mSurface.setViewportAndProjection();
-}
-
-/* ------------------------------------------------------------------------
* RenderSurface::flip()
*/
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index cc5a5b5729..7f47a2ecd4 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -24,6 +24,7 @@
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
#include <gui/BufferQueue.h>
+#include <hidl/HidlTransportSupport.h>
#include <hidl/HidlTransportUtils.h>
namespace android {
@@ -229,6 +230,7 @@ std::string Composer::dumpDebugInfo()
void Composer::registerCallback(const sp<IComposerCallback>& callback)
{
+ android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2);
auto ret = mClient->registerCallback(callback);
if (!ret.isOk()) {
ALOGE("failed to register IComposerCallback");
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index cae1b46c57..83ab5cfce2 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -19,12 +19,7 @@
#define LOG_TAG "Layer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <math.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <algorithm>
-#include <mutex>
+#include "Layer.h"
#include <android-base/stringprintf.h>
#include <compositionengine/Display.h>
@@ -39,7 +34,11 @@
#include <gui/BufferItem.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
+#include <math.h>
#include <renderengine/RenderEngine.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
#include <ui/DebugUtils.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
@@ -49,12 +48,15 @@
#include <utils/StopWatch.h>
#include <utils/Trace.h>
+#include <algorithm>
+#include <mutex>
+#include <sstream>
+
#include "BufferLayer.h"
#include "ColorLayer.h"
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
-#include "Layer.h"
#include "LayerProtoHelper.h"
#include "LayerRejecter.h"
#include "MonitoredProducer.h"
@@ -617,32 +619,6 @@ bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) {
// local state
// ----------------------------------------------------------------------------
-void Layer::computeGeometry(const RenderArea& renderArea,
- renderengine::Mesh& mesh,
- bool useIdentityTransform) const {
- const ui::Transform renderAreaTransform(renderArea.getTransform());
- FloatRect win = getBounds();
-
- vec2 lt = vec2(win.left, win.top);
- vec2 lb = vec2(win.left, win.bottom);
- vec2 rb = vec2(win.right, win.bottom);
- vec2 rt = vec2(win.right, win.top);
-
- ui::Transform layerTransform = getTransform();
- if (!useIdentityTransform) {
- lt = layerTransform.transform(lt);
- lb = layerTransform.transform(lb);
- rb = layerTransform.transform(rb);
- rt = layerTransform.transform(rt);
- }
-
- renderengine::Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
- position[0] = renderAreaTransform.transform(lt);
- position[1] = renderAreaTransform.transform(lb);
- position[2] = renderAreaTransform.transform(rb);
- position[3] = renderAreaTransform.transform(rt);
-}
-
bool Layer::isSecure() const {
const State& s(mDrawingState);
return (s.flags & layer_state_t::eLayerSecure);
@@ -677,6 +653,7 @@ void Layer::pushPendingState() {
if (!mCurrentState.modified) {
return;
}
+ ATRACE_CALL();
// If this transaction is waiting on the receipt of a frame, generate a sync
// point and send it to the remote layer.
@@ -693,6 +670,9 @@ void Layer::pushPendingState() {
} else {
auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy, this);
if (barrierLayer->addSyncPoint(syncPoint)) {
+ std::stringstream ss;
+ ss << "Adding sync point " << mCurrentState.frameNumber_legacy;
+ ATRACE_NAME(ss.str().c_str());
mRemoteSyncPoints.push_back(std::move(syncPoint));
} else {
// We already missed the frame we're supposed to synchronize
@@ -710,6 +690,7 @@ void Layer::pushPendingState() {
}
void Layer::popPendingState(State* stateToCommit) {
+ ATRACE_CALL();
*stateToCommit = mPendingStates[0];
mPendingStates.removeAt(0);
@@ -741,6 +722,7 @@ bool Layer::applyPendingStates(State* stateToCommit) {
}
if (mRemoteSyncPoints.front()->frameIsAvailable()) {
+ ATRACE_NAME("frameIsAvailable");
// Apply the state update
popPendingState(stateToCommit);
stateUpdateAvailable = true;
@@ -749,6 +731,7 @@ bool Layer::applyPendingStates(State* stateToCommit) {
mRemoteSyncPoints.front()->setTransactionApplied();
mRemoteSyncPoints.pop_front();
} else {
+ ATRACE_NAME("!frameIsAvailable");
break;
}
} else {
@@ -1195,6 +1178,7 @@ uint32_t Layer::getLayerStack() const {
}
void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
+ ATRACE_CALL();
mCurrentState.barrierLayer_legacy = barrierLayer;
mCurrentState.frameNumber_legacy = frameNumber;
// We don't set eTransactionNeeded, because just receiving a deferral
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6db6beb4f6..8a4d87f889 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -357,8 +357,6 @@ public:
return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
}
- void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh,
- bool useIdentityTransform) const;
FloatRect getBounds(const Region& activeTransparentRegion) const;
FloatRect getBounds() const;
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index c60421b538..7a959f7b19 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -154,6 +154,10 @@ status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const {
return mProducer->getConsumerUsage(outUsage);
}
+status_t MonitoredProducer::setAutoPrerotation(bool autoPrerotation) {
+ return mProducer->setAutoPrerotation(autoPrerotation);
+}
+
IBinder* MonitoredProducer::onAsBinder() {
return this;
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index d346f821d3..788919b3da 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -70,6 +70,7 @@ public:
virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override;
virtual status_t getUniqueId(uint64_t* outId) const override;
virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+ virtual status_t setAutoPrerotation(bool autoPrerotation) override;
// The Layer which created this producer, and on which queued Buffer's will be displayed.
sp<Layer> getLayer() const;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 66906e950c..72bbf5dc26 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -258,7 +258,7 @@ void RegionSamplingThread::binderDied(const wp<IBinder>& who) {
namespace {
// Using Rec. 709 primaries
-float getLuma(float r, float g, float b) {
+inline float getLuma(float r, float g, float b) {
constexpr auto rec709_red_primary = 0.2126f;
constexpr auto rec709_green_primary = 0.7152f;
constexpr auto rec709_blue_primary = 0.0722f;
@@ -293,10 +293,10 @@ float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t st
const uint32_t* rowBase = data + row * stride;
for (int32_t column = area.left; column < area.right; ++column) {
uint32_t pixel = rowBase[column];
- const float r = (pixel & 0xFF) / 255.0f;
- const float g = ((pixel >> 8) & 0xFF) / 255.0f;
- const float b = ((pixel >> 16) & 0xFF) / 255.0f;
- const uint8_t luma = std::round(getLuma(r, g, b) * 255.0f);
+ const float r = pixel & 0xFF;
+ const float g = (pixel >> 8) & 0xFF;
+ const float b = (pixel >> 16) & 0xFF;
+ const uint8_t luma = std::round(getLuma(r, g, b));
++brightnessBuckets[luma];
if (brightnessBuckets[luma] > majoritySampleNum) return luma / 255.0f;
}
@@ -342,9 +342,19 @@ void RegionSamplingThread::captureSample() {
}
const auto device = mFlinger.getDefaultDisplayDevice();
- const auto display = device->getCompositionDisplay();
- const auto state = display->getState();
- const auto orientation = static_cast<ui::Transform::orientation_flags>(state.orientation);
+ 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());
std::vector<RegionSamplingThread::Descriptor> descriptors;
Region sampleRegion;
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 3c6fcf3872..ac7339c42a 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -27,7 +27,7 @@
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
#include <utils/StrongPointer.h>
-#include "Scheduler/IdleTimer.h"
+#include "Scheduler/OneShotTimer.h"
namespace android {
@@ -107,7 +107,7 @@ private:
SurfaceFlinger& mFlinger;
Scheduler& mScheduler;
const TimingTunables mTunables;
- scheduler::IdleTimer mIdleTimer;
+ scheduler::OneShotTimer mIdleTimer;
std::unique_ptr<SamplingOffsetCallback> const mPhaseCallback;
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 95ff9d0c73..83fd42b43f 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -92,9 +92,12 @@ public:
mPeriod = period;
if (!mModelLocked && referenceTimeChanged) {
for (auto& eventListener : mEventListeners) {
- eventListener.mHasFired = false;
- eventListener.mLastEventTime =
- mReferenceTime - mPeriod + mPhase + eventListener.mPhase;
+ eventListener.mLastEventTime = mReferenceTime + mPhase + eventListener.mPhase;
+ // If mLastEventTime is after mReferenceTime (can happen when positive phase offsets
+ // are used) we treat it as like it happened in previous period.
+ if (eventListener.mLastEventTime > mReferenceTime) {
+ eventListener.mLastEventTime -= mPeriod;
+ }
}
}
if (mTraceDetailedInfo) {
@@ -123,13 +126,6 @@ public:
void unlockModel() {
Mutex::Autolock lock(mMutex);
- if (mModelLocked) {
- for (auto& eventListener : mEventListeners) {
- if (eventListener.mLastEventTime > mReferenceTime) {
- eventListener.mHasFired = true;
- }
- }
- }
mModelLocked = false;
ATRACE_INT("DispSync:ModelLocked", mModelLocked);
}
@@ -259,10 +255,6 @@ public:
listener.mLastCallbackTime = lastCallbackTime;
}
- if (!mModelLocked && listener.mLastEventTime > mReferenceTime) {
- listener.mHasFired = true;
- }
-
mEventListeners.push_back(listener);
mCond.signal();
@@ -300,12 +292,8 @@ public:
// new offset to allow for a seamless offset change without double-firing or
// skipping.
nsecs_t diff = oldPhase - phase;
- if (diff > mPeriod / 2) {
- diff -= mPeriod;
- } else if (diff < -mPeriod / 2) {
- diff += mPeriod;
- }
eventListener.mLastEventTime -= diff;
+ eventListener.mLastCallbackTime -= diff;
mCond.signal();
return NO_ERROR;
}
@@ -320,7 +308,6 @@ private:
nsecs_t mLastEventTime;
nsecs_t mLastCallbackTime;
DispSync::Callback* mCallback;
- bool mHasFired = false;
};
struct CallbackInvocation {
@@ -368,12 +355,7 @@ private:
eventListener.mName);
continue;
}
- if (eventListener.mHasFired && !mModelLocked) {
- eventListener.mLastEventTime = t;
- ALOGV("[%s] [%s] Skipping event due to already firing", mName,
- eventListener.mName);
- continue;
- }
+
CallbackInvocation ci;
ci.mCallback = eventListener.mCallback;
ci.mEventTime = t;
@@ -382,7 +364,6 @@ private:
callbackInvocations.push_back(ci);
eventListener.mLastEventTime = t;
eventListener.mLastCallbackTime = now;
- eventListener.mHasFired = true;
}
}
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 00948aedb4..026b55707c 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -27,18 +27,23 @@
namespace android {
-DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
+DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset,
+ nsecs_t offsetThresholdForNextVsync, bool traceVsync,
const char* name)
: mName(name),
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)),
+ mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)),
+ mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)),
mDispSync(dispSync),
- mPhaseOffset(phaseOffset) {}
+ mPhaseOffset(phaseOffset),
+ mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {}
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
if (enable) {
+ tracePhaseOffset();
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
static_cast<DispSync::Callback*>(this),
mLastCallbackTime);
@@ -64,16 +69,17 @@ void DispSyncSource::setCallback(VSyncSource::Callback* callback) {
void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) {
std::lock_guard lock(mVsyncMutex);
-
- // Normalize phaseOffset to [0, period)
- auto period = mDispSync->getPeriod();
- phaseOffset %= period;
- if (phaseOffset < 0) {
- // If we're here, then phaseOffset is in (-period, 0). After this
- // operation, it will be in (0, period)
- phaseOffset += period;
+ const nsecs_t period = mDispSync->getPeriod();
+ // Check if offset should be handled as negative
+ if (phaseOffset >= mOffsetThresholdForNextVsync) {
+ phaseOffset -= period;
}
+
+ // Normalize phaseOffset to [-period, period)
+ const int numPeriods = phaseOffset / period;
+ phaseOffset -= numPeriods * period;
mPhaseOffset = phaseOffset;
+ tracePhaseOffset();
// If we're not enabled, we don't need to mess with the listeners
if (!mEnabled) {
@@ -92,11 +98,11 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) {
{
std::lock_guard lock(mCallbackMutex);
callback = mCallback;
+ }
- if (mTraceVsync) {
- mValue = (mValue + 1) % 2;
- ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
- }
+ if (mTraceVsync) {
+ mValue = (mValue + 1) % 2;
+ ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
}
if (callback != nullptr) {
@@ -104,4 +110,14 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) {
}
}
-} // namespace android \ No newline at end of file
+void DispSyncSource::tracePhaseOffset() {
+ if (mPhaseOffset > 0) {
+ ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset);
+ ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0);
+ } else {
+ ATRACE_INT(mVsyncOffsetLabel.c_str(), 0);
+ ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset);
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 4759699c5e..50560a5a2b 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -25,7 +25,8 @@ namespace android {
class DispSyncSource final : public VSyncSource, private DispSync::Callback {
public:
- DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name);
+ DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, nsecs_t offsetThresholdForNextVsync,
+ bool traceVsync, const char* name);
~DispSyncSource() override = default;
@@ -38,12 +39,16 @@ private:
// The following method is the implementation of the DispSync::Callback.
virtual void onDispSyncEvent(nsecs_t when);
+ void tracePhaseOffset() REQUIRES(mVsyncMutex);
+
const char* const mName;
int mValue = 0;
const bool mTraceVsync;
const std::string mVsyncOnLabel;
const std::string mVsyncEventLabel;
+ const std::string mVsyncOffsetLabel;
+ const std::string mVsyncNegativeOffsetLabel;
nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0;
DispSync* mDispSync;
@@ -53,7 +58,8 @@ private:
std::mutex mVsyncMutex;
nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex);
+ const nsecs_t mOffsetThresholdForNextVsync;
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
};
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 05bad4ddd8..9d1f777859 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -76,6 +76,10 @@ std::string toString(const DisplayEventReceiver::Event& event) {
return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
", count=%u}",
event.header.displayId, event.vsync.count);
+ case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+ return StringPrintf("ConfigChanged{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+ ", configId=%u}",
+ event.header.displayId, event.config.configId);
default:
return "Event{}";
}
@@ -107,8 +111,10 @@ DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, int32
} // namespace
EventThreadConnection::EventThreadConnection(EventThread* eventThread,
- ResyncCallback resyncCallback)
+ ResyncCallback resyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged)
: resyncCallback(std::move(resyncCallback)),
+ configChanged(configChanged),
mEventThread(eventThread),
mChannel(gui::BitTube::DefaultSize) {}
@@ -203,8 +209,10 @@ void EventThread::setPhaseOffset(nsecs_t phaseOffset) {
mVSyncSource->setPhaseOffset(phaseOffset);
}
-sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const {
- return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback));
+sp<EventThreadConnection> EventThread::createEventConnection(
+ ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) const {
+ return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
+ configChanged);
}
status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -398,9 +406,11 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event,
const sp<EventThreadConnection>& connection) const {
switch (event.header.type) {
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
- case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
return true;
+ case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+ return connection->configChanged == ISurfaceComposer::eConfigChangedDispatch;
+
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
switch (connection->vsyncRequest) {
case VSyncRequest::None:
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 61530c62e5..dd23b88726 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -69,7 +69,8 @@ public:
class EventThreadConnection : public BnDisplayEventConnection {
public:
- EventThreadConnection(EventThread*, ResyncCallback);
+ EventThreadConnection(EventThread*, ResyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged);
virtual ~EventThreadConnection();
virtual status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -82,6 +83,7 @@ public:
const ResyncCallback resyncCallback;
VSyncRequest vsyncRequest = VSyncRequest::None;
+ const ISurfaceComposer::ConfigChanged configChanged;
private:
virtual void onFirstRef();
@@ -93,7 +95,8 @@ class EventThread {
public:
virtual ~EventThread();
- virtual sp<EventThreadConnection> createEventConnection(ResyncCallback) const = 0;
+ virtual sp<EventThreadConnection> createEventConnection(
+ ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const = 0;
// called before the screen is turned off from main thread
virtual void onScreenReleased() = 0;
@@ -128,7 +131,8 @@ public:
EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback, const char* threadName);
~EventThread();
- sp<EventThreadConnection> createEventConnection(ResyncCallback) const override;
+ sp<EventThreadConnection> createEventConnection(
+ ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const override;
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 1db43a32cd..f80c2336f7 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -46,11 +46,13 @@ LayerHistory::LayerHistory() {
LayerHistory::~LayerHistory() = default;
std::unique_ptr<LayerHistory::LayerHandle> LayerHistory::createLayer(const std::string name,
+ float minRefreshRate,
float maxRefreshRate) {
const int64_t id = sNextId++;
std::lock_guard lock(mLock);
- mInactiveLayerInfos.emplace(id, std::make_shared<LayerInfo>(name, maxRefreshRate));
+ mInactiveLayerInfos.emplace(id,
+ std::make_shared<LayerInfo>(name, minRefreshRate, maxRefreshRate));
return std::make_unique<LayerHistory::LayerHandle>(*this, id);
}
@@ -173,5 +175,18 @@ void LayerHistory::removeIrrelevantLayers() {
}
}
+void LayerHistory::clearHistory() {
+ std::lock_guard lock(mLock);
+
+ auto it = mActiveLayerInfos.begin();
+ while (it != mActiveLayerInfos.end()) {
+ auto id = it->first;
+ auto layerInfo = it->second;
+ layerInfo->clearHistory();
+ mInactiveLayerInfos.insert({id, layerInfo});
+ it = mActiveLayerInfos.erase(it);
+ }
+}
+
} // namespace scheduler
} // namespace android \ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index adc5ce5f64..5598cc1cf5 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -53,7 +53,8 @@ public:
~LayerHistory();
// When the layer is first created, register it.
- std::unique_ptr<LayerHandle> createLayer(const std::string name, float maxRefreshRate);
+ std::unique_ptr<LayerHandle> createLayer(const std::string name, float minRefreshRate,
+ float maxRefreshRate);
// Method for inserting layers and their requested present time into the unordered map.
void insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime, bool isHdr);
@@ -64,6 +65,9 @@ public:
// layers. See go/content-fps-detection-in-scheduler for more information.
std::pair<float, bool> getDesiredRefreshRateAndHDR();
+ // Clears all layer history.
+ void clearHistory();
+
// Removes the handle and the object from the map.
void destroyLayer(const int64_t id);
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 95d7d31564..beddb9be61 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -24,9 +24,10 @@
namespace android {
namespace scheduler {
-LayerInfo::LayerInfo(const std::string name, float maxRefreshRate)
+LayerInfo::LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate)
: mName(name),
mMinRefreshDuration(1e9f / maxRefreshRate),
+ mLowActivityRefreshDuration(1e9f / minRefreshRate),
mRefreshRateHistory(mMinRefreshDuration) {}
LayerInfo::~LayerInfo() = default;
@@ -38,10 +39,16 @@ void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) {
mLastUpdatedTime = std::max(lastPresentTime, systemTime());
mPresentTimeHistory.insertPresentTime(mLastUpdatedTime);
+ if (mLastPresentTime == 0) {
+ // First frame
+ mLastPresentTime = lastPresentTime;
+ return;
+ }
+
const nsecs_t timeDiff = lastPresentTime - mLastPresentTime;
mLastPresentTime = lastPresentTime;
// Ignore time diff that are too high - those are stale values
- if (timeDiff > TIME_EPSILON_NS.count()) return;
+ if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return;
const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration;
mRefreshRateHistory.insertRefreshRate(refreshDuration);
}
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 02b6aefa2b..2c50053ebd 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -55,7 +55,7 @@ class LayerInfo {
float getRefreshRateAvg() const {
nsecs_t refreshDuration = mMinRefreshDuration;
- if (mElements.size() == HISTORY_SIZE) {
+ if (mElements.size() > 0) {
refreshDuration = scheduler::calculate_mean(mElements);
}
@@ -86,13 +86,42 @@ class LayerInfo {
// Checks whether the present time that was inserted HISTORY_SIZE ago is within a
// certain threshold: TIME_EPSILON_NS.
bool isRelevant() const {
- const int64_t obsoleteEpsilon = systemTime() - scheduler::TIME_EPSILON_NS.count();
- // The layer had to publish at least HISTORY_SIZE of updates, and the first
- // update should not be older than TIME_EPSILON_NS nanoseconds.
- if (mElements.size() == HISTORY_SIZE &&
- mElements.at(HISTORY_SIZE - 1) > obsoleteEpsilon) {
+ if (mElements.size() < 2) {
+ return false;
+ }
+
+ // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
+ if (mElements.size() != HISTORY_SIZE &&
+ mElements.at(mElements.size() - 1) - mElements.at(0) < HISTORY_TIME.count()) {
+ return false;
+ }
+
+ // The last update should not be older than OBSOLETE_TIME_EPSILON_NS nanoseconds.
+ const int64_t obsoleteEpsilon =
+ systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count();
+ if (mElements.at(mElements.size() - 1) < obsoleteEpsilon) {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool isLowActivityLayer() const {
+ // We want to make sure that we received more than two frames from the layer
+ // in order to check low activity.
+ if (mElements.size() < 2) {
+ return false;
+ }
+
+ const int64_t obsoleteEpsilon =
+ systemTime() - scheduler::LOW_ACTIVITY_EPSILON_NS.count();
+ // Check the frame before last to determine whether there is low activity.
+ // If that frame is older than LOW_ACTIVITY_EPSILON_NS, the layer is sending
+ // infrequent updates.
+ if (mElements.at(mElements.size() - 2) < obsoleteEpsilon) {
return true;
}
+
return false;
}
@@ -101,10 +130,11 @@ class LayerInfo {
private:
std::deque<nsecs_t> mElements;
static constexpr size_t HISTORY_SIZE = 10;
+ static constexpr std::chrono::nanoseconds HISTORY_TIME = 500ms;
};
public:
- LayerInfo(const std::string name, float maxRefreshRate);
+ LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate);
~LayerInfo();
LayerInfo(const LayerInfo&) = delete;
@@ -134,6 +164,10 @@ public:
// Calculate the average refresh rate.
float getDesiredRefreshRate() const {
std::lock_guard lock(mLock);
+
+ if (mPresentTimeHistory.isLowActivityLayer()) {
+ return 1e9f / mLowActivityRefreshDuration;
+ }
return mRefreshRateHistory.getRefreshRateAvg();
}
@@ -165,6 +199,7 @@ public:
private:
const std::string mName;
const nsecs_t mMinRefreshDuration;
+ const nsecs_t mLowActivityRefreshDuration;
mutable std::mutex mLock;
nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0;
nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index baf900df52..fcb307f213 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -96,7 +96,8 @@ void MessageQueue::setEventThread(android::EventThread* eventThread,
}
mEventThread = eventThread;
- mEvents = eventThread->createEventConnection(std::move(resyncCallback));
+ mEvents = eventThread->createEventConnection(std::move(resyncCallback),
+ ISurfaceComposer::eConfigChangedSuppress);
mEvents->stealReceiveChannel(&mEventTube);
mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
this);
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index 37fdfc7c62..4870a3bbdd 100644
--- a/services/surfaceflinger/Scheduler/IdleTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "IdleTimer.h"
+#include "OneShotTimer.h"
#include <chrono>
#include <thread>
@@ -22,23 +22,23 @@
namespace android {
namespace scheduler {
-IdleTimer::IdleTimer(const Interval& interval, const ResetCallback& resetCallback,
- const TimeoutCallback& timeoutCallback)
+OneShotTimer::OneShotTimer(const Interval& interval, const ResetCallback& resetCallback,
+ const TimeoutCallback& timeoutCallback)
: mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {}
-IdleTimer::~IdleTimer() {
+OneShotTimer::~OneShotTimer() {
stop();
}
-void IdleTimer::start() {
+void OneShotTimer::start() {
{
std::lock_guard<std::mutex> lock(mMutex);
mState = TimerState::RESET;
}
- mThread = std::thread(&IdleTimer::loop, this);
+ mThread = std::thread(&OneShotTimer::loop, this);
}
-void IdleTimer::stop() {
+void OneShotTimer::stop() {
{
std::lock_guard<std::mutex> lock(mMutex);
mState = TimerState::STOPPED;
@@ -49,7 +49,7 @@ void IdleTimer::stop() {
}
}
-void IdleTimer::loop() {
+void OneShotTimer::loop() {
while (true) {
bool triggerReset = false;
bool triggerTimeout = false;
@@ -100,7 +100,7 @@ void IdleTimer::loop() {
}
} // namespace scheduler
-void IdleTimer::reset() {
+void OneShotTimer::reset() {
{
std::lock_guard<std::mutex> lock(mMutex);
mState = TimerState::RESET;
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h
index 2646688860..fd1aa02226 100644
--- a/services/surfaceflinger/Scheduler/IdleTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -29,15 +29,15 @@ namespace scheduler {
* Class that sets off a timer for a given interval, and fires a callback when the
* interval expires.
*/
-class IdleTimer {
+class OneShotTimer {
public:
using Interval = std::chrono::milliseconds;
using ResetCallback = std::function<void()>;
using TimeoutCallback = std::function<void()>;
- IdleTimer(const Interval& interval, const ResetCallback& resetCallback,
- const TimeoutCallback& timeoutCallback);
- ~IdleTimer();
+ OneShotTimer(const Interval& interval, const ResetCallback& resetCallback,
+ const TimeoutCallback& timeoutCallback);
+ ~OneShotTimer();
// Initializes and turns on the idle timer.
void start();
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 276bce1f89..8a2604f4a3 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -25,6 +25,7 @@ using namespace android::sysprop;
namespace scheduler {
+using RefreshRateType = RefreshRateConfigs::RefreshRateType;
PhaseOffsets::~PhaseOffsets() = default;
namespace impl {
@@ -72,25 +73,32 @@ PhaseOffsets::PhaseOffsets() {
property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1");
const int phaseOffsetThresholdForNextVsyncNs = atoi(value);
- mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs
- : sfVsyncPhaseOffsetNs,
- earlyAppOffsetNs != -1 ? earlyAppOffsetNs
- : vsyncPhaseOffsetNs};
- mDefaultRefreshRateOffsets.earlyGl = {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs
- : sfVsyncPhaseOffsetNs,
- earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs
- : vsyncPhaseOffsetNs};
- mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
-
- mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
- : highFpsLateSfOffsetNs,
- highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
- : highFpsLateAppOffsetNs};
- mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
- : highFpsLateSfOffsetNs,
- highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
- : highFpsLateAppOffsetNs};
- mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs};
+ Offsets defaultOffsets;
+ Offsets highFpsOffsets;
+ defaultOffsets.early = {RefreshRateType::DEFAULT,
+ earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
+ earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
+ defaultOffsets.earlyGl = {RefreshRateType::DEFAULT,
+ earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
+ earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
+ defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
+
+ highFpsOffsets.early = {RefreshRateType::PERFORMANCE,
+ highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
+ : highFpsLateSfOffsetNs,
+ highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
+ : highFpsLateAppOffsetNs};
+ highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE,
+ highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
+ : highFpsLateSfOffsetNs,
+ highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
+ : highFpsLateAppOffsetNs};
+ highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs,
+ highFpsLateAppOffsetNs};
+
+ mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets});
+ mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets});
+ mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets});
mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1
? phaseOffsetThresholdForNextVsyncNs
@@ -99,12 +107,7 @@ PhaseOffsets::PhaseOffsets() {
PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(
android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const {
- switch (refreshRateType) {
- case RefreshRateConfigs::RefreshRateType::PERFORMANCE:
- return mHighRefreshRateOffsets;
- default:
- return mDefaultRefreshRateOffsets;
- }
+ return mOffsets.at(refreshRateType);
}
void PhaseOffsets::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index dc71e6eb60..2b5c2f10f1 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -17,6 +17,7 @@
#pragma once
#include <cinttypes>
+#include <unordered_map>
#include "RefreshRateConfigs.h"
#include "VSyncModulator.h"
@@ -79,14 +80,10 @@ public:
void dump(std::string& result) const override;
private:
- Offsets getDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; }
- Offsets getHighRefreshRateOffsets() { return mHighRefreshRateOffsets; }
-
std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
RefreshRateConfigs::RefreshRateType::DEFAULT;
- Offsets mDefaultRefreshRateOffsets;
- Offsets mHighRefreshRateOffsets;
+ std::unordered_map<RefreshRateConfigs::RefreshRateType, Offsets> mOffsets;
nsecs_t mOffsetThresholdForNextVsync;
};
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index e2a348e146..65f0e40ffe 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -38,9 +38,9 @@
#include "DispSyncSource.h"
#include "EventControlThread.h"
#include "EventThread.h"
-#include "IdleTimer.h"
#include "InjectVSyncSource.h"
#include "LayerInfo.h"
+#include "OneShotTimer.h"
#include "SchedulerUtils.h"
#include "SurfaceFlingerProperties.h"
@@ -86,50 +86,47 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
if (mSetIdleTimerMs > 0) {
if (mSupportKernelTimer) {
- mIdleTimer =
- std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(
- mSetIdleTimerMs),
- [this] { resetKernelTimerCallback(); },
- [this] {
- expiredKernelTimerCallback();
- });
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
+ std::chrono::milliseconds(mSetIdleTimerMs),
+ [this] { resetKernelTimerCallback(); },
+ [this] { expiredKernelTimerCallback(); });
} else {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(
- mSetIdleTimerMs),
- [this] { resetTimerCallback(); },
- [this] { expiredTimerCallback(); });
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
+ std::chrono::milliseconds(mSetIdleTimerMs), [this] { resetTimerCallback(); },
+ [this] { expiredTimerCallback(); });
}
mIdleTimer->start();
}
if (mSetTouchTimerMs > 0) {
// Touch events are coming to SF every 100ms, so the timer needs to be higher than that
- mTouchTimer =
- std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetTouchTimerMs),
- [this] { resetTouchTimerCallback(); },
- [this] { expiredTouchTimerCallback(); });
+ mTouchTimer = std::make_unique<scheduler::OneShotTimer>(
+ std::chrono::milliseconds(mSetTouchTimerMs), [this] { resetTouchTimerCallback(); },
+ [this] { expiredTouchTimerCallback(); });
mTouchTimer->start();
}
}
Scheduler::~Scheduler() {
- // Ensure the IdleTimer thread is joined before we start destroying state.
+ // Ensure the OneShotTimer threads are joined before we start destroying state.
mTouchTimer.reset();
mIdleTimer.reset();
}
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
- const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
+ const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
+ ResyncCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
std::unique_ptr<EventThread> eventThread =
makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
- std::move(interceptCallback));
+ offsetThresholdForNextVsync, std::move(interceptCallback));
auto eventThreadConnection =
- createConnectionInternal(eventThread.get(), std::move(resyncCallback));
+ createConnectionInternal(eventThread.get(), std::move(resyncCallback),
+ ISurfaceComposer::eConfigChangedSuppress);
mConnections.emplace(id,
std::make_unique<Connection>(new ConnectionHandle(id),
eventThreadConnection,
@@ -138,24 +135,28 @@ sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
}
std::unique_ptr<EventThread> Scheduler::makeEventThread(
- const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
+ nsecs_t offsetThresholdForNextVsync,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
std::unique_ptr<VSyncSource> eventThreadSource =
- std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
+ std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync,
+ true, connectionName);
return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
std::move(interceptCallback), connectionName);
}
-sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread,
- ResyncCallback&& resyncCallback) {
- return eventThread->createEventConnection(std::move(resyncCallback));
+sp<EventThreadConnection> Scheduler::createConnectionInternal(
+ EventThread* eventThread, ResyncCallback&& resyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged) {
+ return eventThread->createEventConnection(std::move(resyncCallback), configChanged);
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
+ const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged) {
RETURN_VALUE_IF_INVALID(nullptr);
return createConnectionInternal(mConnections[handle->id]->thread.get(),
- std::move(resyncCallback));
+ std::move(resyncCallback), configChanged);
}
EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -309,7 +310,7 @@ void Scheduler::setIgnorePresentFences(bool ignore) {
mPrimaryDispSync->setIgnorePresentFences(ignore);
}
-nsecs_t Scheduler::expectedPresentTime() {
+nsecs_t Scheduler::getDispSyncExpectedPresentTime() {
return mPrimaryDispSync->expectedPresentTime();
}
@@ -324,8 +325,11 @@ std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
: RefreshRateType::PERFORMANCE;
const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
- const uint32_t fps = (refreshRate) ? refreshRate->fps : 0;
- return mLayerHistory.createLayer(name, fps);
+ const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0;
+
+ const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT);
+ const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0;
+ return mLayerHistory.createLayer(name, defaultFps, performanceFps);
}
void Scheduler::addLayerPresentTimeAndHDR(
@@ -404,6 +408,10 @@ void Scheduler::notifyTouchEvent() {
if (mSupportKernelTimer) {
resetIdleTimer();
}
+
+ // Touch event will boost the refresh rate to performance.
+ // Clear Layer History to get fresh FPS detection
+ mLayerHistory.clearHistory();
}
void Scheduler::resetTimerCallback() {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index d311f62fdb..a30776059f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -26,9 +26,9 @@
#include "DispSync.h"
#include "EventControlThread.h"
#include "EventThread.h"
-#include "IdleTimer.h"
#include "InjectVSyncSource.h"
#include "LayerHistory.h"
+#include "OneShotTimer.h"
#include "RefreshRateConfigs.h"
#include "SchedulerUtils.h"
@@ -96,12 +96,13 @@ public:
virtual ~Scheduler();
/** Creates an EventThread connection. */
- sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs,
- ResyncCallback,
+ sp<ConnectionHandle> createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
+ nsecs_t offsetThresholdForNextVsync, ResyncCallback,
impl::EventThread::InterceptVSyncsCallback);
- sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
- ResyncCallback);
+ sp<IDisplayEventConnection> createDisplayEventConnection(
+ const sp<ConnectionHandle>& handle, ResyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged);
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -149,7 +150,7 @@ public:
void addResyncSample(const nsecs_t timestamp, bool* periodFlushed);
void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
void setIgnorePresentFences(bool ignore);
- nsecs_t expectedPresentTime();
+ nsecs_t getDispSyncExpectedPresentTime();
// Registers the layer in the scheduler, and returns the handle for future references.
std::unique_ptr<scheduler::LayerHistory::LayerHandle> registerLayer(std::string const& name,
int windowType);
@@ -184,7 +185,8 @@ public:
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
- const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
+ nsecs_t offsetThresholdForNextVsync,
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
@@ -197,7 +199,8 @@ private:
enum class TouchState { INACTIVE, ACTIVE };
// Creates a connection on the given EventThread and forwards the given callbacks.
- sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&);
+ sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
+ ISurfaceComposer::ConfigChanged);
nsecs_t calculateAverage() const;
void updateFrameSkipping(const int64_t skipCount);
@@ -270,14 +273,14 @@ private:
// Timer that records time between requests for next vsync. If the time is higher than a given
// interval, a callback is fired. Set this variable to >0 to use this feature.
int64_t mSetIdleTimerMs = 0;
- std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
+ std::unique_ptr<scheduler::OneShotTimer> mIdleTimer;
// Enables whether to use idle timer callbacks that support the kernel
// timer.
bool mSupportKernelTimer;
// Timer used to monitor touch events.
int64_t mSetTouchTimerMs = 0;
- std::unique_ptr<scheduler::IdleTimer> mTouchTimer;
+ std::unique_ptr<scheduler::OneShotTimer> mTouchTimer;
std::mutex mCallbackLock;
ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index 3bf3922edd..ced1899109 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -36,13 +36,16 @@ static constexpr size_t ARRAY_SIZE = 30;
static constexpr int SCREEN_OFF_CONFIG_ID = -1;
static constexpr uint32_t HWC2_SCREEN_OFF_CONFIG_ID = 0xffffffff;
-// This number is used when we try to determine how long does a given layer stay relevant.
-// Currently it is set to 100ms, because that would indicate 10Hz rendering.
-static constexpr std::chrono::nanoseconds TIME_EPSILON_NS = 100ms;
-
// This number is used when we try to determine how long do we keep layer information around
-// before we remove it. Currently it is set to 100ms.
-static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 100ms;
+// before we remove it. It is also used to determine how long the layer stays relevant.
+// This time period captures infrequent updates when playing YouTube video with static image,
+// or waiting idle in messaging app, when cursor is blinking.
+static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 1200ms;
+
+// Layer is considered low activity if the buffers come more than LOW_ACTIVITY_EPSILON_NS
+// apart. This is helping SF to vote for lower refresh rates when there is not activity
+// in screen.
+static constexpr std::chrono::nanoseconds LOW_ACTIVITY_EPSILON_NS = 250ms;
// Calculates the statistical mean (average) in the data structure (array, vector). The
// function does not modify the contents of the array.
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
new file mode 100644
index 0000000000..d452c19b68
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "VSyncModulator.h"
+
+#include <cutils/properties.h>
+#include <utils/Trace.h>
+
+#include <cinttypes>
+#include <mutex>
+
+namespace android {
+
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+VSyncModulator::VSyncModulator() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.vsync_trace_detailed_info", value, "0");
+ mTraceDetailedInfo = atoi(value);
+ // Populate the offset map with some default offsets.
+ const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0};
+ setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0);
+}
+
+void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
+ nsecs_t thresholdForNextVsync) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mOffsetMap.insert_or_assign(OffsetType::Early, early);
+ mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl);
+ mOffsetMap.insert_or_assign(OffsetType::Late, late);
+ mThresholdForNextVsync = thresholdForNextVsync;
+ updateOffsetsLocked();
+}
+
+void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) {
+ if (transactionStart == Scheduler::TransactionStart::EARLY) {
+ mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION;
+ }
+
+ // An early transaction stays an early transaction.
+ if (transactionStart == mTransactionStart ||
+ mTransactionStart == Scheduler::TransactionStart::EARLY) {
+ return;
+ }
+ mTransactionStart = transactionStart;
+ updateOffsets();
+}
+
+void VSyncModulator::onTransactionHandled() {
+ if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
+ mTransactionStart = Scheduler::TransactionStart::NORMAL;
+ updateOffsets();
+}
+
+void VSyncModulator::onRefreshRateChangeInitiated() {
+ if (mRefreshRateChangePending) {
+ return;
+ }
+ mRefreshRateChangePending = true;
+ updateOffsets();
+}
+
+void VSyncModulator::onRefreshRateChangeCompleted() {
+ if (!mRefreshRateChangePending) {
+ return;
+ }
+ mRefreshRateChangePending = false;
+ updateOffsets();
+}
+
+void VSyncModulator::onRefreshed(bool usedRenderEngine) {
+ bool updateOffsetsNeeded = false;
+ if (mRemainingEarlyFrameCount > 0) {
+ mRemainingEarlyFrameCount--;
+ updateOffsetsNeeded = true;
+ }
+ if (usedRenderEngine) {
+ mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION;
+ updateOffsetsNeeded = true;
+ } else if (mRemainingRenderEngineUsageCount > 0) {
+ mRemainingRenderEngineUsageCount--;
+ updateOffsetsNeeded = true;
+ }
+ if (updateOffsetsNeeded) {
+ updateOffsets();
+ }
+}
+
+VSyncModulator::Offsets VSyncModulator::getOffsets() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mOffsets;
+}
+
+VSyncModulator::Offsets VSyncModulator::getNextOffsets() {
+ return mOffsetMap.at(getNextOffsetType());
+}
+
+VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() {
+ // Early offsets are used if we're in the middle of a refresh rate
+ // change, or if we recently begin a transaction.
+ if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 ||
+ mRefreshRateChangePending) {
+ return OffsetType::Early;
+ } else if (mRemainingRenderEngineUsageCount > 0) {
+ return OffsetType::EarlyGl;
+ } else {
+ return OffsetType::Late;
+ }
+}
+
+void VSyncModulator::updateOffsets() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ updateOffsetsLocked();
+}
+
+void VSyncModulator::updateOffsetsLocked() {
+ const Offsets desired = getNextOffsets();
+ const Offsets current = mOffsets;
+
+ bool changed = false;
+ if (desired.sf != current.sf) {
+ if (mSfConnectionHandle != nullptr) {
+ mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf);
+ } else if (mSfEventThread != nullptr) {
+ mSfEventThread->setPhaseOffset(desired.sf);
+ }
+ changed = true;
+ }
+ if (desired.app != current.app) {
+ if (mAppConnectionHandle != nullptr) {
+ mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
+ } else if (mAppEventThread != nullptr) {
+ mAppEventThread->setPhaseOffset(desired.app);
+ }
+ changed = true;
+ }
+
+ if (changed) {
+ flushOffsets();
+ }
+}
+
+void VSyncModulator::flushOffsets() {
+ OffsetType type = getNextOffsetType();
+ mOffsets = mOffsetMap.at(type);
+ if (!mTraceDetailedInfo) {
+ return;
+ }
+ ATRACE_INT("Vsync-EarlyOffsetsOn",
+ mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early);
+ ATRACE_INT("Vsync-EarlyGLOffsetsOn",
+ mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl);
+ ATRACE_INT("Vsync-LateOffsetsOn",
+ mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late);
+ ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn",
+ mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early);
+ ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn",
+ mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl);
+ ATRACE_INT("Vsync-HighFpsLateOffsetsOn",
+ mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index 41c3a3a605..10cf8e6cc9 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -16,8 +16,6 @@
#pragma once
-#include <utils/Errors.h>
-
#include <cinttypes>
#include <mutex>
@@ -41,11 +39,22 @@ private:
const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
public:
+ VSyncModulator();
+
+ // Wrapper for a collection of surfaceflinger/app offsets for a particular
+ // configuration .
struct Offsets {
+ scheduler::RefreshRateConfigs::RefreshRateType fpsMode;
nsecs_t sf;
nsecs_t app;
};
+ enum class OffsetType {
+ Early,
+ EarlyGl,
+ Late,
+ };
+
// Sets the phase offsets
//
// sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
@@ -56,31 +65,16 @@ public:
// appEarly: Like sfEarly, but for the app-vsync
// appEarlyGl: Like sfEarlyGl, but for the app-vsync.
// appLate: The regular app vsync phase offset.
- void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) {
- mEarlyOffsets = early;
- mEarlyGlOffsets = earlyGl;
- mLateOffsets = late;
-
- if (mSfConnectionHandle && late.sf != mOffsets.load().sf) {
- mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf);
- }
-
- if (mAppConnectionHandle && late.app != mOffsets.load().app) {
- mScheduler->setPhaseOffset(mAppConnectionHandle, late.app);
- }
-
- mOffsets = late;
- }
-
- Offsets getEarlyOffsets() const { return mEarlyOffsets; }
-
- Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; }
+ void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
+ nsecs_t thresholdForNextVsync) EXCLUDES(mMutex);
+ // Sets handles to the SF and app event threads.
void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) {
mSfEventThread = sfEventThread;
mAppEventThread = appEventThread;
}
+ // Sets the scheduler and vsync connection handlers.
void setSchedulerAndHandles(Scheduler* scheduler,
Scheduler::ConnectionHandle* appConnectionHandle,
Scheduler::ConnectionHandle* sfConnectionHandle) {
@@ -89,109 +83,43 @@ public:
mSfConnectionHandle = sfConnectionHandle;
}
- void setTransactionStart(Scheduler::TransactionStart transactionStart) {
- if (transactionStart == Scheduler::TransactionStart::EARLY) {
- mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION;
- }
-
- // An early transaction stays an early transaction.
- if (transactionStart == mTransactionStart ||
- mTransactionStart == Scheduler::TransactionStart::EARLY) {
- return;
- }
- mTransactionStart = transactionStart;
- updateOffsets();
- }
+ // Signals that a transaction has started, and changes offsets accordingly.
+ void setTransactionStart(Scheduler::TransactionStart transactionStart);
- void onTransactionHandled() {
- if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
- mTransactionStart = Scheduler::TransactionStart::NORMAL;
- updateOffsets();
- }
+ // Signals that a transaction has been completed, so that we can finish
+ // special handling for a transaction.
+ void onTransactionHandled();
// Called when we send a refresh rate change to hardware composer, so that
// we can move into early offsets.
- void onRefreshRateChangeInitiated() {
- if (mRefreshRateChangePending) {
- return;
- }
- mRefreshRateChangePending = true;
- updateOffsets();
- }
+ void onRefreshRateChangeInitiated();
// Called when we detect from vsync signals that the refresh rate changed.
// This way we can move out of early offsets if no longer necessary.
- void onRefreshRateChangeCompleted() {
- if (!mRefreshRateChangePending) {
- return;
- }
- mRefreshRateChangePending = false;
- updateOffsets();
- }
+ void onRefreshRateChangeCompleted();
- void onRefreshed(bool usedRenderEngine) {
- bool updateOffsetsNeeded = false;
- if (mRemainingEarlyFrameCount > 0) {
- mRemainingEarlyFrameCount--;
- updateOffsetsNeeded = true;
- }
- if (usedRenderEngine) {
- mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION;
- updateOffsetsNeeded = true;
- } else if (mRemainingRenderEngineUsageCount > 0) {
- mRemainingRenderEngineUsageCount--;
- updateOffsetsNeeded = true;
- }
-
- if (updateOffsetsNeeded) {
- updateOffsets();
- }
- }
+ // Called when the display is presenting a new frame. usedRenderEngine
+ // should be set to true if RenderEngine was involved with composing the new
+ // frame.
+ void onRefreshed(bool usedRenderEngine);
- Offsets getOffsets() {
- // Early offsets are used if we're in the middle of a refresh rate
- // change, or if we recently begin a transaction.
- if (mTransactionStart == Scheduler::TransactionStart::EARLY ||
- mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
- return mEarlyOffsets;
- } else if (mRemainingRenderEngineUsageCount > 0) {
- return mEarlyGlOffsets;
- } else {
- return mLateOffsets;
- }
- }
+ // Returns the offsets that we are currently using
+ Offsets getOffsets() EXCLUDES(mMutex);
private:
- void updateOffsets() {
- const Offsets desired = getOffsets();
- const Offsets current = mOffsets;
-
- bool changed = false;
- if (desired.sf != current.sf) {
- if (mSfConnectionHandle != nullptr) {
- mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf);
- } else {
- mSfEventThread->setPhaseOffset(desired.sf);
- }
- changed = true;
- }
- if (desired.app != current.app) {
- if (mAppConnectionHandle != nullptr) {
- mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
- } else {
- mAppEventThread->setPhaseOffset(desired.app);
- }
- changed = true;
- }
-
- if (changed) {
- mOffsets = desired;
- }
- }
-
- Offsets mLateOffsets;
- Offsets mEarlyOffsets;
- Offsets mEarlyGlOffsets;
+ // Returns the next offsets that we should be using
+ Offsets getNextOffsets() REQUIRES(mMutex);
+ // Returns the next offset type that we should use.
+ OffsetType getNextOffsetType();
+ // Updates offsets and persists them into the scheduler framework.
+ void updateOffsets() EXCLUDES(mMutex);
+ void updateOffsetsLocked() REQUIRES(mMutex);
+ // Updates the internal offsets and offset type.
+ void flushOffsets() REQUIRES(mMutex);
+
+ mutable std::mutex mMutex;
+ std::unordered_map<OffsetType, Offsets> mOffsetMap GUARDED_BY(mMutex);
+ nsecs_t mThresholdForNextVsync;
EventThread* mSfEventThread = nullptr;
EventThread* mAppEventThread = nullptr;
@@ -200,13 +128,15 @@ private:
Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr;
Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr;
- std::atomic<Offsets> mOffsets;
+ Offsets mOffsets GUARDED_BY(mMutex) = {Scheduler::RefreshRateType::DEFAULT, 0, 0};
std::atomic<Scheduler::TransactionStart> mTransactionStart =
Scheduler::TransactionStart::NORMAL;
std::atomic<bool> mRefreshRateChangePending = false;
std::atomic<int> mRemainingEarlyFrameCount = 0;
std::atomic<int> mRemainingRenderEngineUsageCount = 0;
+
+ bool mTraceDetailedInfo = false;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 982a33e48a..2cb2544448 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -302,8 +302,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI
mDefaultCompositionDataspace =
static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB));
- mWideColorGamutCompositionDataspace =
- static_cast<ui::Dataspace>(wcg_composition_dataspace(Dataspace::V0_SRGB));
+ mWideColorGamutCompositionDataspace = static_cast<ui::Dataspace>(wcg_composition_dataspace(
+ hasWideColorDisplay ? Dataspace::DISPLAY_P3 : Dataspace::V0_SRGB));
defaultCompositionDataspace = mDefaultCompositionDataspace;
wideColorGamutCompositionDataspace = mWideColorGamutCompositionDataspace;
defaultCompositionPixelFormat = static_cast<ui::PixelFormat>(
@@ -377,7 +377,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI
mLumaSampling = atoi(value);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
@@ -616,13 +617,16 @@ void SurfaceFlinger::init() {
mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
mAppConnectionHandle =
- mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
+ mScheduler->createConnection("app", mVsyncModulator.getOffsets().app,
+ mPhaseOffsets->getOffsetThresholdForNextVsync(),
resyncCallback,
impl::EventThread::InterceptVSyncsCallback());
- mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
- resyncCallback, [this](nsecs_t timestamp) {
- mInterceptor->saveVSyncEvent(timestamp);
- });
+ mSfConnectionHandle =
+ mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf,
+ mPhaseOffsets->getOffsetThresholdForNextVsync(),
+ resyncCallback, [this](nsecs_t timestamp) {
+ mInterceptor->saveVSyncEvent(timestamp);
+ });
mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
@@ -940,7 +944,8 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
mVsyncModulator.onRefreshRateChangeInitiated();
mPhaseOffsets->setRefreshRateType(info.type);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
}
mDesiredActiveConfigChanged = true;
ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
@@ -974,7 +979,8 @@ void SurfaceFlinger::setActiveConfigInternal() {
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
@@ -992,7 +998,8 @@ void SurfaceFlinger::desiredActiveConfigChangeDone() {
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
}
bool SurfaceFlinger::performSetActiveConfig() {
@@ -1372,7 +1379,7 @@ status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) {
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
- ISurfaceComposer::VsyncSource vsyncSource) {
+ ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) {
auto resyncCallback = mScheduler->makeResyncCallback([this] {
Mutex::Autolock lock(mStateLock);
return getVsyncPeriod();
@@ -1381,7 +1388,8 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
const auto& handle =
vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
- return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback));
+ return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback),
+ configChanged);
}
// ----------------------------------------------------------------------------
@@ -1540,14 +1548,12 @@ void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) {
void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) {
ATRACE_CALL();
+ mHWCVsyncPendingState = enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable;
+
if (const auto displayId = getInternalDisplayIdLocked()) {
sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
if (display && display->isPoweredOn()) {
- getHwComposer().setVsyncEnabled(*displayId,
- enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
- } else {
- // Cache the latest vsync state and apply it when screen is on again
- mEnableHWVsyncScreenOn = enabled;
+ setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
}
}
}
@@ -1661,7 +1667,7 @@ bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS {
nsecs_t SurfaceFlinger::getExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS {
DisplayStatInfo stats;
mScheduler->getDisplayStatInfo(&stats);
- const nsecs_t presentTime = mScheduler->expectedPresentTime();
+ const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime();
// Inflate the expected present time if we're targetting the next vsync.
const nsecs_t correctedTime =
mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
@@ -1795,6 +1801,12 @@ void SurfaceFlinger::handleMessageRefresh() {
mVsyncModulator.onRefreshed(mHadClientComposition);
mLayersWithQueuedFrames.clear();
+ if (mVisibleRegionsDirty) {
+ mVisibleRegionsDirty = false;
+ if (mTracingEnabled) {
+ mTracing.notify("visibleRegionsDirty");
+ }
+ }
}
@@ -1804,9 +1816,6 @@ bool SurfaceFlinger::handleMessageInvalidate() {
if (mVisibleRegionsDirty) {
computeLayerBounds();
- if (mTracingEnabled) {
- mTracing.notify("visibleRegionsDirty");
- }
}
for (auto& layer : mLayersPendingRefresh) {
@@ -2166,7 +2175,14 @@ void SurfaceFlinger::postComposition()
}
mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]);
- mTransactionCompletedThread.sendCallbacks();
+
+ // Lock the mStateLock in case SurfaceFlinger is in the middle of applying a transaction.
+ // If we do not lock here, a callback could be sent without all of its SurfaceControls and
+ // metrics.
+ {
+ Mutex::Autolock _l(mStateLock);
+ mTransactionCompletedThread.sendCallbacks();
+ }
if (mLumaSampling && mRegionSamplingThread) {
mRegionSamplingThread->notifyNewContent();
@@ -2201,7 +2217,6 @@ void SurfaceFlinger::rebuildLayerStacks() {
// rebuild the visible layer list per screen
if (CC_UNLIKELY(mVisibleRegionsDirty)) {
ATRACE_NAME("rebuildLayerStacks VR Dirty");
- mVisibleRegionsDirty = false;
invalidateHwcGeometry();
for (const auto& pair : mDisplays) {
@@ -3519,11 +3534,6 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice,
return true;
}
-void SurfaceFlinger::drawWormhole(const Region& region) const {
- auto& engine(getRenderEngine());
- engine.fillRegionWithColor(region, 0, 0, 0, 0);
-}
-
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
const sp<IBinder>& parentHandle,
@@ -3668,7 +3678,7 @@ bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>&
bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
const Vector<ComposerState>& states) {
- nsecs_t expectedPresentTime = mScheduler->expectedPresentTime();
+ nsecs_t expectedPresentTime = getExpectedPresentTime();
// Do not present if the desiredPresentTime has not passed unless it is more than one second
// in the future. We ignore timestamps more than 1 second in the future for stability reasons.
if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime &&
@@ -3918,6 +3928,11 @@ uint32_t SurfaceFlinger::setClientStateLocked(
sp<Layer> layer(client->getLayerUser(s.surface));
if (layer == nullptr) {
+ for (auto& listenerCallback : listenerCallbacks) {
+ mTransactionCompletedThread.addUnpresentedCallbackHandle(
+ new CallbackHandle(listenerCallback.transactionCompletedListener,
+ listenerCallback.callbackIds, s.surface));
+ }
return 0;
}
@@ -4434,6 +4449,13 @@ void SurfaceFlinger::initializeDisplays() {
new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
}
+void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled) {
+ if (mHWCVsyncState != enabled) {
+ getHwComposer().setVsyncEnabled(displayId, enabled);
+ mHWCVsyncState = enabled;
+ }
+}
+
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
if (display->isVirtual()) {
ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
@@ -4460,11 +4482,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int
// Turn on the display
getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
- if (mEnableHWVsyncScreenOn) {
- setPrimaryVsyncEnabledInternal(mEnableHWVsyncScreenOn);
- mEnableHWVsyncScreenOn = false;
- }
-
+ setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
}
@@ -4490,6 +4508,9 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int
mScheduler->onScreenReleased(mAppConnectionHandle);
}
+ // Make sure HWVsync is disabled before turning off the display
+ setVsyncEnabledInHWC(*displayId, HWC2::Vsync::Disable);
+
getHwComposer().setPowerMode(*displayId, mode);
mVisibleRegionsDirty = true;
// from this point on, SF will stop drawing on this display
@@ -5646,6 +5667,11 @@ status_t SurfaceFlinger::captureScreen(uint64_t displayOrLayerStack, Dataspace*
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;
+ }
*outDataspace =
pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index df6cdf2993..1a9dcdd2ef 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -407,7 +407,9 @@ private:
const sp<IGraphicBufferProducer>& bufferProducer) const override;
status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override;
sp<IDisplayEventConnection> createDisplayEventConnection(
- ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp) override;
+ ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp,
+ 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,
@@ -788,7 +790,6 @@ private:
void postFramebuffer(const sp<DisplayDevice>& display);
void postFrame();
- void drawWormhole(const Region& region) const;
/* ------------------------------------------------------------------------
* Display management
@@ -843,6 +844,7 @@ private:
}
bool previousFrameMissed();
+ void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled);
/*
* Debugging & dumpsys
@@ -1177,8 +1179,9 @@ private:
// be any issues with a raw pointer referencing an invalid object.
std::unordered_set<Layer*> mOffscreenLayers;
- // Flag to indicate whether to re-enable HWVsync when screen is on
- bool mEnableHWVsyncScreenOn = false;
+ // Flags to capture the state of Vsync in HWC
+ HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable;
+ HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 4f352ff9db..2b33ba1746 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -177,15 +177,11 @@ SurfaceFlingerProperties::primary_display_orientation_values primary_display_ori
bool use_color_management(bool defaultValue) {
auto tmpuseColorManagement = SurfaceFlingerProperties::use_color_management();
- auto tmpHasHDRDisplay = SurfaceFlingerProperties::has_HDR_display();
- auto tmpHasWideColorDisplay = SurfaceFlingerProperties::has_wide_color_display();
+ auto tmpHasHDRDisplayVal = has_HDR_display(defaultValue);
+ auto tmpHasWideColorDisplayVal = has_wide_color_display(defaultValue);
auto tmpuseColorManagementVal = tmpuseColorManagement.has_value() ? *tmpuseColorManagement :
defaultValue;
- auto tmpHasHDRDisplayVal = tmpHasHDRDisplay.has_value() ? *tmpHasHDRDisplay :
- defaultValue;
- auto tmpHasWideColorDisplayVal = tmpHasWideColorDisplay.has_value() ? *tmpHasWideColorDisplay :
- defaultValue;
return tmpuseColorManagementVal || tmpHasHDRDisplayVal || tmpHasWideColorDisplayVal;
}
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 4773307a65..18524f02d8 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -61,7 +61,7 @@ public:
void setTraceFlags(uint32_t flags);
private:
- static constexpr auto kDefaultBufferCapInByte = 100_MB;
+ static constexpr auto kDefaultBufferCapInByte = 5_MB;
static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb";
class LayersTraceBuffer { // ring buffer
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
index cb368b0886..d03cb7b22a 100644
--- a/services/surfaceflinger/layerproto/Android.bp
+++ b/services/surfaceflinger/layerproto/Android.bp
@@ -43,7 +43,7 @@ java_library_static {
type: "nano",
},
srcs: ["*.proto"],
- no_framework_libs: true,
+ sdk_version: "core_platform",
target: {
android: {
jarjar_rules: "jarjar-rules.txt",
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index decabd5e88..a8ec7649c6 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -36,7 +36,7 @@ owner: Platform
prop {
api_name: "vsync_event_phase_offset_ns"
type: Long
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns"
}
@@ -44,7 +44,7 @@ prop {
prop {
api_name: "vsync_sf_event_phase_offset_ns"
type: Long
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns"
}
@@ -53,7 +53,7 @@ prop {
prop {
api_name: "use_context_priority"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.use_context_priority"
}
@@ -62,7 +62,7 @@ prop {
prop {
api_name: "max_frame_buffer_acquired_buffers"
type: Long
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
}
@@ -80,7 +80,7 @@ prop {
prop {
api_name: "has_wide_color_display"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.has_wide_color_display"
}
@@ -90,7 +90,7 @@ prop {
prop {
api_name: "running_without_sync_framework"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.running_without_sync_framework"
}
@@ -108,7 +108,7 @@ prop {
prop {
api_name: "has_HDR_display"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.has_HDR_display"
}
@@ -117,7 +117,7 @@ prop {
prop {
api_name: "present_time_offset_from_vsync_ns"
type: Long
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns"
}
@@ -129,7 +129,7 @@ prop {
prop {
api_name: "force_hwc_copy_for_virtual_displays"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays"
}
@@ -139,7 +139,7 @@ prop {
prop {
api_name: "max_virtual_display_dimension"
type: Long
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.max_virtual_display_dimension"
}
@@ -151,7 +151,7 @@ prop {
prop {
api_name: "use_vr_flinger"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.use_vr_flinger"
}
@@ -161,7 +161,7 @@ prop {
prop {
api_name: "start_graphics_allocator_service"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.start_graphics_allocator_service"
}
@@ -171,7 +171,7 @@ prop {
api_name: "primary_display_orientation"
type: Enum
enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.primary_display_orientation"
}
@@ -182,7 +182,7 @@ prop {
prop {
api_name: "use_color_management"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.use_color_management"
}
@@ -209,7 +209,7 @@ prop {
prop {
api_name: "default_composition_dataspace"
type: Long
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.default_composition_dataspace"
}
@@ -220,7 +220,7 @@ prop {
prop {
api_name: "default_composition_pixel_format"
type: Integer
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.default_composition_pixel_format"
}
@@ -235,7 +235,7 @@ prop {
prop {
api_name: "wcg_composition_dataspace"
type: Long
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.wcg_composition_dataspace"
}
@@ -246,7 +246,7 @@ prop {
prop {
api_name: "wcg_composition_pixel_format"
type: Integer
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.wcg_composition_pixel_format"
}
@@ -258,7 +258,7 @@ prop {
prop {
api_name: "display_primary_red"
type: DoubleList
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.display_primary_red"
}
@@ -266,7 +266,7 @@ prop {
prop {
api_name: "display_primary_green"
type: DoubleList
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.display_primary_green"
}
@@ -274,7 +274,7 @@ prop {
prop {
api_name: "display_primary_blue"
type: DoubleList
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.display_primary_blue"
}
@@ -282,7 +282,7 @@ prop {
prop {
api_name: "display_primary_white"
type: DoubleList
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.display_primary_white"
}
@@ -293,7 +293,7 @@ prop {
prop {
api_name: "set_idle_timer_ms"
type: Integer
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.set_idle_timer_ms"
}
@@ -304,7 +304,7 @@ prop {
prop {
api_name: "set_touch_timer_ms"
type: Integer
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.set_touch_timer_ms"
}
@@ -314,7 +314,7 @@ prop {
prop {
api_name: "use_smart_90_for_video"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.use_smart_90_for_video"
}
@@ -322,7 +322,7 @@ prop {
prop {
api_name: "enable_protected_contents"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.protected_contents"
}
@@ -332,7 +332,7 @@ prop {
prop {
api_name: "support_kernel_idle_timer"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.surface_flinger.support_kernel_idle_timer"
}
diff --git a/services/surfaceflinger/test.png b/services/surfaceflinger/test.png
new file mode 100644
index 0000000000..773dcc3e72
--- /dev/null
+++ b/services/surfaceflinger/test.png
Binary files differ
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f842d61c7f..4917bc2a51 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -42,7 +42,7 @@ cc_test {
"DisplayTransactionTest.cpp",
"EventControlThreadTest.cpp",
"EventThreadTest.cpp",
- "IdleTimerTest.cpp",
+ "OneShotTimerTest.cpp",
"LayerHistoryTest.cpp",
"LayerMetadataTest.cpp",
"SchedulerTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 4f8ed1ae1c..e6211c488e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -303,11 +303,6 @@ struct BaseDisplayVariant {
EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
- // TODO: remove once we verify that we can just grab the fence from the
- // FramebufferSurface.
- EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() {
- return base::unique_fd();
- }));
EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index 2e705dad6d..0aa8cf565d 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -51,6 +51,7 @@ protected:
AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder;
static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms;
+ static constexpr std::chrono::nanoseconds mOffsetThresholdForNextVsync = 16ms;
static constexpr int mIterations = 100;
};
@@ -78,7 +79,8 @@ void DispSyncSourceTest::createDispSync() {
void DispSyncSourceTest::createDispSyncSource() {
createDispSync();
- mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true,
+ mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(),
+ mOffsetThresholdForNextVsync.count(), true,
"DispSyncSourceTest");
mDispSyncSource->setCallback(this);
}
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index ea908a9018..dbd9b84039 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -55,8 +55,9 @@ protected:
class MockEventThreadConnection : public EventThreadConnection {
public:
MockEventThreadConnection(android::impl::EventThread* eventThread,
- ResyncCallback&& resyncCallback)
- : EventThreadConnection(eventThread, std::move(resyncCallback)) {}
+ ResyncCallback&& resyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged)
+ : EventThreadConnection(eventThread, std::move(resyncCallback), configChanged) {}
MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
};
@@ -67,7 +68,8 @@ protected:
~EventThreadTest() override;
void createThread();
- sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder);
+ sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder,
+ ISurfaceComposer::ConfigChanged configChanged);
void expectVSyncSetEnabledCallReceived(bool expectedState);
void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset);
@@ -110,7 +112,8 @@ EventThreadTest::EventThreadTest() {
.WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
createThread();
- mConnection = createConnection(mConnectionEventCallRecorder);
+ mConnection = createConnection(mConnectionEventCallRecorder,
+ ISurfaceComposer::eConfigChangedDispatch);
// A display must be connected for VSYNC events to be delivered.
mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true);
@@ -138,9 +141,10 @@ void EventThreadTest::createThread() {
}
sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
- ConnectionEventRecorder& recorder) {
+ ConnectionEventRecorder& recorder, ISurfaceComposer::ConfigChanged configChanged) {
sp<MockEventThreadConnection> connection =
- new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable());
+ new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable(),
+ configChanged);
EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
return connection;
}
@@ -267,7 +271,9 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) {
// Create a first connection, register it, and request a vsync rate of zero.
ConnectionEventRecorder firstConnectionEventRecorder{0};
- sp<MockEventThreadConnection> firstConnection = createConnection(firstConnectionEventRecorder);
+ sp<MockEventThreadConnection> firstConnection =
+ createConnection(firstConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
mThread->setVsyncRate(0, firstConnection);
// By itself, this should not enable vsync events
@@ -277,7 +283,8 @@ TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) {
// However if there is another connection which wants events at a nonzero rate.....
ConnectionEventRecorder secondConnectionEventRecorder{0};
sp<MockEventThreadConnection> secondConnection =
- createConnection(secondConnectionEventRecorder);
+ createConnection(secondConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
mThread->setVsyncRate(1, secondConnection);
// EventThread should enable vsync callbacks.
@@ -363,7 +370,9 @@ TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) {
TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) {
ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
- sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
+ sp<MockEventThreadConnection> errorConnection =
+ createConnection(errorConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
mThread->setVsyncRate(1, errorConnection);
// EventThread should enable vsync callbacks.
@@ -387,7 +396,9 @@ TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) {
TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) {
ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK};
- sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
+ sp<MockEventThreadConnection> errorConnection =
+ createConnection(errorConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
mThread->setVsyncRate(1, errorConnection);
// EventThread should enable vsync callbacks.
@@ -449,5 +460,18 @@ TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7);
}
+TEST_F(EventThreadTest, suppressConfigChanged) {
+ ConnectionEventRecorder suppressConnectionEventRecorder{0};
+ sp<MockEventThreadConnection> suppressConnection =
+ createConnection(suppressConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
+
+ mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 9);
+ expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9);
+
+ auto args = suppressConnectionEventRecorder.waitForCall();
+ ASSERT_FALSE(args.has_value());
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index 96121bb088..1d7501102e 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -23,6 +23,8 @@
namespace android {
namespace scheduler {
+using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+
class FakePhaseOffsets : public android::scheduler::PhaseOffsets {
nsecs_t FAKE_PHASE_OFFSET_NS = 0;
@@ -34,20 +36,20 @@ public:
nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
PhaseOffsets::Offsets getOffsetsForRefreshRate(
- RefreshRateConfigs::RefreshRateType /*refreshRateType*/) const override {
+ RefreshRateType /*refreshRateType*/) const override {
return getCurrentOffsets();
}
// Returns early, early GL, and late offsets for Apps and SF.
PhaseOffsets::Offsets getCurrentOffsets() const override {
- return Offsets{{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
+ return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
}
// This function should be called when the device is switching between different
// refresh rates, to properly update the offsets.
- void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {}
+ void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {}
nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; }
@@ -56,4 +58,4 @@ public:
};
} // namespace scheduler
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 2b1dfa8f38..7ec90660ce 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -25,6 +25,7 @@ public:
protected:
std::unique_ptr<LayerHistory> mLayerHistory;
+ static constexpr float MIN_REFRESH_RATE = 30.f;
static constexpr float MAX_REFRESH_RATE = 90.f;
};
@@ -36,7 +37,7 @@ LayerHistoryTest::~LayerHistoryTest() {}
namespace {
TEST_F(LayerHistoryTest, oneLayer) {
std::unique_ptr<LayerHistory::LayerHandle> testLayer =
- mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE);
+ mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
mLayerHistory->setVisibility(testLayer, true);
mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
@@ -60,7 +61,7 @@ TEST_F(LayerHistoryTest, oneLayer) {
TEST_F(LayerHistoryTest, oneHDRLayer) {
std::unique_ptr<LayerHistory::LayerHandle> testLayer =
- mLayerHistory->createLayer("TestHDRLayer", MAX_REFRESH_RATE);
+ mLayerHistory->createLayer("TestHDRLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
mLayerHistory->setVisibility(testLayer, true);
mLayerHistory->insert(testLayer, 0, true /*isHDR*/);
@@ -74,7 +75,7 @@ TEST_F(LayerHistoryTest, oneHDRLayer) {
TEST_F(LayerHistoryTest, explicitTimestamp) {
std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
- mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE);
+ mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
mLayerHistory->setVisibility(test30FpsLayer, true);
nsecs_t startTime = systemTime();
@@ -87,13 +88,13 @@ TEST_F(LayerHistoryTest, explicitTimestamp) {
TEST_F(LayerHistoryTest, multipleLayers) {
std::unique_ptr<LayerHistory::LayerHandle> testLayer =
- mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE);
+ mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
mLayerHistory->setVisibility(testLayer, true);
std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
- mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE);
+ mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
mLayerHistory->setVisibility(test30FpsLayer, true);
std::unique_ptr<LayerHistory::LayerHandle> testLayer2 =
- mLayerHistory->createLayer("TestLayer2", MAX_REFRESH_RATE);
+ mLayerHistory->createLayer("TestLayer2", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
mLayerHistory->setVisibility(testLayer2, true);
nsecs_t startTime = systemTime();
@@ -119,8 +120,8 @@ TEST_F(LayerHistoryTest, multipleLayers) {
mLayerHistory->insert(testLayer2, 0, false /*isHDR*/);
}
EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- // After 100 ms frames become obsolete.
- std::this_thread::sleep_for(std::chrono::milliseconds(500));
+ // After 1200 ms frames become obsolete.
+ std::this_thread::sleep_for(std::chrono::milliseconds(1500));
// Insert the 31st frame.
mLayerHistory->insert(test30FpsLayer, startTime + (30 * 33333333), false /*isHDR*/);
EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index eff22b6640..0208728026 100644
--- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -21,17 +21,17 @@
#include <utils/Log.h>
#include "AsyncCallRecorder.h"
-#include "Scheduler/IdleTimer.h"
+#include "Scheduler/OneShotTimer.h"
using namespace std::chrono_literals;
namespace android {
namespace scheduler {
-class IdleTimerTest : public testing::Test {
+class OneShotTimerTest : public testing::Test {
protected:
- IdleTimerTest() = default;
- ~IdleTimerTest() override = default;
+ OneShotTimerTest() = default;
+ ~OneShotTimerTest() override = default;
// This timeout should be used when a 3ms callback is expected.
// While the tests typically request a callback after 3ms, the scheduler
@@ -46,7 +46,7 @@ protected:
AsyncCallRecorder<void (*)()> mResetTimerCallback;
AsyncCallRecorder<void (*)()> mExpiredTimerCallback;
- std::unique_ptr<IdleTimer> mIdleTimer;
+ std::unique_ptr<OneShotTimer> mIdleTimer;
void clearPendingCallbacks() {
while (mExpiredTimerCallback.waitForCall(0us).has_value()) {
@@ -55,13 +55,14 @@ protected:
};
namespace {
-TEST_F(IdleTimerTest, createAndDestroyTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, [] {}, [] {});
+TEST_F(OneShotTimerTest, createAndDestroyTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
+ 3ms, [] {}, [] {});
}
-TEST_F(IdleTimerTest, startStopTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, startStopTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(30ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
auto startTime = std::chrono::steady_clock::now();
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -70,7 +71,7 @@ TEST_F(IdleTimerTest, startStopTest) {
bool callbackCalled = mExpiredTimerCallback.waitForCall(25ms).has_value();
// Under ideal conditions there should be no event. But occasionally
// it is possible that the wait just prior takes more than 30ms, and
- // a callback is observed. We check the elapsed time since before the IdleTimer
+ // a callback is observed. We check the elapsed time since before the OneShotTimer
// thread was started as a sanity check to not have a flakey test.
EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms);
@@ -79,9 +80,9 @@ TEST_F(IdleTimerTest, startStopTest) {
mIdleTimer->stop();
}
-TEST_F(IdleTimerTest, resetTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, resetTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
// Observe any event that happens in about 25ms. We don't care if one was
@@ -104,9 +105,9 @@ TEST_F(IdleTimerTest, resetTest) {
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, resetBackToBackTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, resetBackToBackTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -135,9 +136,9 @@ TEST_F(IdleTimerTest, resetBackToBackTest) {
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, startNotCalledTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, startNotCalledTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
// The start hasn't happened, so the callback does not happen.
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
@@ -147,9 +148,9 @@ TEST_F(IdleTimerTest, startNotCalledTest) {
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, idleTimerIdlesTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, idleTimerIdlesTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -167,18 +168,18 @@ TEST_F(IdleTimerTest, idleTimerIdlesTest) {
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
}
-TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
@@ -190,9 +191,9 @@ TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) {
EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
}
-TEST_F(IdleTimerTest, noCallbacksAfterStopTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 1f8b11180b..740115ea32 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -25,7 +25,8 @@ protected:
class MockEventThreadConnection : public android::EventThreadConnection {
public:
explicit MockEventThreadConnection(EventThread* eventThread)
- : EventThreadConnection(eventThread, ResyncCallback()) {}
+ : EventThreadConnection(eventThread, ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress) {}
~MockEventThreadConnection() = default;
MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
@@ -47,7 +48,7 @@ protected:
std::unique_ptr<EventThread> makeEventThread(
const char* /* connectionName */, DispSync* /* dispSync */,
- nsecs_t /* phaseOffsetNs */,
+ nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */,
impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
return std::move(mEventThread);
}
@@ -81,10 +82,10 @@ SchedulerTest::SchedulerTest() {
// createConnection call to scheduler makes a createEventConnection call to EventThread. Make
// sure that call gets executed and returns an EventThread::Connection object.
- EXPECT_CALL(*mEventThread, createEventConnection(_))
+ EXPECT_CALL(*mEventThread, createEventConnection(_, _))
.WillRepeatedly(Return(mEventThreadConnection));
- mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(),
+ mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(),
impl::EventThread::InterceptVSyncsCallback());
EXPECT_TRUE(mConnectionHandle != nullptr);
}
@@ -105,7 +106,10 @@ TEST_F(SchedulerTest, testNullPtr) {
// exceptions, just gracefully continues.
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
- returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback()));
+ returnedValue =
+ mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(),
+ ISurfaceComposer::
+ eConfigChangedSuppress));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
@@ -126,7 +130,9 @@ TEST_F(SchedulerTest, invalidConnectionHandle) {
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
returnedValue =
- mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback()));
+ mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(),
+ ISurfaceComposer::
+ eConfigChangedSuppress));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
@@ -155,7 +161,9 @@ TEST_F(SchedulerTest, validConnectionHandle) {
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
returnedValue =
- mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback()));
+ mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(),
+ ISurfaceComposer::
+ eConfigChangedSuppress));
EXPECT_TRUE(returnedValue != nullptr);
ASSERT_EQ(returnedValue, mEventThreadConnection);
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index c3d2b8de4f..cb6980ed1a 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -17,6 +17,7 @@
#pragma once
#include <gmock/gmock.h>
+#include <gui/ISurfaceComposer.h>
#include "Scheduler/EventThread.h"
#include "Scheduler/RefreshRateConfigs.h"
@@ -34,7 +35,8 @@ public:
// Scheduler::Connection. This allows plugging in mock::EventThread.
sp<Scheduler::ConnectionHandle> addConnection(std::unique_ptr<EventThread> eventThread) {
sp<EventThreadConnection> eventThreadConnection =
- new EventThreadConnection(eventThread.get(), ResyncCallback());
+ new EventThreadConnection(eventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress);
const int64_t id = sNextId++;
mConnections.emplace(id,
std::make_unique<Scheduler::Connection>(new ConnectionHandle(id),
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 5b5f8e7fab..ed35ebf2b6 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -28,7 +28,8 @@ public:
EventThread();
~EventThread() override;
- MOCK_CONST_METHOD1(createEventConnection, sp<EventThreadConnection>(ResyncCallback));
+ MOCK_CONST_METHOD2(createEventConnection,
+ sp<EventThreadConnection>(ResyncCallback, ISurfaceComposer::ConfigChanged));
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 021d8cbfca..1604775da5 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -110,6 +110,7 @@ cc_binary {
"liblog",
"libhardware",
"libhwbinder",
+ "libhidlbase",
"libui",
"libutils",
"libvr_hwc-hal",
diff --git a/vulkan/api/templates/asciidoc.tmpl b/vulkan/api/templates/asciidoc.tmpl
deleted file mode 100644
index 3009e19cad..0000000000
--- a/vulkan/api/templates/asciidoc.tmpl
+++ /dev/null
@@ -1,151 +0,0 @@
-{{Include "vulkan_common.tmpl"}}
-{{if not (Global "AsciiDocPath")}}{{Global "AsciiDocPath" "../../doc/specs/vulkan/"}}{{end}}
-{{$ | Macro "AsciiDoc.Main"}}
-
-
-{{/*
--------------------------------------------------------------------------------
- AsciiDoc generation main entry point.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Main"}}
- {{$docPath := Global "AsciiDocPath"}}
-
- {{/* Generate AsciiDoc files for API enums and bitfields (flags). */}}
- {{range $e := $.Enums}}
- {{if not $e.IsBitfield}}
- {{$filename := print $docPath "enums/" (Macro "EnumName" $e) ".txt"}}
- {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Enum" $e) "File" $filename}}
- {{else}}
- {{$filename := print $docPath "flags/" (Macro "EnumName" $e) ".txt"}}
- {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Flag" $e) "File" $filename}}
- {{end}}
- {{end}}
-
- {{/* Generate AsciiDoc files for API commands (protos). */}}
- {{range $f := (AllCommands $)}}
- {{if not (GetAnnotation $f "pfn")}}
- {{$filename := print $docPath "protos/" $f.Name ".txt"}}
- {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Proto" $f) "File" $filename}}
- {{end}}
- {{end}}
-
- {{/* Generate AsciiDoc files for API structs. */}}
- {{range $c := $.Classes}}
- {{if not (GetAnnotation $c "internal")}}
- {{$filename := print $docPath "structs/" $c.Name ".txt"}}
- {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Struct" $c) "File" $filename}}
- {{end}}
- {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the AsciiDoc contents for the specified API enum.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Enum"}}
- {{AssertType $ "Enum"}}
-
- {{Macro "Docs" $.Docs}}
- typedef enum {
- {{range $i, $e := $.Entries}}
- {{Macro "EnumEntry" $e}} = {{AsSigned $e.Value}}, {{Macro "Docs" $e.Docs}}
- {{end}}
- ¶
- {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}}
- {{$first := Macro "EnumFirstEntry" $}}
- {{$last := Macro "EnumLastEntry" $}}
- {{$name}}_BEGIN_RANGE = {{$first}},
- {{$name}}_END_RANGE = {{$last}},
- {{$name}}_NUM = ({{$last}} - {{$first}} + 1),
- {{$name}}_MAX_ENUM = 0x7FFFFFFF
- } {{Macro "EnumName" $}};
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the AsciiDoc contents for the specified API bitfield.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Flag"}}
- {{AssertType $ "Enum"}}
-
- {{Macro "Docs" $.Docs}}
- typedef VkFlags {{Macro "EnumName" $}};
- {{if $.Entries}}
- typedef enum {
- {{range $e := $.Entries}}
- {{Macro "BitfieldEntryName" $e}} = {{printf "%#.8x" $e.Value}}, {{Macro "Docs" $e.Docs}}
- {{end}}
- } {{Macro "EnumName" $ | TrimRight "s"}}Bits;
- {{end}}
-{{end}}
-
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the AsciiDoc contents for the specified API class.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Struct"}}
- {{AssertType $ "Class"}}
-
- {{Macro "Docs" $.Docs}}
- typedef {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} {
- {{range $f := $.Fields}}
- {{Node "Type" $f}} {{$f.Name}}{{Macro "ArrayPostfix" (TypeOf $f)}}; {{Macro "Docs" $f.Docs}}
- {{end}}
- } {{Macro "StructName" $}};
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the AsciiDoc contents for the specified API function.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Proto"}}
- {{AssertType $ "Function"}}
-
- {{Macro "Docs" $.Docs}}
- {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}});
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Wraps the specified Code in AsciiDoc source tags then writes to the specified File.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Write"}}
- {{AssertType $.Code "string"}}
- {{AssertType $.File "string"}}
-
- {{$code := $.Code | Format (Global "clang-format")}}
- {{JoinWith "\n" (Macro "AsciiDoc.Header") $code (Macro "AsciiDoc.Footer") ""| Write $.File}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits an AsciiDoc source header.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Header"}}
-[source,{basebackend@docbook:c++:cpp}]
-------------------------------------------------------------------------------
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits an AsciiDoc source footer.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Footer"}}
-------------------------------------------------------------------------------
-{{end}}
diff --git a/vulkan/api/templates/vk_xml.tmpl b/vulkan/api/templates/vk_xml.tmpl
deleted file mode 100644
index 893bde7833..0000000000
--- a/vulkan/api/templates/vk_xml.tmpl
+++ /dev/null
@@ -1,435 +0,0 @@
-{{Include "vulkan_common.tmpl"}}
-{{Macro "DefineGlobals" $}}
-{{$ | Macro "vk.xml" | Reflow 4 | Write "vk.xml"}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Entry point
--------------------------------------------------------------------------------
-*/}}
-{{define "vk.xml"}}
-<?xml version="1.0" encoding="UTF-8"?>
-<registry>
- »<comment>«
-Copyright (c) 2015 The Khronos Group Inc.
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and/or associated documentation files (the
-"Materials"), to deal in the Materials without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Materials, and to
-permit persons to whom the Materials are furnished to do so, subject to
-the following conditions:
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Materials.
-THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-------------------------------------------------------------------------
-This file, vk.xml, is the Vulkan API Registry.»
- </comment>
- <!-- SECTION: Vulkan type definitions -->
- <types>»
- <type name="vk_platform" category="include">#include "vk_platform.h"</type>
- <type category="define">#define <name>VK_MAKE_VERSION</name>(major, minor, patch) \
- «((major &lt;&lt; 22) | (minor &lt;&lt; 12) | patch)</type>»
- <type category="define">// Vulkan API version supported by this file««
-#define <name>VK_API_VERSION</name> <type>VK_MAKE_VERSION</type>({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}})</type>
- »»<type category="define">««
-#if (_MSC_VER &gt;= 1800 || __cplusplus &gt;= 201103L)
-#define <name>VK_NONDISP_HANDLE_OPERATOR_BOOL</name>() explicit operator bool() const { return handle != 0; }
-#else
-#define VK_NONDISP_HANDLE_OPERATOR_BOOL()
-«#endif
- »»»</type>
- <type category="define">«««
-#define <name>VK_DEFINE_HANDLE</name>(obj) typedef struct obj##_T* obj;</type>
- »»»<type category="define">«««
-#if defined(__cplusplus)
- »»#if (_MSC_VER &gt;= 1800 || __cplusplus &gt;= 201103L)
- »// The bool operator only works if there are no implicit conversions from an obj to
- // a bool-compatible type, which can then be used to unintentionally violate type safety.
- // C++11 and above supports the "explicit" keyword on conversion operators to stop this
- // from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating
- // the object handle as a bool in expressions like:
- // if (obj) vkDestroy(obj);
- #define VK_NONDISP_HANDLE_OPERATOR_BOOL() explicit operator bool() const { return handle != 0; }
- #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- explicit obj(uint64_t x) : handle(x) { } \
- obj(decltype(nullptr)) : handle(0) { }
- «#else»
- #define VK_NONDISP_HANDLE_OPERATOR_BOOL()
- #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- obj(uint64_t x) : handle(x) { }
- «#endif
- #define <name>VK_DEFINE_NONDISP_HANDLE</name>(obj) \»
- struct obj { \
- obj() { } \
- VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- obj&amp; operator =(uint64_t x) { handle = x; return *this; } \
- bool operator==(const obj&amp; other) const { return handle == other.handle; } \
- bool operator!=(const obj&amp; other) const { return handle != other.handle; } \
- bool operator!() const { return !handle; } \
- VK_NONDISP_HANDLE_OPERATOR_BOOL() \
- uint64_t handle; \
- };
-««#else
- »#define VK_DEFINE_NONDISP_HANDLE(obj) typedef struct obj##_T { uint64_t handle; } obj;«
-#endif
- »»</type>
- <type category="define">
-#if defined(__cplusplus) &amp;&amp; ((defined(_MSC_VER) &amp;&amp; _MSC_VER &gt;= 1800) || __cplusplus &gt;= 201103L)
- »#define <name>VK_NULL_HANDLE</name> nullptr
-«#else
- »#define VK_NULL_HANDLE 0
-«#endif
- »»</type>
- <type requires="vk_platform" name="VkDeviceSize"/>
- <type requires="vk_platform" name="VkSampleMask"/>
- <type requires="vk_platform" name="VkFlags"/>
- <!-- Basic C types, pulled in via vk_platform.h -->
- <type requires="vk_platform" name="char"/>
- <type requires="vk_platform" name="float"/>
- <type requires="vk_platform" name="VkBool32"/>
- <type requires="vk_platform" name="uint8_t"/>
- <type requires="vk_platform" name="uint32_t"/>
- <type requires="vk_platform" name="uint64_t"/>
- <type requires="vk_platform" name="int32_t"/>
- <type requires="vk_platform" name="size_t"/>
- <!-- Bitfield types -->
- {{range $e := $.Enums}}
- {{if $e.IsBitfield}}
- {{$bits := print (Macro "EnumName" $e | TrimRight "s") "Bits"}}
- <type{{if $e.Entries}} requires="{{$bits}}"{{end}} category="bitmask">typedef <type>VkFlags</type> <name>{{$e.Name}}</name>;</type>§
- {{if $e.Entries}}{{Macro "XML.Docs" $e.Docs}}
- {{else}}{{Macro "XML.Docs" (Strings $e.Docs "(no bits yet)")}}
- {{end}}
- {{end}}
- {{end}}
- <!-- Types which can be void pointers or class pointers, selected at compile time -->
- {{range $i, $p := $.Pseudonyms}}
- {{ if (GetAnnotation $p "dispatchHandle")}}
- {{if Global "VK_DEFINE_HANDLE_TYPE_DEFINED"}}
- <type category="handle">VK_DEFINE_HANDLE(<name>{{$p.Name}}</name>)</type>
- {{else}}
- {{Global "VK_DEFINE_HANDLE_TYPE_DEFINED" "YES"}}
- <type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>{{$p.Name}}</name>)</type>
- {{end}}
- {{else if (GetAnnotation $p "nonDispatchHandle")}}
- {{if Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED"}}
- <type category="handle">VK_DEFINE_NONDISP_HANDLE(<name>{{$p.Name}}</name>)</type>
- {{else}}
- {{Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED" "YES"}}
- <type category="handle"><type>VK_DEFINE_NONDISP_HANDLE</type>(<name>{{$p.Name}}</name>)</type>
- {{end}}
- {{end}}
- {{end}}
- <!-- Types generated from corresponding <enums> tags below -->
- {{range $e := SortBy $.Enums "EnumName"}}
- {{if and $e.Entries (not (GetAnnotation $e "internal"))}}
- {{if $e.IsBitfield}}
- <type name="{{Macro "EnumName" $e | TrimRight "s"}}Bits" category="enum"/>
- {{else}}
- <type name="{{$e.Name}}" category="enum"/>
- {{end}}
- {{end}}
- {{end}}
- <!-- The PFN_vk*Function types are used by VkAllocCallbacks below -->
- <type>typedef void* (VKAPI *<name>PFN_vkAllocFunction</name>)(«
- void* pUserData,
- size_t size,
- size_t alignment,
- <type>VkSystemAllocType</type> allocType);</type>»
- <type>typedef void (VKAPI *<name>PFN_vkFreeFunction</name>)(«
- void* pUserData,
- void* pMem);</type>»
- <!-- The PFN_vkVoidFunction type are used by VkGet*ProcAddr below -->
- <type>typedef void (VKAPI *<name>PFN_vkVoidFunction</name>)(void);</type>
- <!-- Struct types -->
- {{range $c := $.Classes}}
- {{if not (GetAnnotation $c "internal")}}
- {{Macro "Struct" $c}}
- {{end}}
- {{end}}
- «</types>
- <!-- SECTION: Vulkan enumerant (token) definitions. -->
- <enums namespace="VK" comment="Misc. hardcoded constants - not an enumerated type">»
- <!-- This is part of the header boilerplate -->
- {{range $d := $.Definitions}}
- {{if HasPrefix $d.Name "VK_"}}
- <enum value="{{$d.Expression}}" name="{{$d.Name}}"/>{{Macro "XML.Docs" $d.Docs}}
- {{end}}
- {{end}}
- <enum value="1000.0f" name="VK_LOD_CLAMP_NONE"/>
- <enum value="(-0U)" name="VK_REMAINING_MIP_LEVELS"/>
- <enum value="(~0U)" name="VK_REMAINING_ARRAY_LAYERS"/>
- <enum value="(_0ULL)" name="VK_WHOLE_SIZE"/>
- <enum value="(~0U)" name="VK_ATTACHMENT_UNUSED"/>
- <enum value="(~0U)" name="VK_QUEUE_FAMILY_IGNORED"/>
- <enum value="(~0U)" name="VK_SUBPASS_EXTERNAL"/>
- «</enums>
- <!-- Unlike OpenGL, most tokens in Vulkan are actual typed enumerants in»
- their own numeric namespaces. The "name" attribute is the C enum
- type name, and is pulled in from a <type> definition above
- (slightly clunky, but retains the type / enum distinction). "type"
- attributes of "enum" or "bitmask" indicate that these values should
- be generated inside an appropriate definition. -->«
- {{range $e := $.Enums}}
- {{if not (or $e.IsBitfield (GetAnnotation $e "internal"))}}
- {{Macro "XML.Enum" $e}}
- {{end}}
- {{end}}
- <!-- Flags -->
- {{range $e := $.Enums}}
- {{if $e.IsBitfield}}
- {{Macro "XML.Bitfield" $e}}
- {{end}}
- {{end}}
- <!-- SECTION: Vulkan command definitions -->
- <commands namespace="vk">»
- {{range $f := AllCommands $}}
- {{if not (GetAnnotation $f "pfn")}}
- {{Macro "XML.Function" $f}}
- {{end}}
- {{end}}
- «</commands>
- <!-- SECTION: Vulkan API interface definitions -->
- <feature api="vulkan" name="VK_VERSION_1_0" number="1.0">»
- <require comment="Header boilerplate">»
- <type name="vk_platform"/>
- «</require>
- <require comment="API version">»
- <type name="VK_API_VERSION"/>
- «</require>
- <require comment="API constants">»
- <enum name="VK_LOD_CLAMP_NONE"/>
- <enum name="VK_REMAINING_MIP_LEVELS"/>
- <enum name="VK_REMAINING_ARRAY_LAYERS"/>
- <enum name="VK_WHOLE_SIZE"/>
- <enum name="VK_ATTACHMENT_UNUSED"/>
- <enum name="VK_TRUE"/>
- <enum name="VK_FALSE"/>
- «</require>
- <require comment="All functions (TODO: split by type)">»
- {{range $f := AllCommands $}}
- {{if not (GetAnnotation $f "pfn")}}
- <command name="{{$f.Name}}"/>
- {{end}}
- {{end}}
- </require>
- «<require comment="Types not directly used by the API">»
- <!-- Include <type name="typename"/> here for e.g. structs that»
- are not parameter types of commands, but still need to be
- defined in the API.
- «-->
- <type name="VkBufferMemoryBarrier"/>
- <type name="VkDispatchIndirectCmd"/>
- <type name="VkDrawIndexedIndirectCmd"/>
- <type name="VkDrawIndirectCmd"/>
- <type name="VkImageMemoryBarrier"/>
- <type name="VkMemoryBarrier"/>
- «</require>
- «</feature>
- <!-- SECTION: Vulkan extension interface definitions (none yet) -->
-«</registry>
-{{end}}
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified bitfield.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Bitfield"}}
- {{AssertType $ "Enum"}}
-
- {{if $.Entries}}
- <enums namespace="VK" name="{{Macro "EnumName" $ | TrimRight "s"}}Bits" type="bitmask">»
- {{range $e := $.Entries}}
- {{$pos := Bitpos $e.Value}}
- <enum §
- {{if gt $pos -1}} bitpos="{{$pos}}" §
- {{else}}value="{{if $e.Value}}{{printf "0x%.8X" $e.Value}}{{else}}0{{end}}" §
- {{end}}name="{{Macro "BitfieldEntryName" $e}}" §
- {{if $d := $e.Docs}} comment="{{$d | JoinWith " "}}"{{end}}/>
- {{end}}
- «</enums>
- {{end}}
-
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified enum.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Enum"}}
- {{AssertType $ "Enum"}}
-
- <enums namespace="VK" name="{{Macro "EnumName" $}}" type="enum" §
- expand="{{Macro "EnumName" $ | SplitPascalCase | Upper | JoinWith "_"}}"{{if $.Docs}} comment="{{$.Docs | JoinWith " "}}"{{end}}>»
- {{range $i, $e := $.Entries}}
- <enum value="{{AsSigned $e.Value}}" name="{{Macro "BitfieldEntryName" $e}}"{{if $e.Docs}} comment="{{$e.Docs | JoinWith " "}}"{{end}}/>
- {{end}}
- {{if $lu := GetAnnotation $ "lastUnused"}}
- <unused start="{{index $lu.Arguments 0}}"/>
- {{end}}
- «</enums>
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified class.
--------------------------------------------------------------------------------
-*/}}
-{{define "Struct"}}
- {{AssertType $ "Class"}}
-
- <type category="{{Macro "StructType" $}}" name="{{Macro "StructName" $}}"{{if $.Docs}} comment="{{$.Docs | JoinWith " "}}"{{end}}>»
- {{range $f := $.Fields}}
- <member>{{Node "XML.Type" $f}} <name>{{$f.Name}}</name>{{Macro "XML.ArrayPostfix" $f}}</member>{{Macro "XML.Docs" $f.Docs}}
- {{end}}
- «</type>
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits either 'struct' or 'union' for the specified class.
--------------------------------------------------------------------------------
-*/}}
-{{define "StructType"}}
- {{AssertType $ "Class"}}
-
- {{if GetAnnotation $ "union"}}union{{else}}struct{{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C function pointer typedef declaration for the specified command.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Function"}}
- {{AssertType $ "Function"}}
-
- {{$ts := GetAnnotation $ "threadSafety"}}
- <command{{if $ts}} threadsafe="{{index $ts.Arguments 0}}"{{end}}>»
- <proto>{{Node "XML.Type" $.Return}} <name>{{$.Name}}</name></proto>
- {{range $p := $.CallParameters}}
- <param>{{Node "XML.Type" $p}} <name>{{$p.Name}}{{Macro "ArrayPostfix" $p}}</name></param>
- {{end}}
- «</command>
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the XML translation for the specified documentation block (string array).
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Docs"}}
- {{if $}} <!-- {{JoinWith " " $ | Replace "<" "" | Replace ">" ""}} -->{{end}}
-{{end}}
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C translation for the specified type.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Type.Class" }}<type>{{Macro "StructName" $.Type}}</type>{{end}}
-{{define "XML.Type.Pseudonym" }}<type>{{$.Type.Name}}</type>{{end}}
-{{define "XML.Type.Enum" }}<type>{{$.Type.Name}}</type>{{end}}
-{{define "XML.Type.StaticArray"}}{{Node "XML.Type" $.Type.ValueType}}{{end}}
-{{define "XML.Type.Pointer" }}{{if $.Type.Const}}{{Node "XML.ConstType" $.Type.To}}{{else}}{{Node "XML.Type" $.Type.To}}{{end}}*{{end}}
-{{define "XML.Type.Slice" }}<type>{{Node "XML.Type" $.Type.To}}</type>*{{end}}
-{{define "XML.Type#s8" }}<type>int8_t</type>{{end}}
-{{define "XML.Type#u8" }}<type>uint8_t</type>{{end}}
-{{define "XML.Type#s16" }}<type>int16_t</type>{{end}}
-{{define "XML.Type#u16" }}<type>uint16_t</type>{{end}}
-{{define "XML.Type#s32" }}<type>int32_t</type>{{end}}
-{{define "XML.Type#u32" }}<type>uint32_t</type>{{end}}
-{{define "XML.Type#f32" }}<type>float</type>{{end}}
-{{define "XML.Type#s64" }}<type>int64_t</type>{{end}}
-{{define "XML.Type#u64" }}<type>uint64_t</type>{{end}}
-{{define "XML.Type#f64" }}<type>double</type>{{end}}
-{{define "XML.Type#char" }}<type>char</type>{{end}}
-{{define "XML.Type#void" }}void{{end}}
-
-{{define "XML.ConstType_Default"}}const {{Node "XML.Type" $.Type}}{{end}}
-{{define "XML.ConstType.Pointer"}}{{Node "XML.Type" $.Type}} const{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits a C type and name for the given parameter
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Parameter"}}
- {{AssertType $ "Parameter"}}
-
- <type>{{Macro "ParameterType" $}}</type> <name>{{$.Name}}{{Macro "ArrayPostfix" $}}</name>
-{{end}}
-
-{{/*
--------------------------------------------------------------------------------
- Emits a comma-separated list of C type-name paired parameters for the given
- command.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Parameters"}}
- {{AssertType $ "Function"}}
-
- {{ForEach $.CallParameters "XML.Parameter" | JoinWith ", "}}
- {{if not $.CallParameters}}<type>void</type>{{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the fixed-size-array postfix for pseudonym types annotated with @array
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.ArrayPostfix"}}{{Node "XML.ArrayPostfix" $}}{{end}}
-{{define "XML.ArrayPostfix.StaticArray"}}[{{Node "XML.NamedValue" $.Type.SizeExpr}}]{{end}}
-{{define "XML.ArrayPostfix_Default"}}{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the value of the given constant, or the <enum> tagged name if existant.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.NamedValue.Definition"}}<enum>{{$.Node.Name}}</enum>{{end}}
-{{define "XML.NamedValue.EnumEntry"}}<enum>{{$.Node.Name}}</enum>{{end}}
-{{define "XML.NamedValue_Default"}}{{$.Node}}{{end}}
diff --git a/vulkan/api/templates/vulkan_h.tmpl b/vulkan/api/templates/vulkan_h.tmpl
deleted file mode 100644
index 83a5e40804..0000000000
--- a/vulkan/api/templates/vulkan_h.tmpl
+++ /dev/null
@@ -1,295 +0,0 @@
-{{Include "vulkan_common.tmpl"}}
-{{Macro "DefineGlobals" $}}
-{{$ | Macro "vulkan.h" | Format (Global "clang-format") | Write "../include/vulkan.h"}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Entry point
--------------------------------------------------------------------------------
-*/}}
-{{define "vulkan.h"}}
-#ifndef __vulkan_h_
-#define __vulkan_h_ 1
-#ifdef __cplusplus
-extern "C" {
-#endif
-/*
-** Copyright (c) 2015-2016 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-/*
-** This header is generated from the Khronos Vulkan API Registry.
-**
-*/
-#define VK_VERSION_1_0 1
-#include "vk_platform.h"
-#define VK_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch))
-// Vulkan API version supported by this file
-#define VK_API_VERSION \
- VK_MAKE_VERSION({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}})
-#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
-#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
-#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
-#if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L)
- #define VK_NULL_HANDLE nullptr
-#else
- #define VK_NULL_HANDLE 0
-#endif
-#define VK_DEFINE_HANDLE(obj) typedef struct obj##_T* obj;
-#if defined(__cplusplus)
-#if ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L)
-// The bool operator only works if there are no implicit conversions from an obj to
-// a bool-compatible type, which can then be used to unintentionally violate type safety.
-// C++11 and above supports the "explicit" keyword on conversion operators to stop this
-// from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating
-// the object handle as a bool in expressions like:
-// if (obj) vkDestroy(obj);
-#define VK_NONDISP_HANDLE_OPERATOR_BOOL() \
- explicit operator bool() const { return handle != 0; }
-#define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- explicit obj(uint64_t x) : handle(x) { } \
- obj(decltype(nullptr)) : handle(0) { }
-#else
-#define VK_NONDISP_HANDLE_OPERATOR_BOOL()
-#define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- obj(uint64_t x) : handle(x) { }
-#endif
-#define VK_DEFINE_NONDISP_HANDLE(obj) \
- struct obj { \
- obj() : handle(0) { } \
- VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- obj& operator=(uint64_t x) { \
- handle = x; \
- return *this; \
- } \
- bool operator==(const obj& other) const { return handle == other.handle; } \
- bool operator!=(const obj& other) const { return handle != other.handle; } \
- bool operator!() const { return !handle; } \
- VK_NONDISP_HANDLE_OPERATOR_BOOL() \
- uint64_t handle; \
- };
-#else
-#define VK_DEFINE_NONDISP_HANDLE(obj) \
- typedef struct obj##_T { uint64_t handle; } obj;
-#endif
-#define VK_LOD_CLAMP_NONE 1000.0f
-#define VK_REMAINING_MIP_LEVELS (~0U)
-#define VK_REMAINING_ARRAY_LAYERS (~0U)
-#define VK_WHOLE_SIZE (~0ULL)
-#define VK_ATTACHMENT_UNUSED (~0U)
-define VK_QUEUE_FAMILY_IGNORED (~0U)
-define VK_SUBPASS_EXTERNAL (~0U)
-{{range $d := $.Definitions}}
- {{if HasPrefix $d.Name "VK_"}}#define {{$d.Name}} {{$d.Expression}}{{end}}
-{{end}}
-{{range $i, $p := $.Pseudonyms}}
- {{if GetAnnotation $p "dispatchHandle"}}VK_DEFINE_HANDLE({{$p.Name}})
- {{else if GetAnnotation $p "nonDispatchHandle"}}VK_DEFINE_NONDISP_HANDLE({{$p.Name}})
- {{end}}
-{{end}}
-// ------------------------------------------------------------------------------------------------
-// Enumerations
- {{range $e := $.Enums}}
- {{if not $e.IsBitfield}}
- {{Macro "Enum" $e}}
- {{end}}
- {{end}}
-// ------------------------------------------------------------------------------------------------
-// Flags
- {{range $e := $.Enums}}
- {{if $e.IsBitfield}}
- {{Macro "Bitfield" $e}}
- {{end}}
- {{end}}
-// ------------------------------------------------------------------------------------------------
-// Vulkan structures
- {{/* Function pointers */}}
- {{range $f := AllCommands $}}
- {{if GetAnnotation $f "pfn"}}
- {{Macro "FunctionTypedef" $f}}
- {{end}}
- {{end}}
- {{range $c := $.Classes}}
- {{if not (GetAnnotation $c "internal")}}
- {{Macro "Struct" $c}}
- {{end}}
- {{end}}
-// ------------------------------------------------------------------------------------------------
-// API functions
- {{range $f := AllCommands $}}
- {{if not (GetAnnotation $f "pfn")}}
- {{Macro "FunctionTypedef" $f}}
- {{end}}
- {{end}}
-#ifdef VK_NO_PROTOTYPES
- {{range $f := AllCommands $}}
- {{if not (GetAnnotation $f "pfn")}}
- {{Macro "FunctionDecl" $f}}
- {{end}}
- {{end}}
-#endif
-#ifdef __cplusplus
-}
-#endif
-#endif
-{{end}}
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified bitfield.
--------------------------------------------------------------------------------
-*/}}
-{{define "Bitfield"}}
- {{AssertType $ "Enum"}}
-
- {{Macro "Docs" $.Docs}}
- typedef VkFlags {{Macro "EnumName" $}};
- {{if $.Entries}}
- typedef enum {
- {{range $b := $.Entries}}
- {{Macro "BitfieldEntryName" $b}} = {{printf "0x%.8X" $b.Value}}, {{Macro "Docs" $b.Docs}}
- {{end}}
- } {{Macro "EnumName" $ | TrimRight "s"}}Bits;
- {{end}}
- ¶
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified enum.
--------------------------------------------------------------------------------
-*/}}
-{{define "Enum"}}
- {{AssertType $ "Enum"}}
-
- {{Macro "Docs" $.Docs}}
- typedef enum {
- {{range $i, $e := $.Entries}}
- {{Macro "EnumEntry" $e}} = {{printf "0x%.8X" $e.Value}}, {{Macro "Docs" $e.Docs}}
- {{end}}
- ¶
- {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}}
- {{if GetAnnotation $ "enumMaxOnly"}}
- VK_MAX_ENUM({{$name | SplitOn "VK_"}})
- {{else}}
- {{$first := Macro "EnumFirstEntry" $ | SplitOn $name | TrimLeft "_"}}
- {{$last := Macro "EnumLastEntry" $ | SplitOn $name | TrimLeft "_"}}
- VK_ENUM_RANGE({{$name | SplitOn "VK_"}}, {{$first}}, {{$last}})
- {{end}}
- } {{Macro "EnumName" $}};
- ¶
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified class.
--------------------------------------------------------------------------------
-*/}}
-{{define "Struct"}}
- {{AssertType $ "Class"}}
-
- {{Macro "Docs" $.Docs}}
- typedef {{Macro "StructType" $}} {
- {{ForEach $.Fields "Field" | JoinWith "\n"}}
- } {{Macro "StructName" $}};
- ¶
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified class field.
--------------------------------------------------------------------------------
-*/}}
-{{define "Field"}}
- {{AssertType $ "Field"}}
-
- {{Node "Type" $}} {{$.Name}}§
- {{Macro "ArrayPostfix" (TypeOf $)}}; {{Macro "Docs" $.Docs}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits either 'struct' or 'union' for the specified class.
--------------------------------------------------------------------------------
-*/}}
-{{define "StructType"}}
- {{AssertType $ "Class"}}
-
- {{if GetAnnotation $ "union"}}union{{else}}struct{{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C function pointer typedef declaration for the specified command.
--------------------------------------------------------------------------------
-*/}}
-{{define "FunctionTypedef"}}
- {{AssertType $ "Function"}}
-
- typedef {{Node "Type" $.Return}} (VKAPI* {{Macro "FunctionPtrName" $}})({{Macro "Parameters" $}});
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C function declaration for the specified command.
--------------------------------------------------------------------------------
-*/}}
-{{define "FunctionDecl"}}
- {{AssertType $ "Function"}}
-
- {{if not (GetAnnotation $ "fptr")}}
- {{Macro "Docs" $.Docs}}
- {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}});
- {{end}}
-{{end}}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 23506bad54..d33e5528e8 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -16,30 +16,29 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include "driver.h"
+
+#include <dlfcn.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/prctl.h>
-
-#include <dlfcn.h>
-#include <algorithm>
-#include <array>
-#include <new>
-
-#include <log/log.h>
#include <android/dlext.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <android-base/properties.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
#include <graphicsenv/GraphicsEnv.h>
+#include <log/log.h>
+#include <sys/prctl.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
-#include <utils/Vector.h>
-#include "android-base/properties.h"
+#include <algorithm>
+#include <array>
+#include <new>
+#include <vector>
-#include "driver.h"
#include "stubhal.h"
using namespace android::hardware::configstore;
@@ -809,8 +808,7 @@ VkResult EnumerateInstanceExtensionProperties(
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
-
- android::Vector<VkExtensionProperties> loader_extensions;
+ std::vector<VkExtensionProperties> loader_extensions;
loader_extensions.push_back({
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_SURFACE_SPEC_VERSION});
@@ -833,7 +831,7 @@ VkResult EnumerateInstanceExtensionProperties(
uint32_t count = std::min(
*pPropertyCount, static_cast<uint32_t>(loader_extensions.size()));
- std::copy_n(loader_extensions.begin(), count, pProperties);
+ std::copy_n(loader_extensions.data(), count, pProperties);
if (count < loader_extensions.size()) {
*pPropertyCount = count;
@@ -879,8 +877,7 @@ VkResult EnumerateInstanceExtensionProperties(
bool QueryPresentationProperties(
VkPhysicalDevice physicalDevice,
- VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties)
-{
+ VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties) {
const InstanceData& data = GetData(physicalDevice);
// GPDP2 must be present and enabled on the instance.
@@ -920,7 +917,7 @@ VkResult EnumerateDeviceExtensionProperties(
VkExtensionProperties* pProperties) {
const InstanceData& data = GetData(physicalDevice);
// extensions that are unconditionally exposed by the loader
- android::Vector<VkExtensionProperties> loader_extensions;
+ std::vector<VkExtensionProperties> loader_extensions;
loader_extensions.push_back({
VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION});
@@ -956,7 +953,7 @@ VkResult EnumerateDeviceExtensionProperties(
uint32_t count = std::min(
*pPropertyCount, static_cast<uint32_t>(loader_extensions.size()));
- std::copy_n(loader_extensions.begin(), count, pProperties);
+ std::copy_n(loader_extensions.data(), count, pProperties);
if (count < loader_extensions.size()) {
*pPropertyCount = count;
@@ -1245,11 +1242,10 @@ VkResult EnumeratePhysicalDeviceGroups(
if (!device_count)
return VK_INCOMPLETE;
- android::Vector<VkPhysicalDevice> devices;
- devices.resize(device_count);
+ std::vector<VkPhysicalDevice> devices(device_count);
*pPhysicalDeviceGroupCount = device_count;
- result = EnumeratePhysicalDevices(instance, &device_count,
- devices.editArray());
+ result =
+ EnumeratePhysicalDevices(instance, &device_count, devices.data());
if (result < 0)
return result;
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 524fe0e594..761d128d79 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -24,7 +24,6 @@
#include <ui/BufferQueueDefs.h>
#include <utils/StrongPointer.h>
#include <utils/Trace.h>
-#include <utils/Vector.h>
#include <algorithm>
#include <unordered_set>
@@ -132,7 +131,6 @@ int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) {
class TimingInfo {
public:
- TimingInfo() = default;
TimingInfo(const VkPresentTimeGOOGLE* qp, uint64_t nativeFrameId)
: vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0},
native_frame_id_(nativeFrameId) {}
@@ -266,7 +264,7 @@ struct Swapchain {
bool dequeued;
} images[android::BufferQueueDefs::NUM_BUFFER_SLOTS];
- android::Vector<TimingInfo> timing;
+ std::vector<TimingInfo> timing;
};
VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
@@ -349,7 +347,7 @@ uint32_t get_num_ready_timings(Swapchain& swapchain) {
uint32_t num_ready = 0;
const size_t num_timings = swapchain.timing.size() - MIN_NUM_FRAMES_AGO + 1;
for (uint32_t i = 0; i < num_timings; i++) {
- TimingInfo& ti = swapchain.timing.editItemAt(i);
+ TimingInfo& ti = swapchain.timing[i];
if (ti.ready()) {
// This TimingInfo is ready to be reported to the user. Add it
// to the num_ready.
@@ -419,7 +417,7 @@ void copy_ready_timings(Swapchain& swapchain,
}
uint32_t num_copied = 0;
- size_t num_to_remove = 0;
+ int32_t num_to_remove = 0;
for (uint32_t i = 0; i <= last_ready && num_copied < *count; i++) {
const TimingInfo& ti = swapchain.timing[i];
if (ti.ready()) {
@@ -431,7 +429,8 @@ void copy_ready_timings(Swapchain& swapchain,
// Discard old frames that aren't ready if newer frames are ready.
// We don't expect to get the timing info for those old frames.
- swapchain.timing.removeItemsAt(0, num_to_remove);
+ swapchain.timing.erase(swapchain.timing.begin(),
+ swapchain.timing.begin() + num_to_remove);
*count = num_copied;
}
@@ -817,11 +816,10 @@ VkResult GetPhysicalDeviceSurfaceFormats2KHR(
} else {
// temp vector for forwarding; we'll marshal it into the pSurfaceFormats
// after the call.
- android::Vector<VkSurfaceFormatKHR> surface_formats;
- surface_formats.resize(*pSurfaceFormatCount);
+ std::vector<VkSurfaceFormatKHR> surface_formats(*pSurfaceFormatCount);
VkResult result = GetPhysicalDeviceSurfaceFormatsKHR(
physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount,
- &surface_formats.editItemAt(0));
+ surface_formats.data());
if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
// marshal results individually due to stride difference.
@@ -863,7 +861,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev,
}
uint32_t max_buffer_count = static_cast<uint32_t>(query_value);
- android::Vector<VkPresentModeKHR> present_modes;
+ std::vector<VkPresentModeKHR> present_modes;
if (min_undequeued_buffers + 1 < max_buffer_count)
present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
@@ -883,7 +881,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev,
if (*count < num_modes)
result = VK_INCOMPLETE;
*count = std::min(*count, num_modes);
- std::copy(present_modes.begin(), present_modes.begin() + int(*count), modes);
+ std::copy_n(present_modes.data(), *count, modes);
} else {
*count = num_modes;
}
@@ -1647,9 +1645,9 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
// Add a new timing record with the user's presentID and
// the nativeFrameId.
- swapchain.timing.push_back(TimingInfo(time, nativeFrameId));
+ swapchain.timing.emplace_back(time, nativeFrameId);
while (swapchain.timing.size() > MAX_TIMING_INFOS) {
- swapchain.timing.removeAt(0);
+ swapchain.timing.erase(swapchain.timing.begin());
}
if (time->desiredPresentTime) {
// Set the desiredPresentTime: