Merge "SF: Omit layer tree dump if flag is specified"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 8d383f5..93bbe90 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -93,7 +93,6 @@
"libutils",
],
srcs: [
- "DumpstateSectionReporter.cpp",
"DumpstateService.cpp",
],
static_libs: [
diff --git a/cmds/dumpstate/DumpstateSectionReporter.cpp b/cmds/dumpstate/DumpstateSectionReporter.cpp
deleted file mode 100644
index f814bde..0000000
--- a/cmds/dumpstate/DumpstateSectionReporter.cpp
+++ /dev/null
@@ -1,42 +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.
- */
-
-#define LOG_TAG "dumpstate"
-
-#include "DumpstateSectionReporter.h"
-
-namespace android {
-namespace os {
-namespace dumpstate {
-
-DumpstateSectionReporter::DumpstateSectionReporter(const std::string& title,
- sp<android::os::IDumpstateListener> listener,
- bool sendReport)
- : title_(title), listener_(listener), sendReport_(sendReport), status_(OK), size_(-1) {
- started_ = std::chrono::steady_clock::now();
-}
-
-DumpstateSectionReporter::~DumpstateSectionReporter() {
- if ((listener_ != nullptr) && (sendReport_)) {
- auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now() - started_);
- listener_->onSectionComplete(title_, status_, size_, (int32_t)elapsed.count());
- }
-}
-
-} // namespace dumpstate
-} // namespace os
-} // namespace android
diff --git a/cmds/dumpstate/DumpstateSectionReporter.h b/cmds/dumpstate/DumpstateSectionReporter.h
deleted file mode 100644
index e971de8..0000000
--- a/cmds/dumpstate/DumpstateSectionReporter.h
+++ /dev/null
@@ -1,65 +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 ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
-#define ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
-
-#include <android/os/IDumpstateListener.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-namespace os {
-namespace dumpstate {
-
-
-/*
- * Helper class used to report per section details to a listener.
- *
- * Typical usage:
- *
- * DumpstateSectionReporter sectionReporter(title, listener, sendReport);
- * sectionReporter.setSize(5000);
- *
- */
-class DumpstateSectionReporter {
- public:
- DumpstateSectionReporter(const std::string& title, sp<android::os::IDumpstateListener> listener,
- bool sendReport);
-
- ~DumpstateSectionReporter();
-
- void setStatus(status_t status) {
- status_ = status;
- }
-
- void setSize(int size) {
- size_ = size;
- }
-
- private:
- std::string title_;
- android::sp<android::os::IDumpstateListener> listener_;
- bool sendReport_;
- status_t status_;
- int size_;
- std::chrono::time_point<std::chrono::steady_clock> started_;
-};
-
-} // namespace dumpstate
-} // namespace os
-} // namespace android
-
-#endif // ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 37ba4f9..f98df99 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -200,8 +200,7 @@
dprintf(fd, "id: %d\n", ds_->id_);
dprintf(fd, "pid: %d\n", ds_->pid_);
dprintf(fd, "update_progress: %s\n", ds_->options_->do_progress_updates ? "true" : "false");
- dprintf(fd, "update_progress_threshold: %d\n", ds_->update_progress_threshold_);
- dprintf(fd, "last_updated_progress: %d\n", ds_->last_updated_progress_);
+ dprintf(fd, "last_percent_progress: %d\n", ds_->last_reported_percent_progress_);
dprintf(fd, "progress:\n");
ds_->progress_->Dump(fd, " ");
dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index ea1e467..e486460 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -61,21 +61,4 @@
* Called when taking bugreport finishes successfully.
*/
void onFinished();
-
- // TODO(b/111441001): Remove old methods when not used anymore.
- void onProgressUpdated(int progress);
- void onMaxProgressUpdated(int maxProgress);
-
- /**
- * Called after every section is complete.
- *
- * @param name section name
- * @param status values from status_t
- * {@code OK} section completed successfully
- * {@code TIMEOUT} dump timed out
- * {@code != OK} error
- * @param size size in bytes, may be invalid if status != OK
- * @param durationMs duration in ms
- */
- void onSectionComplete(@utf8InCpp String name, int status, int size, int durationMs);
}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index fe55fe7..3a0aa95 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -80,7 +80,6 @@
#include <serviceutils/PriorityDumper.h>
#include <utils/StrongPointer.h>
#include "DumpstateInternal.h"
-#include "DumpstateSectionReporter.h"
#include "DumpstateService.h"
#include "dumpstate.h"
@@ -105,7 +104,6 @@
using android::os::IDumpstateListener;
using android::os::dumpstate::CommandOptions;
using android::os::dumpstate::DumpFileToFd;
-using android::os::dumpstate::DumpstateSectionReporter;
using android::os::dumpstate::PropertiesHelper;
// Keep in sync with
@@ -1047,7 +1045,6 @@
RETURN_IF_USER_DENIED_CONSENT();
std::string path(title);
path.append(" - ").append(String8(service).c_str());
- DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
size_t bytes_written = 0;
status_t status = dumpsys.startDumpThread(service, args);
if (status == OK) {
@@ -1055,12 +1052,10 @@
std::chrono::duration<double> elapsed_seconds;
status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
/* as_proto = */ false, elapsed_seconds, bytes_written);
- section_reporter.setSize(bytes_written);
dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
bool dump_complete = (status == OK);
dumpsys.stopDumpThread(dump_complete);
}
- section_reporter.setStatus(status);
auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start);
@@ -1123,7 +1118,6 @@
path.append("_HIGH");
}
path.append(kProtoExt);
- DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
status_t status = dumpsys.startDumpThread(service, args);
if (status == OK) {
status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
@@ -1132,8 +1126,6 @@
}
ZipWriter::FileEntry file_entry;
ds.zip_writer_->GetLastEntry(&file_entry);
- section_reporter.setSize(file_entry.compressed_size);
- section_reporter.setStatus(status);
auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start);
@@ -1270,7 +1262,6 @@
DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
- DumpFile("KERNEL SYNC", "/d/sync");
RunCommand("PROCESSES AND THREADS",
{"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
@@ -2813,6 +2804,7 @@
Dumpstate::Dumpstate(const std::string& version)
: pid_(getpid()),
options_(new Dumpstate::DumpOptions()),
+ last_reported_percent_progress_(0),
version_(version),
now_(time(nullptr)) {
}
@@ -3575,31 +3567,25 @@
}
// Always update progess so stats can be tuned...
- bool max_changed = progress_->Inc(delta_sec);
+ progress_->Inc(delta_sec);
// ...but only notifiy listeners when necessary.
if (!options_->do_progress_updates) return;
int progress = progress_->Get();
int max = progress_->GetMax();
+ int percent = 100 * progress / max;
- // adjusts max on the fly
- if (max_changed && listener_ != nullptr) {
- listener_->onMaxProgressUpdated(max);
- }
-
- int32_t last_update_delta = progress - last_updated_progress_;
- if (last_updated_progress_ > 0 && last_update_delta < update_progress_threshold_) {
+ if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
return;
}
- last_updated_progress_ = progress;
+ last_reported_percent_progress_ = percent;
if (control_socket_fd_ >= 0) {
dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
fsync(control_socket_fd_);
}
- int percent = 100 * progress / max;
if (listener_ != nullptr) {
if (percent % 5 == 0) {
// We don't want to spam logcat, so only log multiples of 5.
@@ -3611,8 +3597,6 @@
fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
progress, max, percent);
}
- // TODO(b/111441001): Remove in favor of onProgress
- listener_->onProgressUpdated(progress);
listener_->onProgress(percent);
}
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index fe330df..77b5e8a 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -405,12 +405,8 @@
// Runtime options.
std::unique_ptr<DumpOptions> options_;
- // How frequently the progess should be updated;the listener will only be notificated when the
- // delta from the previous update is more than the threshold.
- int32_t update_progress_threshold_ = 100;
-
- // Last progress that triggered a listener updated
- int32_t last_updated_progress_;
+ // Last progress that was sent to the listener [0-100].
+ int last_reported_percent_progress_ = 0;
// Whether it should take an screenshot earlier in the process.
bool do_early_screenshot_ = false;
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index f7acaf1..181046a 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -167,26 +167,6 @@
return binder::Status::ok();
}
- binder::Status onProgressUpdated(int32_t progress) override {
- dprintf(out_fd_, "\rIn progress %d/%d", progress, max_progress_);
- return binder::Status::ok();
- }
-
- binder::Status onMaxProgressUpdated(int32_t max_progress) override {
- std::lock_guard<std::mutex> lock(lock_);
- max_progress_ = max_progress;
- return binder::Status::ok();
- }
-
- binder::Status onSectionComplete(const ::std::string& name, int32_t, int32_t size_bytes,
- int32_t) override {
- std::lock_guard<std::mutex> lock(lock_);
- if (sections_.get() != nullptr) {
- sections_->push_back({name, size_bytes});
- }
- return binder::Status::ok();
- }
-
bool getIsFinished() {
std::lock_guard<std::mutex> lock(lock_);
return is_finished_;
@@ -199,7 +179,6 @@
private:
int out_fd_;
- int max_progress_ = 5000;
int error_code_ = -1;
bool is_finished_ = false;
std::shared_ptr<std::vector<SectionInfo>> sections_;
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 4e6b084..cff1d43 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -62,10 +62,6 @@
MOCK_METHOD1(onProgress, binder::Status(int32_t progress));
MOCK_METHOD1(onError, binder::Status(int32_t error_code));
MOCK_METHOD0(onFinished, binder::Status());
- MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
- MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
- MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status,
- int32_t size, int32_t durationMs));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
@@ -590,7 +586,6 @@
SetDryRun(false);
SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
ds.progress_.reset(new Progress());
- ds.update_progress_threshold_ = 0;
ds.options_.reset(new Dumpstate::DumpOptions());
}
@@ -615,10 +610,9 @@
return status;
}
- void SetProgress(long progress, long initial_max, long threshold = 0) {
+ void SetProgress(long progress, long initial_max) {
+ ds.last_reported_percent_progress_ = 0;
ds.options_->do_progress_updates = true;
- ds.update_progress_threshold_ = threshold;
- ds.last_updated_progress_ = 0;
ds.progress_.reset(new Progress(initial_max, progress, 1.2));
}
@@ -796,73 +790,36 @@
ds.listener_name_ = "FoxMulder";
SetProgress(0, 30);
- EXPECT_CALL(*listener, onProgressUpdated(20));
EXPECT_CALL(*listener, onProgress(66)); // 20/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
- EXPECT_CALL(*listener, onProgressUpdated(30));
- EXPECT_CALL(*listener, onProgress(100)); // 35/35 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
- EXPECT_THAT(out, StrEq("stdout\n"));
- EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
-
- // Run a command that will increase maximum timeout.
- EXPECT_CALL(*listener, onProgressUpdated(31));
- EXPECT_CALL(*listener, onMaxProgressUpdated(37));
- EXPECT_CALL(*listener, onProgress(83)); // 31/37 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30); // 20% increase
+ EXPECT_CALL(*listener, onProgress(80)); // 24/30 %
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
+ progress_message = GetProgressMessage(ds.listener_name_, 24, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
// Make sure command ran while in dry_run is counted.
SetDryRun(true);
- EXPECT_CALL(*listener, onProgressUpdated(35));
- EXPECT_CALL(*listener, onProgress(94)); // 35/37 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
+ EXPECT_CALL(*listener, onProgress(90)); // 27/30 %
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
+ progress_message = GetProgressMessage(ds.listener_name_, 27, 30);
EXPECT_THAT(out, IsEmpty());
EXPECT_THAT(err, StrEq(progress_message));
- ds.listener_.clear();
-}
-
-TEST_F(DumpstateTest, RunCommandProgressIgnoreThreshold) {
- sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
- ds.listener_ = listener;
- ds.listener_name_ = "FoxMulder";
- SetProgress(0, 8, 5); // 8 max, 5 threshold
-
- // First update should always be sent.
- EXPECT_CALL(*listener, onProgressUpdated(1));
- EXPECT_CALL(*listener, onProgress(12)); // 1/12 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
- std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8);
+ SetDryRun(false);
+ EXPECT_CALL(*listener, onProgress(96)); // 29/30 %
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(2).Build()));
+ progress_message = GetProgressMessage(ds.listener_name_, 29, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
- // Fourth update should be ignored because it's between the threshold (5 -1 = 4 < 5).
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
- EXPECT_THAT(out, StrEq("stdout\n"));
- EXPECT_THAT(err, StrEq("stderr\n"));
-
- // Third update should be sent because it reaches threshold (6 - 1 = 5).
- EXPECT_CALL(*listener, onProgressUpdated(6));
- EXPECT_CALL(*listener, onProgress(75)); // 6/8 %
+ EXPECT_CALL(*listener, onProgress(100)); // 30/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 6, 8);
- EXPECT_THAT(out, StrEq("stdout\n"));
- EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
-
- // Fourth update should be ignored because it's between the threshold (9 - 6 = 3 < 5).
- // But max update should be sent.
- EXPECT_CALL(*listener, onMaxProgressUpdated(10)); // 9 * 120% = 10.8 = 10
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 9, 10, 8, false);
+ progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
@@ -1090,7 +1047,6 @@
ds.listener_name_ = "FoxMulder";
SetProgress(0, 30);
- EXPECT_CALL(*listener, onProgressUpdated(5));
EXPECT_CALL(*listener, onProgress(16)); // 5/30 %
EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index c2c71e0..5f7dc25 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -52,7 +52,6 @@
}
}
- // TODO(b/136023468): move this check to be first
if (!mAccess->canFind(ctx, name)) {
// returns ok and null for legacy reasons
*outBinder = nullptr;
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index ad7791e..50f117d 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -40,7 +40,6 @@
<feature name="android.software.voice_recognizers" notLowRam="true" />
<feature name="android.software.backup" />
<feature name="android.software.home_screen" />
- <feature name="android.software.print" />
<feature name="android.software.companion_device_setup" />
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index df23f61..690e0a1 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -31,13 +31,16 @@
#include <string>
+#include <android-base/chrono_utils.h>
+
#include <binder/IBinder.h>
#include <input/Input.h>
-#include <utils/Errors.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
+#include <input/LatencyStatistics.h>
#include <utils/BitSet.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
namespace android {
class Parcel;
@@ -286,7 +289,12 @@
status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
private:
+ static constexpr std::chrono::duration TOUCH_STATS_REPORT_PERIOD = 5min;
+
sp<InputChannel> mChannel;
+ LatencyStatistics mTouchStatistics{TOUCH_STATS_REPORT_PERIOD};
+
+ void reportTouchEventForStatistics(nsecs_t evdevTime);
};
/*
diff --git a/include/input/LatencyStatistics.h b/include/input/LatencyStatistics.h
new file mode 100644
index 0000000..bd86266
--- /dev/null
+++ b/include/input/LatencyStatistics.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.
+ */
+
+#ifndef _UI_INPUT_STATISTICS_H
+#define _UI_INPUT_STATISTICS_H
+
+#include <android-base/chrono_utils.h>
+
+#include <stddef.h>
+
+namespace android {
+
+class LatencyStatistics {
+private:
+ /* Minimum sample recorded */
+ float mMin;
+ /* Maximum sample recorded */
+ float mMax;
+ /* Sum of all samples recorded */
+ float mSum;
+ /* Sum of all the squares of samples recorded */
+ float mSum2;
+ /* Count of all samples recorded */
+ size_t mCount;
+ /* The last time statistics were reported */
+ std::chrono::steady_clock::time_point mLastReportTime;
+ /* Statistics Report Frequency */
+ const std::chrono::seconds mReportPeriod;
+
+public:
+ LatencyStatistics(std::chrono::seconds period);
+
+ void addValue(float);
+ void reset();
+ bool shouldReport();
+
+ float getMean();
+ float getMin();
+ float getMax();
+ float getStDev();
+ size_t getCount();
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_STATISTICS_H
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b230943..c6ce576 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -70,6 +70,7 @@
"ProcessInfoService.cpp",
"ProcessState.cpp",
"Static.cpp",
+ "Stability.cpp",
"Status.cpp",
"TextOutput.cpp",
"IpPrefix.cpp",
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index bdf0f8e..f3483ca 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -135,6 +135,7 @@
break;
}
+ // In case this is being transacted on in the same process.
if (reply != nullptr) {
reply->setDataPosition(0);
}
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 5ceb218..74ffde2 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -21,6 +21,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
+#include <binder/Stability.h>
#include <cutils/compiler.h>
#include <utils/Log.h>
@@ -213,9 +214,21 @@
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
+ // user transactions require a given stability level
+ if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
+ using android::internal::Stability;
+
+ auto stability = Stability::get(this);
+
+ if (CC_UNLIKELY(!Stability::check(stability, Stability::kLocalStability))) {
+ return BAD_TYPE;
+ }
+ }
+
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
+
return status;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 6bd97d58..ed6c834 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -35,6 +35,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
+#include <binder/Stability.h>
#include <binder/Status.h>
#include <binder/TextOutput.h>
@@ -77,6 +78,9 @@
namespace android {
+// many things compile this into prebuilts on the stack
+static_assert(sizeof(Parcel) == 60 || sizeof(Parcel) == 120);
+
static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER;
static size_t gParcelGlobalAllocSize = 0;
static size_t gParcelGlobalAllocCount = 0;
@@ -164,14 +168,31 @@
ALOGE("Invalid object type 0x%08x", obj.hdr.type);
}
-inline static status_t finish_flatten_binder(
- const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
+status_t Parcel::finishFlattenBinder(
+ const sp<IBinder>& binder, const flat_binder_object& flat)
{
- return out->writeObject(flat, false);
+ status_t status = writeObject(flat, false);
+ if (status != OK) return status;
+
+ internal::Stability::tryMarkCompilationUnit(binder.get());
+ return writeInt32(internal::Stability::get(binder.get()));
}
-static status_t flatten_binder(const sp<ProcessState>& /*proc*/,
- const sp<IBinder>& binder, Parcel* out)
+status_t Parcel::finishUnflattenBinder(
+ const sp<IBinder>& binder, sp<IBinder>* out) const
+{
+ int32_t stability;
+ status_t status = readInt32(&stability);
+ if (status != OK) return status;
+
+ status = internal::Stability::set(binder.get(), stability, true /*log*/);
+ if (status != OK) return status;
+
+ *out = binder;
+ return OK;
+}
+
+status_t Parcel::flattenBinder(const sp<IBinder>& binder)
{
flat_binder_object obj;
@@ -209,30 +230,24 @@
obj.cookie = 0;
}
- return finish_flatten_binder(binder, obj, out);
+ return finishFlattenBinder(binder, obj);
}
-inline static status_t finish_unflatten_binder(
- BpBinder* /*proxy*/, const flat_binder_object& /*flat*/,
- const Parcel& /*in*/)
+status_t Parcel::unflattenBinder(sp<IBinder>* out) const
{
- return NO_ERROR;
-}
-
-static status_t unflatten_binder(const sp<ProcessState>& proc,
- const Parcel& in, sp<IBinder>* out)
-{
- const flat_binder_object* flat = in.readObject(false);
+ const flat_binder_object* flat = readObject(false);
if (flat) {
switch (flat->hdr.type) {
- case BINDER_TYPE_BINDER:
- *out = reinterpret_cast<IBinder*>(flat->cookie);
- return finish_unflatten_binder(nullptr, *flat, in);
- case BINDER_TYPE_HANDLE:
- *out = proc->getStrongProxyForHandle(flat->handle);
- return finish_unflatten_binder(
- static_cast<BpBinder*>(out->get()), *flat, in);
+ case BINDER_TYPE_BINDER: {
+ sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie);
+ return finishUnflattenBinder(binder, out);
+ }
+ case BINDER_TYPE_HANDLE: {
+ sp<IBinder> binder =
+ ProcessState::self()->getStrongProxyForHandle(flat->handle);
+ return finishUnflattenBinder(binder, out);
+ }
}
}
return BAD_TYPE;
@@ -1032,7 +1047,7 @@
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
- return flatten_binder(ProcessState::self(), val, this);
+ return flattenBinder(val);
}
status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
@@ -1978,7 +1993,7 @@
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
- return unflatten_binder(ProcessState::self(), *this, val);
+ return unflattenBinder(val);
}
sp<IBinder> Parcel::readStrongBinder() const
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 1e1bc3a..07db50f 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -21,6 +21,7 @@
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/Stability.h>
#include <cutils/atomic.h>
#include <utils/Log.h>
#include <utils/String8.h>
@@ -109,7 +110,13 @@
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
- return getStrongProxyForHandle(0);
+ sp<IBinder> context = getStrongProxyForHandle(0);
+
+ // The root object is special since we get it directly from the driver, it is never
+ // written by Parcell::writeStrongBinder.
+ internal::Stability::tryMarkCompilationUnit(context.get());
+
+ return context;
}
void ProcessState::startThreadPool()
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
new file mode 100644
index 0000000..b6f10c8
--- /dev/null
+++ b/libs/binder/Stability.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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/Stability.h>
+
+namespace android {
+namespace internal {
+
+void Stability::markCompilationUnit(IBinder* binder) {
+ status_t result = set(binder, kLocalStability, true /*log*/);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::markVintf(IBinder* binder) {
+ status_t result = set(binder, Level::VINTF, true /*log*/);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::debugLogStability(const std::string& tag, const sp<IBinder>& binder) {
+ ALOGE("%s: stability is %s", tag.c_str(), stabilityString(get(binder.get())).c_str());
+}
+
+void Stability::markVndk(IBinder* binder) {
+ status_t result = set(binder, Level::VENDOR, true /*log*/);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::tryMarkCompilationUnit(IBinder* binder) {
+ (void) set(binder, kLocalStability, false /*log*/);
+}
+
+status_t Stability::set(IBinder* binder, int32_t stability, bool log) {
+ Level currentStability = get(binder);
+
+ // null binder is always written w/ 'UNDECLARED' stability
+ if (binder == nullptr) {
+ if (stability == UNDECLARED) {
+ return OK;
+ } else {
+ if (log) {
+ ALOGE("Null binder written with stability %s.",
+ stabilityString(stability).c_str());
+ }
+ return BAD_TYPE;
+ }
+ }
+
+ if (!isDeclaredStability(stability)) {
+ if (log) {
+ ALOGE("Can only set known stability, not %d.", stability);
+ }
+ return BAD_TYPE;
+ }
+
+ if (currentStability != Level::UNDECLARED && currentStability != stability) {
+ if (log) {
+ ALOGE("Interface being set with %s but it is already marked as %s.",
+ stabilityString(stability).c_str(), stabilityString(currentStability).c_str());
+ }
+ return BAD_TYPE;
+ }
+
+ if (currentStability == stability) return OK;
+
+ binder->attachObject(
+ reinterpret_cast<void*>(&Stability::get),
+ reinterpret_cast<void*>(stability),
+ nullptr /*cleanupCookie*/,
+ nullptr /*cleanup function*/);
+
+ return OK;
+}
+
+Stability::Level Stability::get(IBinder* binder) {
+ if (binder == nullptr) return UNDECLARED;
+
+ return static_cast<Level>(reinterpret_cast<intptr_t>(
+ binder->findObject(reinterpret_cast<void*>(&Stability::get))));
+}
+
+bool Stability::check(int32_t provided, Level required) {
+ bool stable = (provided & required) == required;
+
+ if (!isDeclaredStability(provided) && provided != UNDECLARED) {
+ ALOGE("Unknown stability when checking interface stability %d.", provided);
+
+ stable = false;
+ }
+
+ if (!stable) {
+ ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
+ stabilityString(provided).c_str(),
+ stabilityString(required).c_str());
+ }
+
+ return stable;
+}
+
+bool Stability::isDeclaredStability(int32_t stability) {
+ return stability == VENDOR || stability == SYSTEM || stability == VINTF;
+}
+
+std::string Stability::stabilityString(int32_t stability) {
+ switch (stability) {
+ case Level::UNDECLARED: return "undeclared stability";
+ case Level::VENDOR: return "vendor stability";
+ case Level::SYSTEM: return "system stability";
+ case Level::VINTF: return "vintf stability";
+ }
+ return "unknown stability " + std::to_string(stability);
+}
+
+} // namespace internal
+} // namespace stability
\ No newline at end of file
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 01e57d3..136bdb0 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -11,6 +11,9 @@
},
{
"name": "binderLibTest"
+ },
+ {
+ "name": "binderStabilityTest"
}
]
}
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index aeea1a2..30786fa 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -71,13 +71,6 @@
*/
// NOLINTNEXTLINE(google-default-arguments)
virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
-
- enum {
- GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
- CHECK_SERVICE_TRANSACTION,
- ADD_SERVICE_TRANSACTION,
- LIST_SERVICES_TRANSACTION,
- };
};
sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 28ab4d9..f5aafc7 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -67,7 +67,7 @@
status_t setDataSize(size_t size);
void setDataPosition(size_t pos) const;
status_t setDataCapacity(size_t size);
-
+
status_t setData(const uint8_t* buffer, size_t len);
status_t appendFrom(const Parcel *parcel,
@@ -419,7 +419,13 @@
void scanForFds() const;
status_t validateReadData(size_t len) const;
void updateWorkSourceRequestHeaderPosition() const;
-
+
+ status_t finishFlattenBinder(const sp<IBinder>& binder,
+ const flat_binder_object& flat);
+ status_t finishUnflattenBinder(const sp<IBinder>& binder, sp<IBinder>* out) const;
+ status_t flattenBinder(const sp<IBinder>& binder);
+ status_t unflattenBinder(sp<IBinder>* out) const;
+
template<class T>
status_t readAligned(T *pArg) const;
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
new file mode 100644
index 0000000..f8240e4
--- /dev/null
+++ b/libs/binder/include/binder/Stability.h
@@ -0,0 +1,102 @@
+/*
+ * 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 <binder/IBinder.h>
+#include <string>
+
+namespace android {
+
+class BpBinder;
+class ProcessState;
+
+namespace internal {
+
+// WARNING: These APIs are only ever expected to be called by auto-generated code.
+// Instead of calling them, you should set the stability of a .aidl interface
+class Stability final {
+public:
+ // WARNING: This is only ever expected to be called by auto-generated code. You likely want to
+ // change or modify the stability class of the interface you are using.
+ // This must be called as soon as the binder in question is constructed. No thread safety
+ // is provided.
+ // E.g. stability is according to libbinder compilation unit
+ static void markCompilationUnit(IBinder* binder);
+ // WARNING: This is only ever expected to be called by auto-generated code. You likely want to
+ // change or modify the stability class of the interface you are using.
+ // This must be called as soon as the binder in question is constructed. No thread safety
+ // is provided.
+ // E.g. stability is according to libbinder_ndk or Java SDK AND the interface
+ // expressed here is guaranteed to be stable for multiple years (Stable AIDL)
+ static void markVintf(IBinder* binder);
+
+ // WARNING: for debugging only
+ static void debugLogStability(const std::string& tag, const sp<IBinder>& binder);
+
+ // WARNING: This is only ever expected to be called by auto-generated code or tests.
+ // You likely want to change or modify the stability of the interface you are using.
+ // This must be called as soon as the binder in question is constructed. No thread safety
+ // is provided.
+ // E.g. stability is according to libbinder_ndk or Java SDK AND the interface
+ // expressed here is guaranteed to be stable for multiple years (Stable AIDL)
+ // If this is called when __ANDROID_VNDK__ is not defined, then it is UB and will likely
+ // break the device during GSI or other tests.
+ static void markVndk(IBinder* binder);
+
+private:
+ // Parcel needs to read/write stability level in an unstable format.
+ friend ::android::Parcel;
+
+ // only expose internal APIs inside of libbinder, for checking stability
+ friend ::android::BpBinder;
+
+ // so that it can mark the context object (only the root object doesn't go
+ // through Parcel)
+ friend ::android::ProcessState;
+
+ static void tryMarkCompilationUnit(IBinder* binder);
+
+ enum Level : int32_t {
+ UNDECLARED = 0,
+
+ VENDOR = 0b000011,
+ SYSTEM = 0b001100,
+ VINTF = 0b111111,
+ };
+
+#ifdef __ANDROID_VNDK__
+ static constexpr Level kLocalStability = Level::VENDOR;
+#else
+ static constexpr Level kLocalStability = Level::SYSTEM;
+#endif
+
+ // applies stability to binder if stability level is known
+ __attribute__((warn_unused_result))
+ static status_t set(IBinder* binder, int32_t stability, bool log);
+
+ static Level get(IBinder* binder);
+
+ static bool check(int32_t provided, Level required);
+
+ static bool isDeclaredStability(int32_t stability);
+ static std::string stabilityString(int32_t stability);
+
+ Stability();
+};
+
+} // namespace internal
+} // namespace android
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 6da3086..734a928 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-cc_library {
+cc_library_shared {
name: "libbinder_ndk",
export_include_dirs: [
"include_ndk",
- "include_apex",
+ "include_platform",
],
cflags: [
@@ -33,6 +33,7 @@
"ibinder_jni.cpp",
"parcel.cpp",
"process.cpp",
+ "stability.cpp",
"status.cpp",
"service_manager.cpp",
],
@@ -54,7 +55,7 @@
version_script: "libbinder_ndk.map.txt",
stubs: {
symbol_file: "libbinder_ndk.map.txt",
- versions: ["29"],
+ versions: ["29", "30"],
},
}
@@ -79,6 +80,6 @@
symbol_file: "libbinder_ndk.map.txt",
export_include_dirs: [
"include_ndk",
- "include_apex",
+ "include_platform",
],
}
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
similarity index 100%
rename from libs/binder/ndk/include_apex/android/binder_manager.h
rename to libs/binder/ndk/include_platform/android/binder_manager.h
diff --git a/libs/binder/ndk/include_apex/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
similarity index 100%
rename from libs/binder/ndk/include_apex/android/binder_process.h
rename to libs/binder/ndk/include_platform/android/binder_process.h
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
new file mode 100644
index 0000000..e6aeb04
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+
+__BEGIN_DECLS
+
+#ifdef __ANDROID_VNDK__
+
+/**
+ * This interface has the stability of the vendor image.
+ */
+void AIBinder_markVendorStability(AIBinder* binder);
+
+static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) {
+ AIBinder_markVendorStability(binder);
+}
+
+#else // ndef defined __ANDROID_VNDK__
+
+/**
+ * This interface has the stability of the system image.
+ */
+void AIBinder_markSystemStability(AIBinder* binder);
+
+static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) {
+ AIBinder_markSystemStability(binder);
+}
+
+#endif // ifdef __ANDROID_VNDK__
+
+/**
+ * This interface has system<->vendor stability
+ */
+void AIBinder_markVintfStability(AIBinder* binder);
+
+__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 4f685d1..feedde6 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -98,3 +98,12 @@
local:
*;
};
+
+LIBBINDER_NDK30 { # introduced=30
+ global:
+ AIBinder_markSystemStability; # apex
+ AIBinder_markVendorStability; # vndk
+ AIBinder_markVintfStability; # apex vndk
+ local:
+ *;
+};
diff --git a/libs/binder/ndk/scripts/init_map.sh b/libs/binder/ndk/scripts/init_map.sh
deleted file mode 100755
index 3529b72..0000000
--- a/libs/binder/ndk/scripts/init_map.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env bash
-
-# Simple helper for ease of development until this API is frozen.
-
-echo "LIBBINDER_NDK { # introduced=29"
-echo " global:"
-{
- grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder.h;
- grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder_jni.h;
- grep -oP "AParcel_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_parcel.h;
- grep -oP "AStatus_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_status.h;
-} | sort | uniq | awk '{ print " " $0 ";"; }'
-{
- grep -oP "AServiceManager_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_manager.h;
- grep -oP "ABinderProcess_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_process.h;
-} | sort | uniq | awk '{ print " " $0 "; # apex"; }'
-echo " local:"
-echo " *;"
-echo "};"
diff --git a/libs/binder/ndk/stability.cpp b/libs/binder/ndk/stability.cpp
new file mode 100644
index 0000000..a5b3ece
--- /dev/null
+++ b/libs/binder/ndk/stability.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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/binder_stability.h>
+
+#include <binder/Stability.h>
+#include "ibinder_internal.h"
+
+#include <log/log.h>
+
+using ::android::internal::Stability;
+
+#ifdef __ANDROID_VNDK__
+#error libbinder_ndk should only be built in a system context
+#endif
+
+#ifdef __ANDROID_NDK__
+#error libbinder_ndk should only be built in a system context
+#endif
+
+// explicit extern because symbol is only declared in header when __ANDROID_VNDK__
+extern "C" void AIBinder_markVendorStability(AIBinder* binder) {
+ Stability::markVndk(binder->getBinder().get());
+}
+
+void AIBinder_markSystemStability(AIBinder* binder) {
+ Stability::markCompilationUnit(binder->getBinder().get());
+}
+
+void AIBinder_markVintfStability(AIBinder* binder) {
+ Stability::markVintf(binder->getBinder().get());
+}
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 8cd4e03..bb1fe2f 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -44,10 +44,10 @@
"libandroid_runtime_lazy",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libutils",
],
static_libs: [
- "libbinder_ndk",
"test_libbinder_ndk_library",
],
}
diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh
index 9a4577f..1eba892 100755
--- a/libs/binder/ndk/update.sh
+++ b/libs/binder/ndk/update.sh
@@ -20,4 +20,3 @@
# This script makes sure that the source code is in sync with the various scripts
./scripts/gen_parcel_helper.py
./scripts/format.sh
-./scripts/init_map.sh > libbinder_ndk.map.txt
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 44a691d..d59a40d 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -137,3 +137,32 @@
],
test_suites: ["device-tests"],
}
+
+aidl_interface {
+ name: "binderStabilityTestIface",
+ srcs: [
+ "IBinderStabilityTest.aidl",
+ "IBinderStabilityTestSub.aidl",
+ ],
+}
+
+cc_test {
+ name: "binderStabilityTest",
+ defaults: ["binder_test_defaults"],
+ srcs: [
+ "binderStabilityTest.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder_ndk",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "binderStabilityTestIface-cpp",
+ "binderStabilityTestIface-ndk_platform",
+ ],
+
+ test_suites: ["device-tests"],
+}
diff --git a/libs/binder/tests/IBinderStabilityTest.aidl b/libs/binder/tests/IBinderStabilityTest.aidl
new file mode 100644
index 0000000..9559196
--- /dev/null
+++ b/libs/binder/tests/IBinderStabilityTest.aidl
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+import IBinderStabilityTestSub;
+
+// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+// THIS IS ONLY FOR TESTING!
+interface IBinderStabilityTest {
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ void sendBinder(IBinderStabilityTestSub binder);
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ void sendAndCallBinder(IBinderStabilityTestSub binder);
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinderStabilityTestSub returnNoStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinderStabilityTestSub returnLocalStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinderStabilityTestSub returnVintfStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinderStabilityTestSub returnVendorStabilityBinder();
+}
+// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+// THIS IS ONLY FOR TESTING!
+// Construct and return a binder with a specific stability
diff --git a/libs/binder/tests/IBinderStabilityTestSub.aidl b/libs/binder/tests/IBinderStabilityTestSub.aidl
new file mode 100644
index 0000000..a81ebf9
--- /dev/null
+++ b/libs/binder/tests/IBinderStabilityTestSub.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+interface IBinderStabilityTestSub {
+ void userDefinedTransaction();
+}
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
new file mode 100644
index 0000000..936b821
--- /dev/null
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -0,0 +1,257 @@
+/*
+ * 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/binder_manager.h>
+#include <android/binder_stability.h>
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Stability.h>
+#include <gtest/gtest.h>
+
+#include <sys/prctl.h>
+
+#include "aidl/BnBinderStabilityTestSub.h"
+#include "aidl/BnBinderStabilityTest.h"
+#include "BnBinderStabilityTestSub.h"
+#include "BnBinderStabilityTest.h"
+
+using namespace android;
+using namespace ndk;
+using android::binder::Status;
+using android::internal::Stability; // for testing only!
+
+const String16 kNoStabilityServer = String16("binder_stability_test_service_low");
+const String16 kCompilationUnitServer = String16("binder_stability_test_service_compl");
+const String16 kVintfServer = String16("binder_stability_test_service_vintf");
+
+const String16 kCompilationUnitNdkServer = String16("binder_stability_test_service_compl");
+
+class BadStabilityTestSub : public BnBinderStabilityTestSub {
+public:
+ Status userDefinedTransaction() {
+ return Status::ok();
+ }
+
+ static sp<IBinderStabilityTestSub> system() {
+ sp<BnBinderStabilityTestSub> iface = new BadStabilityTestSub();
+ // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
+ // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
+ Stability::markCompilationUnit(iface.get()); // <- BAD, NO! DO NOT COPY
+ return iface;
+ }
+
+ static sp<IBinderStabilityTestSub> vintf() {
+ sp<BnBinderStabilityTestSub> iface = new BadStabilityTestSub();
+ // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
+ // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
+ Stability::markVintf(iface.get()); // <- BAD, NO! DO NOT COPY
+ return iface;
+ }
+
+ static sp<IBinderStabilityTestSub> vendor() {
+ sp<BnBinderStabilityTestSub> iface = new BadStabilityTestSub();
+ // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
+ // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
+ Stability::markVndk(iface.get()); // <- BAD, NO! DO NOT COPY
+ return iface;
+ }
+};
+
+// NO! NO! NO! Do not even think of doing something like this!
+// This is for testing! If a class like this was actually used in production,
+// it would ruin everything!
+class BadStabilityTester : public BnBinderStabilityTest {
+public:
+ Status sendBinder(const sp<IBinderStabilityTestSub>& /*binder*/) override {
+ return Status::ok();
+ }
+ Status sendAndCallBinder(const sp<IBinderStabilityTestSub>& binder) override {
+ Stability::debugLogStability("sendAndCallBinder got binder", IInterface::asBinder(binder));
+ return binder->userDefinedTransaction();
+ }
+ Status returnNoStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
+ *_aidl_return = new BadStabilityTestSub();
+ return Status::ok();
+ }
+ Status returnLocalStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
+ *_aidl_return = BadStabilityTestSub::system();
+ return Status::ok();
+ }
+ Status returnVintfStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
+ *_aidl_return = BadStabilityTestSub::vintf();
+ return Status::ok();
+ }
+ Status returnVendorStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
+ *_aidl_return = BadStabilityTestSub::vendor();
+ return Status::ok();
+ }
+};
+
+void checkSystemStabilityBinder(const sp<IBinderStabilityTest>& complServer) {
+ EXPECT_TRUE(complServer->sendBinder(new BadStabilityTestSub()).isOk());
+ EXPECT_TRUE(complServer->sendBinder(BadStabilityTestSub::system()).isOk());
+ EXPECT_TRUE(complServer->sendBinder(BadStabilityTestSub::vintf()).isOk());
+ EXPECT_TRUE(complServer->sendBinder(BadStabilityTestSub::vendor()).isOk());
+
+ EXPECT_TRUE(complServer->sendAndCallBinder(new BadStabilityTestSub()).isOk());
+ EXPECT_TRUE(complServer->sendAndCallBinder(BadStabilityTestSub::system()).isOk());
+ EXPECT_TRUE(complServer->sendAndCallBinder(BadStabilityTestSub::vintf()).isOk());
+
+ // !!! user-defined transaction may not be stable for remote server !!!
+ EXPECT_FALSE(complServer->sendAndCallBinder(BadStabilityTestSub::vendor()).isOk());
+
+ sp<IBinderStabilityTestSub> out;
+ EXPECT_TRUE(complServer->returnNoStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
+ EXPECT_TRUE(out->userDefinedTransaction().isOk());
+
+ EXPECT_TRUE(complServer->returnLocalStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
+ EXPECT_TRUE(out->userDefinedTransaction().isOk());
+
+ EXPECT_TRUE(complServer->returnVintfStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
+ EXPECT_TRUE(out->userDefinedTransaction().isOk());
+
+ EXPECT_TRUE(complServer->returnVendorStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+
+ // !!! libbinder-defined transaction works !!!
+ EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
+
+ // !!! user-defined transaction may not be stable !!!
+ EXPECT_FALSE(out->userDefinedTransaction().isOk());
+}
+
+TEST(BinderStability, RemoteNoStabilityServer) {
+ sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kNoStabilityServer);
+ auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+ ASSERT_NE(nullptr, remoteServer.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+ checkSystemStabilityBinder(remoteServer);
+}
+
+TEST(BinderStability, RemoteLowStabilityServer) {
+ sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kCompilationUnitServer);
+ auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+ ASSERT_NE(nullptr, remoteServer.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+ checkSystemStabilityBinder(remoteServer);
+}
+
+TEST(BinderStability, RemoteVintfServer) {
+ sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kVintfServer);
+ auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+ ASSERT_NE(nullptr, remoteServer.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+ checkSystemStabilityBinder(remoteServer);
+}
+
+class NdkBadStabilityTestSub : public aidl::BnBinderStabilityTestSub {
+ ScopedAStatus userDefinedTransaction() {
+ return ScopedAStatus::ok();
+ }
+};
+// for testing only to get around __ANDROID_VNDK__ guard.
+extern "C" void AIBinder_markVendorStability(AIBinder* binder); // <- BAD DO NOT COPY
+
+TEST(BinderStability, NdkClientOfRemoteServer) {
+ SpAIBinder binder = SpAIBinder(AServiceManager_getService(
+ String8(kCompilationUnitServer).c_str()));
+
+ std::shared_ptr<aidl::IBinderStabilityTest> remoteServer =
+ aidl::IBinderStabilityTest::fromBinder(binder);
+
+ ASSERT_NE(nullptr, remoteServer.get());
+
+ std::shared_ptr<aidl::IBinderStabilityTestSub> vendor = SharedRefBase::make<NdkBadStabilityTestSub>();
+
+ // TODO: not ideal: binder must be held once it is marked
+ SpAIBinder vendorBinder = vendor->asBinder();
+ AIBinder_markVendorStability(vendorBinder.get());
+
+ EXPECT_TRUE(remoteServer->sendBinder(vendor).isOk());
+ EXPECT_FALSE(remoteServer->sendAndCallBinder(vendor).isOk());
+}
+
+class MarksStabilityInConstructor : public BBinder {
+public:
+ static bool gDestructed;
+
+ MarksStabilityInConstructor() {
+ Stability::markCompilationUnit(this);
+ }
+ ~MarksStabilityInConstructor() {
+ gDestructed = true;
+ }
+};
+bool MarksStabilityInConstructor::gDestructed = false;
+
+TEST(BinderStability, MarkingObjectNoDestructTest) {
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ // best practice is to put this directly in an sp, but for this test, we
+ // want to explicitly check what happens before that happens
+ MarksStabilityInConstructor* binder = new MarksStabilityInConstructor();
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ sp<MarksStabilityInConstructor> binderSp = binder;
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ binderSp = nullptr;
+ ASSERT_TRUE(MarksStabilityInConstructor::gDestructed);
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ if (fork() == 0) {
+ // child process
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+ sp<IBinder> noStability = new BadStabilityTester;
+ android::defaultServiceManager()->addService(kNoStabilityServer, noStability);
+
+ sp<IBinder> compil = new BadStabilityTester;
+ Stability::markCompilationUnit(compil.get());
+ android::defaultServiceManager()->addService(kCompilationUnitServer, compil);
+
+ sp<IBinder> vintf = new BadStabilityTester;
+ Stability::markVintf(vintf.get());
+ android::defaultServiceManager()->addService(kVintfServer, vintf);
+
+ IPCThreadState::self()->joinThreadPool(true);
+ exit(1); // should not reach
+ }
+
+ // This is not racey. Just giving these services some time to register before we call
+ // getService which sleeps for much longer...
+ usleep(10000);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 56521bf..f11cf62 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -32,5 +32,9 @@
"libutils",
],
+ header_libs: [
+ "libnativeloader-dummy-headers",
+ ],
+
export_include_dirs: ["include"],
}
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 3e29e88..30f5f73 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -32,6 +32,7 @@
#include <cutils/properties.h>
#include <graphicsenv/IGpuService.h>
#include <log/log.h>
+#include <nativeloader/dlext_namespaces.h>
#include <sys/prctl.h>
#include <utils/Trace.h>
@@ -39,22 +40,6 @@
#include <string>
#include <thread>
-// TODO(b/37049319) Get this from a header once one exists
-extern "C" {
-android_namespace_t* android_get_exported_namespace(const char*);
-android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
- const char* default_library_path, uint64_t type,
- const char* permitted_when_isolated_path,
- android_namespace_t* parent);
-bool android_link_namespaces(android_namespace_t* from, android_namespace_t* to,
- const char* shared_libs_sonames);
-
-enum {
- ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
- ANDROID_NAMESPACE_TYPE_SHARED = 2,
-};
-}
-
// TODO(ianelliott@): Get the following from an ANGLE header:
#define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting
// Version-2 API:
@@ -213,7 +198,8 @@
case GpuStatsInfo::Driver::GL:
case GpuStatsInfo::Driver::GL_UPDATED:
case GpuStatsInfo::Driver::ANGLE: {
- if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE) {
+ if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE ||
+ mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::GL) {
mGpuStats.glDriverToLoad = driver;
break;
}
@@ -225,7 +211,8 @@
}
case GpuStatsInfo::Driver::VULKAN:
case GpuStatsInfo::Driver::VULKAN_UPDATED: {
- if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE) {
+ if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE ||
+ mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::VULKAN) {
mGpuStats.vkDriverToLoad = driver;
break;
}
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index ff1ba0a..386f731 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -410,6 +410,19 @@
bgSurface->expectTap(1, 1);
}
+TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) {
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ // In case we pass the very big inset without any checking.
+ fgSurface->mInputInfo.surfaceInset = INT32_MAX;
+ fgSurface->showAt(100, 100);
+
+ fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
+
+ // expect no crash for overflow, and inset size to be clamped to surface size
+ injectTap(202, 202);
+ fgSurface->expectTap(1, 1);
+}
+
// Ensure we ignore transparent region when getting screen bounds when positioning input frame.
TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 2d78811..7749e66 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -48,6 +48,7 @@
"InputTransport.cpp",
"InputWindow.cpp",
"ISetInputWindowsListener.cpp",
+ "LatencyStatistics.cpp",
"VelocityControl.cpp",
"VelocityTracker.cpp",
],
@@ -55,7 +56,8 @@
shared_libs: [
"libutils",
"libbinder",
- "libui"
+ "libui",
+ "libstatslog",
],
sanitize: {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 904a6fe..2ff301e 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -34,6 +34,7 @@
#include <utils/Trace.h>
#include <input/InputTransport.h>
+#include <statslog.h>
using android::base::StringPrintf;
@@ -531,6 +532,10 @@
msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
}
+
+ if (source == AINPUT_SOURCE_TOUCHSCREEN) {
+ reportTouchEventForStatistics(eventTime);
+ }
return mChannel->sendMessage(&msg);
}
@@ -557,6 +562,17 @@
return OK;
}
+void InputPublisher::reportTouchEventForStatistics(nsecs_t evdevTime) {
+ if (mTouchStatistics.shouldReport()) {
+ android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, mTouchStatistics.getMin(),
+ mTouchStatistics.getMax(), mTouchStatistics.getMean(),
+ mTouchStatistics.getStDev(), mTouchStatistics.getCount());
+ mTouchStatistics.reset();
+ }
+ nsecs_t latency = nanoseconds_to_microseconds(systemTime(CLOCK_MONOTONIC) - evdevTime);
+ mTouchStatistics.addValue(latency);
+}
+
// --- InputConsumer ---
InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
diff --git a/libs/input/LatencyStatistics.cpp b/libs/input/LatencyStatistics.cpp
new file mode 100644
index 0000000..e343578
--- /dev/null
+++ b/libs/input/LatencyStatistics.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 <input/LatencyStatistics.h>
+
+#include <android-base/chrono_utils.h>
+
+#include <cmath>
+#include <limits>
+
+namespace android {
+
+LatencyStatistics::LatencyStatistics(std::chrono::seconds period) : mReportPeriod(period) {
+ reset();
+}
+
+/**
+ * Add a raw value to the statistics
+ */
+void LatencyStatistics::addValue(float value) {
+ if (value < mMin) {
+ mMin = value;
+ }
+ if (value > mMax) {
+ mMax = value;
+ }
+ mSum += value;
+ mSum2 += value * value;
+ mCount++;
+}
+
+/**
+ * Get the mean. Should not be called if no samples have been added.
+ */
+float LatencyStatistics::getMean() {
+ return mSum / mCount;
+}
+
+/**
+ * Get the standard deviation. Should not be called if no samples have been added.
+ */
+float LatencyStatistics::getStDev() {
+ float mean = getMean();
+ return sqrt(mSum2 / mCount - mean * mean);
+}
+
+float LatencyStatistics::getMin() {
+ return mMin;
+}
+
+float LatencyStatistics::getMax() {
+ return mMax;
+}
+
+size_t LatencyStatistics::getCount() {
+ return mCount;
+}
+
+/**
+ * Reset internal state. The variable 'when' is the time when the data collection started.
+ * Call this to start a new data collection window.
+ */
+void LatencyStatistics::reset() {
+ mMax = std::numeric_limits<float>::lowest();
+ mMin = std::numeric_limits<float>::max();
+ mSum = 0;
+ mSum2 = 0;
+ mCount = 0;
+ mLastReportTime = std::chrono::steady_clock::now();
+}
+
+bool LatencyStatistics::shouldReport() {
+ std::chrono::duration timeSinceReport = std::chrono::steady_clock::now() - mLastReportTime;
+ return mCount != 0 && timeSinceReport > mReportPeriod;
+}
+
+} // namespace android
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index ade931e..c1c35e1 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -7,6 +7,7 @@
"InputEvent_test.cpp",
"InputPublisherAndConsumer_test.cpp",
"InputWindow_test.cpp",
+ "LatencyStatistics_test.cpp",
"TouchVideoFrame_test.cpp",
"VelocityTracker_test.cpp",
],
diff --git a/libs/input/tests/LatencyStatistics_test.cpp b/libs/input/tests/LatencyStatistics_test.cpp
new file mode 100644
index 0000000..eb12d4e
--- /dev/null
+++ b/libs/input/tests/LatencyStatistics_test.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <input/LatencyStatistics.h>
+#include <cmath>
+#include <limits>
+#include <thread>
+
+namespace android {
+namespace test {
+
+TEST(LatencyStatisticsTest, ResetStats) {
+ LatencyStatistics stats{5min};
+ stats.addValue(5.0);
+ stats.addValue(19.3);
+ stats.addValue(20);
+ stats.reset();
+
+ ASSERT_EQ(stats.getCount(), 0u);
+ ASSERT_EQ(std::isnan(stats.getStDev()), true);
+ ASSERT_EQ(std::isnan(stats.getMean()), true);
+}
+
+TEST(LatencyStatisticsTest, AddStatsValue) {
+ LatencyStatistics stats{5min};
+ stats.addValue(5.0);
+
+ ASSERT_EQ(stats.getMin(), 5.0);
+ ASSERT_EQ(stats.getMax(), 5.0);
+ ASSERT_EQ(stats.getCount(), 1u);
+ ASSERT_EQ(stats.getMean(), 5.0);
+ ASSERT_EQ(stats.getStDev(), 0.0);
+}
+
+TEST(LatencyStatisticsTest, AddMultipleStatsValue) {
+ LatencyStatistics stats{5min};
+ stats.addValue(4.0);
+ stats.addValue(6.0);
+ stats.addValue(8.0);
+ stats.addValue(10.0);
+
+ float stdev = stats.getStDev();
+
+ ASSERT_EQ(stats.getMin(), 4.0);
+ ASSERT_EQ(stats.getMax(), 10.0);
+ ASSERT_EQ(stats.getCount(), 4u);
+ ASSERT_EQ(stats.getMean(), 7.0);
+ ASSERT_EQ(stdev * stdev, 5.0);
+}
+
+TEST(LatencyStatisticsTest, ShouldReportStats) {
+ LatencyStatistics stats{0min};
+ stats.addValue(5.0);
+
+ std::this_thread::sleep_for(1us);
+
+ ASSERT_EQ(stats.shouldReport(), true);
+}
+
+} // namespace test
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 36211ca..cc252d6 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -26,6 +26,7 @@
"libgui",
"liblog",
"libnativewindow",
+ "libprocessgroup",
"libsync",
"libui",
"libutils",
@@ -51,6 +52,7 @@
"gl/GLExtensions.cpp",
"gl/GLFramebuffer.cpp",
"gl/GLImage.cpp",
+ "gl/ImageManager.cpp",
"gl/Program.cpp",
"gl/ProgramCache.cpp",
],
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 8bfd3dd..dd4c55d 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -19,9 +19,8 @@
#define LOG_TAG "RenderEngine"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include "GLESRenderEngine.h"
-
-#include <math.h>
+#include <sched.h>
+#include <cmath>
#include <fstream>
#include <sstream>
#include <unordered_set>
@@ -43,6 +42,7 @@
#include <ui/Region.h>
#include <utils/KeyedVector.h>
#include <utils/Trace.h>
+#include "GLESRenderEngine.h"
#include "GLExtensions.h"
#include "GLFramebuffer.h"
#include "GLImage.h"
@@ -423,10 +423,13 @@
mTraceGpuCompletion = true;
mFlushTracer = std::make_unique<FlushTracer>(this);
}
+ mImageManager = std::make_unique<ImageManager>(this);
mDrawingBuffer = createFramebuffer();
}
GLESRenderEngine::~GLESRenderEngine() {
+ // Destroy the image manager first.
+ mImageManager = nullptr;
std::lock_guard<std::mutex> lock(mRenderingMutex);
unbindFrameBuffer(mDrawingBuffer.get());
mDrawingBuffer = nullptr;
@@ -615,19 +618,41 @@
status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName,
const sp<GraphicBuffer>& buffer,
const sp<Fence>& bufferFence) {
- ATRACE_CALL();
- status_t cacheResult = cacheExternalTextureBuffer(buffer);
-
- if (cacheResult != NO_ERROR) {
- return cacheResult;
+ if (buffer == nullptr) {
+ return BAD_VALUE;
}
+ ATRACE_CALL();
+
+ bool found = false;
+ {
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ auto cachedImage = mImageCache.find(buffer->getId());
+ found = (cachedImage != mImageCache.end());
+ }
+
+ // If we couldn't find the image in the cache at this time, then either
+ // SurfaceFlinger messed up registering the buffer ahead of time or we got
+ // backed up creating other EGLImages.
+ if (!found) {
+ status_t cacheResult = mImageManager->cache(buffer);
+ if (cacheResult != NO_ERROR) {
+ return cacheResult;
+ }
+ }
+
+ // Whether or not we needed to cache, re-check mImageCache to make sure that
+ // there's an EGLImage. The current threading model guarantees that we don't
+ // destroy a cached image until it's really not needed anymore (i.e. this
+ // function should not be called), so the only possibility is that something
+ // terrible went wrong and we should just bind something and move on.
{
std::lock_guard<std::mutex> lock(mRenderingMutex);
auto cachedImage = mImageCache.find(buffer->getId());
if (cachedImage == mImageCache.end()) {
// We failed creating the image if we got here, so bail out.
+ ALOGE("Failed to create an EGLImage when rendering");
bindExternalTextureImage(texName, *createImage());
return NO_INIT;
}
@@ -659,7 +684,18 @@
return NO_ERROR;
}
-status_t GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+void GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+ mImageManager->cacheAsync(buffer, nullptr);
+}
+
+std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::cacheExternalTextureBufferForTesting(
+ const sp<GraphicBuffer>& buffer) {
+ auto barrier = std::make_shared<ImageManager::Barrier>();
+ mImageManager->cacheAsync(buffer, barrier);
+ return barrier;
+}
+
+status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer) {
if (buffer == nullptr) {
return BAD_VALUE;
}
@@ -699,12 +735,30 @@
}
void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
- std::lock_guard<std::mutex> lock(mRenderingMutex);
- const auto& cachedImage = mImageCache.find(bufferId);
- if (cachedImage != mImageCache.end()) {
- ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
- mImageCache.erase(bufferId);
- return;
+ mImageManager->releaseAsync(bufferId, nullptr);
+}
+
+std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::unbindExternalTextureBufferForTesting(
+ uint64_t bufferId) {
+ auto barrier = std::make_shared<ImageManager::Barrier>();
+ mImageManager->releaseAsync(bufferId, barrier);
+ return barrier;
+}
+
+void GLESRenderEngine::unbindExternalTextureBufferInternal(uint64_t bufferId) {
+ std::unique_ptr<Image> image;
+ {
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ const auto& cachedImage = mImageCache.find(bufferId);
+
+ if (cachedImage != mImageCache.end()) {
+ ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
+ // Move the buffer out of cache first, so that we can destroy
+ // without holding the cache's lock.
+ image = std::move(cachedImage->second);
+ mImageCache.erase(bufferId);
+ return;
+ }
}
ALOGV("Failed to find image for buffer: %" PRIu64, bufferId);
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index c8b45d2..501b044 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -17,9 +17,7 @@
#ifndef SF_GLESRENDERENGINE_H_
#define SF_GLESRENDERENGINE_H_
-#include <android-base/thread_annotations.h>
#include <stdint.h>
-#include <sys/types.h>
#include <condition_variable>
#include <deque>
#include <mutex>
@@ -30,8 +28,11 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
+#include <android-base/thread_annotations.h>
#include <renderengine/RenderEngine.h>
#include <renderengine/private/Description.h>
+#include <sys/types.h>
+#include "ImageManager.h"
#define EGL_NO_CONFIG ((EGLConfig)0)
@@ -63,7 +64,7 @@
void bindExternalTextureImage(uint32_t texName, const Image& image) override;
status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
const sp<Fence>& fence) EXCLUDES(mRenderingMutex);
- status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
+ void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex);
status_t bindFrameBuffer(Framebuffer* framebuffer) override;
void unbindFrameBuffer(Framebuffer* framebuffer) override;
@@ -87,6 +88,11 @@
// Returns true iff mFramebufferImageCache contains an image keyed by bufferId
bool isFramebufferImageCachedForTesting(uint64_t bufferId)
EXCLUDES(mFramebufferImageCacheMutex);
+ // These are wrappers around public methods above, but exposing Barrier
+ // objects so that tests can block.
+ std::shared_ptr<ImageManager::Barrier> cacheExternalTextureBufferForTesting(
+ const sp<GraphicBuffer>& buffer);
+ std::shared_ptr<ImageManager::Barrier> unbindExternalTextureBufferForTesting(uint64_t bufferId);
protected:
Framebuffer* getFramebufferForDrawing() override;
@@ -116,6 +122,9 @@
void setScissor(const Rect& region);
void disableScissor();
bool waitSync(EGLSyncKHR sync, EGLint flags);
+ status_t cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer)
+ EXCLUDES(mRenderingMutex);
+ void unbindExternalTextureBufferInternal(uint64_t bufferId) EXCLUDES(mRenderingMutex);
// A data space is considered HDR data space if it has BT2020 color space
// with PQ or HLG transfer function.
@@ -241,7 +250,9 @@
bool mRunning = true;
};
friend class FlushTracer;
+ friend class ImageManager;
std::unique_ptr<FlushTracer> mFlushTracer;
+ std::unique_ptr<ImageManager> mImageManager = std::make_unique<ImageManager>(this);
};
} // namespace gl
diff --git a/libs/renderengine/gl/ImageManager.cpp b/libs/renderengine/gl/ImageManager.cpp
new file mode 100644
index 0000000..5af0e4f
--- /dev/null
+++ b/libs/renderengine/gl/ImageManager.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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 <pthread.h>
+
+#include <processgroup/sched_policy.h>
+#include <utils/Trace.h>
+#include "GLESRenderEngine.h"
+#include "ImageManager.h"
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) {
+ pthread_setname_np(mThread.native_handle(), "ImageManager");
+ // Use SCHED_FIFO to minimize jitter
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO for ImageManager");
+ }
+}
+
+ImageManager::~ImageManager() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mRunning = false;
+ }
+ mCondition.notify_all();
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+void ImageManager::cacheAsync(const sp<GraphicBuffer>& buffer,
+ const std::shared_ptr<Barrier>& barrier) {
+ if (buffer == nullptr) {
+ {
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ barrier->isOpen = true;
+ barrier->result = BAD_VALUE;
+ }
+ barrier->condition.notify_one();
+ return;
+ }
+ ATRACE_CALL();
+ QueueEntry entry = {QueueEntry::Operation::Insert, buffer, buffer->getId(), barrier};
+ queueOperation(std::move(entry));
+}
+
+status_t ImageManager::cache(const sp<GraphicBuffer>& buffer) {
+ ATRACE_CALL();
+ auto barrier = std::make_shared<Barrier>();
+ cacheAsync(buffer, barrier);
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ barrier->condition.wait(barrier->mutex,
+ [&]() REQUIRES(barrier->mutex) { return barrier->isOpen; });
+ return barrier->result;
+}
+
+void ImageManager::releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) {
+ ATRACE_CALL();
+ QueueEntry entry = {QueueEntry::Operation::Delete, nullptr, bufferId, barrier};
+ queueOperation(std::move(entry));
+}
+
+void ImageManager::queueOperation(const QueueEntry&& entry) {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mQueue.emplace(entry);
+ ATRACE_INT("ImageManagerQueueDepth", mQueue.size());
+ }
+ mCondition.notify_one();
+}
+
+void ImageManager::threadMain() {
+ set_sched_policy(0, SP_FOREGROUND);
+ bool run;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ run = mRunning;
+ }
+ while (run) {
+ QueueEntry entry;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCondition.wait(mMutex,
+ [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; });
+ run = mRunning;
+
+ if (!mRunning) {
+ // if mRunning is false, then ImageManager is being destroyed, so
+ // bail out now.
+ break;
+ }
+
+ entry = mQueue.front();
+ mQueue.pop();
+ ATRACE_INT("ImageManagerQueueDepth", mQueue.size());
+ }
+
+ status_t result = NO_ERROR;
+ switch (entry.op) {
+ case QueueEntry::Operation::Delete:
+ mEngine->unbindExternalTextureBufferInternal(entry.bufferId);
+ break;
+ case QueueEntry::Operation::Insert:
+ result = mEngine->cacheExternalTextureBufferInternal(entry.buffer);
+ break;
+ }
+ if (entry.barrier != nullptr) {
+ {
+ std::lock_guard<std::mutex> entryLock(entry.barrier->mutex);
+ entry.barrier->result = result;
+ entry.barrier->isOpen = true;
+ }
+ entry.barrier->condition.notify_one();
+ }
+ }
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/ImageManager.h b/libs/renderengine/gl/ImageManager.h
new file mode 100644
index 0000000..b5ba554
--- /dev/null
+++ b/libs/renderengine/gl/ImageManager.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLESRenderEngine;
+
+class ImageManager {
+public:
+ struct Barrier {
+ std::mutex mutex;
+ std::condition_variable_any condition;
+ bool isOpen GUARDED_BY(mutex) = false;
+ status_t result GUARDED_BY(mutex) = NO_ERROR;
+ };
+ ImageManager(GLESRenderEngine* engine);
+ ~ImageManager();
+ void cacheAsync(const sp<GraphicBuffer>& buffer, const std::shared_ptr<Barrier>& barrier)
+ EXCLUDES(mMutex);
+ status_t cache(const sp<GraphicBuffer>& buffer);
+ void releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) EXCLUDES(mMutex);
+
+private:
+ struct QueueEntry {
+ enum class Operation { Delete, Insert };
+
+ Operation op = Operation::Delete;
+ sp<GraphicBuffer> buffer = nullptr;
+ uint64_t bufferId = 0;
+ std::shared_ptr<Barrier> barrier = nullptr;
+ };
+
+ void queueOperation(const QueueEntry&& entry);
+ void threadMain();
+ GLESRenderEngine* const mEngine;
+ std::thread mThread = std::thread([this]() { threadMain(); });
+ std::condition_variable_any mCondition;
+ std::mutex mMutex;
+ std::queue<QueueEntry> mQueue GUARDED_BY(mMutex);
+
+ bool mRunning GUARDED_BY(mMutex) = true;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 1c480a7..205782b 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -94,10 +94,20 @@
const sp<Fence>& fence) = 0;
// Caches Image resources for this buffer, but does not bind the buffer to
// a particular texture.
- virtual status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
+ // Note that work is deferred to an additional thread, i.e. this call
+ // is made asynchronously, but the caller can expect that cache/unbind calls
+ // are performed in a manner that's conflict serializable, i.e. unbinding
+ // a buffer should never occur before binding the buffer if the caller
+ // called {bind, cache}ExternalTextureBuffer before calling unbind.
+ virtual void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
// Removes internal resources referenced by the bufferId. This method should be
// invoked when the caller will no longer hold a reference to a GraphicBuffer
// and needs to clean up its resources.
+ // Note that work is deferred to an additional thread, i.e. this call
+ // is made asynchronously, but the caller can expect that cache/unbind calls
+ // are performed in a manner that's conflict serializable, i.e. unbinding
+ // a buffer should never occur before binding the buffer if the caller
+ // called {bind, cache}ExternalTextureBuffer before calling unbind.
virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0;
// When binding a native buffer, it must be done before setViewportAndProjection
// Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index f099cd2..0750e86 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -43,7 +43,7 @@
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&));
- MOCK_METHOD1(cacheExternalTextureBuffer, status_t(const sp<GraphicBuffer>&));
+ MOCK_METHOD1(cacheExternalTextureBuffer, void(const sp<GraphicBuffer>&));
MOCK_METHOD3(bindExternalTextureBuffer,
status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&));
MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index 9b483ef..e98babc 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -31,6 +31,7 @@
"libgui",
"liblog",
"libnativewindow",
+ "libprocessgroup",
"libsync",
"libui",
"libutils",
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 7acaecf..f47c7fd 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
+#include <chrono>
+#include <condition_variable>
+#include <gtest/gtest.h>
#include <renderengine/RenderEngine.h>
#include <sync/sync.h>
#include <ui/PixelFormat.h>
@@ -1001,8 +1003,15 @@
invokeDraw(settings, layers, mBuffer);
uint64_t bufferId = layer.source.buffer.buffer->getId();
EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
- sRE->unbindExternalTextureBuffer(bufferId);
+ std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+ sRE->unbindExternalTextureBufferForTesting(bufferId);
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+ [&]() REQUIRES(barrier->mutex) {
+ return barrier->isOpen;
+ }));
EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+ EXPECT_EQ(NO_ERROR, barrier->result);
}
TEST_F(RenderEngineTest, drawLayers_bindExternalBufferWithNullBuffer) {
@@ -1019,21 +1028,52 @@
sRE->bindExternalTextureBuffer(texName, buf, nullptr);
uint64_t bufferId = buf->getId();
EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
- sRE->unbindExternalTextureBuffer(bufferId);
+ std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+ sRE->unbindExternalTextureBufferForTesting(bufferId);
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+ [&]() REQUIRES(barrier->mutex) {
+ return barrier->isOpen;
+ }));
+ EXPECT_EQ(NO_ERROR, barrier->result);
EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
}
TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) {
- status_t result = sRE->cacheExternalTextureBuffer(nullptr);
- ASSERT_EQ(BAD_VALUE, result);
+ std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+ sRE->cacheExternalTextureBufferForTesting(nullptr);
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+ [&]() REQUIRES(barrier->mutex) {
+ return barrier->isOpen;
+ }));
+ EXPECT_TRUE(barrier->isOpen);
+ EXPECT_EQ(BAD_VALUE, barrier->result);
}
TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferCachesImages) {
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
uint64_t bufferId = buf->getId();
- sRE->cacheExternalTextureBuffer(buf);
+ std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+ sRE->cacheExternalTextureBufferForTesting(buf);
+ {
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+ [&]() REQUIRES(barrier->mutex) {
+ return barrier->isOpen;
+ }));
+ EXPECT_EQ(NO_ERROR, barrier->result);
+ }
EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
- sRE->unbindExternalTextureBuffer(bufferId);
+ barrier = sRE->unbindExternalTextureBufferForTesting(bufferId);
+ {
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+ [&]() REQUIRES(barrier->mutex) {
+ return barrier->isOpen;
+ }));
+ EXPECT_EQ(NO_ERROR, barrier->result);
+ }
EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
}
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 2cc6857..2bbb0ee 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -187,3 +187,11 @@
"tests",
"tools",
]
+
+filegroup {
+ name: "libui_host_common",
+ srcs: [
+ "Rect.cpp",
+ "PixelFormat.cpp"
+ ],
+}
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index 127f7ee..5e0b094 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -44,11 +44,28 @@
TEST_F(GraphicBufferTest, AllocateBadDimensions) {
PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+ if (std::numeric_limits<size_t>::max() / std::numeric_limits<uint32_t>::max() /
+ bytesPerPixel(format) >=
+ std::numeric_limits<uint32_t>::max()) {
+ GTEST_SUCCEED() << "Cannot overflow with this format";
+ }
uint32_t width, height;
width = height = std::numeric_limits<uint32_t>::max();
sp<GraphicBuffer> gb(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage,
std::string("test")));
ASSERT_EQ(BAD_VALUE, gb->initCheck());
+
+ const size_t targetArea = std::numeric_limits<size_t>::max() / bytesPerPixel(format);
+ const size_t widthCandidate = targetArea / std::numeric_limits<uint32_t>::max();
+ if (widthCandidate == 0) {
+ width = 1;
+ } else {
+ width = std::numeric_limits<uint32_t>::max();
+ }
+ height = (targetArea / width) + 1;
+ sp<GraphicBuffer> gb2(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage,
+ std::string("test")));
+ ASSERT_EQ(BAD_VALUE, gb2->initCheck());
}
TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) {
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 8dd4d1d..bdee6fe 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -88,7 +88,6 @@
"libui",
"libutils",
"libhardware_legacy",
- "libstatslog",
],
header_libs: [
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 3e236a9..4631bec 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -57,7 +57,6 @@
#include <android-base/stringprintf.h>
#include <input/Keyboard.h>
#include <input/VirtualKeyMap.h>
-#include <statslog.h>
#define INDENT " "
#define INDENT2 " "
@@ -85,9 +84,6 @@
// data.
static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
-// How often to report input event statistics
-static constexpr nsecs_t STATISTICS_REPORT_FREQUENCY = seconds_to_nanoseconds(5 * 60);
-
// --- Static Functions ---
template<typename T>
@@ -4318,26 +4314,12 @@
mExternalStylusFusionTimeout = LLONG_MAX;
}
-void TouchInputMapper::reportEventForStatistics(nsecs_t evdevTime) {
- nsecs_t now = systemTime(CLOCK_MONOTONIC);
- nsecs_t latency = now - evdevTime;
- mStatistics.addValue(nanoseconds_to_microseconds(latency));
- nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime;
- if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) {
- android::util::stats_write(android::util::TOUCH_EVENT_REPORTED,
- mStatistics.min, mStatistics.max,
- mStatistics.mean(), mStatistics.stdev(), mStatistics.count);
- mStatistics.reset(now);
- }
-}
-
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
- reportEventForStatistics(rawEvent->when);
sync(rawEvent->when);
}
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 11ef934..b7f94c1 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -27,11 +27,11 @@
#include <input/VelocityControl.h>
#include <input/VelocityTracker.h>
#include <ui/DisplayInfo.h>
-#include <utils/KeyedVector.h>
+#include <utils/BitSet.h>
#include <utils/Condition.h>
+#include <utils/KeyedVector.h>
#include <utils/Mutex.h>
#include <utils/Timers.h>
-#include <utils/BitSet.h>
#include <optional>
#include <stddef.h>
@@ -572,69 +572,6 @@
}
};
-/**
- * Basic statistics information.
- * Keep track of min, max, average, and standard deviation of the received samples.
- * Used to report latency information about input events.
- */
-struct LatencyStatistics {
- float min;
- float max;
- // Sum of all samples
- float sum;
- // Sum of squares of all samples
- float sum2;
- // The number of samples
- size_t count;
- // The last time statistics were reported.
- nsecs_t lastReportTime;
-
- LatencyStatistics() {
- reset(systemTime(SYSTEM_TIME_MONOTONIC));
- }
-
- inline void addValue(float x) {
- if (x < min) {
- min = x;
- }
- if (x > max) {
- max = x;
- }
- sum += x;
- sum2 += x * x;
- count++;
- }
-
- // Get the average value. Should not be called if no samples have been added.
- inline float mean() {
- if (count == 0) {
- return 0;
- }
- return sum / count;
- }
-
- // Get the standard deviation. Should not be called if no samples have been added.
- inline float stdev() {
- if (count == 0) {
- return 0;
- }
- float average = mean();
- return sqrt(sum2 / count - average * average);
- }
-
- /**
- * Reset internal state. The variable 'when' is the time when the data collection started.
- * Call this to start a new data collection window.
- */
- inline void reset(nsecs_t when) {
- max = 0;
- min = std::numeric_limits<float>::max();
- sum = 0;
- sum2 = 0;
- count = 0;
- lastReportTime = when;
- }
-};
/* Keeps track of the state of single-touch protocol. */
class SingleTouchMotionAccumulator {
@@ -1574,9 +1511,6 @@
VelocityControl mWheelXVelocityControl;
VelocityControl mWheelYVelocityControl;
- // Latency statistics for touch events
- struct LatencyStatistics mStatistics;
-
std::optional<DisplayViewport> findViewport();
void resetExternalStylus();
@@ -1645,8 +1579,6 @@
static void assignPointerIds(const RawState* last, RawState* current);
- void reportEventForStatistics(nsecs_t evdevTime);
-
const char* modeToString(DeviceMode deviceMode);
};
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 717f317..c7a8f5b 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -134,7 +134,12 @@
mActivationCount.add(list[i].sensorHandle, model);
- checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
+ // Only disable all sensors on HAL 1.0 since HAL 2.0
+ // handles this in its initialize method
+ if (!mSensors->supportsMessageQueues()) {
+ checkReturn(mSensors->activate(list[i].sensorHandle,
+ 0 /* enabled */));
+ }
}
}));
}
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index c11b88e..14ed73d 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -299,14 +299,10 @@
}
void SensorService::setSensorAccess(uid_t uid, bool hasAccess) {
- SortedVector< sp<SensorEventConnection> > activeConnections;
- populateActiveConnections(&activeConnections);
- {
- Mutex::Autolock _l(mLock);
- for (size_t i = 0 ; i < activeConnections.size(); i++) {
- if (activeConnections[i] != nullptr && activeConnections[i]->getUid() == uid) {
- activeConnections[i]->setSensorAccess(hasAccess);
- }
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
+ if (conn->getUid() == uid) {
+ conn->setSensorAccess(hasAccess);
}
}
}
@@ -360,7 +356,7 @@
if (args.size() > 2) {
return INVALID_OPERATION;
}
- Mutex::Autolock _l(mLock);
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
SensorDevice& dev(SensorDevice::getInstance());
if (args.size() == 2 && args[0] == String16("restrict")) {
// If already in restricted mode. Ignore.
@@ -374,7 +370,7 @@
mCurrentOperatingMode = RESTRICTED;
// temporarily stop all sensor direct report and disable sensors
- disableAllSensorsLocked();
+ disableAllSensorsLocked(&connLock);
mWhiteListedPackage.setTo(String8(args[1]));
return status_t(NO_ERROR);
} else if (args.size() == 1 && args[0] == String16("enable")) {
@@ -382,7 +378,7 @@
if (mCurrentOperatingMode == RESTRICTED) {
mCurrentOperatingMode = NORMAL;
// enable sensors and recover all sensor direct report
- enableAllSensorsLocked();
+ enableAllSensorsLocked(&connLock);
}
if (mCurrentOperatingMode == DATA_INJECTION) {
resetToNormalModeLocked();
@@ -473,22 +469,18 @@
result.appendFormat("Sensor Privacy: %s\n",
mSensorPrivacyPolicy->isSensorPrivacyEnabled() ? "enabled" : "disabled");
- result.appendFormat("%zd active connections\n", mActiveConnections.size());
- for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
- sp<SensorEventConnection> connection(mActiveConnections[i].promote());
- if (connection != nullptr) {
- result.appendFormat("Connection Number: %zu \n", i);
- connection->dump(result);
- }
+ const auto& activeConnections = connLock.getActiveConnections();
+ result.appendFormat("%zd active connections\n", activeConnections.size());
+ for (size_t i=0 ; i < activeConnections.size() ; i++) {
+ result.appendFormat("Connection Number: %zu \n", i);
+ activeConnections[i]->dump(result);
}
- result.appendFormat("%zd direct connections\n", mDirectConnections.size());
- for (size_t i = 0 ; i < mDirectConnections.size() ; i++) {
- sp<SensorDirectConnection> connection(mDirectConnections[i].promote());
- if (connection != nullptr) {
- result.appendFormat("Direct connection %zu:\n", i);
- connection->dump(result);
- }
+ const auto& directConnections = connLock.getDirectConnections();
+ result.appendFormat("%zd direct connections\n", directConnections.size());
+ for (size_t i = 0 ; i < directConnections.size() ; i++) {
+ result.appendFormat("Direct connection %zu:\n", i);
+ directConnections[i]->dump(result);
}
result.appendFormat("Previous Registrations:\n");
@@ -515,17 +507,14 @@
}
void SensorService::disableAllSensors() {
- Mutex::Autolock _l(mLock);
- disableAllSensorsLocked();
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ disableAllSensorsLocked(&connLock);
}
-void SensorService::disableAllSensorsLocked() {
+void SensorService::disableAllSensorsLocked(ConnectionSafeAutolock* connLock) {
SensorDevice& dev(SensorDevice::getInstance());
- for (auto &i : mDirectConnections) {
- sp<SensorDirectConnection> connection(i.promote());
- if (connection != nullptr) {
- connection->stopAll(true /* backupRecord */);
- }
+ for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
+ connection->stopAll(true /* backupRecord */);
}
dev.disableAllSensors();
// Clear all pending flush connections for all active sensors. If one of the active
@@ -537,11 +526,11 @@
}
void SensorService::enableAllSensors() {
- Mutex::Autolock _l(mLock);
- enableAllSensorsLocked();
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ enableAllSensorsLocked(&connLock);
}
-void SensorService::enableAllSensorsLocked() {
+void SensorService::enableAllSensorsLocked(ConnectionSafeAutolock* connLock) {
// sensors should only be enabled if the operating state is not restricted and sensor
// privacy is not enabled.
if (mCurrentOperatingMode == RESTRICTED || mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
@@ -552,14 +541,12 @@
}
SensorDevice& dev(SensorDevice::getInstance());
dev.enableAllSensors();
- for (auto &i : mDirectConnections) {
- sp<SensorDirectConnection> connection(i.promote());
- if (connection != nullptr) {
- connection->recoverAll();
- }
+ for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
+ connection->recoverAll();
}
}
+
// NOTE: This is a remote API - make sure all args are validated
status_t SensorService::shellCommand(int in, int out, int err, Vector<String16>& args) {
if (!checkCallingPermission(sManageSensorsPermission, nullptr, nullptr)) {
@@ -734,17 +721,8 @@
for (int i = 0; i < count; i++) {
mSensorEventBuffer[i].flags = 0;
}
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
- // Make a copy of the connection vector as some connections may be removed during the course
- // of this loop (especially when one-shot sensor events are present in the sensor_event
- // buffer). Promote all connections to StrongPointers before the lock is acquired. If the
- // destructor of the sp gets called when the lock is acquired, it may result in a deadlock
- // as ~SensorEventConnection() needs to acquire mLock again for cleanup. So copy all the
- // strongPointers to a vector before the lock is acquired.
- SortedVector< sp<SensorEventConnection> > activeConnections;
- populateActiveConnections(&activeConnections);
-
- Mutex::Autolock _l(mLock);
// Poll has returned. Hold a wakelock if one of the events is from a wake up sensor. The
// rest of this loop is under a critical section protected by mLock. Acquiring a wakeLock,
// sending events to clients (incrementing SensorEventConnection::mWakeLockRefCount) should
@@ -818,6 +796,10 @@
}
}
+ // Cache the list of active connections, since we use it in multiple places below but won't
+ // modify it here
+ const std::vector<sp<SensorEventConnection>> activeConnections = connLock.getActiveConnections();
+
for (int i = 0; i < count; ++i) {
// Map flush_complete_events in the buffer to SensorEventConnections which called flush
// on the hardware sensor. mapFlushEventsToConnections[i] will be the
@@ -869,11 +851,8 @@
ALOGE("Dynamic sensor release error.");
}
- size_t numConnections = activeConnections.size();
- for (size_t i=0 ; i < numConnections; ++i) {
- if (activeConnections[i] != nullptr) {
- activeConnections[i]->removeSensor(handle);
- }
+ for (const sp<SensorEventConnection>& connection : activeConnections) {
+ connection->removeSensor(handle);
}
}
}
@@ -882,18 +861,14 @@
// Send our events to clients. Check the state of wake lock for each client and release the
// lock if none of the clients need it.
bool needsWakeLock = false;
- size_t numConnections = activeConnections.size();
- for (size_t i=0 ; i < numConnections; ++i) {
- if (activeConnections[i] != nullptr) {
- activeConnections[i]->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
- mMapFlushEventsToConnections);
- needsWakeLock |= activeConnections[i]->needsWakeLock();
- // If the connection has one-shot sensors, it may be cleaned up after first trigger.
- // Early check for one-shot sensors.
- if (activeConnections[i]->hasOneShotSensors()) {
- cleanupAutoDisabledSensorLocked(activeConnections[i], mSensorEventBuffer,
- count);
- }
+ for (const sp<SensorEventConnection>& connection : activeConnections) {
+ connection->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
+ mMapFlushEventsToConnections);
+ needsWakeLock |= connection->needsWakeLock();
+ // If the connection has one-shot sensors, it may be cleaned up after first trigger.
+ // Early check for one-shot sensors.
+ if (connection->hasOneShotSensors()) {
+ cleanupAutoDisabledSensorLocked(connection, mSensorEventBuffer, count);
}
}
@@ -912,17 +887,11 @@
}
void SensorService::resetAllWakeLockRefCounts() {
- SortedVector< sp<SensorEventConnection> > activeConnections;
- populateActiveConnections(&activeConnections);
- {
- Mutex::Autolock _l(mLock);
- for (size_t i=0 ; i < activeConnections.size(); ++i) {
- if (activeConnections[i] != nullptr) {
- activeConnections[i]->resetWakeLockRefCount();
- }
- }
- setWakeLockAcquiredLocked(false);
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ for (const sp<SensorEventConnection>& connection : connLock.getActiveConnections()) {
+ connection->resetWakeLockRefCount();
}
+ setWakeLockAcquiredLocked(false);
}
void SensorService::setWakeLockAcquiredLocked(bool acquire) {
@@ -1144,9 +1113,7 @@
sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName,
requestedMode == DATA_INJECTION, connOpPackageName, hasSensorAccess));
if (requestedMode == DATA_INJECTION) {
- if (mActiveConnections.indexOf(result) < 0) {
- mActiveConnections.add(result);
- }
+ mConnectionHolder.addEventConnectionIfNotPresent(result);
// Add the associated file descriptor to the Looper for polling whenever there is data to
// be injected.
result->updateLooperRegistration(mLooper);
@@ -1162,7 +1129,7 @@
sp<ISensorEventConnection> SensorService::createSensorDirectConnection(
const String16& opPackageName, uint32_t size, int32_t type, int32_t format,
const native_handle *resource) {
- Mutex::Autolock _l(mLock);
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
// No new direct connections are allowed when sensor privacy is enabled
if (mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
@@ -1190,9 +1157,8 @@
}
// check for duplication
- for (auto &i : mDirectConnections) {
- sp<SensorDirectConnection> connection(i.promote());
- if (connection != nullptr && connection->isEquivalent(&mem)) {
+ for (const sp<SensorDirectConnection>& connection : connLock.getDirectConnections()) {
+ if (connection->isEquivalent(&mem)) {
ALOGE("Duplicate create channel request for the same share memory");
return nullptr;
}
@@ -1229,7 +1195,7 @@
return nullptr;
}
- SensorDirectConnection* conn = nullptr;
+ sp<SensorDirectConnection> conn;
SensorDevice& dev(SensorDevice::getInstance());
int channelHandle = dev.registerDirectChannel(&mem);
@@ -1246,7 +1212,7 @@
} else {
// add to list of direct connections
// sensor service should never hold pointer or sp of SensorDirectConnection object.
- mDirectConnections.add(wp<SensorDirectConnection>(conn));
+ mConnectionHolder.addDirectConnection(conn);
}
return conn;
}
@@ -1358,7 +1324,7 @@
}
void SensorService::cleanupConnection(SensorEventConnection* c) {
- Mutex::Autolock _l(mLock);
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
const wp<SensorEventConnection> connection(c);
size_t size = mActiveSensors.size();
ALOGD_IF(DEBUG_CONNECTIONS, "%zu active sensors", size);
@@ -1391,10 +1357,10 @@
}
}
c->updateLooperRegistration(mLooper);
- mActiveConnections.remove(connection);
+ mConnectionHolder.removeEventConnection(connection);
BatteryService::cleanup(c->getUid());
if (c->needsWakeLock()) {
- checkWakeLockStateLocked();
+ checkWakeLockStateLocked(&connLock);
}
{
@@ -1414,7 +1380,7 @@
SensorDevice& dev(SensorDevice::getInstance());
dev.unregisterDirectChannel(c->getHalChannelHandle());
- mDirectConnections.remove(c);
+ mConnectionHolder.removeDirectConnection(c);
}
sp<SensorInterface> SensorService::getSensorInterfaceFromHandle(int handle) const {
@@ -1433,7 +1399,7 @@
return BAD_VALUE;
}
- Mutex::Autolock _l(mLock);
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
if (mCurrentOperatingMode != NORMAL
&& !isWhiteListedPackage(connection->getPackageName())) {
return INVALID_OPERATION;
@@ -1484,7 +1450,7 @@
}
connection->sendEvents(&event, 1, nullptr);
if (!connection->needsWakeLock() && mWakeLockAcquired) {
- checkWakeLockStateLocked();
+ checkWakeLockStateLocked(&connLock);
}
}
}
@@ -1497,9 +1463,7 @@
BatteryService::enableSensor(connection->getUid(), handle);
// the sensor was added (which means it wasn't already there)
// so, see if this connection becomes active
- if (mActiveConnections.indexOf(connection) < 0) {
- mActiveConnections.add(connection);
- }
+ mConnectionHolder.addEventConnectionIfNotPresent(connection);
} else {
ALOGW("sensor %08x already enabled in connection %p (ignoring)",
handle, connection.get());
@@ -1603,7 +1567,7 @@
}
if (connection->hasAnySensor() == false) {
connection->updateLooperRegistration(mLooper);
- mActiveConnections.remove(connection);
+ mConnectionHolder.removeEventConnection(connection);
}
// see if this sensor becomes inactive
if (rec->removeConnection(connection)) {
@@ -1762,22 +1726,19 @@
}
void SensorService::checkWakeLockState() {
- Mutex::Autolock _l(mLock);
- checkWakeLockStateLocked();
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ checkWakeLockStateLocked(&connLock);
}
-void SensorService::checkWakeLockStateLocked() {
+void SensorService::checkWakeLockStateLocked(ConnectionSafeAutolock* connLock) {
if (!mWakeLockAcquired) {
return;
}
bool releaseLock = true;
- for (size_t i=0 ; i<mActiveConnections.size() ; i++) {
- sp<SensorEventConnection> connection(mActiveConnections[i].promote());
- if (connection != nullptr) {
- if (connection->needsWakeLock()) {
- releaseLock = false;
- break;
- }
+ for (const sp<SensorEventConnection>& connection : connLock->getActiveConnections()) {
+ if (connection->needsWakeLock()) {
+ releaseLock = false;
+ break;
}
}
if (releaseLock) {
@@ -1793,17 +1754,6 @@
}
}
-void SensorService::populateActiveConnections(
- SortedVector< sp<SensorEventConnection> >* activeConnections) {
- Mutex::Autolock _l(mLock);
- for (size_t i=0 ; i < mActiveConnections.size(); ++i) {
- sp<SensorEventConnection> connection(mActiveConnections[i].promote());
- if (connection != nullptr) {
- activeConnections->add(connection);
- }
- }
-}
-
bool SensorService::isWhiteListedPackage(const String8& packageName) {
return (packageName.contains(mWhiteListedPackage.string()));
}
@@ -1938,4 +1888,62 @@
}
return binder::Status::ok();
}
-}; // namespace android
+
+SensorService::ConnectionSafeAutolock::ConnectionSafeAutolock(
+ SensorService::SensorConnectionHolder& holder, Mutex& mutex)
+ : mConnectionHolder(holder), mAutolock(mutex) {}
+
+template<typename ConnectionType>
+const std::vector<sp<ConnectionType>>& SensorService::ConnectionSafeAutolock::getConnectionsHelper(
+ const SortedVector<wp<ConnectionType>>& connectionList,
+ std::vector<std::vector<sp<ConnectionType>>>* referenceHolder) {
+ referenceHolder->emplace_back();
+ std::vector<sp<ConnectionType>>& connections = referenceHolder->back();
+ for (const wp<ConnectionType>& weakConnection : connectionList){
+ sp<ConnectionType> connection = weakConnection.promote();
+ if (connection != nullptr) {
+ connections.push_back(std::move(connection));
+ }
+ }
+ return connections;
+}
+
+const std::vector<sp<SensorService::SensorEventConnection>>&
+ SensorService::ConnectionSafeAutolock::getActiveConnections() {
+ return getConnectionsHelper(mConnectionHolder.mActiveConnections,
+ &mReferencedActiveConnections);
+}
+
+const std::vector<sp<SensorService::SensorDirectConnection>>&
+ SensorService::ConnectionSafeAutolock::getDirectConnections() {
+ return getConnectionsHelper(mConnectionHolder.mDirectConnections,
+ &mReferencedDirectConnections);
+}
+
+void SensorService::SensorConnectionHolder::addEventConnectionIfNotPresent(
+ const sp<SensorService::SensorEventConnection>& connection) {
+ if (mActiveConnections.indexOf(connection) < 0) {
+ mActiveConnections.add(connection);
+ }
+}
+
+void SensorService::SensorConnectionHolder::removeEventConnection(
+ const wp<SensorService::SensorEventConnection>& connection) {
+ mActiveConnections.remove(connection);
+}
+
+void SensorService::SensorConnectionHolder::addDirectConnection(
+ const sp<SensorService::SensorDirectConnection>& connection) {
+ mDirectConnections.add(connection);
+}
+
+void SensorService::SensorConnectionHolder::removeDirectConnection(
+ const wp<SensorService::SensorDirectConnection>& connection) {
+ mDirectConnections.remove(connection);
+}
+
+SensorService::ConnectionSafeAutolock SensorService::SensorConnectionHolder::lock(Mutex& mutex) {
+ return ConnectionSafeAutolock(*this, mutex);
+}
+
+} // namespace android
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index e6ec96d..060b5eb 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -20,6 +20,7 @@
#include "SensorList.h"
#include "RecentEventLogger.h"
+#include <android-base/macros.h>
#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IUidObserver.h>
@@ -42,6 +43,7 @@
#include <sys/types.h>
#include <unordered_map>
#include <unordered_set>
+#include <vector>
#if __clang__
// Clang warns about SensorEventConnection::dump hiding BBinder::dump. The cause isn't fixable
@@ -95,10 +97,67 @@
friend class BinderService<SensorService>;
// nested class/struct for internal use
- class SensorRecord;
+ class ConnectionSafeAutolock;
+ class SensorConnectionHolder;
class SensorEventAckReceiver;
+ class SensorRecord;
class SensorRegistrationInfo;
+ // Promoting a SensorEventConnection or SensorDirectConnection from wp to sp must be done with
+ // mLock held, but destroying that sp must be done unlocked to avoid a race condition that
+ // causes a deadlock (remote dies while we hold a local sp, then our decStrong() call invokes
+ // the dtor -> cleanupConnection() tries to re-lock the mutex). This class ensures safe usage
+ // by wrapping a Mutex::Autolock on SensorService's mLock, plus vectors that hold promoted sp<>
+ // references until the lock is released, when they are safely destroyed.
+ // All read accesses to the connection lists in mConnectionHolder must be done via this class.
+ class ConnectionSafeAutolock final {
+ public:
+ // Returns a list of non-null promoted connection references
+ const std::vector<sp<SensorEventConnection>>& getActiveConnections();
+ const std::vector<sp<SensorDirectConnection>>& getDirectConnections();
+
+ private:
+ // Constructed via SensorConnectionHolder::lock()
+ friend class SensorConnectionHolder;
+ explicit ConnectionSafeAutolock(SensorConnectionHolder& holder, Mutex& mutex);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ConnectionSafeAutolock);
+
+ // NOTE: Order of these members is important, as the destructor for non-static members
+ // get invoked in the reverse order of their declaration. Here we are relying on the
+ // Autolock to be destroyed *before* the vectors, so the sp<> objects are destroyed without
+ // the lock held, which avoids the deadlock.
+ SensorConnectionHolder& mConnectionHolder;
+ std::vector<std::vector<sp<SensorEventConnection>>> mReferencedActiveConnections;
+ std::vector<std::vector<sp<SensorDirectConnection>>> mReferencedDirectConnections;
+ Mutex::Autolock mAutolock;
+
+ template<typename ConnectionType>
+ const std::vector<sp<ConnectionType>>& getConnectionsHelper(
+ const SortedVector<wp<ConnectionType>>& connectionList,
+ std::vector<std::vector<sp<ConnectionType>>>* referenceHolder);
+ };
+
+ // Encapsulates the collection of active SensorEventConection and SensorDirectConnection
+ // references. Write access is done through this class with mLock held, but all read access
+ // must be routed through ConnectionSafeAutolock.
+ class SensorConnectionHolder {
+ public:
+ void addEventConnectionIfNotPresent(const sp<SensorEventConnection>& connection);
+ void removeEventConnection(const wp<SensorEventConnection>& connection);
+
+ void addDirectConnection(const sp<SensorDirectConnection>& connection);
+ void removeDirectConnection(const wp<SensorDirectConnection>& connection);
+
+ // Pass in the mutex that protects this connection holder; acquires the lock and returns an
+ // object that can be used to safely read the lists of connections
+ ConnectionSafeAutolock lock(Mutex& mutex);
+
+ private:
+ friend class ConnectionSafeAutolock;
+ SortedVector< wp<SensorEventConnection> > mActiveConnections;
+ SortedVector< wp<SensorDirectConnection> > mDirectConnections;
+ };
+
// If accessing a sensor we need to make sure the UID has access to it. If
// the app UID is idle then it cannot access sensors and gets no trigger
// events, no on-change events, flush event behavior does not change, and
@@ -250,7 +309,7 @@
// method checks whether all the events from these wake up sensors have been delivered to the
// corresponding applications, if yes the wakelock is released.
void checkWakeLockState();
- void checkWakeLockStateLocked();
+ void checkWakeLockStateLocked(ConnectionSafeAutolock* connLock);
bool isWakeLockAcquired();
bool isWakeUpSensorEvent(const sensors_event_t& event) const;
@@ -268,10 +327,6 @@
// Send events from the event cache for this particular connection.
void sendEventsFromCache(const sp<SensorEventConnection>& connection);
- // Promote all weak referecences in mActiveConnections vector to strong references and add them
- // to the output vector.
- void populateActiveConnections( SortedVector< sp<SensorEventConnection> >* activeConnections);
-
// If SensorService is operating in RESTRICTED mode, only select whitelisted packages are
// allowed to register for or call flush on sensors. Typically only cts test packages are
// allowed.
@@ -306,10 +361,10 @@
// temporarily stops all active direct connections and disables all sensors
void disableAllSensors();
- void disableAllSensorsLocked();
+ void disableAllSensorsLocked(ConnectionSafeAutolock* connLock);
// restarts the previously stopped direct connections and enables all sensors
void enableAllSensors();
- void enableAllSensorsLocked();
+ void enableAllSensorsLocked(ConnectionSafeAutolock* connLock);
static uint8_t sHmacGlobalKey[128];
static bool sHmacGlobalKeyIsValid;
@@ -327,12 +382,13 @@
mutable Mutex mLock;
DefaultKeyedVector<int, SensorRecord*> mActiveSensors;
std::unordered_set<int> mActiveVirtualSensors;
- SortedVector< wp<SensorEventConnection> > mActiveConnections;
+ SensorConnectionHolder mConnectionHolder;
bool mWakeLockAcquired;
sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
+ // WARNING: these SensorEventConnection instances must not be promoted to sp, except via
+ // modification to add support for them in ConnectionSafeAutolock
wp<const SensorEventConnection> * mMapFlushEventsToConnections;
std::unordered_map<int, SensorServiceUtil::RecentEventLogger*> mRecentEvent;
- SortedVector< wp<SensorDirectConnection> > mDirectConnections;
Mode mCurrentOperatingMode;
// This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 59ea9af..87bec11 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -132,13 +132,15 @@
return inverse(tr);
}
-bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
+std::optional<renderengine::LayerSettings> BufferLayer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
ATRACE_CALL();
- Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
- supportProtectedContent, layer);
+
+ auto result = Layer::prepareClientComposition(targetSettings);
+ if (!result) {
+ return result;
+ }
+
if (CC_UNLIKELY(mActiveBuffer == 0)) {
// the texture has not been created yet, this Layer has
// in fact never been drawn into. This happens frequently with
@@ -159,15 +161,16 @@
under.orSelf(layer->visibleRegion);
});
// if not everything below us is covered, we plug the holes!
- Region holes(clip.subtract(under));
+ Region holes(targetSettings.clip.subtract(under));
if (!holes.isEmpty()) {
- clearRegion.orSelf(holes);
+ targetSettings.clearRegion.orSelf(holes);
}
- return false;
+ return std::nullopt;
}
- bool blackOutLayer =
- (isProtected() && !supportProtectedContent) || (isSecure() && !renderArea.isSecure());
+ bool blackOutLayer = (isProtected() && !targetSettings.supportProtectedContent) ||
+ (isSecure() && !targetSettings.isSecure);
const State& s(getDrawingState());
+ auto& layer = *result;
if (!blackOutLayer) {
layer.source.buffer.buffer = mActiveBuffer;
layer.source.buffer.isOpaque = isOpaque(s);
@@ -176,8 +179,7 @@
layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
layer.source.buffer.isY410BT2020 = isHdrY410();
// TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = needsFiltering(renderArea.getDisplayDevice()) ||
- renderArea.needsFiltering() || isFixedSize();
+ const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
@@ -244,7 +246,7 @@
layer.alpha = 1.0;
}
- return true;
+ return result;
}
bool BufferLayer::isHdrY410() const {
@@ -572,21 +574,23 @@
}
bool BufferLayer::needsFiltering(const sp<const DisplayDevice>& displayDevice) const {
- // If we are not capturing based on the state of a known display device, we
- // only return mNeedsFiltering
+ // If we are not capturing based on the state of a known display device,
+ // just return false.
if (displayDevice == nullptr) {
- return mNeedsFiltering;
+ return false;
}
const auto outputLayer = findOutputLayerForDisplay(displayDevice);
if (outputLayer == nullptr) {
- return mNeedsFiltering;
+ return false;
}
+ // We need filtering if the sourceCrop rectangle size does not match the
+ // displayframe rectangle size (not a 1:1 render)
const auto& compositionState = outputLayer->getState();
const auto displayFrame = compositionState.displayFrame;
const auto sourceCrop = compositionState.sourceCrop;
- return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
+ return sourceCrop.getHeight() != displayFrame.getHeight() ||
sourceCrop.getWidth() != displayFrame.getWidth();
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index bb0205d..c86acf0 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -82,7 +82,6 @@
bool isHdrY410() const override;
- bool onPreComposition(nsecs_t refreshStartTime) override;
bool onPostComposition(const std::optional<DisplayId>& displayId,
const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
@@ -146,7 +145,13 @@
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
protected:
- void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const override;
+ /*
+ * compositionengine::LayerFE overrides
+ */
+ bool onPreComposition(nsecs_t) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
// Loads the corresponding system property once per process
static bool latchUnsignaledBuffers();
@@ -163,15 +168,9 @@
bool mRefreshPending{false};
- // prepareClientLayer - constructs a RenderEngine layer for GPU composition.
- bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) override;
-
private:
// Returns true if this layer requires filtering
- bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const;
+ bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const override;
uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 5e994b7..ea55795 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -470,7 +470,6 @@
if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr ||
oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) {
mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE);
- mRE.cacheExternalTextureBuffer(item.mGraphicBuffer);
}
}
}
@@ -507,6 +506,12 @@
ConsumerBase::dumpLocked(result, prefix);
}
+BufferLayerConsumer::Image::Image(const sp<GraphicBuffer>& graphicBuffer,
+ renderengine::RenderEngine& engine)
+ : mGraphicBuffer(graphicBuffer), mRE(engine) {
+ mRE.cacheExternalTextureBuffer(mGraphicBuffer);
+}
+
BufferLayerConsumer::Image::~Image() {
if (mGraphicBuffer != nullptr) {
ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId());
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 8536f6b..39ed370 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -223,8 +223,7 @@
// Utility class for managing GraphicBuffer references into renderengine
class Image {
public:
- Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine)
- : mGraphicBuffer(graphicBuffer), mRE(engine) {}
+ Image(const sp<GraphicBuffer>& graphicBuffer, renderengine::RenderEngine& engine);
virtual ~Image();
const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index f15957a..b65d351 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -50,16 +50,14 @@
ColorLayer::~ColorLayer() = default;
-bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
- supportProtectedContent, layer);
- half4 color(getColor());
- half3 solidColor(color.r, color.g, color.b);
- layer.source.solidColor = solidColor;
- return true;
+std::optional<renderengine::LayerSettings> ColorLayer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+ auto result = Layer::prepareClientComposition(targetSettings);
+ if (!result) {
+ return result;
+ }
+ result->source.solidColor = getColor().rgb;
+ return result;
}
bool ColorLayer::isVisible() const {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 2483ff0..015b939 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -39,16 +39,13 @@
void commitTransaction(const State& stateToCommit) override;
- bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
-
protected:
- virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
-
-private:
+ /*
+ * compositionengine::LayerFE overrides
+ */
void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 1f2cae9..94fab1f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -16,6 +16,9 @@
#pragma once
+#include <optional>
+
+#include <renderengine/LayerSettings.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
@@ -40,6 +43,34 @@
// geometry state can be skipped.
virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0;
+ struct ClientCompositionTargetSettings {
+ // The clip region, or visible region that is being rendered to
+ const Region& clip;
+
+ // If true, the layer should use an identity transform for its position
+ // transform. Used only by the captureScreen API call.
+ const bool useIdentityTransform;
+
+ // If set to true, the layer should enable filtering when rendering.
+ const bool needsFiltering;
+
+ // If set to true, the buffer is being sent to a destination that is
+ // expected to treat the buffer contents as secure.
+ const bool isSecure;
+
+ // If set to true, the target buffer has protected content support.
+ const bool supportProtectedContent;
+
+ // Modified by each call to prepareClientComposition to indicate the
+ // region of the target buffer that should be cleared.
+ Region& clearRegion;
+ };
+
+ // Returns the LayerSettings to pass to RenderEngine::drawLayers, or
+ // nullopt_t if the layer does not render
+ virtual std::optional<renderengine::LayerSettings> prepareClientComposition(
+ ClientCompositionTargetSettings&) = 0;
+
// Called after the layer is displayed to update the presentation fence
virtual void onLayerDisplayed(const sp<Fence>&) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index ebfda1f..4dfcfa4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -150,6 +150,9 @@
// Takes (moves) the set of layers being released this frame.
virtual ReleasedLayers takeReleasedLayers() = 0;
+ // Signals that a frame is beginning on the output
+ virtual void beginFrame() = 0;
+
// Prepares a frame for display
virtual void prepareFrame() = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index b454212..5f4a764 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -75,6 +75,7 @@
void setReleasedLayers(ReleasedLayers&&) override;
ReleasedLayers takeReleasedLayers() override;
+ void beginFrame() override;
void prepareFrame() override;
void postFramebuffer() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 952f702..48c2dbf 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -33,6 +33,9 @@
MOCK_METHOD1(onPreComposition, bool(nsecs_t));
MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool));
+ MOCK_METHOD1(prepareClientComposition,
+ std::optional<renderengine::LayerSettings>(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&));
MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
MOCK_CONST_METHOD0(getDebugName, const char*());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 8aaebc2..d494413 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -73,6 +73,7 @@
MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&));
MOCK_METHOD0(takeReleasedLayers, ReleasedLayers());
+ MOCK_METHOD0(beginFrame, void());
MOCK_METHOD0(prepareFrame, void());
MOCK_METHOD0(chooseCompositionStrategy, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6d060e4..6878e99 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -251,6 +251,34 @@
return std::move(mReleasedLayers);
}
+void Output::beginFrame() {
+ const bool dirty = !getDirtyRegion(false).isEmpty();
+ const bool empty = mOutputLayersOrderedByZ.empty();
+ const bool wasEmpty = !mState.lastCompositionHadVisibleLayers;
+
+ // If nothing has changed (!dirty), don't recompose.
+ // If something changed, but we don't currently have any visible layers,
+ // and didn't when we last did a composition, then skip it this time.
+ // The second rule does two things:
+ // - When all layers are removed from a display, we'll emit one black
+ // frame, then nothing more until we get new layers.
+ // - When a display is created with a private layer stack, we won't
+ // emit any black frames until a layer is added to the layer stack.
+ const bool mustRecompose = dirty && !(empty && wasEmpty);
+
+ const char flagPrefix[] = {'-', '+'};
+ static_cast<void>(flagPrefix);
+ ALOGV_IF("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __FUNCTION__,
+ mustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty],
+ flagPrefix[empty], flagPrefix[wasEmpty]);
+
+ mRenderSurface->beginFrame(mustRecompose);
+
+ if (mustRecompose) {
+ mState.lastCompositionHadVisibleLayers = !empty;
+ }
+}
+
void Output::prepareFrame() {
ATRACE_CALL();
ALOGV(__FUNCTION__);
@@ -272,10 +300,10 @@
return;
}
- mRenderSurface->onPresentDisplayCompleted();
-
auto frame = presentAndGetFrameFences();
+ mRenderSurface->onPresentDisplayCompleted();
+
for (auto& layer : getOutputLayersOrderedByZ()) {
// The layer buffer from the previous frame (if any) is released
// by HWC only when the release fence from this frame (if any) is
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 3a5f3fa..d40a38c 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,11 +26,6 @@
ContainerLayer::~ContainerLayer() = default;
-bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&, const bool,
- renderengine::LayerSettings&) {
- return false;
-}
-
bool ContainerLayer::isVisible() const {
return false;
}
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 57267c7..a1607ff 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -34,14 +34,6 @@
bool canReceiveInput() const override;
bool isCreatedFromMainThread() const override { return true; }
-
- bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
-
-protected:
- bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) override;
};
} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8150ca7..e7fbfe9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -458,6 +458,10 @@
}
}
+bool Layer::onPreComposition(nsecs_t) {
+ return false;
+}
+
void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState,
bool includeGeometry) const {
if (includeGeometry) {
@@ -507,54 +511,33 @@
// drawing...
// ---------------------------------------------------------------------------
-bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- return prepareClientLayer(renderArea, clip, false, clearRegion, supportProtectedContent, layer);
-}
+std::optional<renderengine::LayerSettings> Layer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+ if (!getCompositionLayer()) {
+ return {};
+ }
-bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform,
- clearRegion, supportProtectedContent, layer);
-}
-
-bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
- bool useIdentityTransform, Region& /*clearRegion*/,
- const bool /*supportProtectedContent*/,
- renderengine::LayerSettings& layer) {
FloatRect bounds = getBounds();
half alpha = getAlpha();
- layer.geometry.boundaries = bounds;
- if (useIdentityTransform) {
- layer.geometry.positionTransform = mat4();
+ renderengine::LayerSettings layerSettings;
+ layerSettings.geometry.boundaries = bounds;
+ if (targetSettings.useIdentityTransform) {
+ layerSettings.geometry.positionTransform = mat4();
} else {
- const ui::Transform transform = getTransform();
- mat4 m;
- m[0][0] = transform[0][0];
- m[0][1] = transform[0][1];
- m[0][3] = transform[0][2];
- m[1][0] = transform[1][0];
- m[1][1] = transform[1][1];
- m[1][3] = transform[1][2];
- m[3][0] = transform[2][0];
- m[3][1] = transform[2][1];
- m[3][3] = transform[2][2];
- layer.geometry.positionTransform = m;
+ layerSettings.geometry.positionTransform = getTransform().asMatrix4();
}
if (hasColorTransform()) {
- layer.colorTransform = getColorTransform();
+ layerSettings.colorTransform = getColorTransform();
}
const auto roundedCornerState = getRoundedCornerState();
- layer.geometry.roundedCornersRadius = roundedCornerState.radius;
- layer.geometry.roundedCornersCrop = roundedCornerState.cropRect;
+ layerSettings.geometry.roundedCornersRadius = roundedCornerState.radius;
+ layerSettings.geometry.roundedCornersCrop = roundedCornerState.cropRect;
- layer.alpha = alpha;
- layer.sourceDataspace = mCurrentDataSpace;
- return true;
+ layerSettings.alpha = alpha;
+ layerSettings.sourceDataspace = mCurrentDataSpace;
+ return layerSettings;
}
Hwc2::IComposerClient::Composition Layer::getCompositionType(
@@ -1982,13 +1965,6 @@
return mRemovedFromCurrentState;
}
-// Debug helper for b/137560795
-#define INT32_MIGHT_OVERFLOW(n) (((n) >= INT32_MAX / 2) || ((n) <= INT32_MIN / 2))
-
-#define RECT_BOUNDS_INVALID(rect) \
- (INT32_MIGHT_OVERFLOW((rect).left) || INT32_MIGHT_OVERFLOW((rect).right) || \
- INT32_MIGHT_OVERFLOW((rect).bottom) || INT32_MIGHT_OVERFLOW((rect).top))
-
InputWindowInfo Layer::fillInputInfo() {
InputWindowInfo info = mDrawingState.inputInfo;
@@ -1999,14 +1975,14 @@
ui::Transform t = getTransform();
const float xScale = t.sx();
const float yScale = t.sy();
- float xSurfaceInset = info.surfaceInset;
- float ySurfaceInset = info.surfaceInset;
+ int32_t xSurfaceInset = info.surfaceInset;
+ int32_t ySurfaceInset = info.surfaceInset;
if (xScale != 1.0f || yScale != 1.0f) {
- info.windowXScale *= 1.0f / xScale;
- info.windowYScale *= 1.0f / yScale;
+ info.windowXScale *= (xScale != 0.0f) ? 1.0f / xScale : 0.0f;
+ info.windowYScale *= (yScale != 0.0f) ? 1.0f / yScale : 0.0f;
info.touchableRegion.scaleSelf(xScale, yScale);
- xSurfaceInset *= xScale;
- ySurfaceInset *= yScale;
+ xSurfaceInset = std::round(xSurfaceInset * xScale);
+ ySurfaceInset = std::round(ySurfaceInset * yScale);
}
// Transform layer size to screen space and inset it by surface insets.
@@ -2019,25 +1995,10 @@
}
layerBounds = t.transform(layerBounds);
- // debug check for b/137560795
- {
- if (RECT_BOUNDS_INVALID(layerBounds)) {
- ALOGE("layer %s bounds are invalid (%" PRIi32 ", %" PRIi32 ", %" PRIi32 ", %" PRIi32
- ")",
- mName.c_str(), layerBounds.left, layerBounds.top, layerBounds.right,
- layerBounds.bottom);
- std::string out;
- getTransform().dump(out, "Transform");
- ALOGE("%s", out.c_str());
- layerBounds.left = layerBounds.top = layerBounds.right = layerBounds.bottom = 0;
- }
+ // clamp inset to layer bounds
+ xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0;
+ ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0;
- if (INT32_MIGHT_OVERFLOW(xSurfaceInset) || INT32_MIGHT_OVERFLOW(ySurfaceInset)) {
- ALOGE("layer %s surface inset are invalid (%" PRIi32 ", %" PRIi32 ")", mName.c_str(),
- int32_t(xSurfaceInset), int32_t(ySurfaceInset));
- xSurfaceInset = ySurfaceInset = 0;
- }
- }
layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset);
// Input coordinate should match the layer bounds.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index aa7e2f1..953f25d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -461,19 +461,17 @@
return s.activeTransparentRegion_legacy;
}
virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
-
-protected:
- virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
+ virtual bool needsFiltering(const sp<const DisplayDevice>&) const { return false; }
public:
/*
* compositionengine::LayerFE overrides
*/
+ bool onPreComposition(nsecs_t) override;
void latchCompositionState(compositionengine::LayerFECompositionState&,
bool includeGeometry) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
const char* getDebugName() const override;
@@ -509,17 +507,6 @@
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
/*
- * prepareClientLayer - populates a renderengine::LayerSettings to passed to
- * RenderEngine::drawLayers. Returns true if the layer can be used, and
- * false otherwise.
- */
- bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion,
- const bool supportProtectedContent, renderengine::LayerSettings& layer);
- bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
-
- /*
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
*/
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 67735aa..213160d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1790,11 +1790,12 @@
mCompositionEngine->preComposition(refreshArgs);
rebuildLayerStacks();
calculateWorkingSet();
- for (const auto& [token, display] : mDisplays) {
- beginFrame(display);
- display->getCompositionDisplay()->prepareFrame();
- doDebugFlashRegions(display, repaintEverything);
- doComposition(display, repaintEverything);
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ display->beginFrame();
+ display->prepareFrame();
+ doDebugFlashRegions(displayDevice, repaintEverything);
+ doComposition(displayDevice, repaintEverything);
}
logLayerStats();
@@ -2373,38 +2374,6 @@
profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
}
-void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& displayDevice) {
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- bool dirty = !display->getDirtyRegion(false).isEmpty();
- bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
- bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
-
- // If nothing has changed (!dirty), don't recompose.
- // If something changed, but we don't currently have any visible layers,
- // and didn't when we last did a composition, then skip it this time.
- // The second rule does two things:
- // - When all layers are removed from a display, we'll emit one black
- // frame, then nothing more until we get new layers.
- // - When a display is created with a private layer stack, we won't
- // emit any black frames until a layer is added to the layer stack.
- bool mustRecompose = dirty && !(empty && wasEmpty);
-
- const char flagPrefix[] = {'-', '+'};
- static_cast<void>(flagPrefix);
- ALOGV_IF(displayDevice->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
- __FUNCTION__, mustRecompose ? "doing" : "skipping",
- displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty],
- flagPrefix[wasEmpty]);
-
- display->getRenderSurface()->beginFrame(mustRecompose);
-
- if (mustRecompose) {
- display->editState().lastCompositionHadVisibleLayers = !empty;
- }
-}
-
void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool repaintEverything) {
ATRACE_CALL();
ALOGV("doComposition");
@@ -3350,6 +3319,7 @@
*/
ALOGV("Rendering client layers");
+ const bool useIdentityTransform = false;
bool firstLayer = true;
Region clearRegion = Region::INVALID_REGION;
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
@@ -3370,13 +3340,20 @@
layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
- renderengine::LayerSettings layerSettings;
Region dummyRegion;
- bool prepared =
- layer->prepareClientLayer(renderArea, clip, dummyRegion,
- supportProtectedContent, layerSettings);
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering(renderArea.getDisplayDevice()) ||
+ renderArea.needsFiltering(),
+ renderArea.isSecure(),
+ supportProtectedContent,
+ dummyRegion,
+ };
+ auto result = layer->prepareClientComposition(targetSettings);
- if (prepared) {
+ if (result) {
+ auto& layerSettings = *result;
layerSettings.source.buffer.buffer = nullptr;
layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
layerSettings.alpha = half(0.0);
@@ -3387,12 +3364,18 @@
break;
}
case Hwc2::IComposerClient::Composition::CLIENT: {
- renderengine::LayerSettings layerSettings;
- bool prepared =
- layer->prepareClientLayer(renderArea, clip, clearRegion,
- supportProtectedContent, layerSettings);
- if (prepared) {
- clientCompositionLayers.push_back(layerSettings);
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering(renderArea.getDisplayDevice()) ||
+ renderArea.needsFiltering(),
+ renderArea.isSecure(),
+ supportProtectedContent,
+ clearRegion,
+ };
+ auto result = layer->prepareClientComposition(targetSettings);
+ if (result) {
+ clientCompositionLayers.push_back(*result);
}
break;
}
@@ -3974,15 +3957,6 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
- if (what & layer_state_t::eReparent) {
- bool hadParent = layer->hasParent();
- if (layer->reparent(s.parentHandleForChild)) {
- if (!hadParent) {
- mCurrentState.layersSortedByZ.remove(layer);
- }
- flags |= eTransactionNeeded|eTraversalNeeded;
- }
- }
if (what & layer_state_t::eReparentChildren) {
if (layer->reparentChildren(s.reparentHandle)) {
flags |= eTransactionNeeded|eTraversalNeeded;
@@ -4043,6 +4017,19 @@
flags |= eTraversalNeeded;
}
}
+ // This has to happen after we reparent children because when we reparent to null we remove
+ // child layers from current state and remove its relative z. If the children are reparented in
+ // the same transaction, then we have to make sure we reparent the children first so we do not
+ // lose its relative z order.
+ if (what & layer_state_t::eReparent) {
+ bool hadParent = layer->hasParent();
+ if (layer->reparent(s.parentHandleForChild)) {
+ if (!hadParent) {
+ mCurrentState.layersSortedByZ.remove(layer);
+ }
+ flags |= eTransactionNeeded | eTraversalNeeded;
+ }
+ }
std::vector<sp<CallbackHandle>> callbackHandles;
if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!listenerCallbacks.empty())) {
for (const auto& [listener, callbackIds] : listenerCallbacks) {
@@ -5936,11 +5923,19 @@
Region clearRegion = Region::INVALID_REGION;
traverseLayers([&](Layer* layer) {
- renderengine::LayerSettings layerSettings;
- bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
- false, layerSettings);
- if (prepared) {
- clientCompositionLayers.push_back(layerSettings);
+ const bool supportProtectedContent = false;
+ Region clip(renderArea.getBounds());
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering(renderArea.getDisplayDevice()) || renderArea.needsFiltering(),
+ renderArea.isSecure(),
+ supportProtectedContent,
+ clearRegion,
+ };
+ auto result = layer->prepareClientComposition(targetSettings);
+ if (result) {
+ clientCompositionLayers.push_back(*result);
}
});
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index af21603..3974a8c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -760,12 +760,6 @@
ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const;
void calculateWorkingSet();
- /*
- * beginFrame - This function handles any pre-frame processing that needs to be
- * prior to any CompositionInfo handling and is not dependent on data in
- * CompositionInfo
- */
- void beginFrame(const sp<DisplayDevice>& display);
void doComposition(const sp<DisplayDevice>& display, bool repainEverything);
void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
void logLayerStats();
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index fdc6c58..6858c4d 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -46,7 +46,7 @@
using Increment = surfaceflinger::Increment;
using DisplayChange = surfaceflinger::DisplayChange;
-constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
class SurfaceInterceptor {
public:
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 1ac5098..93fe7d0 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -173,8 +173,8 @@
ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
- const std::string& layerName = layerRecord.layerName;
if (prevTimeRecord.ready) {
+ const std::string& layerName = layerRecord.layerName;
if (!mTimeStats.stats.count(layerName)) {
mTimeStats.stats[layerName].layerName = layerName;
mTimeStats.stats[layerName].packageName = getPackageName(layerName);
@@ -220,18 +220,6 @@
timeRecords[0].frameTime.frameNumber, presentToPresentMs);
timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
}
-
- // Output additional trace points to track frame time.
- ATRACE_INT64(("TimeStats-Post - " + layerName).c_str(), timeRecords[0].frameTime.postTime);
- ATRACE_INT64(("TimeStats-Acquire - " + layerName).c_str(),
- timeRecords[0].frameTime.acquireTime);
- ATRACE_INT64(("TimeStats-Latch - " + layerName).c_str(),
- timeRecords[0].frameTime.latchTime);
- ATRACE_INT64(("TimeStats-Desired - " + layerName).c_str(),
- timeRecords[0].frameTime.desiredTime);
- ATRACE_INT64(("TimeStats-Present - " + layerName).c_str(),
- timeRecords[0].frameTime.presentTime);
-
prevTimeRecord = timeRecords[0];
timeRecords.pop_front();
layerRecord.waitData--;
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index bc5f1aa..59e9c00 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -60,7 +60,7 @@
constexpr auto LAYER_NAME = "Layer Create and Delete Test";
constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0";
-constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
// Fill an RGBA_8888 formatted surface with a single color.
static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) {
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index c8f5618..b1fde22 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -4686,6 +4686,34 @@
}
}
+TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) {
+ sp<SurfaceControl> mGrandChild =
+ createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+ fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
+
+ // draw grand child behind the foreground surface
+ asTransaction([&](Transaction& t) {
+ t.setRelativeLayer(mGrandChild, mFGSurfaceControl->getHandle(), -1);
+ });
+
+ {
+ SCOPED_TRACE("Child visible");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 200, 200, 200);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.reparent(mChild, nullptr);
+ t.reparentChildren(mChild, mFGSurfaceControl->getHandle());
+ });
+
+ {
+ SCOPED_TRACE("foreground visible reparenting grandchild");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 195, 63, 63);
+ }
+}
+
TEST_F(ChildLayerTest, DetachChildrenSameClient) {
asTransaction([&](Transaction& t) {
t.show(mChild);
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index 7747734..4934970 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -31,6 +31,5 @@
subdirs = [
"nulldrv",
"libvulkan",
- "tools",
"vkjson",
]
diff --git a/vulkan/README.md b/vulkan/README.md
index 0f66097..185aa39 100644
--- a/vulkan/README.md
+++ b/vulkan/README.md
@@ -2,6 +2,10 @@
This subdirectory contains Android's Vulkan loader, as well as some Vulkan-related tools useful to platform developers.
+## Documentation
+
+The former contents of doc/implementors_guide/ are now at https://source.android.com/devices/graphics/implement-vulkan.
+
## Coding Style
We follow the [Chromium coding style](https://www.chromium.org/developers/coding-style) for naming and formatting, except with four-space indentation instead of two spaces. In general, any C++ features supported by the prebuilt platform toolchain are allowed.
@@ -12,6 +16,7 @@
We generate several parts of the loader and tools driectly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator.
- To run the generator:
-- Install Python3 (if not already installed)
-- `$ ./<path to>/frameworks/native/vulkan/scripts/code_generator.py`
+### Run The Code Generator
+
+Install Python3 (if not already installed) and execute below:
+`$ ./scripts/code_generator.py`
diff --git a/vulkan/doc/README b/vulkan/doc/README
deleted file mode 100644
index d1dc2e1..0000000
--- a/vulkan/doc/README
+++ /dev/null
@@ -1,2 +0,0 @@
-The former contents of implementors_guide/ are now at
-https://source.android.com/devices/graphics/implement-vulkan
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 993b751..85ef475 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -75,6 +75,7 @@
header_libs: [
"hwvulkan_headers",
+ "libnativeloader-dummy-headers",
"vulkan_headers",
],
export_header_lib_headers: ["vulkan_headers"],
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index f596086..9a670f6 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -30,6 +30,7 @@
#include <cutils/properties.h>
#include <graphicsenv/GraphicsEnv.h>
#include <log/log.h>
+#include <nativeloader/dlext_namespaces.h>
#include <sys/prctl.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -44,11 +45,6 @@
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
-// TODO(b/37049319) Get this from a header once one exists
-extern "C" {
-android_namespace_t* android_get_exported_namespace(const char*);
-}
-
// #define ENABLE_ALLOC_CALLSTACKS 1
#if ENABLE_ALLOC_CALLSTACKS
#include <utils/CallStack.h>
diff --git a/vulkan/tools/Android.bp b/vulkan/tools/Android.bp
deleted file mode 100644
index 2514094..0000000
--- a/vulkan/tools/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_binary {
- name: "vkinfo",
-
- clang: true,
- cflags: [
- "-fvisibility=hidden",
- "-fstrict-aliasing",
-
- "-DLOG_TAG=\"vkinfo\"",
-
- "-Weverything",
- "-Werror",
- "-Wno-padded",
- "-Wno-undef",
- "-Wno-switch-enum",
- ],
- cppflags: [
- "-Wno-c++98-compat-pedantic",
- "-Wno-c99-extensions",
- "-Wno-old-style-cast",
- ],
-
- srcs: ["vkinfo.cpp"],
-
- shared_libs: [
- "libvulkan",
- "liblog",
- ],
-}
diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp
deleted file mode 100644
index 89bc926..0000000
--- a/vulkan/tools/vkinfo.cpp
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Copyright 2015 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 <inttypes.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <array>
-#include <sstream>
-#include <vector>
-
-#include <vulkan/vulkan.h>
-
-namespace {
-
-struct Options {
- bool layer_description;
- bool layer_extensions;
- bool unsupported_features;
- bool validate;
-};
-
-struct GpuInfo {
- VkPhysicalDeviceProperties properties;
- VkPhysicalDeviceMemoryProperties memory;
- VkPhysicalDeviceFeatures features;
- std::vector<VkQueueFamilyProperties> queue_families;
- std::vector<VkExtensionProperties> extensions;
- std::vector<VkLayerProperties> layers;
- std::vector<std::vector<VkExtensionProperties>> layer_extensions;
-};
-struct VulkanInfo {
- std::vector<VkExtensionProperties> extensions;
- std::vector<VkLayerProperties> layers;
- std::vector<std::vector<VkExtensionProperties>> layer_extensions;
- std::vector<GpuInfo> gpus;
-};
-
-// ----------------------------------------------------------------------------
-
-[[noreturn]] void die(const char* proc, VkResult result) {
- const char* result_str;
- switch (result) {
- // clang-format off
- case VK_SUCCESS: result_str = "VK_SUCCESS"; break;
- case VK_NOT_READY: result_str = "VK_NOT_READY"; break;
- case VK_TIMEOUT: result_str = "VK_TIMEOUT"; break;
- case VK_EVENT_SET: result_str = "VK_EVENT_SET"; break;
- case VK_EVENT_RESET: result_str = "VK_EVENT_RESET"; break;
- case VK_INCOMPLETE: result_str = "VK_INCOMPLETE"; break;
- case VK_ERROR_OUT_OF_HOST_MEMORY: result_str = "VK_ERROR_OUT_OF_HOST_MEMORY"; break;
- case VK_ERROR_OUT_OF_DEVICE_MEMORY: result_str = "VK_ERROR_OUT_OF_DEVICE_MEMORY"; break;
- case VK_ERROR_INITIALIZATION_FAILED: result_str = "VK_ERROR_INITIALIZATION_FAILED"; break;
- case VK_ERROR_DEVICE_LOST: result_str = "VK_ERROR_DEVICE_LOST"; break;
- case VK_ERROR_MEMORY_MAP_FAILED: result_str = "VK_ERROR_MEMORY_MAP_FAILED"; break;
- case VK_ERROR_LAYER_NOT_PRESENT: result_str = "VK_ERROR_LAYER_NOT_PRESENT"; break;
- case VK_ERROR_EXTENSION_NOT_PRESENT: result_str = "VK_ERROR_EXTENSION_NOT_PRESENT"; break;
- case VK_ERROR_INCOMPATIBLE_DRIVER: result_str = "VK_ERROR_INCOMPATIBLE_DRIVER"; break;
- default: result_str = "<unknown VkResult>"; break;
- // clang-format on
- }
- fprintf(stderr, "%s failed: %s (%d)\n", proc, result_str, result);
- exit(1);
-}
-
-bool HasExtension(const std::vector<VkExtensionProperties>& extensions,
- const char* name) {
- return std::find_if(extensions.cbegin(), extensions.cend(),
- [=](const VkExtensionProperties& prop) {
- return strcmp(prop.extensionName, name) == 0;
- }) != extensions.end();
-}
-
-void EnumerateInstanceExtensions(
- const char* layer_name,
- std::vector<VkExtensionProperties>* extensions) {
- VkResult result;
- uint32_t count;
- result =
- vkEnumerateInstanceExtensionProperties(layer_name, &count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceExtensionProperties (count)", result);
- do {
- extensions->resize(count);
- result = vkEnumerateInstanceExtensionProperties(layer_name, &count,
- extensions->data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceExtensionProperties (data)", result);
-}
-
-void EnumerateDeviceExtensions(VkPhysicalDevice gpu,
- const char* layer_name,
- std::vector<VkExtensionProperties>* extensions) {
- VkResult result;
- uint32_t count;
- result =
- vkEnumerateDeviceExtensionProperties(gpu, layer_name, &count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceExtensionProperties (count)", result);
- do {
- extensions->resize(count);
- result = vkEnumerateDeviceExtensionProperties(gpu, layer_name, &count,
- extensions->data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceExtensionProperties (data)", result);
-}
-
-void GatherGpuInfo(VkPhysicalDevice gpu,
- const Options &options,
- GpuInfo& info) {
- VkResult result;
- uint32_t count;
-
- vkGetPhysicalDeviceProperties(gpu, &info.properties);
- vkGetPhysicalDeviceMemoryProperties(gpu, &info.memory);
- vkGetPhysicalDeviceFeatures(gpu, &info.features);
-
- vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
- info.queue_families.resize(count);
- vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count,
- info.queue_families.data());
-
- result = vkEnumerateDeviceLayerProperties(gpu, &count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceLayerProperties (count)", result);
- do {
- info.layers.resize(count);
- result =
- vkEnumerateDeviceLayerProperties(gpu, &count, info.layers.data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceLayerProperties (data)", result);
- info.layer_extensions.resize(info.layers.size());
-
- EnumerateDeviceExtensions(gpu, nullptr, &info.extensions);
- for (size_t i = 0; i < info.layers.size(); i++) {
- EnumerateDeviceExtensions(gpu, info.layers[i].layerName,
- &info.layer_extensions[i]);
- }
-
- const std::array<const char*, 1> kDesiredExtensions = {
- {VK_KHR_SWAPCHAIN_EXTENSION_NAME},
- };
- const char* extensions[kDesiredExtensions.size()];
- uint32_t num_extensions = 0;
- for (const auto& desired_ext : kDesiredExtensions) {
- bool available = HasExtension(info.extensions, desired_ext);
- if (options.validate) {
- for (size_t i = 0; !available && i < info.layer_extensions.size();
- i++)
- available = HasExtension(info.layer_extensions[i], desired_ext);
- }
- if (available)
- extensions[num_extensions++] = desired_ext;
- }
-
- VkDevice device;
- float queue_priorities[] = {0.0};
- const VkDeviceQueueCreateInfo queue_create_info = {
- .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
- .queueFamilyIndex = 0,
- .queueCount = 1,
- .pQueuePriorities = queue_priorities
- };
- // clang-format off
- const char *kValidationLayers[] = {
- "VK_LAYER_GOOGLE_threading",
- "VK_LAYER_LUNARG_parameter_validation",
- "VK_LAYER_LUNARG_device_limits",
- "VK_LAYER_LUNARG_object_tracker",
- "VK_LAYER_LUNARG_image",
- "VK_LAYER_LUNARG_core_validation",
- "VK_LAYER_LUNARG_swapchain",
- "VK_LAYER_GOOGLE_unique_objects"
- };
- // clang-format on
- uint32_t num_layers = sizeof(kValidationLayers) / sizeof(char*);
- const VkDeviceCreateInfo create_info = {
- .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
- .queueCreateInfoCount = 1,
- .pQueueCreateInfos = &queue_create_info,
- .enabledExtensionCount = num_extensions,
- .ppEnabledExtensionNames = extensions,
- .enabledLayerCount = (options.validate) ? num_layers : 0,
- .ppEnabledLayerNames = kValidationLayers,
- .pEnabledFeatures = &info.features,
- };
- result = vkCreateDevice(gpu, &create_info, nullptr, &device);
- if (result != VK_SUCCESS)
- die("vkCreateDevice", result);
- vkDestroyDevice(device, nullptr);
-}
-
-void GatherInfo(VulkanInfo* info, const Options& options) {
- VkResult result;
- uint32_t count;
-
- result = vkEnumerateInstanceLayerProperties(&count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceLayerProperties (count)", result);
- do {
- info->layers.resize(count);
- result =
- vkEnumerateInstanceLayerProperties(&count, info->layers.data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceLayerProperties (data)", result);
- info->layer_extensions.resize(info->layers.size());
-
- EnumerateInstanceExtensions(nullptr, &info->extensions);
- for (size_t i = 0; i < info->layers.size(); i++) {
- EnumerateInstanceExtensions(info->layers[i].layerName,
- &info->layer_extensions[i]);
- }
-
- const char* kDesiredExtensions[] = {
- VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
- };
- const char*
- extensions[sizeof(kDesiredExtensions) / sizeof(kDesiredExtensions[0])];
- uint32_t num_extensions = 0;
- for (const auto& desired_ext : kDesiredExtensions) {
- bool available = HasExtension(info->extensions, desired_ext);
- if (options.validate) {
- for (size_t i = 0; !available && i < info->layer_extensions.size();
- i++)
- available =
- HasExtension(info->layer_extensions[i], desired_ext);
- }
- if (available)
- extensions[num_extensions++] = desired_ext;
- }
-
- // clang-format off
- const char *kValidationLayers[] = {
- "VK_LAYER_GOOGLE_threading",
- "VK_LAYER_LUNARG_parameter_validation",
- "VK_LAYER_LUNARG_device_limits",
- "VK_LAYER_LUNARG_object_tracker",
- "VK_LAYER_LUNARG_image",
- "VK_LAYER_LUNARG_core_validation",
- "VK_LAYER_LUNARG_swapchain",
- "VK_LAYER_GOOGLE_unique_objects"
- };
- // clang-format on
- uint32_t num_layers = sizeof(kValidationLayers) / sizeof(char*);
-
- const VkApplicationInfo application_info = {
- .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
- .pApplicationName = "vkinfo",
- .applicationVersion = 0,
- .pEngineName = "vkinfo",
- .engineVersion = 0,
- .apiVersion = VK_API_VERSION_1_0,
- };
- const VkInstanceCreateInfo create_info = {
- .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
- .pApplicationInfo = &application_info,
- .enabledExtensionCount = num_extensions,
- .ppEnabledExtensionNames = extensions,
- .enabledLayerCount = (options.validate) ? num_layers : 0,
- .ppEnabledLayerNames = kValidationLayers,
- };
- VkInstance instance;
- result = vkCreateInstance(&create_info, nullptr, &instance);
- if (result != VK_SUCCESS)
- die("vkCreateInstance", result);
-
- uint32_t num_gpus;
- result = vkEnumeratePhysicalDevices(instance, &num_gpus, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumeratePhysicalDevices (count)", result);
- std::vector<VkPhysicalDevice> gpus(num_gpus, VK_NULL_HANDLE);
- do {
- gpus.resize(num_gpus, VK_NULL_HANDLE);
- result = vkEnumeratePhysicalDevices(instance, &num_gpus, gpus.data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumeratePhysicalDevices (data)", result);
-
- info->gpus.resize(num_gpus);
- for (size_t i = 0; i < gpus.size(); i++)
- GatherGpuInfo(gpus[i], options, info->gpus.at(i));
-
- vkDestroyInstance(instance, nullptr);
-}
-
-// ----------------------------------------------------------------------------
-
-const size_t kMaxIndent = 8;
-const size_t kIndentSize = 3;
-std::array<char, kMaxIndent * kIndentSize + 1> kIndent;
-const char* Indent(size_t n) {
- static bool initialized = false;
- if (!initialized) {
- kIndent.fill(' ');
- kIndent.back() = '\0';
- initialized = true;
- }
- return kIndent.data() +
- (kIndent.size() - (kIndentSize * std::min(n, kMaxIndent) + 1));
-}
-
-const char* VkPhysicalDeviceTypeStr(VkPhysicalDeviceType type) {
- switch (type) {
- case VK_PHYSICAL_DEVICE_TYPE_OTHER:
- return "OTHER";
- case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
- return "INTEGRATED_GPU";
- case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
- return "DISCRETE_GPU";
- case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
- return "VIRTUAL_GPU";
- case VK_PHYSICAL_DEVICE_TYPE_CPU:
- return "CPU";
- default:
- return "<UNKNOWN>";
- }
-}
-
-void PrintExtensions(const std::vector<VkExtensionProperties>& extensions,
- const Options& /*options*/,
- size_t indent) {
- for (const auto& e : extensions)
- printf("%s%s (v%u)\n", Indent(indent), e.extensionName, e.specVersion);
-}
-
-void PrintLayers(
- const std::vector<VkLayerProperties>& layers,
- const std::vector<std::vector<VkExtensionProperties>> extensions,
- const Options& options,
- size_t indent) {
- for (size_t i = 0; i < layers.size(); i++) {
- printf("%s%s %u.%u.%u/%u\n", Indent(indent), layers[i].layerName,
- VK_VERSION_MAJOR(layers[i].specVersion),
- VK_VERSION_MINOR(layers[i].specVersion),
- VK_VERSION_PATCH(layers[i].specVersion),
- layers[i].implementationVersion);
- if (options.layer_description)
- printf("%s%s\n", Indent(indent + 1), layers[i].description);
- if (options.layer_extensions && !extensions[i].empty()) {
- if (!extensions[i].empty()) {
- printf("%sExtensions [%zu]:\n", Indent(indent + 1),
- extensions[i].size());
- PrintExtensions(extensions[i], options, indent + 2);
- }
- }
- }
-}
-
-void PrintAllFeatures(const char* indent,
- const VkPhysicalDeviceFeatures& features) {
- // clang-format off
- printf("%srobustBufferAccess: %s\n", indent, features.robustBufferAccess ? "YES" : "NO");
- printf("%sfullDrawIndexUint32: %s\n", indent, features.fullDrawIndexUint32 ? "YES" : "NO");
- printf("%simageCubeArray: %s\n", indent, features.imageCubeArray ? "YES" : "NO");
- printf("%sindependentBlend: %s\n", indent, features.independentBlend ? "YES" : "NO");
- printf("%sgeometryShader: %s\n", indent, features.geometryShader ? "YES" : "NO");
- printf("%stessellationShader: %s\n", indent, features.tessellationShader ? "YES" : "NO");
- printf("%ssampleRateShading: %s\n", indent, features.sampleRateShading ? "YES" : "NO");
- printf("%sdualSrcBlend: %s\n", indent, features.dualSrcBlend ? "YES" : "NO");
- printf("%slogicOp: %s\n", indent, features.logicOp ? "YES" : "NO");
- printf("%smultiDrawIndirect: %s\n", indent, features.multiDrawIndirect ? "YES" : "NO");
- printf("%sdrawIndirectFirstInstance: %s\n", indent, features.drawIndirectFirstInstance ? "YES" : "NO");
- printf("%sdepthClamp: %s\n", indent, features.depthClamp ? "YES" : "NO");
- printf("%sdepthBiasClamp: %s\n", indent, features.depthBiasClamp ? "YES" : "NO");
- printf("%sfillModeNonSolid: %s\n", indent, features.fillModeNonSolid ? "YES" : "NO");
- printf("%sdepthBounds: %s\n", indent, features.depthBounds ? "YES" : "NO");
- printf("%swideLines: %s\n", indent, features.wideLines ? "YES" : "NO");
- printf("%slargePoints: %s\n", indent, features.largePoints ? "YES" : "NO");
- printf("%salphaToOne: %s\n", indent, features.alphaToOne ? "YES" : "NO");
- printf("%smultiViewport: %s\n", indent, features.multiViewport ? "YES" : "NO");
- printf("%ssamplerAnisotropy: %s\n", indent, features.samplerAnisotropy ? "YES" : "NO");
- printf("%stextureCompressionETC2: %s\n", indent, features.textureCompressionETC2 ? "YES" : "NO");
- printf("%stextureCompressionASTC_LDR: %s\n", indent, features.textureCompressionASTC_LDR ? "YES" : "NO");
- printf("%stextureCompressionBC: %s\n", indent, features.textureCompressionBC ? "YES" : "NO");
- printf("%socclusionQueryPrecise: %s\n", indent, features.occlusionQueryPrecise ? "YES" : "NO");
- printf("%spipelineStatisticsQuery: %s\n", indent, features.pipelineStatisticsQuery ? "YES" : "NO");
- printf("%svertexPipelineStoresAndAtomics: %s\n", indent, features.vertexPipelineStoresAndAtomics ? "YES" : "NO");
- printf("%sfragmentStoresAndAtomics: %s\n", indent, features.fragmentStoresAndAtomics ? "YES" : "NO");
- printf("%sshaderTessellationAndGeometryPointSize: %s\n", indent, features.shaderTessellationAndGeometryPointSize ? "YES" : "NO");
- printf("%sshaderImageGatherExtended: %s\n", indent, features.shaderImageGatherExtended ? "YES" : "NO");
- printf("%sshaderStorageImageExtendedFormats: %s\n", indent, features.shaderStorageImageExtendedFormats ? "YES" : "NO");
- printf("%sshaderStorageImageMultisample: %s\n", indent, features.shaderStorageImageMultisample ? "YES" : "NO");
- printf("%sshaderStorageImageReadWithoutFormat: %s\n", indent, features.shaderStorageImageReadWithoutFormat ? "YES" : "NO");
- printf("%sshaderStorageImageWriteWithoutFormat: %s\n", indent, features.shaderStorageImageWriteWithoutFormat ? "YES" : "NO");
- printf("%sshaderUniformBufferArrayDynamicIndexing: %s\n", indent, features.shaderUniformBufferArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderSampledImageArrayDynamicIndexing: %s\n", indent, features.shaderSampledImageArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderStorageBufferArrayDynamicIndexing: %s\n", indent, features.shaderStorageBufferArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderStorageImageArrayDynamicIndexing: %s\n", indent, features.shaderStorageImageArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderClipDistance: %s\n", indent, features.shaderClipDistance ? "YES" : "NO");
- printf("%sshaderCullDistance: %s\n", indent, features.shaderCullDistance ? "YES" : "NO");
- printf("%sshaderFloat64: %s\n", indent, features.shaderFloat64 ? "YES" : "NO");
- printf("%sshaderInt64: %s\n", indent, features.shaderInt64 ? "YES" : "NO");
- printf("%sshaderInt16: %s\n", indent, features.shaderInt16 ? "YES" : "NO");
- printf("%sshaderResourceResidency: %s\n", indent, features.shaderResourceResidency ? "YES" : "NO");
- printf("%sshaderResourceMinLod: %s\n", indent, features.shaderResourceMinLod ? "YES" : "NO");
- printf("%ssparseBinding: %s\n", indent, features.sparseBinding ? "YES" : "NO");
- printf("%ssparseResidencyBuffer: %s\n", indent, features.sparseResidencyBuffer ? "YES" : "NO");
- printf("%ssparseResidencyImage2D: %s\n", indent, features.sparseResidencyImage2D ? "YES" : "NO");
- printf("%ssparseResidencyImage3D: %s\n", indent, features.sparseResidencyImage3D ? "YES" : "NO");
- printf("%ssparseResidency2Samples: %s\n", indent, features.sparseResidency2Samples ? "YES" : "NO");
- printf("%ssparseResidency4Samples: %s\n", indent, features.sparseResidency4Samples ? "YES" : "NO");
- printf("%ssparseResidency8Samples: %s\n", indent, features.sparseResidency8Samples ? "YES" : "NO");
- printf("%ssparseResidency16Samples: %s\n", indent, features.sparseResidency16Samples ? "YES" : "NO");
- printf("%ssparseResidencyAliased: %s\n", indent, features.sparseResidencyAliased ? "YES" : "NO");
- printf("%svariableMultisampleRate: %s\n", indent, features.variableMultisampleRate ? "YES" : "NO");
- printf("%sinheritedQueries: %s\n", indent, features.inheritedQueries ? "YES" : "NO");
- // clang-format on
-}
-
-void PrintSupportedFeatures(const char* indent,
- const VkPhysicalDeviceFeatures& features) {
- // clang-format off
- if (features.robustBufferAccess) printf("%srobustBufferAccess\n", indent);
- if (features.fullDrawIndexUint32) printf("%sfullDrawIndexUint32\n", indent);
- if (features.imageCubeArray) printf("%simageCubeArray\n", indent);
- if (features.independentBlend) printf("%sindependentBlend\n", indent);
- if (features.geometryShader) printf("%sgeometryShader\n", indent);
- if (features.tessellationShader) printf("%stessellationShader\n", indent);
- if (features.sampleRateShading) printf("%ssampleRateShading\n", indent);
- if (features.dualSrcBlend) printf("%sdualSrcBlend\n", indent);
- if (features.logicOp) printf("%slogicOp\n", indent);
- if (features.multiDrawIndirect) printf("%smultiDrawIndirect\n", indent);
- if (features.drawIndirectFirstInstance) printf("%sdrawIndirectFirstInstance\n", indent);
- if (features.depthClamp) printf("%sdepthClamp\n", indent);
- if (features.depthBiasClamp) printf("%sdepthBiasClamp\n", indent);
- if (features.fillModeNonSolid) printf("%sfillModeNonSolid\n", indent);
- if (features.depthBounds) printf("%sdepthBounds\n", indent);
- if (features.wideLines) printf("%swideLines\n", indent);
- if (features.largePoints) printf("%slargePoints\n", indent);
- if (features.alphaToOne) printf("%salphaToOne\n", indent);
- if (features.multiViewport) printf("%smultiViewport\n", indent);
- if (features.samplerAnisotropy) printf("%ssamplerAnisotropy\n", indent);
- if (features.textureCompressionETC2) printf("%stextureCompressionETC2\n", indent);
- if (features.textureCompressionASTC_LDR) printf("%stextureCompressionASTC_LDR\n", indent);
- if (features.textureCompressionBC) printf("%stextureCompressionBC\n", indent);
- if (features.occlusionQueryPrecise) printf("%socclusionQueryPrecise\n", indent);
- if (features.pipelineStatisticsQuery) printf("%spipelineStatisticsQuery\n", indent);
- if (features.vertexPipelineStoresAndAtomics) printf("%svertexPipelineStoresAndAtomics\n", indent);
- if (features.fragmentStoresAndAtomics) printf("%sfragmentStoresAndAtomics\n", indent);
- if (features.shaderTessellationAndGeometryPointSize) printf("%sshaderTessellationAndGeometryPointSize\n", indent);
- if (features.shaderImageGatherExtended) printf("%sshaderImageGatherExtended\n", indent);
- if (features.shaderStorageImageExtendedFormats) printf("%sshaderStorageImageExtendedFormats\n", indent);
- if (features.shaderStorageImageMultisample) printf("%sshaderStorageImageMultisample\n", indent);
- if (features.shaderStorageImageReadWithoutFormat) printf("%sshaderStorageImageReadWithoutFormat\n", indent);
- if (features.shaderStorageImageWriteWithoutFormat) printf("%sshaderStorageImageWriteWithoutFormat\n", indent);
- if (features.shaderUniformBufferArrayDynamicIndexing) printf("%sshaderUniformBufferArrayDynamicIndexing\n", indent);
- if (features.shaderSampledImageArrayDynamicIndexing) printf("%sshaderSampledImageArrayDynamicIndexing\n", indent);
- if (features.shaderStorageBufferArrayDynamicIndexing) printf("%sshaderStorageBufferArrayDynamicIndexing\n", indent);
- if (features.shaderStorageImageArrayDynamicIndexing) printf("%sshaderStorageImageArrayDynamicIndexing\n", indent);
- if (features.shaderClipDistance) printf("%sshaderClipDistance\n", indent);
- if (features.shaderCullDistance) printf("%sshaderCullDistance\n", indent);
- if (features.shaderFloat64) printf("%sshaderFloat64\n", indent);
- if (features.shaderInt64) printf("%sshaderInt64\n", indent);
- if (features.shaderInt16) printf("%sshaderInt16\n", indent);
- if (features.shaderResourceResidency) printf("%sshaderResourceResidency\n", indent);
- if (features.shaderResourceMinLod) printf("%sshaderResourceMinLod\n", indent);
- if (features.sparseBinding) printf("%ssparseBinding\n", indent);
- if (features.sparseResidencyBuffer) printf("%ssparseResidencyBuffer\n", indent);
- if (features.sparseResidencyImage2D) printf("%ssparseResidencyImage2D\n", indent);
- if (features.sparseResidencyImage3D) printf("%ssparseResidencyImage3D\n", indent);
- if (features.sparseResidency2Samples) printf("%ssparseResidency2Samples\n", indent);
- if (features.sparseResidency4Samples) printf("%ssparseResidency4Samples\n", indent);
- if (features.sparseResidency8Samples) printf("%ssparseResidency8Samples\n", indent);
- if (features.sparseResidency16Samples) printf("%ssparseResidency16Samples\n", indent);
- if (features.sparseResidencyAliased) printf("%ssparseResidencyAliased\n", indent);
- if (features.variableMultisampleRate) printf("%svariableMultisampleRate\n", indent);
- if (features.inheritedQueries) printf("%sinheritedQueries\n", indent);
- // clang-format on
-}
-
-void PrintGpuInfo(const GpuInfo& info, const Options& options, size_t indent) {
- VkResult result;
- std::ostringstream strbuf;
-
- printf("%s\"%s\" (%s) %u.%u.%u/%#x [%04x:%04x]\n", Indent(indent),
- info.properties.deviceName,
- VkPhysicalDeviceTypeStr(info.properties.deviceType),
- VK_VERSION_MAJOR(info.properties.apiVersion),
- VK_VERSION_MINOR(info.properties.apiVersion),
- VK_VERSION_PATCH(info.properties.apiVersion),
- info.properties.driverVersion, info.properties.vendorID,
- info.properties.deviceID);
-
- for (uint32_t heap = 0; heap < info.memory.memoryHeapCount; heap++) {
- if ((info.memory.memoryHeaps[heap].flags &
- VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
- strbuf << "DEVICE_LOCAL";
- printf("%sHeap %u: %" PRIu64 " MiB (0x%" PRIx64 " B) %s\n",
- Indent(indent + 1), heap,
- info.memory.memoryHeaps[heap].size / 0x100000,
- info.memory.memoryHeaps[heap].size, strbuf.str().c_str());
- strbuf.str(std::string());
-
- for (uint32_t type = 0; type < info.memory.memoryTypeCount; type++) {
- if (info.memory.memoryTypes[type].heapIndex != heap)
- continue;
- VkMemoryPropertyFlags flags =
- info.memory.memoryTypes[type].propertyFlags;
- if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
- strbuf << " DEVICE_LOCAL";
- if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
- strbuf << " HOST_VISIBLE";
- if ((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
- strbuf << " COHERENT";
- if ((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
- strbuf << " CACHED";
- if ((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
- strbuf << " LAZILY_ALLOCATED";
- printf("%sType %u:%s\n", Indent(indent + 2), type,
- strbuf.str().c_str());
- strbuf.str(std::string());
- }
- }
-
- for (uint32_t family = 0; family < info.queue_families.size(); family++) {
- const VkQueueFamilyProperties& qprops = info.queue_families[family];
- VkQueueFlags flags = qprops.queueFlags;
- char flags_str[5];
- flags_str[0] = (flags & VK_QUEUE_GRAPHICS_BIT) ? 'G' : '_';
- flags_str[1] = (flags & VK_QUEUE_COMPUTE_BIT) ? 'C' : '_';
- flags_str[2] = (flags & VK_QUEUE_TRANSFER_BIT) ? 'T' : '_';
- flags_str[3] = (flags & VK_QUEUE_SPARSE_BINDING_BIT) ? 'S' : '_';
- flags_str[4] = '\0';
- printf(
- "%sQueue Family %u: %ux %s\n"
- "%stimestampValidBits: %ub\n"
- "%sminImageTransferGranularity: (%u,%u,%u)\n",
- Indent(indent + 1), family, qprops.queueCount, flags_str,
- Indent(indent + 2), qprops.timestampValidBits, Indent(indent + 2),
- qprops.minImageTransferGranularity.width,
- qprops.minImageTransferGranularity.height,
- qprops.minImageTransferGranularity.depth);
- }
-
- printf("%sFeatures:\n", Indent(indent + 1));
- if (options.unsupported_features) {
- PrintAllFeatures(Indent(indent + 2), info.features);
- } else {
- PrintSupportedFeatures(Indent(indent + 2), info.features);
- }
-
- printf("%sExtensions [%zu]:\n", Indent(indent + 1), info.extensions.size());
- if (!info.extensions.empty())
- PrintExtensions(info.extensions, options, indent + 2);
- printf("%sLayers [%zu]:\n", Indent(indent + 1), info.layers.size());
- if (!info.layers.empty())
- PrintLayers(info.layers, info.layer_extensions, options, indent + 2);
-}
-
-void PrintInfo(const VulkanInfo& info, const Options& options) {
- std::ostringstream strbuf;
- size_t indent = 0;
-
- printf("%sInstance Extensions [%zu]:\n", Indent(indent),
- info.extensions.size());
- PrintExtensions(info.extensions, options, indent + 1);
- printf("%sInstance Layers [%zu]:\n", Indent(indent), info.layers.size());
- if (!info.layers.empty())
- PrintLayers(info.layers, info.layer_extensions, options, indent + 1);
-
- printf("%sPhysicalDevices [%zu]:\n", Indent(indent), info.gpus.size());
- for (const auto& gpu : info.gpus)
- PrintGpuInfo(gpu, options, indent + 1);
-}
-
-const char kUsageString[] =
- "usage: vkinfo [options]\n"
- " -v enable all the following verbose options\n"
- " -layer_description print layer description strings\n"
- " -layer_extensions print extensions supported by each layer\n"
- " -unsupported_features print all physical device features\n"
- " -validate enable validation layers if present\n"
- " -debug_pause pause at start until resumed via debugger\n";
-
-} // namespace
-
-// ----------------------------------------------------------------------------
-
-int main(int argc, char const* argv[]) {
- static volatile bool startup_pause = false;
- Options options = {
- .layer_description = false, .layer_extensions = false,
- .unsupported_features = false,
- .validate = false,
- };
- for (int argi = 1; argi < argc; argi++) {
- if (strcmp(argv[argi], "-h") == 0) {
- fputs(kUsageString, stdout);
- return 0;
- }
- if (strcmp(argv[argi], "-v") == 0) {
- options.layer_description = true;
- options.layer_extensions = true;
- options.unsupported_features = true;
- } else if (strcmp(argv[argi], "-layer_description") == 0) {
- options.layer_description = true;
- } else if (strcmp(argv[argi], "-layer_extensions") == 0) {
- options.layer_extensions = true;
- } else if (strcmp(argv[argi], "-unsupported_features") == 0) {
- options.unsupported_features = true;
- } else if (strcmp(argv[argi], "-validate") == 0) {
- options.validate = true;
- } else if (strcmp(argv[argi], "-debug_pause") == 0) {
- startup_pause = true;
- }
- }
-
- while (startup_pause) {
- sleep(0);
- }
-
- VulkanInfo info;
- GatherInfo(&info, options);
- PrintInfo(info, options);
- return 0;
-}
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 6204779..8f714d8 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -53,7 +53,7 @@
// parsing in between C++ and Java, becasue Java json library simply cannot
// handle infinity.
static const double SAFE_DOUBLE_MAX = 0.99 * std::numeric_limits<double>::max();
-static const double SAFE_DOUBLE_MIN = 0.99 * std::numeric_limits<double>::min();
+static const double SAFE_DOUBLE_MIN = -SAFE_DOUBLE_MAX;
template <typename T> struct EnumTraits;
template <> struct EnumTraits<VkPhysicalDeviceType> {