Merge "Fix broken opto-electronic transfer functions"
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index 3987fce..e11bf30 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -58,8 +58,9 @@
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder
LOCAL_C_INCLUDES := $(LOCAL_PATH)/binder
LOCAL_SRC_FILES := \
+ binder/android/os/IDumpstate.aidl \
binder/android/os/IDumpstateListener.aidl \
- binder/android/os/IDumpstate.aidl
+ binder/android/os/IDumpstateToken.aidl
include $(BUILD_SHARED_LIBRARY)
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index ce78ec6..f2dcf2b 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -25,6 +25,10 @@
namespace android {
namespace os {
+namespace {
+class DumpstateToken : public BnDumpstateToken {};
+}
+
DumpstateService::DumpstateService() : ds_(Dumpstate::GetInstance()) {
}
@@ -45,33 +49,38 @@
}
binder::Status DumpstateService::setListener(const std::string& name,
- const sp<IDumpstateListener>& listener, bool* set) {
+ const sp<IDumpstateListener>& listener,
+ sp<IDumpstateToken>* returned_token) {
+ *returned_token = nullptr;
if (name.empty()) {
MYLOGE("setListener(): name not set\n");
- *set = false;
return binder::Status::ok();
}
if (listener == nullptr) {
MYLOGE("setListener(): listener not set\n");
- *set = false;
return binder::Status::ok();
}
std::lock_guard<std::mutex> lock(lock_);
if (ds_.listener_ != nullptr) {
MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_.listener_name_.c_str());
- *set = false;
return binder::Status::ok();
}
+
ds_.listener_name_ = name;
ds_.listener_ = listener;
- *set = true;
+ *returned_token = new DumpstateToken();
+
return binder::Status::ok();
}
status_t DumpstateService::dump(int fd, const Vector<String16>&) {
- dprintf(fd, "id: %lu\n", ds_.id_);
+ dprintf(fd, "id: %d\n", ds_.id_);
dprintf(fd, "pid: %d\n", ds_.pid_);
- dprintf(fd, "progress: %d / %d\n", ds_.progress_, ds_.weight_total_);
+ dprintf(fd, "update_progress: %s\n", ds_.update_progress_ ? "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, "progress:\n");
+ ds_.progress_->Dump(fd, " ");
dprintf(fd, "args: %s\n", ds_.args_.c_str());
dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str());
dprintf(fd, "version: %s\n", ds_.version_.c_str());
@@ -79,7 +88,8 @@
dprintf(fd, "screenshot_path: %s\n", ds_.screenshot_path_.c_str());
dprintf(fd, "log_path: %s\n", ds_.log_path_.c_str());
dprintf(fd, "tmp_path: %s\n", ds_.tmp_path_.c_str());
- dprintf(fd, "path: %s\n", ds_.extra_options_.c_str());
+ dprintf(fd, "path: %s\n", ds_.path_.c_str());
+ dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str());
dprintf(fd, "base_name: %s\n", ds_.base_name_.c_str());
dprintf(fd, "name: %s\n", ds_.name_.c_str());
dprintf(fd, "now: %ld\n", ds_.now_);
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 544a7b6..4352d3d 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -23,6 +23,7 @@
#include <binder/BinderService.h>
#include "android/os/BnDumpstate.h"
+#include "android/os/BnDumpstateToken.h"
#include "dumpstate.h"
namespace android {
@@ -37,7 +38,7 @@
status_t dump(int fd, const Vector<String16>& args) override;
binder::Status setListener(const std::string& name, const sp<IDumpstateListener>& listener,
- bool* set) override;
+ sp<IDumpstateToken>* returned_token) override;
private:
Dumpstate& ds_;
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index e585a0e..4becccf 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -17,6 +17,7 @@
package android.os;
import android.os.IDumpstateListener;
+import android.os.IDumpstateToken;
/**
* Binder interface for the currently running dumpstate process.
@@ -25,9 +26,10 @@
interface IDumpstate {
/*
- * Sets the listener for dumpstate progress.
+ * Sets the listener for this dumpstate progress.
*
- * Returns true if the listener was set (it's like a Highlander: There Can be Only One).
+ * Returns a token used to monitor dumpstate death, or `nullptr` if the listener was already
+ * set (the listener behaves like a Highlander: There Can be Only One).
*/
- boolean setListener(@utf8InCpp String name, IDumpstateListener listener);
+ IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener);
}
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl b/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
new file mode 100644
index 0000000..7f74ceb
--- /dev/null
+++ b/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Token used by the IDumpstateListener to watch for dumpstate death.
+ * {@hide}
+ */
+interface IDumpstateToken {
+}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 80a1b07..ea70fe5 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -683,7 +683,7 @@
JustDumpFile("", "/proc/version");
printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
printf("Bugreport format version: %s\n", version_.c_str());
- printf("Dumpstate info: id=%lu pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
+ printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
dry_run_, args_.c_str(), extra_options_.c_str());
printf("\n");
}
@@ -1154,10 +1154,10 @@
DumpModemLogs();
printf("========================================================\n");
- printf("== Final progress (pid %d): %d/%d (originally %d)\n", ds.pid_, ds.progress_,
- ds.weight_total_, WEIGHT_TOTAL);
+ printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
+ ds.progress_->GetMax(), ds.progress_->GetInitialMax());
printf("========================================================\n");
- printf("== dumpstate: done (id %lu)\n", ds.id_);
+ printf("== dumpstate: done (id %d)\n", ds.id_);
printf("========================================================\n");
}
@@ -1222,7 +1222,7 @@
char date[80];
time_t the_real_now_please_stand_up = time(nullptr);
strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
- MYLOGD("dumpstate id %lu finished around %s (%ld s)\n", ds.id_, date,
+ MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
the_real_now_please_stand_up - ds.now_);
if (!ds.AddZipEntry(entry_name, tmp_path_)) {
@@ -1253,13 +1253,9 @@
// TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
ds.zip_file.reset(nullptr);
- if (IsUserBuild()) {
- MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
- if (remove(tmp_path_.c_str()) != 0) {
- ALOGW("remove(%s): %s\n", tmp_path_.c_str(), strerror(errno));
- }
- } else {
- MYLOGD("Keeping temporary file %s on non-user build\n", tmp_path_.c_str())
+ MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
+ if (remove(tmp_path_.c_str()) != 0) {
+ MYLOGE("Failed to remove temporary file (%s): %s\n", tmp_path_.c_str(), strerror(errno));
}
return true;
@@ -1418,8 +1414,17 @@
exit(0);
}
+ /* redirect output if needed */
+ bool is_redirecting = !use_socket && use_outfile;
+
+ // TODO: temporarily set progress until it's part of the Dumpstate constructor
+ std::string stats_path =
+ is_redirecting ? android::base::StringPrintf("%s/dumpstate-stats.txt", dirname(use_outfile))
+ : "";
+ ds.progress_.reset(new Progress(stats_path));
+
/* gets the sequential id */
- int last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
+ uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
ds.id_ = ++last_id;
android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
@@ -1445,7 +1450,7 @@
MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
}
- MYLOGI("dumpstate info: id=%lu, args='%s', extra_options= %s)\n", ds.id_, ds.args_.c_str(),
+ MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", ds.id_, ds.args_.c_str(),
ds.extra_options_.c_str());
MYLOGI("bugreport format version: %s\n", ds.version_.c_str());
@@ -1464,9 +1469,6 @@
ds.update_progress_ = 1;
}
- /* redirect output if needed */
- bool is_redirecting = !use_socket && use_outfile;
-
if (is_redirecting) {
ds.bugreport_dir_ = dirname(use_outfile);
ds.base_name_ = basename(use_outfile);
@@ -1517,7 +1519,7 @@
"--es", "android.intent.extra.NAME", ds.name_,
"--ei", "android.intent.extra.ID", std::to_string(ds.id_),
"--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
- "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
+ "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
};
// clang-format on
send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
@@ -1720,7 +1722,7 @@
"--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
"--ei", "android.intent.extra.ID", std::to_string(ds.id_),
"--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
- "--ei", "android.intent.extra.MAX", std::to_string(ds.weight_total_),
+ "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
"--es", "android.intent.extra.BUGREPORT", ds.path_,
"--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
};
@@ -1743,8 +1745,10 @@
}
}
- MYLOGD("Final progress: %d/%d (originally %d)\n", ds.progress_, ds.weight_total_, WEIGHT_TOTAL);
- MYLOGI("done (id %lu)\n", ds.id_);
+ MYLOGD("Final progress: %d/%d (estimated %d)\n", ds.progress_->Get(), ds.progress_->GetMax(),
+ ds.progress_->GetInitialMax());
+ ds.progress_->Save();
+ MYLOGI("done (id %d)\n", ds.id_);
if (is_redirecting) {
fclose(stderr);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 0680db2..3d3d7ed 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -184,20 +184,65 @@
};
/*
- * Estimated total weight of bugreport generation.
+ * Keeps track of current progress and estimated max, saving stats on file to tune up future runs.
*
- * Each section contributes to the total weight by an individual weight, so the overall progress
- * can be calculated by dividing the all completed weight by the total weight.
+ * Each `dumpstate` section contributes to the total weight by an individual weight, so the overall
+ * progress can be calculated by dividing the estimate max progress by the current progress.
*
- * This value is defined empirically and it need to be adjusted as more sections are added.
+ * The estimated max progress is initially set to a value (`kDefaultMax) defined empirically, but
+ * it's adjusted after each dumpstate run by storing the average duration in a file.
*
- * It does not need to match the exact sum of all sections, but ideally it should to be slight more
- * than such sum: a value too high will cause the bugreport to finish before the user expected (for
- * example, jumping from 70% to 100%), while a value too low will cause the progress to get stuck
- * at an almost-finished value (like 99%) for a while.
*/
-// TODO: move to dumpstate.cpp / utils.cpp once it's used in just one file
-static const int WEIGHT_TOTAL = 6500;
+class Progress {
+ friend class ProgressTest;
+ friend class DumpstateTest;
+
+ public:
+ /*
+ * Default estimation of the max duration of a bugreport generation.
+ *
+ * It does not need to match the exact sum of all sections, but ideally it should to be slight
+ * more than such sum: a value too high will cause the bugreport to finish before the user
+ * expected (for example, jumping from 70% to 100%), while a value too low will cause the
+ * progress to get stuck at an almost-finished value (like 99%) for a while.
+ *
+ * This constant is only used when the average duration from previous runs cannot be used.
+ */
+ static const int kDefaultMax;
+
+ Progress(const std::string& path = "");
+
+ // Gets the current progress.
+ int32_t Get() const;
+
+ // Gets the current estimated max progress.
+ int32_t GetMax() const;
+
+ // Gets the initial estimated max progress.
+ int32_t GetInitialMax() const;
+
+ // Increments progress (ignored if not positive).
+ // Returns `true` if the max progress increased as well.
+ bool Inc(int32_t delta);
+
+ // Persist the stats.
+ void Save();
+
+ void Dump(int fd, const std::string& prefix) const;
+
+ private:
+ Progress(int32_t initial_max, float growth_factor,
+ const std::string& path = ""); // Used by test cases.
+ Progress(int32_t initial_max, int32_t progress, float growth_factor); // Used by test cases.
+ void Load();
+ int32_t initial_max_;
+ int32_t progress_;
+ int32_t max_;
+ float growth_factor_;
+ int32_t n_runs_;
+ int32_t average_max_;
+ const std::string& path_;
+};
/*
* List of supported zip format versions.
@@ -310,12 +355,17 @@
*/
void TakeScreenshot(const std::string& path = "");
- // TODO: members below should be private once refactor is finished
+ /////////////////////////////////////////////////////////////////////
+ // TODO: members below should be private once refactor is finished //
+ /////////////////////////////////////////////////////////////////////
+
+ // TODO: temporary method until Dumpstate object is properly set
+ void SetProgress(std::unique_ptr<Progress> progress);
/*
* Updates the overall progress of the bugreport generation by the given weight increment.
*/
- void UpdateProgress(int delta);
+ void UpdateProgress(int32_t delta);
/* Prints the dumpstate header on `stdout`. */
void PrintHeader() const;
@@ -332,7 +382,7 @@
// TODO: initialize fields on constructor
// dumpstate id - unique after each device reboot.
- unsigned long id_;
+ uint32_t id_;
// dumpstate pid
pid_t pid_;
@@ -340,14 +390,17 @@
// Whether progress updates should be published.
bool update_progress_ = false;
+ // 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_;
+
// Whether it should take an screenshot earlier in the process.
bool do_early_screenshot_ = false;
- // Currrent progress.
- int progress_ = 0;
-
- // Total estimated progress.
- int weight_total_ = WEIGHT_TOTAL;
+ std::unique_ptr<Progress> progress_;
// When set, defines a socket file-descriptor use to report progress to bugreportz.
int control_socket_fd_ = -1;
diff --git a/cmds/dumpstate/testdata/empty-file.txt b/cmds/dumpstate/testdata/empty-file.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/dumpstate/testdata/empty-file.txt
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-NAN.txt b/cmds/dumpstate/testdata/stats-invalid-1st-NAN.txt
new file mode 100644
index 0000000..dad9fe8
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-1st-NAN.txt
@@ -0,0 +1 @@
+SIX_SIX_SIX 42
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-negative.txt b/cmds/dumpstate/testdata/stats-invalid-1st-negative.txt
new file mode 100644
index 0000000..4facef9
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-1st-negative.txt
@@ -0,0 +1 @@
+-666 42
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-too-big.txt b/cmds/dumpstate/testdata/stats-invalid-1st-too-big.txt
new file mode 100644
index 0000000..42508f1
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-1st-too-big.txt
@@ -0,0 +1 @@
+4815162342 42
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-NAN.txt b/cmds/dumpstate/testdata/stats-invalid-2nd-NAN.txt
new file mode 100644
index 0000000..a23ba2c
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-2nd-NAN.txt
@@ -0,0 +1 @@
+666 FORTY_TWO
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-negative.txt b/cmds/dumpstate/testdata/stats-invalid-2nd-negative.txt
new file mode 100644
index 0000000..dd529b4
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-2nd-negative.txt
@@ -0,0 +1 @@
+666 -42
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-too-big.txt b/cmds/dumpstate/testdata/stats-invalid-2nd-too-big.txt
new file mode 100644
index 0000000..b148b46
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-2nd-too-big.txt
@@ -0,0 +1 @@
+666 4815162342
diff --git a/cmds/dumpstate/testdata/stats-invalid-both-NAN.txt b/cmds/dumpstate/testdata/stats-invalid-both-NAN.txt
new file mode 100644
index 0000000..4a9466d
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-both-NAN.txt
@@ -0,0 +1 @@
+N_RUNS AVERAGE
\ No newline at end of file
diff --git a/cmds/dumpstate/testdata/stats-one-run-no-newline.txt b/cmds/dumpstate/testdata/stats-one-run-no-newline.txt
new file mode 100644
index 0000000..0aef60c
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-one-run-no-newline.txt
@@ -0,0 +1 @@
+1 10
\ No newline at end of file
diff --git a/cmds/dumpstate/testdata/stats-two-runs.txt b/cmds/dumpstate/testdata/stats-two-runs.txt
new file mode 100644
index 0000000..9af1233
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-two-runs.txt
@@ -0,0 +1 @@
+2 15
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index d692fda..0d68901 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -38,7 +38,9 @@
using namespace android;
using ::testing::EndsWith;
+using ::testing::IsNull;
using ::testing::IsEmpty;
+using ::testing::NotNull;
using ::testing::StrEq;
using ::testing::StartsWith;
using ::testing::Test;
@@ -49,6 +51,7 @@
using os::DumpstateService;
using os::IDumpstateListener;
+using os::IDumpstateToken;
// Not used on test cases yet...
void dumpstate_board(void) {
@@ -63,12 +66,50 @@
MOCK_METHOD0(onAsBinder, IBinder*());
};
-class DumpstateTest : public Test {
+// Base class for all tests in this file
+class DumpstateBaseTest : public Test {
+ protected:
+ const std::string kTestPath = dirname(android::base::GetExecutablePath().c_str());
+ const std::string kFixturesPath = kTestPath + "/../dumpstate_test_fixture/";
+ const std::string kTestDataPath = kFixturesPath + "/testdata/";
+ const std::string kSimpleCommand = kFixturesPath + "dumpstate_test_fixture";
+ const std::string kEchoCommand = "/system/bin/echo";
+
+ /*
+ * Copies a text file fixture to a temporary file, returning it's path.
+ *
+ * Useful in cases where the test case changes the content of the tile.
+ */
+ std::string CopyTextFileFixture(const std::string& relative_name) {
+ std::string from = kTestDataPath + relative_name;
+ // Not using TemporaryFile because it's deleted at the end, and it's useful to keep it
+ // around for poking when the test fails.
+ std::string to = kTestDataPath + relative_name + ".tmp";
+ ALOGD("CopyTextFileFixture: from %s to %s\n", from.c_str(), to.c_str());
+ android::base::RemoveFileIfExists(to);
+ CopyTextFile(from, to);
+ return to.c_str();
+ }
+
+ private:
+ // Need a function that returns void to use assertions -
+ // https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#assertion-placement
+ void CopyTextFile(const std::string& from, const std::string& to) {
+ std::string content;
+ ASSERT_TRUE(android::base::ReadFileToString(from, &content)) << "could not read from "
+ << from;
+ ASSERT_TRUE(android::base::WriteStringToFile(content, to)) << "could not write to " << to;
+ }
+};
+
+class DumpstateTest : public DumpstateBaseTest {
public:
void SetUp() {
SetDryRun(false);
SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
+ ds.progress_.reset(new Progress());
ds.update_progress_ = false;
+ ds.update_progress_threshold_ = 0;
}
// Runs a command and capture `stdout` and `stderr`.
@@ -112,63 +153,37 @@
ASSERT_EQ(2000, (int)uid);
}
- // TODO: remove when progress is set by Binder callbacks.
- void AssertSystemProperty(const std::string& key, const std::string& expected_value) {
- std::string actualValue = android::base::GetProperty(key, "not set");
- EXPECT_THAT(expected_value, StrEq(actualValue)) << "invalid value for property " << key;
+ void SetProgress(long progress, long initial_max, long threshold = 0) {
+ ds.update_progress_ = true;
+ ds.update_progress_threshold_ = threshold;
+ ds.last_updated_progress_ = 0;
+ ds.progress_.reset(new Progress(initial_max, progress, 1.2));
}
- // TODO: remove when progress is set by Binder callbacks.
- std::string GetProgressMessageAndAssertSystemProperties(int progress, int weight_total,
- int old_weight_total = 0) {
- EXPECT_EQ(progress, ds.progress_) << "invalid progress";
- EXPECT_EQ(weight_total, ds.weight_total_) << "invalid weight_total";
+ std::string GetProgressMessage(const std::string& listener_name, int progress, int max,
+ int old_max = 0, bool update_progress = true) {
+ EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress";
+ EXPECT_EQ(max, ds.progress_->GetMax()) << "invalid max";
- AssertSystemProperty(android::base::StringPrintf("dumpstate.%d.progress", getpid()),
- std::to_string(progress));
+ bool max_increased = old_max > 0;
- bool max_increased = old_weight_total > 0;
-
- std::string adjustment_message = "";
+ std::string message = "";
if (max_increased) {
- AssertSystemProperty(android::base::StringPrintf("dumpstate.%d.max", getpid()),
- std::to_string(weight_total));
- adjustment_message = android::base::StringPrintf(
- "Adjusting total weight from %d to %d\n", old_weight_total, weight_total);
+ message =
+ android::base::StringPrintf("Adjusting max progress from %d to %d\n", old_max, max);
}
- return android::base::StringPrintf("%sSetting progress (dumpstate.%d.progress): %d/%d\n",
- adjustment_message.c_str(), getpid(), progress,
- weight_total);
- }
-
- std::string GetProgressMessage(const std::string& listener_name, int progress, int weight_total,
- int old_weight_total = 0) {
- EXPECT_EQ(progress, ds.progress_) << "invalid progress";
- EXPECT_EQ(weight_total, ds.weight_total_) << "invalid weight_total";
-
- bool max_increased = old_weight_total > 0;
-
- std::string adjustment_message = "";
- if (max_increased) {
- adjustment_message = android::base::StringPrintf(
- "Adjusting total weight from %d to %d\n", old_weight_total, weight_total);
+ if (update_progress) {
+ message += android::base::StringPrintf("Setting progress (%s): %d/%d\n",
+ listener_name.c_str(), progress, max);
}
- return android::base::StringPrintf("%sSetting progress (%s): %d/%d\n",
- adjustment_message.c_str(), listener_name.c_str(),
- progress, weight_total);
+ return message;
}
// `stdout` and `stderr` from the last command ran.
std::string out, err;
- std::string test_path = dirname(android::base::GetExecutablePath().c_str());
- std::string fixtures_path = test_path + "/../dumpstate_test_fixture/";
- std::string test_data_path = fixtures_path + "/testdata/";
- std::string simple_command = fixtures_path + "dumpstate_test_fixture";
- std::string echo_command = "/system/bin/echo";
-
Dumpstate& ds = Dumpstate::GetInstance();
};
@@ -177,52 +192,52 @@
}
TEST_F(DumpstateTest, RunCommandNoTitle) {
- EXPECT_EQ(0, RunCommand("", {simple_command}));
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n"));
}
TEST_F(DumpstateTest, RunCommandWithTitle) {
- EXPECT_EQ(0, RunCommand("I AM GROOT", {simple_command}));
+ EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
EXPECT_THAT(err, StrEq("stderr\n"));
// We don't know the exact duration, so we check the prefix and suffix
EXPECT_THAT(out,
- StartsWith("------ I AM GROOT (" + simple_command + ") ------\nstdout\n------"));
+ StartsWith("------ I AM GROOT (" + kSimpleCommand + ") ------\nstdout\n------"));
EXPECT_THAT(out, EndsWith("s was the duration of 'I AM GROOT' ------\n"));
}
TEST_F(DumpstateTest, RunCommandWithLoggingMessage) {
EXPECT_EQ(
- 0, RunCommand("", {simple_command},
+ 0, RunCommand("", {kSimpleCommand},
CommandOptions::WithTimeout(10).Log("COMMAND, Y U NO LOG FIRST?").Build()));
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("COMMAND, Y U NO LOG FIRST?stderr\n"));
}
TEST_F(DumpstateTest, RunCommandRedirectStderr) {
- EXPECT_EQ(0, RunCommand("", {simple_command},
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand},
CommandOptions::WithTimeout(10).RedirectStderr().Build()));
EXPECT_THAT(out, IsEmpty());
EXPECT_THAT(err, StrEq("stdout\nstderr\n"));
}
TEST_F(DumpstateTest, RunCommandWithOneArg) {
- EXPECT_EQ(0, RunCommand("", {echo_command, "one"}));
+ EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one"}));
EXPECT_THAT(err, IsEmpty());
EXPECT_THAT(out, StrEq("one\n"));
}
TEST_F(DumpstateTest, RunCommandWithMultipleArgs) {
- EXPECT_EQ(0, RunCommand("", {echo_command, "one", "is", "the", "loniest", "number"}));
+ EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one", "is", "the", "loniest", "number"}));
EXPECT_THAT(err, IsEmpty());
EXPECT_THAT(out, StrEq("one is the loniest number\n"));
}
TEST_F(DumpstateTest, RunCommandDryRun) {
SetDryRun(true);
- EXPECT_EQ(0, RunCommand("I AM GROOT", {simple_command}));
+ EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
// We don't know the exact duration, so we check the prefix and suffix
- EXPECT_THAT(out, StartsWith("------ I AM GROOT (" + simple_command +
+ EXPECT_THAT(out, StartsWith("------ I AM GROOT (" + kSimpleCommand +
") ------\n\t(skipped on dry run)\n------"));
EXPECT_THAT(out, EndsWith("s was the duration of 'I AM GROOT' ------\n"));
EXPECT_THAT(err, IsEmpty());
@@ -230,14 +245,14 @@
TEST_F(DumpstateTest, RunCommandDryRunNoTitle) {
SetDryRun(true);
- EXPECT_EQ(0, RunCommand("", {simple_command}));
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
EXPECT_THAT(out, IsEmpty());
EXPECT_THAT(err, IsEmpty());
}
TEST_F(DumpstateTest, RunCommandDryRunAlways) {
SetDryRun(true);
- EXPECT_EQ(0, RunCommand("", {simple_command}, CommandOptions::WithTimeout(10).Always().Build()));
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Always().Build()));
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n"));
}
@@ -249,28 +264,28 @@
}
TEST_F(DumpstateTest, RunCommandFails) {
- EXPECT_EQ(42, RunCommand("", {simple_command, "--exit", "42"}));
- EXPECT_THAT(out, StrEq("stdout\n*** command '" + simple_command +
+ EXPECT_EQ(42, RunCommand("", {kSimpleCommand, "--exit", "42"}));
+ EXPECT_THAT(out, StrEq("stdout\n*** command '" + kSimpleCommand +
" --exit 42' failed: exit code 42\n"));
- EXPECT_THAT(err, StrEq("stderr\n*** command '" + simple_command +
+ EXPECT_THAT(err, StrEq("stderr\n*** command '" + kSimpleCommand +
" --exit 42' failed: exit code 42\n"));
}
TEST_F(DumpstateTest, RunCommandCrashes) {
- EXPECT_NE(0, RunCommand("", {simple_command, "--crash"}));
+ EXPECT_NE(0, RunCommand("", {kSimpleCommand, "--crash"}));
// We don't know the exit code, so check just the prefix.
EXPECT_THAT(
- out, StartsWith("stdout\n*** command '" + simple_command + " --crash' failed: exit code"));
+ out, StartsWith("stdout\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
EXPECT_THAT(
- err, StartsWith("stderr\n*** command '" + simple_command + " --crash' failed: exit code"));
+ err, StartsWith("stderr\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
}
TEST_F(DumpstateTest, RunCommandTimesout) {
- EXPECT_EQ(-1, RunCommand("", {simple_command, "--sleep", "2"},
+ EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
CommandOptions::WithTimeout(1).Build()));
- EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + simple_command +
+ EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand +
" --sleep 2' timed out after 1"));
- EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + simple_command +
+ EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand +
" --sleep 2' timed out after 1"));
}
@@ -279,7 +294,7 @@
CaptureStderr();
std::thread t([=]() {
- EXPECT_EQ(SIGTERM, ds.RunCommand("", {simple_command, "--pid", "--sleep", "20"},
+ EXPECT_EQ(SIGTERM, ds.RunCommand("", {kSimpleCommand, "--pid", "--sleep", "20"},
CommandOptions::WithTimeout(100).Always().Build()));
});
@@ -306,93 +321,96 @@
out = GetCapturedStdout();
err = GetCapturedStderr();
- EXPECT_THAT(out, StrEq("*** command '" + simple_command +
+ EXPECT_THAT(out, StrEq("*** command '" + kSimpleCommand +
" --pid --sleep 20' failed: killed by signal 15\n"));
- EXPECT_THAT(err, StrEq("*** command '" + simple_command +
+ EXPECT_THAT(err, StrEq("*** command '" + kSimpleCommand +
" --pid --sleep 20' failed: killed by signal 15\n"));
}
-TEST_F(DumpstateTest, RunCommandProgressNoListener) {
- ds.update_progress_ = true;
- ds.progress_ = 0;
- ds.weight_total_ = 30;
-
- EXPECT_EQ(0, RunCommand("", {simple_command}, CommandOptions::WithTimeout(20).Build()));
- std::string progress_message = GetProgressMessageAndAssertSystemProperties(20, 30);
- EXPECT_THAT(out, StrEq("stdout\n"));
- EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
-
- EXPECT_EQ(0, RunCommand("", {simple_command}, CommandOptions::WithTimeout(10).Build()));
- progress_message = GetProgressMessageAndAssertSystemProperties(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_EQ(0, RunCommand("", {simple_command}, CommandOptions::WithTimeout(1).Build()));
- progress_message = GetProgressMessageAndAssertSystemProperties(31, 36, 30); // 20% increase
- 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_EQ(0, RunCommand("", {simple_command}, CommandOptions::WithTimeout(4).Build()));
- progress_message = GetProgressMessageAndAssertSystemProperties(35, 36);
- EXPECT_THAT(out, IsEmpty());
- EXPECT_THAT(err, StrEq(progress_message));
-}
-
TEST_F(DumpstateTest, RunCommandProgress) {
sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
ds.listener_ = listener;
ds.listener_name_ = "FoxMulder";
-
- ds.update_progress_ = true;
- ds.progress_ = 0;
- ds.weight_total_ = 30;
+ SetProgress(0, 30);
EXPECT_CALL(*listener, onProgressUpdated(20));
- EXPECT_EQ(0, RunCommand("", {simple_command}, CommandOptions::WithTimeout(20).Build()));
+ 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_EQ(0, RunCommand("", {simple_command}, CommandOptions::WithTimeout(10).Build()));
+ 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(36));
- EXPECT_EQ(0, RunCommand("", {simple_command}, CommandOptions::WithTimeout(1).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 31, 36, 30); // 20% increase
+ EXPECT_CALL(*listener, onMaxProgressUpdated(37));
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
+ progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30); // 20% increase
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_EQ(0, RunCommand("", {simple_command}, CommandOptions::WithTimeout(4).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 35, 36);
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
+ progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
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_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
+ std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 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 (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_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);
+ EXPECT_THAT(out, StrEq("stdout\n"));
+ EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
+
+ ds.listener_.clear();
+}
+
TEST_F(DumpstateTest, RunCommandDropRoot) {
// First check root case - only available when running with 'adb root'.
uid_t uid = getuid();
if (uid == 0) {
- EXPECT_EQ(0, RunCommand("", {simple_command, "--uid"}));
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"}));
EXPECT_THAT(out, StrEq("0\nstdout\n"));
EXPECT_THAT(err, StrEq("stderr\n"));
return;
}
- // Then drop root.
-
- EXPECT_EQ(0, RunCommand("", {simple_command, "--uid"},
+ // Then run dropping root.
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
CommandOptions::WithTimeout(1).DropRoot().Build()));
EXPECT_THAT(out, StrEq("2000\nstdout\n"));
EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
@@ -406,29 +424,14 @@
DropRoot();
- EXPECT_EQ(0, RunCommand("", {simple_command}, CommandOptions::WithTimeout(1).AsRoot().Build()));
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).AsRoot().Build()));
// We don't know the exact path of su, so we just check for the 'root ...' commands
EXPECT_THAT(out, StartsWith("Skipping"));
- EXPECT_THAT(out, EndsWith("root " + simple_command + "' on user build.\n"));
+ EXPECT_THAT(out, EndsWith("root " + kSimpleCommand + "' on user build.\n"));
EXPECT_THAT(err, IsEmpty());
}
-TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild) {
- if (IsUserBuild()) {
- ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
- return;
- }
-
- DropRoot();
-
- EXPECT_EQ(0, RunCommand("", {simple_command, "--uid"},
- CommandOptions::WithTimeout(1).AsRoot().Build()));
-
- EXPECT_THAT(out, StrEq("0\nstdout\n"));
- EXPECT_THAT(err, StrEq("stderr\n"));
-}
-
TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
EXPECT_THAT(out,
@@ -446,70 +449,54 @@
}
TEST_F(DumpstateTest, DumpFileSingleLine) {
- EXPECT_EQ(0, DumpFile("", test_data_path + "single-line.txt"));
+ EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
EXPECT_THAT(err, IsEmpty());
EXPECT_THAT(out, StrEq("I AM LINE1\n")); // dumpstate adds missing newline
}
TEST_F(DumpstateTest, DumpFileSingleLineWithNewLine) {
- EXPECT_EQ(0, DumpFile("", test_data_path + "single-line-with-newline.txt"));
+ EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line-with-newline.txt"));
EXPECT_THAT(err, IsEmpty());
EXPECT_THAT(out, StrEq("I AM LINE1\n"));
}
TEST_F(DumpstateTest, DumpFileMultipleLines) {
- EXPECT_EQ(0, DumpFile("", test_data_path + "multiple-lines.txt"));
+ EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines.txt"));
EXPECT_THAT(err, IsEmpty());
EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
}
TEST_F(DumpstateTest, DumpFileMultipleLinesWithNewLine) {
- EXPECT_EQ(0, DumpFile("", test_data_path + "multiple-lines-with-newline.txt"));
+ EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines-with-newline.txt"));
EXPECT_THAT(err, IsEmpty());
EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
}
TEST_F(DumpstateTest, DumpFileOnDryRunNoTitle) {
SetDryRun(true);
- EXPECT_EQ(0, DumpFile("", test_data_path + "single-line.txt"));
+ EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
EXPECT_THAT(err, IsEmpty());
EXPECT_THAT(out, IsEmpty());
}
TEST_F(DumpstateTest, DumpFileOnDryRun) {
SetDryRun(true);
- EXPECT_EQ(0, DumpFile("Might as well dump. Dump!", test_data_path + "single-line.txt"));
+ EXPECT_EQ(0, DumpFile("Might as well dump. Dump!", kTestDataPath + "single-line.txt"));
EXPECT_THAT(err, IsEmpty());
- EXPECT_THAT(out, StartsWith("------ Might as well dump. Dump! (" + test_data_path +
+ EXPECT_THAT(out, StartsWith("------ Might as well dump. Dump! (" + kTestDataPath +
"single-line.txt) ------\n\t(skipped on dry run)\n------"));
EXPECT_THAT(out, EndsWith("s was the duration of 'Might as well dump. Dump!' ------\n"));
EXPECT_THAT(err, IsEmpty());
}
-TEST_F(DumpstateTest, DumpFileUpdateProgressNoListener) {
- ds.update_progress_ = true;
- ds.progress_ = 0;
- ds.weight_total_ = 30;
-
- EXPECT_EQ(0, DumpFile("", test_data_path + "single-line.txt"));
-
- std::string progress_message =
- GetProgressMessageAndAssertSystemProperties(5, 30); // TODO: unhardcode WEIGHT_FILE (5)?
-
- EXPECT_THAT(err, StrEq(progress_message));
- EXPECT_THAT(out, StrEq("I AM LINE1\n")); // dumpstate adds missing newline
-}
-
TEST_F(DumpstateTest, DumpFileUpdateProgress) {
sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
ds.listener_ = listener;
ds.listener_name_ = "FoxMulder";
- ds.update_progress_ = true;
- ds.progress_ = 0;
- ds.weight_total_ = 30;
+ SetProgress(0, 30);
EXPECT_CALL(*listener, onProgressUpdated(5));
- EXPECT_EQ(0, DumpFile("", test_data_path + "single-line.txt"));
+ EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
std::string progress_message =
GetProgressMessage(ds.listener_name_, 5, 30); // TODO: unhardcode WEIGHT_FILE (5)?
@@ -519,32 +506,259 @@
ds.listener_.clear();
}
-class DumpstateServiceTest : public Test {
+class DumpstateServiceTest : public DumpstateBaseTest {
public:
DumpstateService dss;
};
TEST_F(DumpstateServiceTest, SetListenerNoName) {
sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
- bool result;
- EXPECT_TRUE(dss.setListener("", listener, &result).isOk());
- EXPECT_FALSE(result);
+ sp<IDumpstateToken> token;
+ EXPECT_TRUE(dss.setListener("", listener, &token).isOk());
+ ASSERT_THAT(token, IsNull());
}
TEST_F(DumpstateServiceTest, SetListenerNoPointer) {
- bool result;
- EXPECT_TRUE(dss.setListener("whatever", nullptr, &result).isOk());
- EXPECT_FALSE(result);
+ sp<IDumpstateToken> token;
+ EXPECT_TRUE(dss.setListener("whatever", nullptr, &token).isOk());
+ ASSERT_THAT(token, IsNull());
}
TEST_F(DumpstateServiceTest, SetListenerTwice) {
sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
- bool result;
- EXPECT_TRUE(dss.setListener("whatever", listener, &result).isOk());
- EXPECT_TRUE(result);
-
+ sp<IDumpstateToken> token;
+ EXPECT_TRUE(dss.setListener("whatever", listener, &token).isOk());
+ ASSERT_THAT(token, NotNull());
EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
- EXPECT_TRUE(dss.setListener("whatever", listener, &result).isOk());
- EXPECT_FALSE(result);
+ token.clear();
+ EXPECT_TRUE(dss.setListener("whatsoever", listener, &token).isOk());
+ ASSERT_THAT(token, IsNull());
+ EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
+}
+
+class ProgressTest : public DumpstateBaseTest {
+ public:
+ Progress GetInstance(int32_t max, double growth_factor, const std::string& path = "") {
+ return Progress(max, growth_factor, path);
+ }
+
+ void AssertStats(const std::string& path, int32_t expected_runs, int32_t expected_average) {
+ std::string expected_content =
+ android::base::StringPrintf("%d %d\n", expected_runs, expected_average);
+ std::string actual_content;
+ ASSERT_TRUE(android::base::ReadFileToString(path, &actual_content))
+ << "could not read statsfrom" << path;
+ ASSERT_THAT(actual_content, StrEq(expected_content)) << "invalid stats on " << path;
+ }
+};
+
+TEST_F(ProgressTest, SimpleTest) {
+ Progress progress;
+ EXPECT_EQ(0, progress.Get());
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+
+ bool max_increased = progress.Inc(1);
+ EXPECT_EQ(1, progress.Get());
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+ EXPECT_FALSE(max_increased);
+
+ // Ignore negative increase.
+ max_increased = progress.Inc(-1);
+ EXPECT_EQ(1, progress.Get());
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+ EXPECT_FALSE(max_increased);
+}
+
+TEST_F(ProgressTest, MaxGrowsInsideNewRange) {
+ Progress progress = GetInstance(10, 1.2); // 20% growth factor
+ EXPECT_EQ(0, progress.Get());
+ EXPECT_EQ(10, progress.GetInitialMax());
+ EXPECT_EQ(10, progress.GetMax());
+
+ // No increase
+ bool max_increased = progress.Inc(10);
+ EXPECT_EQ(10, progress.Get());
+ EXPECT_EQ(10, progress.GetMax());
+ EXPECT_FALSE(max_increased);
+
+ // Increase, with new value < max*20%
+ max_increased = progress.Inc(1);
+ EXPECT_EQ(11, progress.Get());
+ EXPECT_EQ(13, progress.GetMax()); // 11 average * 20% growth = 13.2 = 13
+ EXPECT_TRUE(max_increased);
+}
+
+TEST_F(ProgressTest, MaxGrowsOutsideNewRange) {
+ Progress progress = GetInstance(10, 1.2); // 20% growth factor
+ EXPECT_EQ(0, progress.Get());
+ EXPECT_EQ(10, progress.GetInitialMax());
+ EXPECT_EQ(10, progress.GetMax());
+
+ // No increase
+ bool max_increased = progress.Inc(10);
+ EXPECT_EQ(10, progress.Get());
+ EXPECT_EQ(10, progress.GetMax());
+ EXPECT_FALSE(max_increased);
+
+ // Increase, with new value > max*20%
+ max_increased = progress.Inc(5);
+ EXPECT_EQ(15, progress.Get());
+ EXPECT_EQ(18, progress.GetMax()); // 15 average * 20% growth = 18
+ EXPECT_TRUE(max_increased);
+}
+
+TEST_F(ProgressTest, InvalidPath) {
+ Progress progress("/devil/null");
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, EmptyFile) {
+ Progress progress(CopyTextFileFixture("empty-file.txt"));
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine1stEntryNAN) {
+ Progress progress(CopyTextFileFixture("stats-invalid-1st-NAN.txt"));
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine2ndEntryNAN) {
+ Progress progress(CopyTextFileFixture("stats-invalid-2nd-NAN.txt"));
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLineBothNAN) {
+ Progress progress(CopyTextFileFixture("stats-invalid-both-NAN.txt"));
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine1stEntryNegative) {
+ Progress progress(CopyTextFileFixture("stats-invalid-1st-negative.txt"));
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine2ndEntryNegative) {
+ Progress progress(CopyTextFileFixture("stats-invalid-2nd-negative.txt"));
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine1stEntryTooBig) {
+ Progress progress(CopyTextFileFixture("stats-invalid-1st-too-big.txt"));
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine2ndEntryTooBig) {
+ Progress progress(CopyTextFileFixture("stats-invalid-2nd-too-big.txt"));
+ EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+// Tests stats are properly saved when the file does not exists.
+TEST_F(ProgressTest, FirstTime) {
+ std::string path = kTestDataPath + "FirstTime.txt";
+ android::base::RemoveFileIfExists(path);
+
+ Progress run1(path);
+ EXPECT_EQ(0, run1.Get());
+ EXPECT_EQ(Progress::kDefaultMax, run1.GetInitialMax());
+ EXPECT_EQ(Progress::kDefaultMax, run1.GetMax());
+
+ bool max_increased = run1.Inc(20);
+ EXPECT_EQ(20, run1.Get());
+ EXPECT_EQ(Progress::kDefaultMax, run1.GetMax());
+ EXPECT_FALSE(max_increased);
+
+ run1.Save();
+ AssertStats(path, 1, 20);
+}
+
+// Tests what happens when the persistent settings contains the average duration of 1 run.
+// Data on file is 1 run and 109 average.
+TEST_F(ProgressTest, SecondTime) {
+ std::string path = CopyTextFileFixture("stats-one-run-no-newline.txt");
+
+ Progress run1 = GetInstance(-42, 1.2, path);
+ EXPECT_EQ(0, run1.Get());
+ EXPECT_EQ(10, run1.GetInitialMax());
+ EXPECT_EQ(10, run1.GetMax());
+
+ bool max_increased = run1.Inc(20);
+ EXPECT_EQ(20, run1.Get());
+ EXPECT_EQ(24, run1.GetMax());
+ EXPECT_TRUE(max_increased);
+
+ // Average now is 2 runs and (10 + 20)/ 2 = 15
+ run1.Save();
+ AssertStats(path, 2, 15);
+
+ Progress run2 = GetInstance(-42, 1.2, path);
+ EXPECT_EQ(0, run2.Get());
+ EXPECT_EQ(15, run2.GetInitialMax());
+ EXPECT_EQ(15, run2.GetMax());
+
+ max_increased = run2.Inc(25);
+ EXPECT_EQ(25, run2.Get());
+ EXPECT_EQ(30, run2.GetMax());
+ EXPECT_TRUE(max_increased);
+
+ // Average now is 3 runs and (15 * 2 + 25)/ 3 = 18.33 = 18
+ run2.Save();
+ AssertStats(path, 3, 18);
+
+ Progress run3 = GetInstance(-42, 1.2, path);
+ EXPECT_EQ(0, run3.Get());
+ EXPECT_EQ(18, run3.GetInitialMax());
+ EXPECT_EQ(18, run3.GetMax());
+
+ // Make sure average decreases as well
+ max_increased = run3.Inc(5);
+ EXPECT_EQ(5, run3.Get());
+ EXPECT_EQ(18, run3.GetMax());
+ EXPECT_FALSE(max_increased);
+
+ // Average now is 4 runs and (18 * 3 + 5)/ 4 = 14.75 = 14
+ run3.Save();
+ AssertStats(path, 4, 14);
+}
+
+// Tests what happens when the persistent settings contains the average duration of 2 runs.
+// Data on file is 2 runs and 15 average.
+TEST_F(ProgressTest, ThirdTime) {
+ std::string path = CopyTextFileFixture("stats-two-runs.txt");
+ AssertStats(path, 2, 15); // Sanity check
+
+ Progress run1 = GetInstance(-42, 1.2, path);
+ EXPECT_EQ(0, run1.Get());
+ EXPECT_EQ(15, run1.GetInitialMax());
+ EXPECT_EQ(15, run1.GetMax());
+
+ bool max_increased = run1.Inc(20);
+ EXPECT_EQ(20, run1.Get());
+ EXPECT_EQ(24, run1.GetMax());
+ EXPECT_TRUE(max_increased);
+
+ // Average now is 3 runs and (15 * 2 + 20)/ 3 = 16.66 = 16
+ run1.Save();
+ AssertStats(path, 3, 16);
+}
+
+// TODO: RunCommandAsRootNonUserBuild must be the last test because it drops root, which could cause
+// other tests to fail if they're relyin on the process running as root.
+// For now this is fine, but eventually it might need to be moved to its own test case / process.
+TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild) {
+ if (IsUserBuild()) {
+ ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
+ return;
+ }
+
+ DropRoot();
+
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+ CommandOptions::WithTimeout(1).AsRoot().Build()));
+
+ EXPECT_THAT(out, StrEq("0\nstdout\n"));
+ EXPECT_THAT(err, StrEq("stderr\n"));
}
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 34e09d7..b5f328d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -19,6 +19,7 @@
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
+#include <math.h>
#include <poll.h>
#include <signal.h>
#include <stdarg.h>
@@ -42,6 +43,7 @@
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <cutils/debugger.h>
#include <cutils/log.h>
#include <cutils/properties.h>
@@ -67,7 +69,7 @@
static bool IsDryRun() {
return Dumpstate::GetInstance().IsDryRun();
}
-static void UpdateProgress(int delta) {
+static void UpdateProgress(int32_t delta) {
ds.UpdateProgress(delta);
}
@@ -90,6 +92,10 @@
/* Most simple commands have 10 as timeout, so 5 is a good estimate */
static const int WEIGHT_FILE = 5;
+// Reasonable value for max stats.
+static const int STATS_MAX_N_RUNS = 1000;
+static const long STATS_MAX_AVERAGE = 100000;
+
CommandOptions CommandOptions::DEFAULT = CommandOptions::WithTimeout(10).Build();
CommandOptions CommandOptions::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
CommandOptions CommandOptions::AS_ROOT_5 = CommandOptions::WithTimeout(5).AsRoot().Build();
@@ -207,6 +213,115 @@
return (uint64_t) ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec;
}
+const int32_t Progress::kDefaultMax = 5000;
+
+Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
+}
+
+Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
+ : Progress(initial_max, growth_factor, "") {
+ progress_ = progress;
+}
+
+Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
+ : initial_max_(initial_max),
+ progress_(0),
+ max_(initial_max),
+ growth_factor_(growth_factor),
+ n_runs_(0),
+ average_max_(0),
+ path_(path) {
+ if (!path_.empty()) {
+ Load();
+ }
+}
+
+void Progress::Load() {
+ MYLOGD("Loading stats from %s\n", path_.c_str());
+ std::string content;
+ if (!android::base::ReadFileToString(path_, &content)) {
+ MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
+ return;
+ }
+ if (content.empty()) {
+ MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
+ return;
+ }
+ std::vector<std::string> lines = android::base::Split(content, "\n");
+
+ if (lines.size() < 1) {
+ MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
+ (int)lines.size(), max_);
+ return;
+ }
+ char* ptr;
+ n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
+ average_max_ = strtol(ptr, nullptr, 10);
+ if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
+ average_max_ > STATS_MAX_AVERAGE) {
+ MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
+ initial_max_ = Progress::kDefaultMax;
+ } else {
+ initial_max_ = average_max_;
+ }
+ max_ = initial_max_;
+
+ MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
+}
+
+void Progress::Save() {
+ int32_t total = n_runs_ * average_max_ + progress_;
+ int32_t runs = n_runs_ + 1;
+ int32_t average = floor(((float)total) / runs);
+ MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
+ path_.c_str());
+ if (path_.empty()) {
+ return;
+ }
+
+ std::string content = android::base::StringPrintf("%d %d\n", runs, average);
+ if (!android::base::WriteStringToFile(content, path_)) {
+ MYLOGE("Could not save stats on %s\n", path_.c_str());
+ }
+}
+
+int32_t Progress::Get() const {
+ return progress_;
+}
+
+bool Progress::Inc(int32_t delta) {
+ bool changed = false;
+ if (delta >= 0) {
+ progress_ += delta;
+ if (progress_ > max_) {
+ int32_t old_max = max_;
+ max_ = floor((float)progress_ * growth_factor_);
+ MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
+ changed = true;
+ }
+ }
+ return changed;
+}
+
+int32_t Progress::GetMax() const {
+ return max_;
+}
+
+int32_t Progress::GetInitialMax() const {
+ return initial_max_;
+}
+
+void Progress::Dump(int fd, const std::string& prefix) const {
+ const char* pr = prefix.c_str();
+ dprintf(fd, "%sprogress: %d\n", pr, progress_);
+ dprintf(fd, "%smax: %d\n", pr, max_);
+ dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
+ dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
+ dprintf(fd, "%spath: %s\n", pr, path_.c_str());
+ dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
+ dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
+}
+
bool Dumpstate::IsDryRun() const {
return dry_run_;
}
@@ -224,6 +339,10 @@
name_.c_str(), suffix.c_str());
}
+void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
+ progress_ = std::move(progress);
+}
+
void for_each_userid(void (*func)(int), const char *header) {
if (IsDryRun()) return;
@@ -1320,69 +1439,47 @@
}
// TODO: make this function thread safe if sections are generated in parallel.
-void Dumpstate::UpdateProgress(int delta) {
- if (!update_progress_) return;
-
- progress_ += delta;
-
- // TODO: remove property support once Shell uses IDumpstateListener
- char key[PROPERTY_KEY_MAX];
- char value[PROPERTY_VALUE_MAX];
-
- // adjusts max on the fly
- if (progress_ > weight_total_) {
- int new_total = weight_total_ * 1.2;
- MYLOGD("Adjusting total weight from %d to %d\n", weight_total_, new_total);
- weight_total_ = new_total;
-
- if (listener_ != nullptr) {
- listener_->onMaxProgressUpdated(weight_total_);
- } else {
- snprintf(key, sizeof(key), "dumpstate.%d.max", pid_);
- snprintf(value, sizeof(value), "%d", weight_total_);
- int status = property_set(key, value);
- if (status != 0) {
- MYLOGE("Could not update max weight by setting system property %s to %s: %d\n", key,
- value, status);
- }
- }
+void Dumpstate::UpdateProgress(int32_t delta) {
+ if (progress_ == nullptr) {
+ MYLOGE("UpdateProgress: progress_ not set\n");
+ return;
}
+ // Always update progess so stats can be tuned...
+ bool max_changed = progress_->Inc(delta);
+
+ // ...but only notifiy listeners when necessary.
+ if (!update_progress_) return;
+
+ int progress = progress_->Get();
+ int max = progress_->GetMax();
+
+ // 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_) {
+ return;
+ }
+ last_updated_progress_ = progress;
+
if (control_socket_fd_ >= 0) {
- dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress_, weight_total_);
+ dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
fsync(control_socket_fd_);
}
if (listener_ != nullptr) {
- if (progress_ % 100 == 0) {
+ if (progress % 100 == 0) {
// We don't want to spam logcat, so only log multiples of 100.
- MYLOGD("Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress_,
- weight_total_);
+ MYLOGD("Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
} else {
// stderr is ignored on normal invocations, but useful when calling
// /system/bin/dumpstate directly for debuggging.
- fprintf(stderr, "Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress_,
- weight_total_);
+ fprintf(stderr, "Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
}
- listener_->onProgressUpdated(progress_);
- } else {
- snprintf(key, sizeof(key), "dumpstate.%d.progress", pid_);
- snprintf(value, sizeof(value), "%d", progress_);
-
- if (progress_ % 100 == 0) {
- // We don't want to spam logcat, so only log multiples of 100.
- MYLOGD("Setting progress (%s): %s/%d\n", key, value, weight_total_);
- } else {
- // stderr is ignored on normal invocations, but useful when calling
- // /system/bin/dumpstate directly for debuggging.
- fprintf(stderr, "Setting progress (%s): %s/%d\n", key, value, weight_total_);
- }
-
- int status = property_set(key, value);
- if (status) {
- MYLOGE("Could not update progress by setting system property %s to %s: %d\n", key,
- value, status);
- }
+ listener_->onProgressUpdated(progress);
}
}
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 078db26..5ffc0c2 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -797,7 +797,7 @@
ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno));
}
-static void run_dex2oat(int zip_fd, int oat_fd, int vdex_fd, int image_fd,
+static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
const char* input_file_name, const char* output_file_name, int swap_fd,
const char *instruction_set, const char* compiler_filter, bool vm_safe_mode,
bool debuggable, bool post_bootcomplete, int profile_fd, const char* shared_libraries) {
@@ -881,7 +881,8 @@
char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN];
char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX];
- char vdex_fd_arg[strlen("--vdex-fd=") + MAX_INT_LEN];
+ char input_vdex_fd_arg[strlen("--input-vdex-fd=") + MAX_INT_LEN];
+ char output_vdex_fd_arg[strlen("--output-vdex-fd=") + MAX_INT_LEN];
char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN];
char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX];
char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
@@ -897,7 +898,8 @@
sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
sprintf(zip_location_arg, "--zip-location=%s", input_file_name);
- sprintf(vdex_fd_arg, "--vdex-fd=%d", vdex_fd);
+ sprintf(input_vdex_fd_arg, "--input-vdex-fd=%d", input_vdex_fd);
+ sprintf(output_vdex_fd_arg, "--output-vdex-fd=%d", output_vdex_fd);
sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
@@ -960,7 +962,7 @@
ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);
- const char* argv[8 // program name, mandatory arguments and the final NULL
+ const char* argv[9 // program name, mandatory arguments and the final NULL
+ (have_dex2oat_isa_variant ? 1 : 0)
+ (have_dex2oat_isa_features ? 1 : 0)
+ (have_dex2oat_Xms_flag ? 2 : 0)
@@ -981,7 +983,8 @@
argv[i++] = DEX2OAT_BIN;
argv[i++] = zip_fd_arg;
argv[i++] = zip_location_arg;
- argv[i++] = vdex_fd_arg;
+ argv[i++] = input_vdex_fd_arg;
+ argv[i++] = output_vdex_fd_arg;
argv[i++] = oat_fd_arg;
argv[i++] = oat_location_arg;
argv[i++] = instruction_set_arg;
@@ -1507,6 +1510,14 @@
return true;
}
+static bool IsOutputDalvikCache(const char* oat_dir) {
+ // InstallerConnection.java (which invokes installd) transforms Java null arguments
+ // into '!'. Play it safe by handling it both.
+ // TODO: ensure we never get null.
+ // TODO: pass a flag instead of inferring if the output is dalvik cache.
+ return oat_dir == nullptr || oat_dir[0] == '!';
+}
+
static bool create_oat_out_path(const char* apk_path, const char* instruction_set,
const char* oat_dir, /*out*/ char* out_oat_path) {
// Early best-effort check whether we can fit the the path into our buffers.
@@ -1518,9 +1529,9 @@
return false;
}
- if (oat_dir != NULL && oat_dir[0] != '!') {
+ if (!IsOutputDalvikCache(oat_dir)) {
if (validate_apk_path(oat_dir)) {
- ALOGE("invalid oat_dir '%s'\n", oat_dir);
+ ALOGE("cannot validate apk path with oat_dir '%s'\n", oat_dir);
return false;
}
if (!calculate_oat_file_path(out_oat_path, oat_dir, apk_path, instruction_set)) {
@@ -1709,22 +1720,6 @@
return -1;
}
- // If invoking patchoat, open the VDEX associated with the OAT too.
- std::string in_vdex_path_str;
- base::unique_fd input_vdex_fd;
- if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED
- || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) {
- in_vdex_path_str = create_vdex_filename(input_file);
- if (in_vdex_path_str.empty()) {
- return -1;
- }
- input_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
- if (input_vdex_fd.get() < 0) {
- ALOGE("installd cannot open '%s' for input during dexopt\n", in_vdex_path_str.c_str());
- return -1;
- }
- }
-
// Create the output OAT file.
const std::string out_oat_path_str(out_oat_path);
Dex2oatFileWrapper<std::function<void ()>> out_oat_fd(
@@ -1738,6 +1733,47 @@
return -1;
}
+ // Open the existing VDEX. We do this before creating the new output VDEX, which will
+ // unlink the old one.
+ base::unique_fd in_vdex_fd;
+ std::string in_vdex_path_str;
+ if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED
+ || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) {
+ // `input_file` is the OAT file to be relocated. The VDEX has to be there as well.
+ in_vdex_path_str = create_vdex_filename(input_file);
+ if (in_vdex_path_str.empty()) {
+ ALOGE("installd cannot compute input vdex location for '%s'\n", input_file);
+ return -1;
+ }
+ in_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
+ if (in_vdex_fd.get() < 0) {
+ ALOGE("installd cannot open '%s' for input during dexopt: %s\n",
+ in_vdex_path_str.c_str(), strerror(errno));
+ return -1;
+ }
+ } else {
+ // Open the possibly existing vdex in the `out_oat_path`. If none exist, we pass -1
+ // to dex2oat for input-vdex-fd.
+ in_vdex_path_str = create_vdex_filename(out_oat_path);
+ if (in_vdex_path_str.empty()) {
+ ALOGE("installd cannot compute input vdex location for '%s'\n", out_oat_path);
+ return -1;
+ }
+ in_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
+ // If there is no vdex file in out_oat_path, check if we have a vdex
+ // file next to the odex file. For other failures, we will just pass a -1 fd.
+ if (in_vdex_fd.get() < 0 && (errno == ENOENT) && IsOutputDalvikCache(oat_dir)) {
+ if (calculate_odex_file_path(in_odex_path, apk_path, instruction_set)) {
+ in_vdex_path_str = create_vdex_filename(std::string(in_odex_path));
+ if (in_vdex_path_str.empty()) {
+ ALOGE("installd cannot compute input vdex location for '%s'\n", in_odex_path);
+ return -1;
+ }
+ in_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
+ }
+ }
+ }
+
// Infer the name of the output VDEX and create it.
const std::string out_vdex_path_str = create_vdex_filename(out_oat_path_str);
if (out_vdex_path_str.empty()) {
@@ -1832,7 +1868,7 @@
if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED
|| dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) {
run_patchoat(input_fd.get(),
- input_vdex_fd.get(),
+ in_vdex_fd.get(),
out_oat_fd.get(),
out_vdex_fd.get(),
input_file,
@@ -1846,6 +1882,7 @@
const char *input_file_name = get_location_from_path(input_file);
run_dex2oat(input_fd.get(),
out_oat_fd.get(),
+ in_vdex_fd.get(),
out_vdex_fd.get(),
image_fd.get(),
input_file_name,
diff --git a/data/etc/android.hardware.wifi.nan.xml b/data/etc/android.hardware.wifi.aware.xml
similarity index 90%
rename from data/etc/android.hardware.wifi.nan.xml
rename to data/etc/android.hardware.wifi.aware.xml
index e557610..ae6272e 100644
--- a/data/etc/android.hardware.wifi.nan.xml
+++ b/data/etc/android.hardware.wifi.aware.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<!-- This is the standard feature indicating that the device includes WiFi NAN. -->
+<!-- This is the standard feature indicating that the device includes WiFi Aware. -->
<permissions>
- <feature name="android.hardware.wifi.nan" />
+ <feature name="android.hardware.wifi.aware" />
</permissions>
diff --git a/include/batteryservice/BatteryService.h b/include/batteryservice/BatteryService.h
index b399905..30d7317 100644
--- a/include/batteryservice/BatteryService.h
+++ b/include/batteryservice/BatteryService.h
@@ -24,25 +24,7 @@
namespace android {
-// must be kept in sync with definitions in BatteryManager.java
-enum {
- BATTERY_STATUS_UNKNOWN = 1, // equals BatteryManager.BATTERY_STATUS_UNKNOWN constant
- BATTERY_STATUS_CHARGING = 2, // equals BatteryManager.BATTERY_STATUS_CHARGING constant
- BATTERY_STATUS_DISCHARGING = 3, // equals BatteryManager.BATTERY_STATUS_DISCHARGING constant
- BATTERY_STATUS_NOT_CHARGING = 4, // equals BatteryManager.BATTERY_STATUS_NOT_CHARGING constant
- BATTERY_STATUS_FULL = 5, // equals BatteryManager.BATTERY_STATUS_FULL constant
-};
-
-// must be kept in sync with definitions in BatteryManager.java
-enum {
- BATTERY_HEALTH_UNKNOWN = 1, // equals BatteryManager.BATTERY_HEALTH_UNKNOWN constant
- BATTERY_HEALTH_GOOD = 2, // equals BatteryManager.BATTERY_HEALTH_GOOD constant
- BATTERY_HEALTH_OVERHEAT = 3, // equals BatteryManager.BATTERY_HEALTH_OVERHEAT constant
- BATTERY_HEALTH_DEAD = 4, // equals BatteryManager.BATTERY_HEALTH_DEAD constant
- BATTERY_HEALTH_OVER_VOLTAGE = 5, // equals BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE constant
- BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6, // equals BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE constant
- BATTERY_HEALTH_COLD = 7, // equals BatteryManager.BATTERY_HEALTH_COLD constant
-};
+#include "BatteryServiceConstants.h"
// must be kept in sync with definitions in BatteryProperty.java
enum {
diff --git a/include/batteryservice/BatteryServiceConstants.h b/include/batteryservice/BatteryServiceConstants.h
new file mode 100644
index 0000000..8a90a12
--- /dev/null
+++ b/include/batteryservice/BatteryServiceConstants.h
@@ -0,0 +1,32 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+#ifndef HIDL_GENERATED_android_hardware_health_V1_0_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_android_hardware_health_V1_0_EXPORTED_CONSTANTS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ BATTERY_STATUS_UNKNOWN = 1,
+ BATTERY_STATUS_CHARGING = 2,
+ BATTERY_STATUS_DISCHARGING = 3,
+ BATTERY_STATUS_NOT_CHARGING = 4,
+ BATTERY_STATUS_FULL = 5,
+};
+
+enum {
+ BATTERY_HEALTH_UNKNOWN = 1,
+ BATTERY_HEALTH_GOOD = 2,
+ BATTERY_HEALTH_OVERHEAT = 3,
+ BATTERY_HEALTH_DEAD = 4,
+ BATTERY_HEALTH_OVER_VOLTAGE = 5,
+ BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6,
+ BATTERY_HEALTH_COLD = 7,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HIDL_GENERATED_android_hardware_health_V1_0_EXPORTED_CONSTANTS_H_
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 39deb64..69de136 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -697,8 +697,16 @@
return UNEXPECTED_NULL;
}
+ if (val->max_size() < static_cast<size_t>(size)) {
+ return NO_MEMORY;
+ }
+
val->resize(static_cast<size_t>(size));
+ if (val->size() < static_cast<size_t>(size)) {
+ return NO_MEMORY;
+ }
+
for (auto& v: *val) {
status = (this->*read_func)(&v);
diff --git a/include/gui/GraphicBufferAlloc.h b/include/gui/GraphicBufferAlloc.h
index 62e3877..b19a1ac 100644
--- a/include/gui/GraphicBufferAlloc.h
+++ b/include/gui/GraphicBufferAlloc.h
@@ -34,8 +34,9 @@
GraphicBufferAlloc();
virtual ~GraphicBufferAlloc();
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
- uint32_t height, PixelFormat format, uint32_t usage,
- std::string requestorName, status_t* error) override;
+ uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint32_t usage, std::string requestorName,
+ status_t* error) override;
};
diff --git a/include/gui/IGraphicBufferAlloc.h b/include/gui/IGraphicBufferAlloc.h
index acc2f30..2a7690a 100644
--- a/include/gui/IGraphicBufferAlloc.h
+++ b/include/gui/IGraphicBufferAlloc.h
@@ -38,12 +38,14 @@
/* Create a new GraphicBuffer for the client to use.
*/
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t usage, std::string requestorName,
- status_t* error) = 0;
+ PixelFormat format, uint32_t layerCount, uint32_t usage,
+ std::string requestorName, status_t* error) = 0;
sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t usage, status_t* error) {
- return createGraphicBuffer(w, h, format, usage, "<Unknown>", error);
+ PixelFormat format, uint32_t layerCount, uint32_t usage,
+ status_t* error) {
+ return createGraphicBuffer(w, h, format, layerCount, usage, "<Unknown>",
+ error);
}
};
diff --git a/include/ui/Gralloc1.h b/include/ui/Gralloc1.h
index cf8c173..64dacd7 100644
--- a/include/ui/Gralloc1.h
+++ b/include/ui/Gralloc1.h
@@ -49,6 +49,7 @@
mWidth(0),
mHeight(0),
mFormat(static_cast<android_pixel_format_t>(0)),
+ mLayerCount(0),
mProducerUsage(GRALLOC1_PRODUCER_USAGE_NONE),
mConsumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {}
@@ -58,6 +59,7 @@
gralloc1_error_t setDimensions(uint32_t width, uint32_t height);
gralloc1_error_t setFormat(android_pixel_format_t format);
+ gralloc1_error_t setLayerCount(uint32_t layerCount);
gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage);
gralloc1_error_t setConsumerUsage(gralloc1_consumer_usage_t usage);
@@ -68,6 +70,7 @@
uint32_t mWidth;
uint32_t mHeight;
android_pixel_format_t mFormat;
+ uint32_t mLayerCount;
gralloc1_producer_usage_t mProducerUsage;
gralloc1_consumer_usage_t mConsumerUsage;
@@ -178,6 +181,8 @@
GRALLOC1_FUNCTION_SET_DIMENSIONS> setDimensions;
FunctionLoader<GRALLOC1_PFN_SET_FORMAT,
GRALLOC1_FUNCTION_SET_FORMAT> setFormat;
+ FunctionLoader<GRALLOC1_PFN_SET_LAYER_COUNT,
+ GRALLOC1_FUNCTION_SET_LAYER_COUNT> setLayerCount;
FunctionLoader<GRALLOC1_PFN_SET_PRODUCER_USAGE,
GRALLOC1_FUNCTION_SET_PRODUCER_USAGE> setProducerUsage;
FunctionLoader<GRALLOC1_PFN_GET_BACKING_STORE,
@@ -188,6 +193,8 @@
GRALLOC1_FUNCTION_GET_DIMENSIONS> getDimensions;
FunctionLoader<GRALLOC1_PFN_GET_FORMAT,
GRALLOC1_FUNCTION_GET_FORMAT> getFormat;
+ FunctionLoader<GRALLOC1_PFN_GET_LAYER_COUNT,
+ GRALLOC1_FUNCTION_GET_LAYER_COUNT> getLayerCount;
FunctionLoader<GRALLOC1_PFN_GET_PRODUCER_USAGE,
GRALLOC1_FUNCTION_GET_PRODUCER_USAGE> getProducerUsage;
FunctionLoader<GRALLOC1_PFN_GET_STRIDE,
diff --git a/include/ui/Gralloc1On0Adapter.h b/include/ui/Gralloc1On0Adapter.h
index d523c4f..2508ce9 100644
--- a/include/ui/Gralloc1On0Adapter.h
+++ b/include/ui/Gralloc1On0Adapter.h
@@ -131,6 +131,7 @@
width(0),
height(0),
format(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ layerCount(1),
producerUsage(GRALLOC1_PRODUCER_USAGE_NONE),
consumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {}
@@ -145,6 +146,11 @@
return GRALLOC1_ERROR_NONE;
}
+ gralloc1_error_t setLayerCount(uint32_t lc) {
+ layerCount = lc;
+ return GRALLOC1_ERROR_NONE;
+ }
+
gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage) {
producerUsage = usage;
return GRALLOC1_ERROR_NONE;
@@ -161,6 +167,7 @@
uint32_t width;
uint32_t height;
int32_t format;
+ uint32_t layerCount;
gralloc1_producer_usage_t producerUsage;
gralloc1_consumer_usage_t consumerUsage;
};
@@ -197,6 +204,12 @@
&Descriptor::setFormat, format);
}
+ static int32_t setLayerCountHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId, uint32_t layerCount) {
+ return callDescriptorFunction(device, descriptorId,
+ &Descriptor::setLayerCount, layerCount);
+ }
+
static int32_t setProducerUsageHook(gralloc1_device_t* device,
gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) {
auto usage = static_cast<gralloc1_producer_usage_t>(intUsage);
@@ -246,6 +259,11 @@
return GRALLOC1_ERROR_NONE;
}
+ gralloc1_error_t getLayerCount(uint32_t* outLayerCount) const {
+ *outLayerCount = mDescriptor.layerCount;
+ return GRALLOC1_ERROR_NONE;
+ }
+
gralloc1_error_t getNumFlexPlanes(uint32_t* outNumPlanes) const {
// TODO: This is conservative, and we could do better by examining
// the format, but it won't hurt anything for now
diff --git a/include/ui/GrallocMapper.h b/include/ui/GrallocMapper.h
index 5517449..868fd14 100644
--- a/include/ui/GrallocMapper.h
+++ b/include/ui/GrallocMapper.h
@@ -63,6 +63,11 @@
return mMapper->getFormat(mDevice, handle, &format);
}
+ Error getLayerCount(buffer_handle_t handle, uint32_t& layerCount) const
+ {
+ return mMapper->getLayerCount(mDevice, handle, &layerCount);
+ }
+
Error getProducerUsageMask(buffer_handle_t handle,
uint64_t& usageMask) const
{
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 3e127a1..1bbcee2 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -76,10 +76,15 @@
GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
uint32_t inUsage, std::string requestorName = "<Unknown>");
+ // creates w * h buffer with a layer count
+ GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint32_t inUsage,
+ std::string requestorName = "<Unknown>");
+
// create a buffer from an existing handle
GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
- uint32_t inUsage, uint32_t inStride, native_handle_t* inHandle,
- bool keepOwnership);
+ uint32_t inLayerCount, uint32_t inUsage, uint32_t inStride,
+ native_handle_t* inHandle, bool keepOwnership);
// create a buffer from an existing ANativeWindowBuffer
GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership);
@@ -92,6 +97,7 @@
uint32_t getStride() const { return static_cast<uint32_t>(stride); }
uint32_t getUsage() const { return static_cast<uint32_t>(usage); }
PixelFormat getPixelFormat() const { return format; }
+ uint32_t getLayerCount() const { return static_cast<uint32_t>(layerCount); }
Rect getBounds() const { return Rect(width, height); }
uint64_t getId() const { return mId; }
@@ -101,10 +107,10 @@
}
status_t reallocate(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inUsage);
+ PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage);
bool needsReallocation(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inUsage);
+ PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage);
status_t lock(uint32_t inUsage, void** vaddr);
status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr);
@@ -160,7 +166,7 @@
const GraphicBuffer& operator = (const GraphicBuffer& rhs) const;
status_t initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
- uint32_t inUsage, std::string requestorName);
+ uint32_t inLayerCount, uint32_t inUsage, std::string requestorName);
void free_handle();
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
index 9cc5806..16967d4 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/include/ui/GraphicBufferAllocator.h
@@ -65,8 +65,9 @@
static inline GraphicBufferAllocator& get() { return getInstance(); }
status_t allocate(uint32_t w, uint32_t h, PixelFormat format,
- uint32_t usage, buffer_handle_t* handle, uint32_t* stride,
- uint64_t graphicBufferId, std::string requestorName);
+ uint32_t layerCount, uint32_t usage, buffer_handle_t* handle,
+ uint32_t* stride, uint64_t graphicBufferId,
+ std::string requestorName);
status_t free(buffer_handle_t handle);
@@ -79,6 +80,7 @@
uint32_t height;
uint32_t stride;
PixelFormat format;
+ uint32_t layerCount;
uint32_t usage;
size_t size;
std::string requestorName;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 470fc59..15c441e 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -514,7 +514,7 @@
// grow objects
if (mObjectsCapacity < mObjectsSize + numObjects) {
size_t newSize = ((mObjectsSize + numObjects)*3)/2;
- if (newSize < mObjectsSize) return NO_MEMORY; // overflow
+ if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY; // overflow
binder_size_t *objects =
(binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
if (objects == (binder_size_t*)0) {
@@ -1314,7 +1314,7 @@
}
if (!enoughObjects) {
size_t newSize = ((mObjectsSize+2)*3)/2;
- if (newSize < mObjectsSize) return NO_MEMORY; // overflow
+ if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY; // overflow
binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
if (objects == NULL) return NO_MEMORY;
mObjects = objects;
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 9e9799b..9ba85a6 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -104,7 +104,7 @@
"liblog",
],
- export_shared_lib_headers: ["libbinder"],
+ export_shared_lib_headers: ["libbinder", "libui"],
}
subdirs = ["tests"]
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 7fbf312..ee4c58c 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -716,6 +716,7 @@
}
sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
+ Mutex::Autolock lock(mCore->mMutex);
return mCore->mSidebandStream;
}
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 90b4b9d..81d4f31 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -42,6 +42,8 @@
namespace android {
+static constexpr uint32_t BQ_LAYER_COUNT = 1;
+
BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core,
bool consumerIsSurfaceFlinger) :
mCore(core),
@@ -414,7 +416,8 @@
// buffer. If this buffer would require reallocation to meet the
// requested attributes, we free it and attempt to get another one.
if (!mCore->mAllowAllocation) {
- if (buffer->needsReallocation(width, height, format, usage)) {
+ if (buffer->needsReallocation(width, height, format,
+ BQ_LAYER_COUNT, usage)) {
if (mCore->mSharedBufferSlot == found) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
"buffer");
@@ -430,7 +433,8 @@
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
if (mCore->mSharedBufferSlot == found &&
- buffer->needsReallocation(width, height, format, usage)) {
+ buffer->needsReallocation(width, height, format,
+ BQ_LAYER_COUNT, usage)) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
"buffer");
@@ -449,7 +453,8 @@
mSlots[found].mBufferState.dequeue();
if ((buffer == NULL) ||
- buffer->needsReallocation(width, height, format, usage))
+ buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT,
+ usage))
{
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = NULL;
@@ -500,7 +505,7 @@
status_t error;
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
- width, height, format, usage,
+ width, height, format, BQ_LAYER_COUNT, usage,
{mConsumerName.string(), mConsumerName.size()}, &error));
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
@@ -1039,6 +1044,10 @@
case NATIVE_WINDOW_FORMAT:
value = static_cast<int32_t>(mCore->mDefaultBufferFormat);
break;
+ case NATIVE_WINDOW_LAYER_COUNT:
+ // All BufferQueue buffers have a single layer.
+ value = BQ_LAYER_COUNT;
+ break;
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
value = mCore->getMinUndequeuedBufferCountLocked();
break;
@@ -1287,8 +1296,9 @@
for (size_t i = 0; i < newBufferCount; ++i) {
status_t result = NO_ERROR;
sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
- allocWidth, allocHeight, allocFormat, allocUsage,
- {mConsumerName.string(), mConsumerName.size()}, &result));
+ allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
+ allocUsage, {mConsumerName.string(), mConsumerName.size()},
+ &result));
if (result != NO_ERROR) {
BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
" %u, usage %u)", width, height, format, usage);
@@ -1366,6 +1376,7 @@
String8 BufferQueueProducer::getConsumerName() const {
ATRACE_CALL();
+ Mutex::Autolock lock(mCore->mMutex);
BQ_LOGV("getConsumerName: %s", mConsumerName.string());
return mConsumerName;
}
diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp
index e6150f4..9d045dd 100644
--- a/libs/gui/GraphicBufferAlloc.cpp
+++ b/libs/gui/GraphicBufferAlloc.cpp
@@ -32,19 +32,21 @@
}
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
- uint32_t height, PixelFormat format, uint32_t usage,
- std::string requestorName, status_t* error) {
+ uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint32_t usage, std::string requestorName, status_t* error) {
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(
- width, height, format, usage, std::move(requestorName)));
+ width, height, format, layerCount, usage,
+ std::move(requestorName)));
status_t err = graphicBuffer->initCheck();
*error = err;
if (err != 0 || graphicBuffer->handle == 0) {
if (err == NO_MEMORY) {
GraphicBuffer::dumpAllocationsToSystemLog();
}
- ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
+ ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%u, h=%u, lc=%u) "
"failed (%s), handle=%p",
- width, height, strerror(-err), graphicBuffer->handle);
+ width, height, layerCount, strerror(-err),
+ graphicBuffer->handle);
return 0;
}
return graphicBuffer;
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index 2fb380c..a3d3b74 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -45,13 +45,14 @@
virtual ~BpGraphicBufferAlloc();
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
- uint32_t height, PixelFormat format, uint32_t usage,
- std::string requestorName, status_t* error) {
+ uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint32_t usage, std::string requestorName, status_t* error) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
data.writeUint32(width);
data.writeUint32(height);
data.writeInt32(static_cast<int32_t>(format));
+ data.writeUint32(layerCount);
data.writeUint32(usage);
if (requestorName.empty()) {
requestorName += "[PID ";
@@ -106,12 +107,13 @@
uint32_t width = data.readUint32();
uint32_t height = data.readUint32();
PixelFormat format = static_cast<PixelFormat>(data.readInt32());
+ uint32_t layerCount = data.readUint32();
uint32_t usage = data.readUint32();
status_t error = NO_ERROR;
std::string requestorName;
data.readUtf8FromUtf16(&requestorName);
sp<GraphicBuffer> result = createGraphicBuffer(width, height,
- format, usage, requestorName, &error);
+ format, layerCount, usage, requestorName, &error);
reply->writeInt32(error);
if (result != 0) {
reply->write(*result);
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 3c7958f..092d597 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -35,7 +35,6 @@
"libbinder",
"libcutils",
"libgui",
- "libsync",
"libui",
"libutils",
],
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 0de60c9..1aa03a5 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -140,6 +140,14 @@
EXPECT_EQ(NATIVE_WINDOW_SURFACE, result);
}
+TEST_F(SurfaceTest, LayerCountIsOne) {
+ sp<ANativeWindow> anw(mSurface);
+ int result = -123;
+ int err = anw->query(anw.get(), NATIVE_WINDOW_LAYER_COUNT, &result);
+ EXPECT_EQ(NO_ERROR, err);
+ EXPECT_EQ(1, result);
+}
+
TEST_F(SurfaceTest, QueryConsumerUsage) {
const int TEST_USAGE_FLAGS =
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
diff --git a/libs/ui/Gralloc1.cpp b/libs/ui/Gralloc1.cpp
index 4c73ce4..367d1ce 100644
--- a/libs/ui/Gralloc1.cpp
+++ b/libs/ui/Gralloc1.cpp
@@ -77,6 +77,17 @@
mShimDevice.mDevice, mDeviceId, format, &mFormat);
}
+gralloc1_error_t Descriptor::setLayerCount(uint32_t layerCount)
+{
+ if (mShimDevice.hasCapability(GRALLOC1_CAPABILITY_LAYERED_BUFFERS)) {
+ return setHelper<uint32_t>(mShimDevice.mFunctions.setLayerCount.pfn,
+ mShimDevice.mDevice, mDeviceId, layerCount, &mLayerCount);
+ } else {
+ // Layered buffers are not supported on this device.
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+}
+
gralloc1_error_t Descriptor::setProducerUsage(gralloc1_producer_usage_t usage)
{
return setHelper<uint64_t>(mShimDevice.mFunctions.setProducerUsage.pfn,
@@ -366,6 +377,15 @@
mFunctions.allocate.load(mDevice, false);
}
+ if (hasCapability(GRALLOC1_CAPABILITY_LAYERED_BUFFERS)) {
+ if (!mFunctions.setLayerCount.load(mDevice, true)) {
+ return false;
+ }
+ if (!mFunctions.getLayerCount.load(mDevice, true)) {
+ return false;
+ }
+ }
+
return true;
}
diff --git a/libs/ui/Gralloc1On0Adapter.cpp b/libs/ui/Gralloc1On0Adapter.cpp
index d5b88de..111879a 100644
--- a/libs/ui/Gralloc1On0Adapter.cpp
+++ b/libs/ui/Gralloc1On0Adapter.cpp
@@ -97,6 +97,8 @@
return asFP<GRALLOC1_PFN_SET_DIMENSIONS>(setDimensionsHook);
case GRALLOC1_FUNCTION_SET_FORMAT:
return asFP<GRALLOC1_PFN_SET_FORMAT>(setFormatHook);
+ case GRALLOC1_FUNCTION_SET_LAYER_COUNT:
+ return asFP<GRALLOC1_PFN_SET_LAYER_COUNT>(setLayerCountHook);
case GRALLOC1_FUNCTION_SET_PRODUCER_USAGE:
return asFP<GRALLOC1_PFN_SET_PRODUCER_USAGE>(setProducerUsageHook);
case GRALLOC1_FUNCTION_GET_BACKING_STORE:
@@ -113,6 +115,10 @@
return asFP<GRALLOC1_PFN_GET_FORMAT>(
bufferHook<decltype(&Buffer::getFormat),
&Buffer::getFormat, int32_t*>);
+ case GRALLOC1_FUNCTION_GET_LAYER_COUNT:
+ return asFP<GRALLOC1_PFN_GET_LAYER_COUNT>(
+ bufferHook<decltype(&Buffer::getLayerCount),
+ &Buffer::getLayerCount, uint32_t*>);
case GRALLOC1_FUNCTION_GET_PRODUCER_USAGE:
return asFP<GRALLOC1_PFN_GET_PRODUCER_USAGE>(getProducerUsageHook);
case GRALLOC1_FUNCTION_GET_STRIDE:
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 6d72900..07164a4 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -50,6 +50,7 @@
height =
stride =
format =
+ layerCount =
usage = 0;
handle = NULL;
}
@@ -63,15 +64,33 @@
height =
stride =
format =
+ layerCount =
usage = 0;
handle = NULL;
- mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage,
+ mInitCheck = initSize(inWidth, inHeight, inFormat, 1, inUsage,
std::move(requestorName));
}
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inUsage, uint32_t inStride,
- native_handle_t* inHandle, bool keepOwnership)
+ PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
+ std::string requestorName)
+ : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
+{
+ width =
+ height =
+ stride =
+ format =
+ layerCount =
+ usage = 0;
+ handle = NULL;
+ mInitCheck = initSize(inWidth, inHeight, inFormat, inLayerCount, inUsage,
+ std::move(requestorName));
+}
+
+GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
+ PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
+ uint32_t inStride, native_handle_t* inHandle, bool keepOwnership)
: BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
@@ -80,6 +99,7 @@
height = static_cast<int>(inHeight);
stride = static_cast<int>(inStride);
format = inFormat;
+ layerCount = inLayerCount;
usage = static_cast<int>(inUsage);
handle = inHandle;
}
@@ -94,6 +114,7 @@
height = buffer->height;
stride = buffer->stride;
format = buffer->format;
+ layerCount = buffer->layerCount;
usage = buffer->usage;
handle = buffer->handle;
}
@@ -138,7 +159,7 @@
}
status_t GraphicBuffer::reallocate(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inUsage)
+ PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage)
{
if (mOwner != ownData)
return INVALID_OPERATION;
@@ -147,6 +168,7 @@
static_cast<int>(inWidth) == width &&
static_cast<int>(inHeight) == height &&
inFormat == format &&
+ inLayerCount == layerCount &&
static_cast<int>(inUsage) == usage)
return NO_ERROR;
@@ -155,30 +177,34 @@
allocator.free(handle);
handle = 0;
}
- return initSize(inWidth, inHeight, inFormat, inUsage, "[Reallocation]");
+ return initSize(inWidth, inHeight, inFormat, inLayerCount, inUsage,
+ "[Reallocation]");
}
bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inUsage)
+ PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage)
{
if (static_cast<int>(inWidth) != width) return true;
if (static_cast<int>(inHeight) != height) return true;
if (inFormat != format) return true;
+ if (inLayerCount != layerCount) return true;
if ((static_cast<uint32_t>(usage) & inUsage) != inUsage) return true;
return false;
}
status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inUsage, std::string requestorName)
+ PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
+ std::string requestorName)
{
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
uint32_t outStride = 0;
- status_t err = allocator.allocate(inWidth, inHeight, inFormat, inUsage,
- &handle, &outStride, mId, std::move(requestorName));
+ status_t err = allocator.allocate(inWidth, inHeight, inFormat, inLayerCount,
+ inUsage, &handle, &outStride, mId, std::move(requestorName));
if (err == NO_ERROR) {
width = static_cast<int>(inWidth);
height = static_cast<int>(inHeight);
format = inFormat;
+ layerCount = inLayerCount;
usage = static_cast<int>(inUsage);
stride = static_cast<int>(outStride);
}
@@ -284,7 +310,7 @@
}
size_t GraphicBuffer::getFlattenedSize() const {
- return static_cast<size_t>(11 + (handle ? handle->numInts : 0)) * sizeof(int);
+ return static_cast<size_t>(12 + (handle ? handle->numInts : 0)) * sizeof(int);
}
size_t GraphicBuffer::getFdCount() const {
@@ -304,19 +330,20 @@
buf[2] = height;
buf[3] = stride;
buf[4] = format;
- buf[5] = usage;
- buf[6] = static_cast<int32_t>(mId >> 32);
- buf[7] = static_cast<int32_t>(mId & 0xFFFFFFFFull);
- buf[8] = static_cast<int32_t>(mGenerationNumber);
- buf[9] = 0;
+ buf[5] = static_cast<int32_t>(layerCount);
+ buf[6] = usage;
+ buf[7] = static_cast<int32_t>(mId >> 32);
+ buf[8] = static_cast<int32_t>(mId & 0xFFFFFFFFull);
+ buf[9] = static_cast<int32_t>(mGenerationNumber);
buf[10] = 0;
+ buf[11] = 0;
if (handle) {
- buf[9] = handle->numFds;
- buf[10] = handle->numInts;
+ buf[10] = handle->numFds;
+ buf[11] = handle->numInts;
memcpy(fds, handle->data,
static_cast<size_t>(handle->numFds) * sizeof(int));
- memcpy(&buf[11], handle->data + handle->numFds,
+ memcpy(&buf[12], handle->data + handle->numFds,
static_cast<size_t>(handle->numInts) * sizeof(int));
}
@@ -332,28 +359,28 @@
status_t GraphicBuffer::unflatten(
void const*& buffer, size_t& size, int const*& fds, size_t& count) {
- if (size < 11 * sizeof(int)) return NO_MEMORY;
+ if (size < 12 * sizeof(int)) return NO_MEMORY;
int const* buf = static_cast<int const*>(buffer);
if (buf[0] != 'GBFR') return BAD_TYPE;
- const size_t numFds = static_cast<size_t>(buf[9]);
- const size_t numInts = static_cast<size_t>(buf[10]);
+ const size_t numFds = static_cast<size_t>(buf[10]);
+ const size_t numInts = static_cast<size_t>(buf[11]);
// Limit the maxNumber to be relatively small. The number of fds or ints
// should not come close to this number, and the number itself was simply
// chosen to be high enough to not cause issues and low enough to prevent
// overflow problems.
const size_t maxNumber = 4096;
- if (numFds >= maxNumber || numInts >= (maxNumber - 11)) {
- width = height = stride = format = usage = 0;
+ if (numFds >= maxNumber || numInts >= (maxNumber - 12)) {
+ width = height = stride = format = layerCount = usage = 0;
handle = NULL;
ALOGE("unflatten: numFds or numInts is too large: %zd, %zd",
numFds, numInts);
return BAD_VALUE;
}
- const size_t sizeNeeded = (11 + numInts) * sizeof(int);
+ const size_t sizeNeeded = (12 + numInts) * sizeof(int);
if (size < sizeNeeded) return NO_MEMORY;
size_t fdCountNeeded = numFds;
@@ -369,34 +396,35 @@
height = buf[2];
stride = buf[3];
format = buf[4];
- usage = buf[5];
+ layerCount = static_cast<uintptr_t>(buf[5]);
+ usage = buf[6];
native_handle* h = native_handle_create(
static_cast<int>(numFds), static_cast<int>(numInts));
if (!h) {
- width = height = stride = format = usage = 0;
+ width = height = stride = format = layerCount = usage = 0;
handle = NULL;
ALOGE("unflatten: native_handle_create failed");
return NO_MEMORY;
}
memcpy(h->data, fds, numFds * sizeof(int));
- memcpy(h->data + numFds, &buf[11], numInts * sizeof(int));
+ memcpy(h->data + numFds, &buf[12], numInts * sizeof(int));
handle = h;
} else {
- width = height = stride = format = usage = 0;
+ width = height = stride = format = layerCount = usage = 0;
handle = NULL;
}
- mId = static_cast<uint64_t>(buf[6]) << 32;
- mId |= static_cast<uint32_t>(buf[7]);
+ mId = static_cast<uint64_t>(buf[7]) << 32;
+ mId |= static_cast<uint32_t>(buf[8]);
- mGenerationNumber = static_cast<uint32_t>(buf[8]);
+ mGenerationNumber = static_cast<uint32_t>(buf[9]);
mOwner = ownHandle;
if (handle != 0) {
status_t err = mBufferMapper.registerBuffer(this);
if (err != NO_ERROR) {
- width = height = stride = format = usage = 0;
+ width = height = stride = format = layerCount = usage = 0;
handle = NULL;
ALOGE("unflatten: registerBuffer failed: %s (%d)",
strerror(-err), err);
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 693c7cb..e333bc1 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -64,15 +64,15 @@
for (size_t i=0 ; i<c ; i++) {
const alloc_rec_t& rec(list.valueAt(i));
if (rec.size) {
- snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x | %s\n",
+ snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%08x | %s\n",
list.keyAt(i), rec.size/1024.0f,
- rec.width, rec.stride, rec.height, rec.format, rec.usage,
- rec.requestorName.c_str());
+ rec.width, rec.stride, rec.height, rec.layerCount, rec.format,
+ rec.usage, rec.requestorName.c_str());
} else {
- snprintf(buffer, SIZE, "%10p: unknown | %4u (%4u) x %4u | %8X | 0x%08x | %s\n",
+ snprintf(buffer, SIZE, "%10p: unknown | %4u (%4u) x %4u | %4u | %8X | 0x%08x | %s\n",
list.keyAt(i),
- rec.width, rec.stride, rec.height, rec.format, rec.usage,
- rec.requestorName.c_str());
+ rec.width, rec.stride, rec.height, rec.layerCount, rec.format,
+ rec.usage, rec.requestorName.c_str());
}
result.append(buffer);
total += rec.size;
@@ -103,21 +103,22 @@
public:
HalBuffer(const Gralloc2::Allocator* allocator,
uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage)
+ PixelFormat format, uint32_t layerCount, uint32_t usage)
: mAllocator(allocator), mBufferValid(false)
{
Gralloc2::IAllocator::BufferDescriptorInfo info = {};
info.width = width;
info.height = height;
info.format = static_cast<Gralloc2::PixelFormat>(format);
+ info.layerCount = layerCount;
info.producerUsageMask = usage;
info.consumerUsageMask = usage;
Gralloc2::BufferDescriptor descriptor;
auto error = mAllocator->createBufferDescriptor(info, descriptor);
if (error != Gralloc2::Error::NONE) {
- ALOGE("Failed to create desc (%u x %u) format %d usage %u: %d",
- width, height, format, usage, error);
+ ALOGE("Failed to create desc (%u x %u) layerCount %u format %d usage %u: %d",
+ width, height, layerCount, format, usage, error);
return;
}
@@ -127,8 +128,8 @@
}
if (error != Gralloc2::Error::NONE) {
- ALOGE("Failed to allocate (%u x %u) format %d usage %u: %d",
- width, height, format, usage, error);
+ ALOGE("Failed to allocate (%u x %u) layerCount %u format %d usage %u: %d",
+ width, height, layerCount, format, usage, error);
mAllocator->destroyBufferDescriptor(descriptor);
return;
}
@@ -195,8 +196,9 @@
} // namespace
status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage, buffer_handle_t* handle,
- uint32_t* stride, uint64_t graphicBufferId, std::string requestorName)
+ PixelFormat format, uint32_t layerCount, uint32_t usage,
+ buffer_handle_t* handle, uint32_t* stride, uint64_t graphicBufferId,
+ std::string requestorName)
{
ATRACE_CALL();
@@ -205,12 +207,17 @@
if (!width || !height)
width = height = 1;
+ // Ensure that layerCount is valid.
+ if (layerCount < 1)
+ layerCount = 1;
+
// Filter out any usage bits that should not be passed to the gralloc module
usage &= GRALLOC_USAGE_ALLOC_MASK;
gralloc1_error_t error;
if (mAllocator->valid()) {
- HalBuffer buffer(mAllocator.get(), width, height, format, usage);
+ HalBuffer buffer(mAllocator.get(), width, height, format, layerCount,
+ usage);
if (!buffer.exportHandle(mMapper, handle, stride)) {
return NO_MEMORY;
}
@@ -229,6 +236,17 @@
ALOGE("Failed to set format to %d: %d", format, error);
return BAD_VALUE;
}
+ if (mDevice->hasCapability(GRALLOC1_CAPABILITY_LAYERED_BUFFERS)) {
+ error = descriptor->setLayerCount(layerCount);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to set layer count to %u: %d", layerCount, error);
+ return BAD_VALUE;
+ }
+ } else if (layerCount > 1) {
+ ALOGE("Failed to set layer count to %u: capability unsupported",
+ layerCount);
+ return BAD_VALUE;
+ }
error = descriptor->setProducerUsage(
static_cast<gralloc1_producer_usage_t>(usage));
if (error != GRALLOC1_ERROR_NONE) {
@@ -244,8 +262,8 @@
error = mDevice->allocate(descriptor, graphicBufferId, handle);
if (error != GRALLOC1_ERROR_NONE) {
- ALOGE("Failed to allocate (%u x %u) format %d usage %u: %d",
- width, height, format, usage, error);
+ ALOGE("Failed to allocate (%u x %u) layerCount %u format %d usage %u: %d",
+ width, height, layerCount, format, usage, error);
return NO_MEMORY;
}
@@ -264,6 +282,7 @@
rec.height = height;
rec.stride = *stride;
rec.format = format;
+ rec.layerCount = layerCount;
rec.usage = usage;
rec.size = static_cast<size_t>(height * (*stride) * bpp);
rec.requestorName = std::move(requestorName);
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 8e69330..7cb608e 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -607,6 +607,7 @@
#ifndef EGL_ANDROID_create_native_client_buffer
#define EGL_ANDROID_create_native_client_buffer 1
+#define EGL_LAYER_COUNT_ANDROID 0x3434
#define EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143
#define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001
#define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 3f2861f..0bfefd0 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1802,6 +1802,7 @@
uint32_t width = 0;
uint32_t height = 0;
uint32_t format = 0;
+ uint32_t layer_count = 1;
uint32_t red_size = 0;
uint32_t green_size = 0;
uint32_t blue_size = 0;
@@ -1827,6 +1828,7 @@
GET_NONNEGATIVE_VALUE(EGL_GREEN_SIZE, green_size);
GET_NONNEGATIVE_VALUE(EGL_BLUE_SIZE, blue_size);
GET_NONNEGATIVE_VALUE(EGL_ALPHA_SIZE, alpha_size);
+ GET_NONNEGATIVE_VALUE(EGL_LAYER_COUNT_ANDROID, layer_count);
case EGL_NATIVE_BUFFER_USAGE_ANDROID:
if (value & EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID) {
usage |= GRALLOC_USAGE_PROTECTED;
@@ -1862,7 +1864,7 @@
alpha_size == 0) {
format = HAL_PIXEL_FORMAT_RGB_565;
} else {
- ALOGE("Invalid native pixel format { r=%d, g=%d, b=%d, a=%d }",
+ ALOGE("Invalid native pixel format { r=%u, g=%u, b=%u, a=%u }",
red_size, green_size, blue_size, alpha_size);
return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
}
@@ -1907,7 +1909,9 @@
CHECK_ERROR_CONDITION("Unable to write height");
err = data.writeInt32(static_cast<int32_t>(format));
CHECK_ERROR_CONDITION("Unable to write format");
- err = data.writeUint32(usage);
+ err = data.writeUint32(layer_count);
+ CHECK_ERROR_CONDITION("Unable to write layer count");
+ err = data.writeUint32(usage);
CHECK_ERROR_CONDITION("Unable to write usage");
err = data.writeUtf8AsUtf16(
std::string("[eglCreateNativeClientBufferANDROID pid ") +
@@ -1924,12 +1928,13 @@
err = gBuffer->initCheck();
if (err != NO_ERROR) {
- ALOGE("Unable to create native buffer { w=%d, h=%d, f=%d, u=%#x }: %#x",
- width, height, format, usage, err);
+ ALOGE("Unable to create native buffer "
+ "{ w=%u, h=%u, f=%u, u=%#x, lc=%u}: %#x", width, height, format,
+ usage, layer_count, err);
goto error_condition;
}
- ALOGD("Created new native buffer %p { w=%d, h=%d, f=%d, u=%#x }",
- gBuffer, width, height, format, usage);
+ ALOGV("Created new native buffer %p { w=%u, h=%u, f=%u, u=%#x, lc=%u}",
+ gBuffer, width, height, format, usage, layer_count);
return static_cast<EGLClientBuffer>(gBuffer->getNativeBuffer());
#undef CHECK_ERROR_CONDITION
diff --git a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt b/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
index a6fae80..9b2bbbc 100644
--- a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
+++ b/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
@@ -20,7 +20,7 @@
Version
- Version 1, January 19, 2016
+ Version 1.1, October 26, 2016
Number
@@ -53,6 +53,7 @@
New Tokens
+ EGL_NATIVE_BUFFER_LAYER_COUNT_ANDROID 0x3434
EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143
EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001
EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002
@@ -103,6 +104,8 @@
| EGL_ALPHA_SIZE | The bits of Alpha in | 0 |
| | the color buffer | |
| | buffer data | |
+ | EGL_LAYER_COUNT_ANDROID | The number of image | 1 |
+ | | layers in the buffer | |
| EGL_NATIVE_BUFFER_USAGE_ANDROID | The usage bits of | 0 |
| | the buffer data | |
+---------------------------------+----------------------+---------------+
@@ -114,8 +117,10 @@
EGL_RED_SIZE, EGL_GREEN_SIZE, and EGL_BLUE_SIZE must be non-zero and
correspond to a valid pixel format for the implementation. If EGL_ALPHA_SIZE
is non-zero then the combination of all four sizes must correspond to a
- valid pixel format for the implementation. The
- EGL_NATIVE_BUFFER_USAGE_ANDROID flag may include any of the following bits:
+ valid pixel format for the implementation. The value of
+ EGL_LAYER_COUNT_ANDROID must be a valid number of image layers for the
+ implementation. The EGL_NATIVE_BUFFER_USAGE_ANDROID flag may include any of
+ the following bits:
EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID: Indicates that the
created buffer must have a hardware-protected path to external display
@@ -189,6 +194,10 @@
Revision History
+#3 (Craig Donner, October 26, 2016)
+ - Added EGL_LAYER_COUNT_ANDROID for creating buffers that back texture
+ arrays.
+
#2 (Craig Donner, April 15, 2016)
- Set color formats and usage bits explicitly using additional attributes,
and add value for new token EGL_NATIVE_BUFFER_USAGE_ANDROID.
diff --git a/services/sensorservice/SensorDeviceTreble.cpp b/services/sensorservice/SensorDeviceTreble.cpp
index 66b0f5a..6f946d0 100644
--- a/services/sensorservice/SensorDeviceTreble.cpp
+++ b/services/sensorservice/SensorDeviceTreble.cpp
@@ -27,7 +27,7 @@
#include "SensorDevice.h"
#include "SensorService.h"
-#include "convert.h"
+#include <sensors/convert.h>
using android::hardware::sensors::V1_0::ISensors;
using android::hardware::hidl_vec;
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index ba036dd..3800ce8 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -15,6 +15,7 @@
GpuService.cpp \
Layer.cpp \
LayerDim.cpp \
+ LayerRejecter.cpp \
MessageQueue.cpp \
MonitoredProducer.cpp \
SurfaceFlingerConsumer.cpp \
@@ -51,7 +52,11 @@
LOCAL_SRC_FILES += \
SurfaceFlinger.cpp \
DisplayHardware/HWComposer.cpp
+ ifeq ($(TARGET_USES_HWC2ON1ADAPTER), true)
+ LOCAL_CFLAGS += -DBYPASS_IHWC
+ endif
else
+ LOCAL_CFLAGS += -DBYPASS_IHWC
LOCAL_SRC_FILES += \
SurfaceFlinger_hwc1.cpp \
DisplayHardware/HWComposer_hwc1.cpp
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index c79caf4..31af8a1 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -614,6 +614,8 @@
auto error = static_cast<Error>(intError);
if (error != Error::None) {
+ ALOGE("Unable to get active config for mId:[%" PRIu64 "]", mId);
+ *outConfig = nullptr;
return error;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 1145ba1..1c709b2 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -17,10 +17,6 @@
#ifndef ANDROID_SF_HWC2_H
#define ANDROID_SF_HWC2_H
-#ifndef USE_HWC2
-#define BYPASS_IHWC
-#endif
-
#define HWC2_INCLUDE_STRINGIFICATION
#define HWC2_USE_CPP11
#include <hardware/hwcomposer2.h>
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
index b699b2c..1107c99 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
@@ -1841,29 +1841,39 @@
auto activeConfig = mDevice.mHwc1Device->getActiveConfig(
mDevice.mHwc1Device, mHwc1Id);
- if (activeConfig >= 0) {
- for (const auto& config : mConfigs) {
- if (config->hasHwc1Id(activeConfig)) {
- ALOGV("Setting active config to %d for HWC1 config %u",
- config->getId(), activeConfig);
- mActiveConfig = config;
- if (config->getColorModeForHwc1Id(activeConfig, &mActiveColorMode) != Error::None) {
- // This should never happen since we checked for the config's presence before
- // setting it as active.
- ALOGE("Unable to find color mode for active HWC1 config %d",
- config->getId());
- mActiveColorMode = HAL_COLOR_MODE_NATIVE;
- }
- break;
+
+ // Some devices startup without an activeConfig:
+ // We need to set one ourselves.
+ if (activeConfig == HWC_ERROR) {
+ ALOGV("There is no active configuration: Picking the first one: 0.");
+ const int defaultIndex = 0;
+ mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device, mHwc1Id, defaultIndex);
+ activeConfig = defaultIndex;
+ }
+
+ for (const auto& config : mConfigs) {
+ if (config->hasHwc1Id(activeConfig)) {
+ ALOGE("Setting active config to %d for HWC1 config %u", config->getId(), activeConfig);
+ mActiveConfig = config;
+ if (config->getColorModeForHwc1Id(activeConfig, &mActiveColorMode) != Error::None) {
+ // This should never happen since we checked for the config's presence before
+ // setting it as active.
+ ALOGE("Unable to find color mode for active HWC1 config %d", config->getId());
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
}
- }
- if (!mActiveConfig) {
- ALOGV("Unable to find active HWC1 config %u, defaulting to "
- "config 0", activeConfig);
- mActiveConfig = mConfigs[0];
- mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+ break;
}
}
+ if (!mActiveConfig) {
+ ALOGV("Unable to find active HWC1 config %u, defaulting to "
+ "config 0", activeConfig);
+ mActiveConfig = mConfigs[0];
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+ }
+
+
+
+
}
void HWC2On1Adapter::Display::reallocateHwc1Contents()
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index bb2e45a..82a900c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -346,14 +346,14 @@
std::shared_ptr<const HWC2::Display::Config>
HWComposer::getActiveConfig(int32_t displayId) const {
if (!isValidDisplay(displayId)) {
- ALOGE("getActiveConfigs: Attempted to access invalid display %d",
+ ALOGV("getActiveConfigs: Attempted to access invalid display %d",
displayId);
return nullptr;
}
std::shared_ptr<const HWC2::Display::Config> config;
auto error = mDisplayData[displayId].hwcDisplay->getActiveConfig(&config);
if (error == HWC2::Error::BadConfig) {
- ALOGV("getActiveConfig: No config active, returning null");
+ ALOGE("getActiveConfig: No config active, returning null");
return nullptr;
} else if (error != HWC2::Error::None) {
ALOGE("getActiveConfig failed for display %d: %s (%d)", displayId,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f9e93d3..5f96f66 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -44,6 +44,7 @@
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "Layer.h"
+#include "LayerRejecter.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
@@ -1786,6 +1787,32 @@
#endif
}
+bool Layer::allTransactionsSignaled() {
+ auto headFrameNumber = getHeadFrameNumber();
+ bool matchingFramesFound = false;
+ bool allTransactionsApplied = true;
+ Mutex::Autolock lock(mLocalSyncPointMutex);
+
+ for (auto& point : mLocalSyncPoints) {
+ if (point->getFrameNumber() > headFrameNumber) {
+ break;
+ }
+ matchingFramesFound = true;
+
+ if (!point->frameIsAvailable()) {
+ // We haven't notified the remote layer that the frame for
+ // this point is available yet. Notify it now, and then
+ // abort this attempt to latch.
+ point->setFrameAvailable();
+ allTransactionsApplied = false;
+ break;
+ }
+
+ allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied();
+ }
+ return !matchingFramesFound || allTransactionsApplied;
+}
+
Region Layer::latchBuffer(bool& recomputeVisibleRegions)
{
ATRACE_CALL();
@@ -1829,163 +1856,7 @@
const bool oldOpacity = isOpaque(s);
sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
- struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
- Layer::State& front;
- Layer::State& current;
- bool& recomputeVisibleRegions;
- bool stickyTransformSet;
- const char* name;
- int32_t overrideScalingMode;
- bool& freezePositionUpdates;
-
- Reject(Layer::State& front, Layer::State& current,
- bool& recomputeVisibleRegions, bool stickySet,
- const char* name,
- int32_t overrideScalingMode,
- bool& freezePositionUpdates)
- : front(front), current(current),
- recomputeVisibleRegions(recomputeVisibleRegions),
- stickyTransformSet(stickySet),
- name(name),
- overrideScalingMode(overrideScalingMode),
- freezePositionUpdates(freezePositionUpdates) {
- }
-
- virtual bool reject(const sp<GraphicBuffer>& buf,
- const BufferItem& item) {
- if (buf == NULL) {
- return false;
- }
-
- uint32_t bufWidth = buf->getWidth();
- uint32_t bufHeight = buf->getHeight();
-
- // check that we received a buffer of the right size
- // (Take the buffer's orientation into account)
- if (item.mTransform & Transform::ROT_90) {
- swap(bufWidth, bufHeight);
- }
-
- int actualScalingMode = overrideScalingMode >= 0 ?
- overrideScalingMode : item.mScalingMode;
- bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
- if (front.active != front.requested) {
-
- if (isFixedSize ||
- (bufWidth == front.requested.w &&
- bufHeight == front.requested.h))
- {
- // Here we pretend the transaction happened by updating the
- // current and drawing states. Drawing state is only accessed
- // in this thread, no need to have it locked
- front.active = front.requested;
-
- // We also need to update the current state so that
- // we don't end-up overwriting the drawing state with
- // this stale current state during the next transaction
- //
- // NOTE: We don't need to hold the transaction lock here
- // because State::active is only accessed from this thread.
- current.active = front.active;
- current.modified = true;
-
- // recompute visible region
- recomputeVisibleRegions = true;
- }
-
- ALOGD_IF(DEBUG_RESIZE,
- "[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n"
- " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
- " requested={ wh={%4u,%4u} }}\n",
- name,
- bufWidth, bufHeight, item.mTransform, item.mScalingMode,
- front.active.w, front.active.h,
- front.crop.left,
- front.crop.top,
- front.crop.right,
- front.crop.bottom,
- front.crop.getWidth(),
- front.crop.getHeight(),
- front.requested.w, front.requested.h);
- }
-
- if (!isFixedSize && !stickyTransformSet) {
- if (front.active.w != bufWidth ||
- front.active.h != bufHeight) {
- // reject this buffer
- ALOGE("[%s] rejecting buffer: "
- "bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}",
- name, bufWidth, bufHeight, front.active.w, front.active.h);
- return true;
- }
- }
-
- // if the transparent region has changed (this test is
- // conservative, but that's fine, worst case we're doing
- // a bit of extra work), we latch the new one and we
- // trigger a visible-region recompute.
- if (!front.activeTransparentRegion.isTriviallyEqual(
- front.requestedTransparentRegion)) {
- front.activeTransparentRegion = front.requestedTransparentRegion;
-
- // We also need to update the current state so that
- // we don't end-up overwriting the drawing state with
- // this stale current state during the next transaction
- //
- // NOTE: We don't need to hold the transaction lock here
- // because State::active is only accessed from this thread.
- current.activeTransparentRegion = front.activeTransparentRegion;
-
- // recompute visible region
- recomputeVisibleRegions = true;
- }
-
- if (front.crop != front.requestedCrop) {
- front.crop = front.requestedCrop;
- current.crop = front.requestedCrop;
- recomputeVisibleRegions = true;
- }
- freezePositionUpdates = false;
-
- return false;
- }
- };
-
- Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
- getProducerStickyTransform() != 0, mName.string(),
- mOverrideScalingMode, mFreezePositionUpdates);
-
-
- // Check all of our local sync points to ensure that all transactions
- // which need to have been applied prior to the frame which is about to
- // be latched have signaled
-
- auto headFrameNumber = getHeadFrameNumber();
- bool matchingFramesFound = false;
- bool allTransactionsApplied = true;
- {
- Mutex::Autolock lock(mLocalSyncPointMutex);
- for (auto& point : mLocalSyncPoints) {
- if (point->getFrameNumber() > headFrameNumber) {
- break;
- }
-
- matchingFramesFound = true;
-
- if (!point->frameIsAvailable()) {
- // We haven't notified the remote layer that the frame for
- // this point is available yet. Notify it now, and then
- // abort this attempt to latch.
- point->setFrameAvailable();
- allTransactionsApplied = false;
- break;
- }
-
- allTransactionsApplied &= point->transactionIsApplied();
- }
- }
-
- if (matchingFramesFound && !allTransactionsApplied) {
+ if (!allTransactionsSignaled()) {
mFlinger->signalLayerUpdate();
return outDirtyRegion;
}
@@ -1995,6 +1866,9 @@
// BufferItem's that weren't actually queued. This can happen in shared
// buffer mode.
bool queuedBuffer = false;
+ LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
+ getProducerStickyTransform() != 0, mName.string(),
+ mOverrideScalingMode, mFreezePositionUpdates);
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
mLastFrameNumberReceived);
@@ -2056,12 +1930,6 @@
mFlinger->signalLayerUpdate();
}
- if (updateResult != NO_ERROR) {
- // something happened!
- recomputeVisibleRegions = true;
- return outDirtyRegion;
- }
-
// update the active buffer
mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
if (mActiveBuffer == NULL) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index efb0fb8..64b049c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -558,6 +558,11 @@
// -----------------------------------------------------------------------
+ // Check all of the local sync points to ensure that all transactions
+ // which need to have been applied prior to the frame which is about to
+ // be latched have signaled
+ bool allTransactionsSignaled();
+
// constants
sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
sp<IGraphicBufferProducer> mProducer;
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
new file mode 100644
index 0000000..2bc0605
--- /dev/null
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2011 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 "LayerRejecter.h"
+
+#include "clz.h"
+
+#define DEBUG_RESIZE 0
+
+namespace android {
+
+LayerRejecter::LayerRejecter(Layer::State& front,
+ Layer::State& current,
+ bool& recomputeVisibleRegions,
+ bool stickySet,
+ const char* name,
+ int32_t overrideScalingMode,
+ bool& freezePositionUpdates)
+ : mFront(front),
+ mCurrent(current),
+ mRecomputeVisibleRegions(recomputeVisibleRegions),
+ mStickyTransformSet(stickySet),
+ mName(name),
+ mOverrideScalingMode(overrideScalingMode),
+ mFreezePositionUpdates(freezePositionUpdates) {}
+
+bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item) {
+ if (buf == NULL) {
+ return false;
+ }
+
+ uint32_t bufWidth = buf->getWidth();
+ uint32_t bufHeight = buf->getHeight();
+
+ // check that we received a buffer of the right size
+ // (Take the buffer's orientation into account)
+ if (item.mTransform & Transform::ROT_90) {
+ swap(bufWidth, bufHeight);
+ }
+
+ int actualScalingMode = mOverrideScalingMode >= 0 ? mOverrideScalingMode : item.mScalingMode;
+ bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ if (mFront.active != mFront.requested) {
+ if (isFixedSize || (bufWidth == mFront.requested.w && bufHeight == mFront.requested.h)) {
+ // Here we pretend the transaction happened by updating the
+ // current and drawing states. Drawing state is only accessed
+ // in this thread, no need to have it locked
+ mFront.active = mFront.requested;
+
+ // We also need to update the current state so that
+ // we don't end-up overwriting the drawing state with
+ // this stale current state during the next transaction
+ //
+ // NOTE: We don't need to hold the transaction lock here
+ // because State::active is only accessed from this thread.
+ mCurrent.active = mFront.active;
+ mCurrent.modified = true;
+
+ // recompute visible region
+ mRecomputeVisibleRegions = true;
+ }
+
+ ALOGD_IF(DEBUG_RESIZE,
+ "[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n"
+ " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) "
+ "}\n"
+ " requested={ wh={%4u,%4u} }}\n",
+ mName, bufWidth, bufHeight, item.mTransform, item.mScalingMode, mFront.active.w,
+ mFront.active.h, mFront.crop.left, mFront.crop.top, mFront.crop.right,
+ mFront.crop.bottom, mFront.crop.getWidth(), mFront.crop.getHeight(),
+ mFront.requested.w, mFront.requested.h);
+ }
+
+ if (!isFixedSize && !mStickyTransformSet) {
+ if (mFront.active.w != bufWidth || mFront.active.h != bufHeight) {
+ // reject this buffer
+ ALOGE("[%s] rejecting buffer: "
+ "bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}",
+ mName, bufWidth, bufHeight, mFront.active.w, mFront.active.h);
+ return true;
+ }
+ }
+
+ // if the transparent region has changed (this test is
+ // conservative, but that's fine, worst case we're doing
+ // a bit of extra work), we latch the new one and we
+ // trigger a visible-region recompute.
+ if (!mFront.activeTransparentRegion.isTriviallyEqual(mFront.requestedTransparentRegion)) {
+ mFront.activeTransparentRegion = mFront.requestedTransparentRegion;
+
+ // We also need to update the current state so that
+ // we don't end-up overwriting the drawing state with
+ // this stale current state during the next transaction
+ //
+ // NOTE: We don't need to hold the transaction lock here
+ // because State::active is only accessed from this thread.
+ mCurrent.activeTransparentRegion = mFront.activeTransparentRegion;
+
+ // recompute visible region
+ mRecomputeVisibleRegions = true;
+ }
+
+ if (mFront.crop != mFront.requestedCrop) {
+ mFront.crop = mFront.requestedCrop;
+ mCurrent.crop = mFront.requestedCrop;
+ mRecomputeVisibleRegions = true;
+ }
+ mFreezePositionUpdates = false;
+
+ return false;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h
new file mode 100644
index 0000000..c2a9483
--- /dev/null
+++ b/services/surfaceflinger/LayerRejecter.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 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_LAYER_REJECTER_H
+#define ANDROID_LAYER_REJECTER_H
+
+#include "Layer.h"
+#include "SurfaceFlingerConsumer.h"
+
+namespace android {
+ class LayerRejecter : public SurfaceFlingerConsumer::BufferRejecter {
+ public:
+ LayerRejecter(Layer::State &front,
+ Layer::State ¤t,
+ bool &recomputeVisibleRegions,
+ bool stickySet,
+ const char *name,
+ int32_t overrideScalingMode,
+ bool &freezePositionUpdates);
+
+ virtual bool reject(const sp<GraphicBuffer> &buf, const BufferItem &item);
+
+ private:
+ Layer::State &mFront;
+ Layer::State &mCurrent;
+ bool &mRecomputeVisibleRegions;
+ bool mStickyTransformSet;
+ const char *mName;
+ int32_t mOverrideScalingMode;
+ bool &mFreezePositionUpdates;
+ };
+} // namespace android
+
+#endif // ANDROID_LAYER_REJECTER_H
\ No newline at end of file
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 99a9265..37fd70d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -91,19 +91,6 @@
EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-// Workaround for b/30067360: /proc/self/environ inaccessible in SurfaceFlinger
-// => ASan fails to read ASAN_OPTIONS => alloc-dealloc-mismatch bug is not
-// suppressed and prevents the device from booting.
-#ifndef __has_feature
-#define __has_feature(x) 0
-#endif
-#if __has_feature(address_sanitizer)
-__attribute__((visibility("default")))
-extern "C" const char* __asan_default_options() {
- return "alloc_dealloc_mismatch=0";
-}
-#endif
-
namespace android {
// This is the phase offset in nanoseconds of the software vsync event
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 3ae2c04..8e5c565 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -93,19 +93,6 @@
EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-// Workaround for b/30067360: /proc/self/environ inaccessible in SurfaceFlinger
-// => ASan fails to read ASAN_OPTIONS => alloc-dealloc-mismatch bug is not
-// suppressed and prevents the device from booting.
-#ifndef __has_feature
-#define __has_feature(x) 0
-#endif
-#if __has_feature(address_sanitizer)
-__attribute__((visibility("default")))
-extern "C" const char *__asan_default_options() {
- return "alloc_dealloc_mismatch=0";
-}
-#endif
-
namespace android {
// This is the phase offset in nanoseconds of the software vsync event