Show bugreport progress.
am: 97b73a0daf -s ours
Change-Id: Ieebb19470dc463ecc1514d01afc30ea237786fe9
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index 8a3eb08..9ed44a7 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -14,23 +14,40 @@
* limitations under the License.
*/
+#define TRACE_TAG ADB
+
+#include "bugreport.h"
+
#include <string>
+#include <vector>
#include <android-base/strings.h>
-#include "bugreport.h"
+#include "sysdeps.h"
+#include "adb_utils.h"
#include "file_sync_service.h"
-static constexpr char BUGZ_OK_PREFIX[] = "OK:";
-static constexpr char BUGZ_FAIL_PREFIX[] = "FAIL:";
+static constexpr char BUGZ_BEGIN_PREFIX[] = "BEGIN:";
static constexpr char BUGZ_PROGRESS_PREFIX[] = "PROGRESS:";
static constexpr char BUGZ_PROGRESS_SEPARATOR[] = "/";
+static constexpr char BUGZ_OK_PREFIX[] = "OK:";
+static constexpr char BUGZ_FAIL_PREFIX[] = "FAIL:";
// Custom callback used to handle the output of zipped bugreports.
class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface {
public:
- BugreportStandardStreamsCallback(const std::string& dest_file, bool show_progress, Bugreport* br)
- : br_(br), dest_file_(dest_file), show_progress_(show_progress), status_(-1), line_() {
+ BugreportStandardStreamsCallback(const std::string& dest_dir, const std::string& dest_file,
+ bool show_progress, Bugreport* br)
+ : br_(br),
+ src_file_(),
+ dest_dir_(dest_dir),
+ dest_file_(dest_file),
+ line_message_(),
+ invalid_lines_(),
+ show_progress_(show_progress),
+ status_(0),
+ line_() {
+ SetLineMessage();
}
void OnStdout(const char* buffer, int length) {
@@ -49,28 +66,72 @@
OnStream(nullptr, stderr, buffer, length);
}
int Done(int unused_) {
- // Process remaining line, if any...
+ // Process remaining line, if any.
ProcessLine(line_);
- // ..then return.
+
+ // Warn about invalid lines, if any.
+ if (!invalid_lines_.empty()) {
+ fprintf(stderr,
+ "WARNING: bugreportz generated %zu line(s) with unknown commands, "
+ "device might not support zipped bugreports:\n",
+ invalid_lines_.size());
+ for (const auto& line : invalid_lines_) {
+ fprintf(stderr, "\t%s\n", line.c_str());
+ }
+ fprintf(stderr,
+ "If the zipped bugreport was not generated, try 'adb bugreport' instead.\n");
+ }
+
+ // Pull the generated bug report.
+ if (status_ == 0) {
+ if (src_file_.empty()) {
+ fprintf(stderr, "bugreportz did not return a '%s' or '%s' line\n", BUGZ_OK_PREFIX,
+ BUGZ_FAIL_PREFIX);
+ return -1;
+ }
+ std::string destination;
+ if (dest_dir_.empty()) {
+ destination = dest_file_;
+ } else {
+ destination = android::base::StringPrintf("%s%c%s", dest_dir_.c_str(),
+ OS_PATH_SEPARATOR, dest_file_.c_str());
+ }
+ std::vector<const char*> srcs{src_file_.c_str()};
+ status_ =
+ br_->DoSyncPull(srcs, destination.c_str(), true, line_message_.c_str()) ? 0 : 1;
+ if (status_ != 0) {
+ fprintf(stderr,
+ "Bug report finished but could not be copied to '%s'.\n"
+ "Try to run 'adb pull %s <directory>'\n"
+ "to copy it to a directory that can be written.\n",
+ destination.c_str(), src_file_.c_str());
+ }
+ }
return status_;
}
private:
+ void SetLineMessage() {
+ line_message_ =
+ android::base::StringPrintf("generating %s", adb_basename(dest_file_).c_str());
+ }
+
+ void SetSrcFile(const std::string path) {
+ src_file_ = path;
+ if (!dest_dir_.empty()) {
+ // Only uses device-provided name when user passed a directory.
+ dest_file_ = adb_basename(path);
+ SetLineMessage();
+ }
+ }
+
void ProcessLine(const std::string& line) {
if (line.empty()) return;
- if (android::base::StartsWith(line, BUGZ_OK_PREFIX)) {
- if (show_progress_) {
- // Make sure pull message doesn't conflict with generation message.
- br_->UpdateProgress(dest_file_, 100, 100, true);
- }
-
- const char* zip_file = &line[strlen(BUGZ_OK_PREFIX)];
- std::vector<const char*> srcs{zip_file};
- status_ = br_->DoSyncPull(srcs, dest_file_.c_str(), true, dest_file_.c_str()) ? 0 : 1;
- if (status_ != 0) {
- fprintf(stderr, "Could not copy file '%s' to '%s'\n", zip_file, dest_file_.c_str());
- }
+ if (android::base::StartsWith(line, BUGZ_BEGIN_PREFIX)) {
+ SetSrcFile(&line[strlen(BUGZ_BEGIN_PREFIX)]);
+ } else if (android::base::StartsWith(line, BUGZ_OK_PREFIX)) {
+ SetSrcFile(&line[strlen(BUGZ_OK_PREFIX)]);
} else if (android::base::StartsWith(line, BUGZ_FAIL_PREFIX)) {
const char* error_message = &line[strlen(BUGZ_FAIL_PREFIX)];
fprintf(stderr, "Device failed to take a zipped bugreport: %s\n", error_message);
@@ -84,23 +145,38 @@
size_t idx2 = line.rfind(BUGZ_PROGRESS_SEPARATOR);
int progress = std::stoi(line.substr(idx1, (idx2 - idx1)));
int total = std::stoi(line.substr(idx2 + 1));
- br_->UpdateProgress(dest_file_, progress, total);
+ br_->UpdateProgress(line_message_, progress, total);
} else {
- fprintf(stderr,
- "WARNING: unexpected line (%s) returned by bugreportz, "
- "device probably does not support zipped bugreports.\n"
- "Try 'adb bugreport' instead.",
- line.c_str());
+ invalid_lines_.push_back(line);
}
}
Bugreport* br_;
- const std::string dest_file_;
+
+ // Path of bugreport on device.
+ std::string src_file_;
+
+ // Bugreport destination on host, depending on argument passed on constructor:
+ // - if argument is a directory, dest_dir_ is set with it and dest_file_ will be the name
+ // of the bugreport reported by the device.
+ // - if argument is empty, dest_dir is set as the current directory and dest_file_ will be the
+ // name of the bugreport reported by the device.
+ // - otherwise, dest_dir_ is not set and dest_file_ is set with the value passed on constructor.
+ std::string dest_dir_, dest_file_;
+
+ // Message displayed on LinePrinter, it's updated every time the destination above change.
+ std::string line_message_;
+
+ // Lines sent by bugreportz that contain invalid commands; will be displayed at the end.
+ std::vector<std::string> invalid_lines_;
+
+ // Whether PROGRESS_LINES should be interpreted as progress.
bool show_progress_;
+
+ // Overall process of the operation, as returned by Done().
int status_;
- // Temporary buffer containing the characters read since the last newline
- // (\n).
+ // Temporary buffer containing the characters read since the last newline (\n).
std::string line_;
DISALLOW_COPY_AND_ASSIGN(BugreportStandardStreamsCallback);
@@ -110,34 +186,62 @@
int usage();
int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc, const char** argv) {
- if (argc == 1) return SendShellCommand(transport_type, serial, "bugreport", false);
- if (argc != 2) return usage();
-
- // Zipped bugreport option - will call 'bugreportz', which prints the location
- // of the generated
- // file, then pull it to the destination file provided by the user.
- std::string dest_file = argv[1];
- if (!android::base::EndsWith(argv[1], ".zip")) {
- // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase
- dest_file += ".zip";
- }
+ if (argc > 2) return usage();
// Gets bugreportz version.
- std::string bugz_stderr;
- DefaultStandardStreamsCallback version_callback(nullptr, &bugz_stderr);
+ std::string bugz_stdout, bugz_stderr;
+ DefaultStandardStreamsCallback version_callback(&bugz_stdout, &bugz_stderr);
int status = SendShellCommand(transport_type, serial, "bugreportz -v", false, &version_callback);
-
- if (status != 0) {
- fprintf(stderr,
- "Failed to get bugreportz version: 'bugreport -v' returned '%s' "
- "(code %d)."
- "\nIf the device does not support it, try running 'adb bugreport' "
- "to get a "
- "flat-file bugreport.",
- bugz_stderr.c_str(), status);
- return status;
- }
std::string bugz_version = android::base::Trim(bugz_stderr);
+ std::string bugz_output = android::base::Trim(bugz_stdout);
+
+ if (status != 0 || bugz_version.empty()) {
+ D("'bugreportz' -v results: status=%d, stdout='%s', stderr='%s'", status,
+ bugz_output.c_str(), bugz_version.c_str());
+ if (argc == 1) {
+ // Device does not support bugreportz: if called as 'adb bugreport', just falls out to
+ // the flat-file version.
+ fprintf(stderr,
+ "Failed to get bugreportz version, which is only available on devices "
+ "running Android 7.0 or later.\nTrying a plain-text bug report instead.\n");
+ return SendShellCommand(transport_type, serial, "bugreport", false);
+ }
+
+ // But if user explicitly asked for a zipped bug report, fails instead (otherwise calling
+ // 'bugreport' would generate a lot of output the user might not be prepared to handle).
+ fprintf(stderr,
+ "Failed to get bugreportz version: 'bugreportz -v' returned '%s' (code %d).\n"
+ "If the device does not run Android 7.0 or above, try 'adb bugreport' instead.\n",
+ bugz_output.c_str(), status);
+ return status != 0 ? status : -1;
+ }
+
+ std::string dest_file, dest_dir;
+
+ if (argc == 1) {
+ // No args - use current directory
+ if (!getcwd(&dest_dir)) {
+ perror("adb: getcwd failed");
+ return 1;
+ }
+ } else {
+ // Check whether argument is a directory or file
+ if (directory_exists(argv[1])) {
+ dest_dir = argv[1];
+ } else {
+ dest_file = argv[1];
+ }
+ }
+
+ if (dest_file.empty()) {
+ // Uses a default value until device provides the proper name
+ dest_file = "bugreport.zip";
+ } else {
+ if (!android::base::EndsWith(dest_file, ".zip")) {
+ // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase
+ dest_file += ".zip";
+ }
+ }
bool show_progress = true;
std::string bugz_command = "bugreportz -p";
@@ -147,24 +251,19 @@
fprintf(stderr,
"Bugreport is in progress and it could take minutes to complete.\n"
"Please be patient and do not cancel or disconnect your device "
- "until it completes."
- "\n");
+ "until it completes.\n");
show_progress = false;
bugz_command = "bugreportz";
}
- BugreportStandardStreamsCallback bugz_callback(dest_file, show_progress, this);
+ BugreportStandardStreamsCallback bugz_callback(dest_dir, dest_file, show_progress, this);
return SendShellCommand(transport_type, serial, bugz_command, false, &bugz_callback);
}
-void Bugreport::UpdateProgress(const std::string& file_name, int progress, int total,
- bool keep_info_line) {
+void Bugreport::UpdateProgress(const std::string& message, int progress, int total) {
int progress_percentage = (progress * 100 / total);
- line_printer_.Print(android::base::StringPrintf("[%3d%%] generating %s", progress_percentage,
- file_name.c_str()),
- LinePrinter::INFO);
- if (keep_info_line) {
- line_printer_.KeepInfoLine();
- }
+ line_printer_.Print(
+ android::base::StringPrintf("[%3d%%] %s", progress_percentage, message.c_str()),
+ LinePrinter::INFO);
}
int Bugreport::SendShellCommand(TransportType transport_type, const char* serial,
diff --git a/adb/bugreport.h b/adb/bugreport.h
index fd11a4a..ee99cbc 100644
--- a/adb/bugreport.h
+++ b/adb/bugreport.h
@@ -43,8 +43,7 @@
const char* name);
private:
- virtual void UpdateProgress(const std::string& file_name, int progress, int total,
- bool keep_info_line = false);
+ virtual void UpdateProgress(const std::string& file_name, int progress, int total);
LinePrinter line_printer_;
DISALLOW_COPY_AND_ASSIGN(Bugreport);
};
diff --git a/adb/bugreport_test.cpp b/adb/bugreport_test.cpp
index e695b24..3cd2b6d 100644
--- a/adb/bugreport_test.cpp
+++ b/adb/bugreport_test.cpp
@@ -19,6 +19,12 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <android-base/strings.h>
+#include <android-base/test_utils.h>
+
+#include "sysdeps.h"
+#include "adb_utils.h"
+
using ::testing::_;
using ::testing::Action;
using ::testing::ActionInterface;
@@ -30,7 +36,9 @@
using ::testing::StrEq;
using ::testing::WithArg;
using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
// Empty function so tests don't need to be linked against file_sync_service.cpp, which requires
// SELinux and its transitive dependencies...
@@ -117,86 +125,144 @@
bool disable_shell_protocol, StandardStreamsCallbackInterface* callback));
MOCK_METHOD4(DoSyncPull, bool(const std::vector<const char*>& srcs, const char* dst,
bool copy_attrs, const char* name));
- MOCK_METHOD4(UpdateProgress, void(const std::string&, int, int, bool));
+ MOCK_METHOD3(UpdateProgress, void(const std::string&, int, int));
};
class BugreportTest : public ::testing::Test {
public:
- void SetBugreportzVersion(const std::string& version) {
+ void SetUp() {
+ if (!getcwd(&cwd_)) {
+ ADD_FAILURE() << "getcwd failed: " << strerror(errno);
+ return;
+ }
+ }
+
+ void ExpectBugreportzVersion(const std::string& version) {
EXPECT_CALL(br_,
SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStderr(version.c_str())),
WithArg<4>(ReturnCallbackDone(0))));
}
- void ExpectProgress(int progress, int total, bool keep_info_line = false) {
- EXPECT_CALL(br_, UpdateProgress(StrEq("file.zip"), progress, total, keep_info_line));
+ void ExpectProgress(int progress, int total, const std::string& file = "file.zip") {
+ EXPECT_CALL(br_, UpdateProgress(StrEq("generating " + file), progress, total));
}
BugreportMock br_;
+ std::string cwd_; // TODO: make it static
};
-// Tests when called with invalid number of argumnts
+// Tests when called with invalid number of arguments
TEST_F(BugreportTest, InvalidNumberArgs) {
- const char* args[1024] = {"bugreport", "to", "principal"};
+ const char* args[] = {"bugreport", "to", "principal"};
ASSERT_EQ(-42, br_.DoIt(kTransportLocal, "HannibalLecter", 3, args));
}
-// Tests the legacy 'adb bugreport' option
-TEST_F(BugreportTest, FlatFileFormat) {
+// Tests the 'adb bugreport' option when the device does not support 'bugreportz' - it falls back
+// to the flat-file format ('bugreport' binary on device)
+TEST_F(BugreportTest, NoArgumentsPreNDevice) {
+ // clang-format off
+ EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _))
+ .WillOnce(DoAll(WithArg<4>(WriteOnStderr("")),
+ // Write some bogus output on stdout to make sure it's ignored
+ WithArg<4>(WriteOnStdout("Dude, where is my bugreportz?")),
+ WithArg<4>(ReturnCallbackDone(0))));
+ // clang-format on
+ std::string bugreport = "Reported the bug was.";
+ CaptureStdout();
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreport", false, _))
- .WillOnce(Return(0));
+ .WillOnce(DoAll(WithArg<4>(WriteOnStdout(bugreport)), Return(0)));
- const char* args[1024] = {"bugreport"};
+ const char* args[] = {"bugreport"};
+ ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args));
+ ASSERT_THAT(GetCapturedStdout(), StrEq(bugreport));
+}
+
+// Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.0 - it will
+// save the bugreport in the current directory with the name provided by the device.
+TEST_F(BugreportTest, NoArgumentsNDevice) {
+ ExpectBugreportzVersion("1.0");
+
+ std::string dest_file =
+ android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR);
+ EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
+ .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
+ WithArg<4>(ReturnCallbackDone())));
+ EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
+ true, StrEq("generating da_bugreport.zip")))
+ .WillOnce(Return(true));
+
+ const char* args[] = {"bugreport"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args));
}
-// Tests 'adb bugreport file.zip' when it succeeds and device does not support
-// progress.
-TEST_F(BugreportTest, OkLegacy) {
- SetBugreportzVersion("1.0");
+// Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.1 - it will
+// save the bugreport in the current directory with the name provided by the device.
+TEST_F(BugreportTest, NoArgumentsPostNDevice) {
+ ExpectBugreportzVersion("1.1");
+ std::string dest_file =
+ android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR);
+ ExpectProgress(50, 100, "da_bugreport.zip");
+ EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
+ .WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
+ WithArg<4>(WriteOnStdout("PROGRESS:50/100\n")),
+ WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip\n")),
+ WithArg<4>(ReturnCallbackDone())));
+ EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
+ true, StrEq("generating da_bugreport.zip")))
+ .WillOnce(Return(true));
+
+ const char* args[] = {"bugreport"};
+ ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args));
+}
+
+// Tests 'adb bugreport file.zip' when it succeeds and device does not support progress.
+TEST_F(BugreportTest, OkNDevice) {
+ ExpectBugreportzVersion("1.0");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, StrEq("file.zip")))
+ true, StrEq("generating file.zip")))
.WillOnce(Return(true));
- const char* args[1024] = {"bugreport", "file.zip"};
+ const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
}
// Tests 'adb bugreport file.zip' when it succeeds but response was sent in
// multiple buffer writers and without progress updates.
-TEST_F(BugreportTest, OkLegacySplitBuffer) {
- SetBugreportzVersion("1.0");
+TEST_F(BugreportTest, OkNDeviceSplitBuffer) {
+ ExpectBugreportzVersion("1.0");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device")),
WithArg<4>(WriteOnStdout("/bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, StrEq("file.zip")))
+ true, StrEq("generating file.zip")))
.WillOnce(Return(true));
- const char* args[1024] = {"bugreport", "file.zip"};
+ const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
}
// Tests 'adb bugreport file.zip' when it succeeds and displays progress.
-TEST_F(BugreportTest, Ok) {
- SetBugreportzVersion("1.1");
+TEST_F(BugreportTest, OkProgress) {
+ ExpectBugreportzVersion("1.1");
ExpectProgress(1, 100);
ExpectProgress(10, 100);
ExpectProgress(50, 100);
ExpectProgress(99, 100);
- ExpectProgress(100, 100, true);
// clang-format off
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
+ // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
.WillOnce(DoAll(
+ // Name might change on OK, so make sure the right one is picked.
+ WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport___NOT.zip\n")),
// Progress line in one write
WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")),
// Add some bogus lines
- WithArg<4>(WriteOnStdout("\nDUDE:SWEET\n\n")),
+ WithArg<4>(WriteOnStdout("\nDUDE:SWEET\n\nBLA\n\nBLA\nBLA\n\n")),
// Multiple progress lines in one write
WithArg<4>(WriteOnStdout("PROGRESS:10/100\nPROGRESS:50/100\n")),
// Progress line in multiple writes
@@ -207,38 +273,76 @@
WithArg<4>(WriteOnStdout("OK:/device/bugreport")),
WithArg<4>(WriteOnStdout(".zip")),
WithArg<4>(ReturnCallbackDone())));
+ // clang-format on
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, StrEq("file.zip")))
+ true, StrEq("generating file.zip")))
.WillOnce(Return(true));
- const char* args[1024] = {"bugreport", "file.zip"};
+ const char* args[] = {"bugreport", "file.zip"};
+ ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+}
+
+// Tests 'adb bugreport dir' when it succeeds and destination is a directory.
+TEST_F(BugreportTest, OkDirectory) {
+ ExpectBugreportzVersion("1.1");
+ TemporaryDir td;
+ std::string dest_file =
+ android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR);
+
+ EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
+ .WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
+ WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
+ WithArg<4>(ReturnCallbackDone())));
+ EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
+ true, StrEq("generating da_bugreport.zip")))
+ .WillOnce(Return(true));
+
+ const char* args[] = {"bugreport", td.path};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
}
// Tests 'adb bugreport file' when it succeeds
TEST_F(BugreportTest, OkNoExtension) {
- SetBugreportzVersion("1.1");
- ExpectProgress(100, 100, true);
+ ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip\n")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, StrEq("file.zip")))
+ true, StrEq("generating file.zip")))
.WillOnce(Return(true));
- const char* args[1024] = {"bugreport", "file"};
+ const char* args[] = {"bugreport", "file"};
+ ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+}
+
+// Tests 'adb bugreport dir' when it succeeds and destination is a directory and device runs N.
+TEST_F(BugreportTest, OkNDeviceDirectory) {
+ ExpectBugreportzVersion("1.0");
+ TemporaryDir td;
+ std::string dest_file =
+ android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR);
+
+ EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
+ .WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
+ WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
+ WithArg<4>(ReturnCallbackDone())));
+ EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
+ true, StrEq("generating da_bugreport.zip")))
+ .WillOnce(Return(true));
+
+ const char* args[] = {"bugreport", td.path};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
}
// Tests 'adb bugreport file.zip' when the bugreport itself failed
TEST_F(BugreportTest, BugreportzReturnedFail) {
- SetBugreportzVersion("1.1");
+ ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(
DoAll(WithArg<4>(WriteOnStdout("FAIL:D'OH!\n")), WithArg<4>(ReturnCallbackDone())));
CaptureStderr();
- const char* args[1024] = {"bugreport", "file.zip"};
+ const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!"));
}
@@ -247,13 +351,13 @@
// was sent in
// multiple buffer writes
TEST_F(BugreportTest, BugreportzReturnedFailSplitBuffer) {
- SetBugreportzVersion("1.1");
+ ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("FAIL")), WithArg<4>(WriteOnStdout(":D'OH!\n")),
WithArg<4>(ReturnCallbackDone())));
CaptureStderr();
- const char* args[1024] = {"bugreport", "file.zip"};
+ const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!"));
}
@@ -261,13 +365,13 @@
// Tests 'adb bugreport file.zip' when the bugreportz returned an unsupported
// response.
TEST_F(BugreportTest, BugreportzReturnedUnsupported) {
- SetBugreportzVersion("1.1");
+ ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("bugreportz? What am I, a zombie?")),
WithArg<4>(ReturnCallbackDone())));
CaptureStderr();
- const char* args[1024] = {"bugreport", "file.zip"};
+ const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
ASSERT_THAT(GetCapturedStderr(), HasSubstr("bugreportz? What am I, a zombie?"));
}
@@ -277,31 +381,38 @@
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _))
.WillOnce(Return(666));
- const char* args[1024] = {"bugreport", "file.zip"};
+ const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(666, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
}
+// Tests 'adb bugreport file.zip' when the bugreportz -v returns status 0 but with no output.
+TEST_F(BugreportTest, BugreportzVersionEmpty) {
+ ExpectBugreportzVersion("");
+
+ const char* args[] = {"bugreport", "file.zip"};
+ ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+}
+
// Tests 'adb bugreport file.zip' when the main bugreportz command failed
TEST_F(BugreportTest, BugreportzFailed) {
- SetBugreportzVersion("1.1");
+ ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(Return(666));
- const char* args[1024] = {"bugreport", "file.zip"};
+ const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(666, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
}
// Tests 'adb bugreport file.zip' when the bugreport could not be pulled
TEST_F(BugreportTest, PullFails) {
- SetBugreportzVersion("1.1");
- ExpectProgress(100, 100, true);
+ ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
- true, StrEq("file.zip")))
+ true, HasSubstr("file.zip")))
.WillOnce(Return(false));
- const char* args[1024] = {"bugreport", "file.zip"};
+ const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 4394e60..c69fe19 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -82,6 +82,7 @@
static void help() {
fprintf(stderr, "%s\n", adb_version().c_str());
+ // clang-format off
fprintf(stderr,
" -a - directs adb to listen on all interfaces for a connection\n"
" -d - directs command to the only connected USB device\n"
@@ -174,9 +175,11 @@
" (-g: grant all runtime permissions)\n"
" adb uninstall [-k] <package> - remove this app package from the device\n"
" ('-k' means keep the data and cache directories)\n"
- " adb bugreport [<zip_file>] - return all information from the device\n"
- " that should be included in a bug report.\n"
- "\n"
+ " adb bugreport [<path>] - return all information from the device that should be included in a zipped bug report.\n"
+ " If <path> is a file, the bug report will be saved as that file.\n"
+ " If <path> is a directory, the bug report will be saved in that directory with the name provided by the device.\n"
+ " If <path> is omitted, the bug report will be saved in the current directory with the name provided by the device.\n"
+ " NOTE: if the device does not support zipped bug reports, the bug report will be output on stdout.\n"
" adb backup [-f <file>] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n"
" - write an archive of the device's data to <file>.\n"
" If no -f option is supplied then the data is written\n"
@@ -250,8 +253,8 @@
" ADB_TRACE - Print debug information. A comma separated list of the following values\n"
" 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
" ANDROID_SERIAL - The serial number to connect to. -s takes priority over this if given.\n"
- " ANDROID_LOG_TAGS - When used with the logcat option, only these debug tags are printed.\n"
- );
+ " ANDROID_LOG_TAGS - When used with the logcat option, only these debug tags are printed.\n");
+ // clang-format on
}
int usage() {
@@ -361,19 +364,7 @@
*buf = '\0';
}
-static void copy_to_file(int inFd, int outFd) {
- const size_t BUFSIZE = 32 * 1024;
- char* buf = (char*) malloc(BUFSIZE);
- if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file");
- int len;
- long total = 0;
-#ifdef _WIN32
- int old_stdin_mode = -1;
- int old_stdout_mode = -1;
-#endif
-
- D("copy_to_file(%d -> %d)", inFd, outFd);
-
+static void stdinout_raw_prologue(int inFd, int outFd, int& old_stdin_mode, int& old_stdout_mode) {
if (inFd == STDIN_FILENO) {
stdin_raw_init();
#ifdef _WIN32
@@ -392,6 +383,39 @@
}
}
#endif
+}
+
+static void stdinout_raw_epilogue(int inFd, int outFd, int old_stdin_mode, int old_stdout_mode) {
+ if (inFd == STDIN_FILENO) {
+ stdin_raw_restore();
+#ifdef _WIN32
+ if (_setmode(STDIN_FILENO, old_stdin_mode) == -1) {
+ fatal_errno("could not restore stdin mode");
+ }
+#endif
+ }
+
+#ifdef _WIN32
+ if (outFd == STDOUT_FILENO) {
+ if (_setmode(STDOUT_FILENO, old_stdout_mode) == -1) {
+ fatal_errno("could not restore stdout mode");
+ }
+ }
+#endif
+}
+
+static void copy_to_file(int inFd, int outFd) {
+ const size_t BUFSIZE = 32 * 1024;
+ char* buf = (char*) malloc(BUFSIZE);
+ if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file");
+ int len;
+ long total = 0;
+ int old_stdin_mode = -1;
+ int old_stdout_mode = -1;
+
+ D("copy_to_file(%d -> %d)", inFd, outFd);
+
+ stdinout_raw_prologue(inFd, outFd, old_stdin_mode, old_stdout_mode);
while (true) {
if (inFd == STDIN_FILENO) {
@@ -416,22 +440,7 @@
total += len;
}
- if (inFd == STDIN_FILENO) {
- stdin_raw_restore();
-#ifdef _WIN32
- if (_setmode(STDIN_FILENO, old_stdin_mode) == -1) {
- fatal_errno("could not restore stdin mode");
- }
-#endif
- }
-
-#ifdef _WIN32
- if (outFd == STDOUT_FILENO) {
- if (_setmode(STDOUT_FILENO, old_stdout_mode) == -1) {
- fatal_errno("could not restore stdout mode");
- }
- }
-#endif
+ stdinout_raw_epilogue(inFd, outFd, old_stdin_mode, old_stdout_mode);
D("copy_to_file() finished after %lu bytes", total);
free(buf);
@@ -1169,6 +1178,29 @@
return send_shell_command(transport, serial, cmd, true);
}
+static void write_zeros(int bytes, int fd) {
+ int old_stdin_mode = -1;
+ int old_stdout_mode = -1;
+ char* buf = (char*) calloc(1, bytes);
+ if (buf == nullptr) fatal("couldn't allocate buffer for write_zeros");
+
+ D("write_zeros(%d) -> %d", bytes, fd);
+
+ stdinout_raw_prologue(-1, fd, old_stdin_mode, old_stdout_mode);
+
+ if (fd == STDOUT_FILENO) {
+ fwrite(buf, 1, bytes, stdout);
+ fflush(stdout);
+ } else {
+ adb_write(fd, buf, bytes);
+ }
+
+ stdinout_raw_prologue(-1, fd, old_stdin_mode, old_stdout_mode);
+
+ D("write_zeros() finished");
+ free(buf);
+}
+
static int backup(int argc, const char** argv) {
const char* filename = "backup.ab";
@@ -1249,6 +1281,9 @@
printf("Now unlock your device and confirm the restore operation.\n");
copy_to_file(tarFd, fd);
+ // Provide an in-band EOD marker in case the archive file is malformed
+ write_zeros(512*2, fd);
+
// Wait until the other side finishes, or it'll get sent SIGHUP.
copy_to_file(fd, STDOUT_FILENO);
@@ -1284,7 +1319,7 @@
if (hint.find_first_of(OS_PATH_SEPARATORS) != std::string::npos) { // NOLINT
std::string cwd;
if (!getcwd(&cwd)) {
- fprintf(stderr, "adb: getcwd failed: %s\n", strerror(errno));
+ perror("adb: getcwd failed");
return "";
}
return android::base::StringPrintf("%s%c%s", cwd.c_str(), OS_PATH_SEPARATOR, hint.c_str());
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index d61c3e5..ce8df88 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -99,20 +99,42 @@
};
static struct {
- char img_name[13];
- char sig_name[13];
+ char img_name[17];
+ char sig_name[17];
char part_name[9];
bool is_optional;
+ bool is_secondary;
} images[] = {
- {"boot.img", "boot.sig", "boot", false},
- {"recovery.img", "recovery.sig", "recovery", true},
- {"system.img", "system.sig", "system", false},
- {"vendor.img", "vendor.sig", "vendor", true},
+ {"boot.img", "boot.sig", "boot", false, false},
+ {"boot_other.img", "boot.sig", "boot", true, true},
+ {"recovery.img", "recovery.sig", "recovery", true, false},
+ {"system.img", "system.sig", "system", false, false},
+ {"system_other.img", "system.sig", "system", true, true},
+ {"vendor.img", "vendor.sig", "vendor", true, false},
+ {"vendor_other.img", "vendor.sig", "vendor", true, true},
};
-static std::string find_item(const char* item, const char* product) {
+static std::string find_item_given_name(const char* img_name, const char* product) {
+ char *dir;
+
+ if(product) {
+ std::string path = get_my_path();
+ return android::base::StringPrintf("%s/../../../target/product/%s/%s",
+ path.c_str(), product, img_name);
+ }
+
+ dir = getenv("ANDROID_PRODUCT_OUT");
+ if((dir == 0) || (dir[0] == 0)) {
+ die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
+ }
+
+ return android::base::StringPrintf("%s/%s", dir, img_name);
+}
+
+std::string find_item(const char* item, const char* product) {
const char *fn;
- if (!strcmp(item,"boot")) {
+
+ if(!strcmp(item,"boot")) {
fn = "boot.img";
} else if(!strcmp(item,"recovery")) {
fn = "recovery.img";
@@ -131,19 +153,7 @@
return "";
}
- if (product) {
- std::string path = get_my_path();
- path.erase(path.find_last_of('/'));
- return android::base::StringPrintf("%s/../../../target/product/%s/%s",
- path.c_str(), product, fn);
- }
-
- char* dir = getenv("ANDROID_PRODUCT_OUT");
- if (dir == nullptr || dir[0] == '\0') {
- die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
- }
-
- return android::base::StringPrintf("%s/%s", dir, fn);
+ return find_item_given_name(fn, product);
}
static int64_t get_file_size(int fd) {
@@ -309,8 +319,13 @@
"\n"
"commands:\n"
" update <filename> Reflash device from update.zip.\n"
+ " Sets the flashed slot as active.\n"
" flashall Flash boot, system, vendor, and --\n"
- " if found -- recovery.\n"
+ " if found -- recovery. If the device\n"
+ " supports slots, the slot that has\n"
+ " been flashed to is set as active.\n"
+ " Secondary images may be flashed to\n"
+ " an inactive slot.\n"
" flash <partition> [ <filename> ] Write a file to a flash partition.\n"
" flashing lock Locks the device. Prevents flashing.\n"
" flashing unlock Unlocks the device. Allows flashing\n"
@@ -333,7 +348,7 @@
" override the fs type and/or size\n"
" the bootloader reports.\n"
" getvar <variable> Display a bootloader variable.\n"
- " set_active <suffix> Sets the active slot. If slots are\n"
+ " set_active <slot> Sets the active slot. If slots are\n"
" not supported, this does nothing.\n"
" boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
" flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
@@ -370,19 +385,24 @@
" (default: 2048).\n"
" -S <size>[K|M|G] Automatically sparse files greater\n"
" than 'size'. 0 to disable.\n"
- " --slot <suffix> Specify slot suffix to be used if the\n"
- " device supports slots. This will be\n"
- " added to all partition names that use\n"
- " slots. 'all' can be given to refer\n"
- " to all slots. 'other' can be given to\n"
- " refer to a non-current slot. If this\n"
- " flag is not used, slotted partitions\n"
- " will default to the current active slot.\n"
- " -a, --set-active[=<suffix>] Sets the active slot. If no suffix is\n"
+ " --slot <slot> Specify slot name to be used if the\n"
+ " device supports slots. All operations\n"
+ " on partitions that support slots will\n"
+ " be done on the slot specified.\n"
+ " 'all' can be given to refer to all slots.\n"
+ " 'other' can be given to refer to a\n"
+ " non-current slot. If this flag is not\n"
+ " used, slotted partitions will default\n"
+ " to the current active slot.\n"
+ " -a, --set-active[=<slot>] Sets the active slot. If no slot is\n"
" provided, this will default to the value\n"
" given by --slot. If slots are not\n"
- " supported, this does nothing. This will\n"
- " run after all non-reboot commands.\n"
+ " supported, this sets the current slot\n"
+ " to be active. This will run after all\n"
+ " non-reboot commands.\n"
+ " --skip-secondary Will not flash secondary slots when\n"
+ " performing a flashall or update. This\n"
+ " will preserve data on other slots.\n"
#if !defined(_WIN32)
" --wipe-and-use-fbe On devices which support it,\n"
" erase userdata and cache, and\n"
@@ -842,83 +862,138 @@
}
}
-static std::vector<std::string> get_suffixes(Transport* transport) {
+static std::string get_current_slot(Transport* transport)
+{
+ std::string current_slot;
+ if (fb_getvar(transport, "current-slot", ¤t_slot)) {
+ if (current_slot == "_a") return "a"; // Legacy support
+ if (current_slot == "_b") return "b"; // Legacy support
+ return current_slot;
+ }
+ return "";
+}
+
+// Legacy support
+static std::vector<std::string> get_suffixes_obsolete(Transport* transport) {
std::vector<std::string> suffixes;
std::string suffix_list;
if (!fb_getvar(transport, "slot-suffixes", &suffix_list)) {
- die("Could not get suffixes.\n");
+ return suffixes;
}
- return android::base::Split(suffix_list, ",");
+ suffixes = android::base::Split(suffix_list, ",");
+ // Unfortunately some devices will return an error message in the
+ // guise of a valid value. If we only see only one suffix, it's probably
+ // not real.
+ if (suffixes.size() == 1) {
+ suffixes.clear();
+ }
+ return suffixes;
}
-static std::string verify_slot(Transport* transport, const char *slot, bool allow_all) {
- if (strcmp(slot, "all") == 0) {
+// Legacy support
+static bool supports_AB_obsolete(Transport* transport) {
+ return !get_suffixes_obsolete(transport).empty();
+}
+
+static int get_slot_count(Transport* transport) {
+ std::string var;
+ int count;
+ if (!fb_getvar(transport, "slot-count", &var)) {
+ if (supports_AB_obsolete(transport)) return 2; // Legacy support
+ }
+ if (!android::base::ParseInt(var.c_str(), &count)) return 0;
+ return count;
+}
+
+static bool supports_AB(Transport* transport) {
+ return get_slot_count(transport) >= 2;
+}
+
+// Given a current slot, this returns what the 'other' slot is.
+static std::string get_other_slot(const std::string& current_slot, int count) {
+ if (count == 0) return "";
+
+ char next = (current_slot[0] - 'a' + 1)%count + 'a';
+ return std::string(1, next);
+}
+
+static std::string get_other_slot(Transport* transport, const std::string& current_slot) {
+ return get_other_slot(current_slot, get_slot_count(transport));
+}
+
+static std::string get_other_slot(Transport* transport, int count) {
+ return get_other_slot(get_current_slot(transport), count);
+}
+
+static std::string get_other_slot(Transport* transport) {
+ return get_other_slot(get_current_slot(transport), get_slot_count(transport));
+}
+
+static std::string verify_slot(Transport* transport, const std::string& slot_name, bool allow_all) {
+ std::string slot = slot_name;
+ if (slot == "_a") slot = "a"; // Legacy support
+ if (slot == "_b") slot = "b"; // Legacy support
+ if (slot == "all") {
if (allow_all) {
return "all";
} else {
- std::vector<std::string> suffixes = get_suffixes(transport);
- if (!suffixes.empty()) {
- return suffixes[0];
+ int count = get_slot_count(transport);
+ if (count > 0) {
+ return "a";
} else {
die("No known slots.");
}
}
}
- std::vector<std::string> suffixes = get_suffixes(transport);
+ int count = get_slot_count(transport);
+ if (count == 0) die("Device does not support slots.\n");
- if (strcmp(slot, "other") == 0) {
- std::string current_slot;
- if (!fb_getvar(transport, "current-slot", ¤t_slot)) {
- die("Failed to identify current slot.");
+ if (slot == "other") {
+ std::string other = get_other_slot(transport, count);
+ if (other == "") {
+ die("No known slots.");
}
- if (!suffixes.empty()) {
- for (size_t i = 0; i < suffixes.size(); i++) {
- if (current_slot == suffixes[i])
- return suffixes[(i+1)%suffixes.size()];
- }
- } else {
- die("No known slots.");
- }
+ return other;
}
- for (const std::string &suffix : suffixes) {
- if (suffix == slot)
- return slot;
+ if (slot.size() == 1 && (slot[0]-'a' >= 0 && slot[0]-'a' < count)) return slot;
+
+ fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot.c_str());
+ for (int i=0; i<count; i++) {
+ fprintf(stderr, "%c\n", (char)(i + 'a'));
}
- fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot);
- for (const std::string &suffix : suffixes) {
- fprintf(stderr, "%s\n", suffix.c_str());
- }
+
exit(1);
}
-static std::string verify_slot(Transport* transport, const char *slot) {
+static std::string verify_slot(Transport* transport, const std::string& slot) {
return verify_slot(transport, slot, true);
}
-static void do_for_partition(Transport* transport, const char *part, const char *slot,
+static void do_for_partition(Transport* transport, const std::string& part, const std::string& slot,
const std::function<void(const std::string&)>& func, bool force_slot) {
std::string has_slot;
std::string current_slot;
- if (!fb_getvar(transport, std::string("has-slot:")+part, &has_slot)) {
+ if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
/* If has-slot is not supported, the answer is no. */
has_slot = "no";
}
if (has_slot == "yes") {
- if (!slot || slot[0] == 0) {
- if (!fb_getvar(transport, "current-slot", ¤t_slot)) {
+ if (slot == "") {
+ current_slot = get_current_slot(transport);
+ if (current_slot == "") {
die("Failed to identify current slot.\n");
}
- func(std::string(part) + current_slot);
+ func(part + "_" + current_slot);
} else {
- func(std::string(part) + slot);
+ func(part + '_' + slot);
}
} else {
- if (force_slot && slot && slot[0]) {
+ if (force_slot && slot != "") {
fprintf(stderr, "Warning: %s does not support slots, and slot %s was requested.\n",
- part, slot);
+ part.c_str(), slot.c_str());
}
func(part);
}
@@ -929,18 +1004,17 @@
* partition names. If force_slot is true, it will fail if a slot is specified, and the given
* partition does not support slots.
*/
-static void do_for_partitions(Transport* transport, const char *part, const char *slot,
+static void do_for_partitions(Transport* transport, const std::string& part, const std::string& slot,
const std::function<void(const std::string&)>& func, bool force_slot) {
std::string has_slot;
- if (slot && strcmp(slot, "all") == 0) {
- if (!fb_getvar(transport, std::string("has-slot:") + part, &has_slot)) {
- die("Could not check if partition %s has slot.", part);
+ if (slot == "all") {
+ if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
+ die("Could not check if partition %s has slot.", part.c_str());
}
if (has_slot == "yes") {
- std::vector<std::string> suffixes = get_suffixes(transport);
- for (std::string &suffix : suffixes) {
- do_for_partition(transport, part, suffix.c_str(), func, force_slot);
+ for (int i=0; i < get_slot_count(transport); i++) {
+ do_for_partition(transport, part, std::string(1, (char)(i + 'a')), func, force_slot);
}
} else {
do_for_partition(transport, part, "", func, force_slot);
@@ -967,7 +1041,28 @@
fb_queue_command("signature", "installing signature");
}
-static void do_update(Transport* transport, const char* filename, const char* slot_override, bool erase_first) {
+// Sets slot_override as the active slot. If slot_override is blank,
+// set current slot as active instead. This clears slot-unbootable.
+static void set_active(Transport* transport, const std::string& slot_override) {
+ std::string separator = "";
+ if (!supports_AB(transport)) {
+ if (supports_AB_obsolete(transport)) {
+ separator = "_"; // Legacy support
+ } else {
+ return;
+ }
+ }
+ if (slot_override != "") {
+ fb_set_active((separator + slot_override).c_str());
+ } else {
+ std::string current_slot = get_current_slot(transport);
+ if (current_slot != "") {
+ fb_set_active((separator + current_slot).c_str());
+ }
+ }
+}
+
+static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool erase_first, bool skip_secondary) {
queue_info_dump();
fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -988,7 +1083,30 @@
setup_requirements(reinterpret_cast<char*>(data), sz);
+ std::string secondary;
+ if (!skip_secondary) {
+ if (slot_override != "") {
+ secondary = get_other_slot(transport, slot_override);
+ } else {
+ secondary = get_other_slot(transport);
+ }
+ if (secondary == "") {
+ if (supports_AB(transport)) {
+ fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
+ }
+ skip_secondary = true;
+ }
+ }
for (size_t i = 0; i < arraysize(images); ++i) {
+ const char* slot = slot_override.c_str();
+ if (images[i].is_secondary) {
+ if (!skip_secondary) {
+ slot = secondary.c_str();
+ } else {
+ continue;
+ }
+ }
+
int fd = unzip_to_file(zip, images[i].img_name);
if (fd == -1) {
if (images[i].is_optional) {
@@ -1013,10 +1131,15 @@
* program exits.
*/
};
- do_for_partitions(transport, images[i].part_name, slot_override, update, false);
+ do_for_partitions(transport, images[i].part_name, slot, update, false);
}
CloseArchive(zip);
+ if (slot_override == "all") {
+ set_active(transport, "a");
+ } else {
+ set_active(transport, slot_override);
+ }
}
static void do_send_signature(const char* filename) {
@@ -1036,26 +1159,49 @@
fb_queue_command("signature", "installing signature");
}
-static void do_flashall(Transport* transport, const char* slot_override, int erase_first) {
+static void do_flashall(Transport* transport, const std::string& slot_override, int erase_first, bool skip_secondary) {
+ std::string fname;
queue_info_dump();
fb_queue_query_save("product", cur_product, sizeof(cur_product));
- std::string fname = find_item("info", product);
+ fname = find_item("info", product);
if (fname.empty()) die("cannot find android-info.txt");
int64_t sz;
- void* data = load_file(fname, &sz);
+ void* data = load_file(fname.c_str(), &sz);
if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno));
setup_requirements(reinterpret_cast<char*>(data), sz);
+ std::string secondary;
+ if (!skip_secondary) {
+ if (slot_override != "") {
+ secondary = get_other_slot(transport, slot_override);
+ } else {
+ secondary = get_other_slot(transport);
+ }
+ if (secondary == "") {
+ if (supports_AB(transport)) {
+ fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
+ }
+ skip_secondary = true;
+ }
+ }
+
for (size_t i = 0; i < arraysize(images); i++) {
- fname = find_item(images[i].part_name, product);
+ const char* slot = NULL;
+ if (images[i].is_secondary) {
+ if (!skip_secondary) slot = secondary.c_str();
+ } else {
+ slot = slot_override.c_str();
+ }
+ if (!slot) continue;
+ fname = find_item_given_name(images[i].img_name, product);
fastboot_buffer buf;
if (!load_buf(transport, fname.c_str(), &buf)) {
if (images[i].is_optional) continue;
- die("could not load '%s': %s", images[i].img_name, strerror(errno));
+ die("could not load %s\n", images[i].img_name);
}
auto flashall = [&](const std::string &partition) {
@@ -1065,7 +1211,13 @@
}
flash_buf(partition.c_str(), &buf);
};
- do_for_partitions(transport, images[i].part_name, slot_override, flashall, false);
+ do_for_partitions(transport, images[i].part_name, slot, flashall, false);
+ }
+
+ if (slot_override == "all") {
+ set_active(transport, "a");
+ } else {
+ set_active(transport, slot_override);
}
}
@@ -1245,6 +1397,7 @@
bool wants_reboot = false;
bool wants_reboot_bootloader = false;
bool wants_set_active = false;
+ bool skip_secondary = false;
bool erase_first = true;
bool set_fbe_marker = false;
void *data;
@@ -1269,6 +1422,7 @@
{"slot", required_argument, 0, 0},
{"set_active", optional_argument, 0, 'a'},
{"set-active", optional_argument, 0, 'a'},
+ {"skip-secondary", no_argument, 0, 0},
#if !defined(_WIN32)
{"wipe-and-use-fbe", no_argument, 0, 0},
#endif
@@ -1353,6 +1507,8 @@
return 0;
} else if (strcmp("slot", longopts[longindex].name) == 0) {
slot_override = std::string(optarg);
+ } else if (strcmp("skip-secondary", longopts[longindex].name) == 0 ) {
+ skip_secondary = true;
#if !defined(_WIN32)
} else if (strcmp("wipe-and-use-fbe", longopts[longindex].name) == 0) {
wants_wipe = true;
@@ -1393,17 +1549,23 @@
return 1;
}
- if (slot_override != "")
- slot_override = verify_slot(transport, slot_override.c_str());
- if (next_active != "")
- next_active = verify_slot(transport, next_active.c_str(), false);
+ if (!supports_AB(transport) && supports_AB_obsolete(transport)) {
+ fprintf(stderr, "Warning: Device A/B support is outdated. Bootloader update required.\n");
+ }
+ if (slot_override != "") slot_override = verify_slot(transport, slot_override);
+ if (next_active != "") next_active = verify_slot(transport, next_active, false);
if (wants_set_active) {
if (next_active == "") {
if (slot_override == "") {
- wants_set_active = false;
+ std::string current_slot;
+ if (fb_getvar(transport, "current-slot", ¤t_slot)) {
+ next_active = verify_slot(transport, current_slot, false);
+ } else {
+ wants_set_active = false;
+ }
} else {
- next_active = verify_slot(transport, slot_override.c_str(), false);
+ next_active = verify_slot(transport, slot_override, false);
}
}
}
@@ -1426,7 +1588,7 @@
fb_queue_erase(partition.c_str());
};
- do_for_partitions(transport, argv[1], slot_override.c_str(), erase, true);
+ do_for_partitions(transport, argv[1], slot_override, erase, true);
skip(2);
} else if(!strncmp(*argv, "format", strlen("format"))) {
char *overrides;
@@ -1462,7 +1624,7 @@
fb_perform_format(transport, partition.c_str(), 0,
type_override, size_override, "");
};
- do_for_partitions(transport, argv[1], slot_override.c_str(), format, true);
+ do_for_partitions(transport, argv[1], slot_override, format, true);
skip(2);
} else if(!strcmp(*argv, "signature")) {
require(2);
@@ -1529,7 +1691,7 @@
}
do_flash(transport, partition.c_str(), fname.c_str());
};
- do_for_partitions(transport, pname, slot_override.c_str(), flash, true);
+ do_for_partitions(transport, pname, slot_override, flash, true);
} else if(!strcmp(*argv, "flash:raw")) {
char *kname = argv[2];
char *rname = 0;
@@ -1549,23 +1711,32 @@
auto flashraw = [&](const std::string &partition) {
fb_queue_flash(partition.c_str(), data, sz);
};
- do_for_partitions(transport, argv[1], slot_override.c_str(), flashraw, true);
+ do_for_partitions(transport, argv[1], slot_override, flashraw, true);
} else if(!strcmp(*argv, "flashall")) {
skip(1);
- do_flashall(transport, slot_override.c_str(), erase_first);
+ if (slot_override == "all") {
+ fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
+ do_flashall(transport, slot_override, erase_first, true);
+ } else {
+ do_flashall(transport, slot_override, erase_first, skip_secondary);
+ }
wants_reboot = true;
} else if(!strcmp(*argv, "update")) {
+ bool slot_all = (slot_override == "all");
+ if (slot_all) {
+ fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
+ }
if (argc > 1) {
- do_update(transport, argv[1], slot_override.c_str(), erase_first);
+ do_update(transport, argv[1], slot_override, erase_first, skip_secondary || slot_all);
skip(2);
} else {
- do_update(transport, "update.zip", slot_override.c_str(), erase_first);
+ do_update(transport, "update.zip", slot_override, erase_first, skip_secondary || slot_all);
skip(1);
}
wants_reboot = 1;
} else if(!strcmp(*argv, "set_active")) {
require(2);
- std::string slot = verify_slot(transport, argv[1], false);
+ std::string slot = verify_slot(transport, std::string(argv[1]), false);
fb_set_active(slot.c_str());
skip(2);
} else if(!strcmp(*argv, "oem")) {
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 6d44e06..45adb34 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -32,11 +32,12 @@
int partnum;
int swap_prio;
unsigned int zram_size;
+ unsigned int file_encryption_mode;
};
struct flag_list {
const char *name;
- unsigned flag;
+ unsigned int flag;
};
static struct flag_list mount_flags[] = {
@@ -63,7 +64,7 @@
{ "check", MF_CHECK },
{ "encryptable=",MF_CRYPT },
{ "forceencrypt=",MF_FORCECRYPT },
- { "fileencryption",MF_FILEENCRYPTION },
+ { "fileencryption=",MF_FILEENCRYPTION },
{ "forcefdeorfbe=",MF_FORCEFDEORFBE },
{ "nonremovable",MF_NONREMOVABLE },
{ "voldmanaged=",MF_VOLDMANAGED},
@@ -81,6 +82,15 @@
{ 0, 0 },
};
+#define EM_SOFTWARE 1
+#define EM_ICE 2
+
+static struct flag_list encryption_modes[] = {
+ {"software", EM_SOFTWARE},
+ {"ice", EM_ICE},
+ {0, 0}
+};
+
static uint64_t calculate_zram_size(unsigned int percentage)
{
uint64_t total;
@@ -147,6 +157,21 @@
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+ flag_vals->file_encryption_mode = EM_SOFTWARE;
+ } else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) {
+ /* The fileencryption flag is followed by an = and the
+ * type of the encryption. Get it and return it.
+ */
+ const struct flag_list *j;
+ const char *mode = strchr(p, '=') + 1;
+ for (j = encryption_modes; j->name; ++j) {
+ if (!strcmp(mode, j->name)) {
+ flag_vals->file_encryption_mode = j->flag;
+ }
+ }
+ if (flag_vals->file_encryption_mode == 0) {
+ ERROR("Unknown file encryption mode: %s\n", mode);
+ }
} else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
@@ -337,6 +362,7 @@
fstab->recs[cnt].partnum = flag_vals.partnum;
fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
fstab->recs[cnt].zram_size = flag_vals.zram_size;
+ fstab->recs[cnt].file_encryption_mode = flag_vals.file_encryption_mode;
cnt++;
}
/* If an A/B partition, modify block device to be the real block device */
@@ -479,6 +505,17 @@
return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
}
+const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab)
+{
+ const struct flag_list *j;
+ for (j = encryption_modes; j->name; ++j) {
+ if (fstab->file_encryption_mode == j->flag) {
+ return j->name;
+ }
+ }
+ return NULL;
+}
+
int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 67104cc..031b042 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -181,7 +181,7 @@
return -1;
}
-static void verity_ioctl_init(struct dm_ioctl *io, char *name, unsigned flags)
+static void verity_ioctl_init(struct dm_ioctl *io, const char *name, unsigned flags)
{
memset(io, 0, DM_BUF_SIZE);
io->data_size = DM_BUF_SIZE;
@@ -784,8 +784,9 @@
int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
{
alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
+ bool system_root = false;
char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
- char *mount_point;
+ const char *mount_point;
char propbuf[PROPERTY_VALUE_MAX];
char *status;
int fd = -1;
@@ -813,6 +814,9 @@
property_get("ro.hardware", propbuf, "");
snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
+ property_get("ro.build.system_root_image", propbuf, "");
+ system_root = !strcmp(propbuf, "true");
+
fstab = fs_mgr_read_fstab(fstab_filename);
if (!fstab) {
@@ -825,7 +829,12 @@
continue;
}
- mount_point = basename(fstab->recs[i].mount_point);
+ if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) {
+ mount_point = "system";
+ } else {
+ mount_point = basename(fstab->recs[i].mount_point);
+ }
+
verity_ioctl_init(io, mount_point, 0);
if (ioctl(fd, DM_TABLE_STATUS, io)) {
@@ -836,7 +845,9 @@
status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
- callback(&fstab->recs[i], mount_point, mode, *status);
+ if (*status == 'C' || *status == 'V') {
+ callback(&fstab->recs[i], mount_point, mode, *status);
+ }
}
rc = 0;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 3847011..6f2548d 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -66,6 +66,7 @@
int partnum;
int swap_prio;
unsigned int zram_size;
+ unsigned int file_encryption_mode;
};
// Callback function for verity status
@@ -86,6 +87,7 @@
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
+
int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
char *tmp_mount_point);
int fs_mgr_do_tmpfs_mount(char *n_name);
@@ -103,6 +105,7 @@
int fs_mgr_is_verified(const struct fstab_rec *fstab);
int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
+const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab);
int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab);
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
int fs_mgr_is_notrim(struct fstab_rec *fstab);
diff --git a/include/system/graphics.h b/include/system/graphics.h
index a9e451f..529a562 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -477,6 +477,102 @@
uint32_t reserved[8];
};
+/*
+ * Structures for describing flexible YUVA/RGBA formats for consumption by
+ * applications. Such flexible formats contain a plane for each component (e.g.
+ * red, green, blue), where each plane is laid out in a grid-like pattern
+ * occupying unique byte addresses and with consistent byte offsets between
+ * neighboring pixels.
+ *
+ * The android_flex_layout structure is used with any pixel format that can be
+ * represented by it, such as:
+ * - HAL_PIXEL_FORMAT_YCbCr_*_888
+ * - HAL_PIXEL_FORMAT_FLEX_RGB*_888
+ * - HAL_PIXEL_FORMAT_RGB[AX]_888[8],BGRA_8888,RGB_888
+ * - HAL_PIXEL_FORMAT_YV12,Y8,Y16,YCbCr_422_SP/I,YCrCb_420_SP
+ * - even implementation defined formats that can be represented by
+ * the structures
+ *
+ * Vertical increment (aka. row increment or stride) describes the distance in
+ * bytes from the first pixel of one row to the first pixel of the next row
+ * (below) for the component plane. This can be negative.
+ *
+ * Horizontal increment (aka. column or pixel increment) describes the distance
+ * in bytes from one pixel to the next pixel (to the right) on the same row for
+ * the component plane. This can be negative.
+ *
+ * Each plane can be subsampled either vertically or horizontally by
+ * a power-of-two factor.
+ *
+ * The bit-depth of each component can be arbitrary, as long as the pixels are
+ * laid out on whole bytes, in native byte-order, using the most significant
+ * bits of each unit.
+ */
+
+typedef enum android_flex_component {
+ /* luma */
+ FLEX_COMPONENT_Y = 1 << 0,
+ /* chroma blue */
+ FLEX_COMPONENT_Cb = 1 << 1,
+ /* chroma red */
+ FLEX_COMPONENT_Cr = 1 << 2,
+
+ /* red */
+ FLEX_COMPONENT_R = 1 << 10,
+ /* green */
+ FLEX_COMPONENT_G = 1 << 11,
+ /* blue */
+ FLEX_COMPONENT_B = 1 << 12,
+
+ /* alpha */
+ FLEX_COMPONENT_A = 1 << 30,
+} android_flex_component_t;
+
+typedef struct android_flex_plane {
+ /* pointer to the first byte of the top-left pixel of the plane. */
+ uint8_t *top_left;
+
+ android_flex_component_t component;
+
+ /* bits allocated for the component in each pixel. Must be a positive
+ multiple of 8. */
+ int32_t bits_per_component;
+ /* number of the most significant bits used in the format for this
+ component. Must be between 1 and bits_per_component, inclusive. */
+ int32_t bits_used;
+
+ /* horizontal increment */
+ int32_t h_increment;
+ /* vertical increment */
+ int32_t v_increment;
+ /* horizontal subsampling. Must be a positive power of 2. */
+ int32_t h_subsampling;
+ /* vertical subsampling. Must be a positive power of 2. */
+ int32_t v_subsampling;
+} android_flex_plane_t;
+
+typedef enum android_flex_format {
+ /* not a flexible format */
+ FLEX_FORMAT_INVALID = 0x0,
+ FLEX_FORMAT_Y = FLEX_COMPONENT_Y,
+ FLEX_FORMAT_YCbCr = FLEX_COMPONENT_Y | FLEX_COMPONENT_Cb | FLEX_COMPONENT_Cr,
+ FLEX_FORMAT_YCbCrA = FLEX_FORMAT_YCbCr | FLEX_COMPONENT_A,
+ FLEX_FORMAT_RGB = FLEX_COMPONENT_R | FLEX_COMPONENT_G | FLEX_COMPONENT_B,
+ FLEX_FORMAT_RGBA = FLEX_FORMAT_RGB | FLEX_COMPONENT_A,
+} android_flex_format_t;
+
+typedef struct android_flex_layout {
+ /* the kind of flexible format */
+ android_flex_format_t format;
+
+ /* number of planes; 0 for FLEX_FORMAT_INVALID */
+ uint32_t num_planes;
+ /* a plane for each component; ordered in increasing component value order.
+ E.g. FLEX_FORMAT_RGBA maps 0 -> R, 1 -> G, etc.
+ Can be NULL for FLEX_FORMAT_INVALID */
+ android_flex_plane_t *planes;
+} android_flex_layout_t;
+
/**
* Structure used to define depth point clouds for format HAL_PIXEL_FORMAT_BLOB
* with dataSpace value of HAL_DATASPACE_DEPTH.
@@ -1039,6 +1135,236 @@
} android_dataspace_t;
/*
+ * Color modes that may be supported by a display.
+ *
+ * Definitions:
+ * Rendering intent generally defines the goal in mapping a source (input)
+ * color to a destination device color for a given color mode.
+ *
+ * It is important to keep in mind three cases where mapping may be applied:
+ * 1. The source gamut is much smaller than the destination (display) gamut
+ * 2. The source gamut is much larger than the destination gamut (this will
+ * ordinarily be handled using colorimetric rendering, below)
+ * 3. The source and destination gamuts are roughly equal, although not
+ * completely overlapping
+ * Also, a common requirement for mappings is that skin tones should be
+ * preserved, or at least remain natural in appearance.
+ *
+ * Colorimetric Rendering Intent (All cases):
+ * Colorimetric indicates that colors should be preserved. In the case
+ * that the source gamut lies wholly within the destination gamut or is
+ * about the same (#1, #3), this will simply mean that no manipulations
+ * (no saturation boost, for example) are applied. In the case where some
+ * source colors lie outside the destination gamut (#2, #3), those will
+ * need to be mapped to colors that are within the destination gamut,
+ * while the already in-gamut colors remain unchanged.
+ *
+ * Non-colorimetric transforms can take many forms. There are no hard
+ * rules and it's left to the implementation to define.
+ * Two common intents are described below.
+ *
+ * Stretched-Gamut Enhancement Intent (Source < Destination):
+ * When the destination gamut is much larger than the source gamut (#1), the
+ * source primaries may be redefined to reflect the full extent of the
+ * destination space, or to reflect an intermediate gamut.
+ * Skin-tone preservation would likely be applied. An example might be sRGB
+ * input displayed on a DCI-P3 capable device, with skin-tone preservation.
+ *
+ * Within-Gamut Enhancement Intent (Source >= Destination):
+ * When the device (destination) gamut is not larger than the source gamut
+ * (#2 or #3), but the appearance of a larger gamut is desired, techniques
+ * such as saturation boost may be applied to the source colors. Skin-tone
+ * preservation may be applied. There is no unique method for within-gamut
+ * enhancement; it would be defined within a flexible color mode.
+ *
+ */
+typedef enum android_color_mode {
+
+ /*
+ * HAL_COLOR_MODE_DEFAULT is the "native" gamut of the display.
+ * White Point: Vendor/OEM defined
+ * Panel Gamma: Vendor/OEM defined (typically 2.2)
+ * Rendering Intent: Vendor/OEM defined (typically 'enhanced')
+ */
+ HAL_COLOR_MODE_NATIVE = 0,
+
+ /*
+ * HAL_COLOR_MODE_STANDARD_BT601_625 corresponds with display
+ * settings that implement the ITU-R Recommendation BT.601
+ * or Rec 601. Using 625 line version
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ *
+ * Gamma Correction (GC):
+ *
+ * if Vlinear < 0.018
+ * Vnonlinear = 4.500 * Vlinear
+ * else
+ * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+ */
+ HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
+
+ /*
+ * Primaries:
+ * x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
+ * for RGB conversion.
+ *
+ * Gamma Correction (GC):
+ *
+ * if Vlinear < 0.018
+ * Vnonlinear = 4.500 * Vlinear
+ * else
+ * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+ */
+ HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
+
+ /*
+ * Primaries:
+ * x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ *
+ * Gamma Correction (GC):
+ *
+ * if Vlinear < 0.018
+ * Vnonlinear = 4.500 * Vlinear
+ * else
+ * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+ */
+ HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
+
+ /*
+ * Primaries:
+ * x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
+ * for RGB conversion (as in SMPTE 240M).
+ *
+ * Gamma Correction (GC):
+ *
+ * if Vlinear < 0.018
+ * Vnonlinear = 4.500 * Vlinear
+ * else
+ * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+ */
+ HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
+
+ /*
+ * HAL_COLOR_MODE_REC709 corresponds with display settings that implement
+ * the ITU-R Recommendation BT.709 / Rec. 709 for high-definition television.
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.300 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * HDTV REC709 Inverse Gamma Correction (IGC): V represents normalized
+ * (with [0 to 1] range) value of R, G, or B.
+ *
+ * if Vnonlinear < 0.081
+ * Vlinear = Vnonlinear / 4.5
+ * else
+ * Vlinear = ((Vnonlinear + 0.099) / 1.099) ^ (1/0.45)
+ *
+ * HDTV REC709 Gamma Correction (GC):
+ *
+ * if Vlinear < 0.018
+ * Vnonlinear = 4.5 * Vlinear
+ * else
+ * Vnonlinear = 1.099 * (Vlinear) ^ 0.45 – 0.099
+ */
+ HAL_COLOR_MODE_STANDARD_BT709 = 5,
+
+ /*
+ * HAL_COLOR_MODE_DCI_P3 corresponds with display settings that implement
+ * SMPTE EG 432-1 and SMPTE RP 431-2
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.265 0.690
+ * blue 0.150 0.060
+ * red 0.680 0.320
+ * white (D65) 0.3127 0.3290
+ *
+ * Gamma: 2.2
+ */
+ HAL_COLOR_MODE_DCI_P3 = 6,
+
+ /*
+ * HAL_COLOR_MODE_SRGB corresponds with display settings that implement
+ * the sRGB color space. Uses the same primaries as ITU-R Recommendation
+ * BT.709
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.300 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * PC/Internet (sRGB) Inverse Gamma Correction (IGC):
+ *
+ * if Vnonlinear ≤ 0.03928
+ * Vlinear = Vnonlinear / 12.92
+ * else
+ * Vlinear = ((Vnonlinear + 0.055)/1.055) ^ 2.4
+ *
+ * PC/Internet (sRGB) Gamma Correction (GC):
+ *
+ * if Vlinear ≤ 0.0031308
+ * Vnonlinear = 12.92 * Vlinear
+ * else
+ * Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055
+ */
+ HAL_COLOR_MODE_SRGB = 7,
+
+ /*
+ * HAL_COLOR_MODE_ADOBE_RGB corresponds with the RGB color space developed
+ * by Adobe Systems, Inc. in 1998.
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.210 0.710
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Gamma: 2.2
+ */
+ HAL_COLOR_MODE_ADOBE_RGB = 8
+
+} android_color_mode_t;
+
+/*
* Color transforms that may be applied by hardware composer to the whole
* display.
*/
diff --git a/include/system/window.h b/include/system/window.h
index b8f33ff..33b7c3d 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -278,6 +278,16 @@
* age will be 0.
*/
NATIVE_WINDOW_BUFFER_AGE = 13,
+
+ /*
+ * Returns the duration of the last dequeueBuffer call in microseconds
+ */
+ NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14,
+
+ /*
+ * Returns the duration of the last queueBuffer call in microseconds
+ */
+ NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
};
/* Valid operations for the (*perform)() hook.
@@ -314,6 +324,7 @@
NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
+ NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 23,
};
/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -976,6 +987,18 @@
return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh);
}
+static inline int native_window_get_frame_timestamps(
+ struct ANativeWindow* window, uint32_t framesAgo,
+ int64_t* outPostedTime, int64_t* outAcquireTime,
+ int64_t* outRefreshStartTime, int64_t* outGlCompositionDoneTime,
+ int64_t* outDisplayRetireTime, int64_t* outReleaseTime)
+{
+ return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS,
+ framesAgo, outPostedTime, outAcquireTime, outRefreshStartTime,
+ outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime);
+}
+
+
__END_DECLS
#endif /* SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H */
diff --git a/init/Android.mk b/init/Android.mk
index 4a8df32..98bf12d 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -83,7 +83,7 @@
LOCAL_STATIC_LIBRARIES := \
libinit \
- libbootloader_message_writer \
+ libbootloader_message \
libfs_mgr \
libfec \
libfec_rs \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 48b1ad7..055723f 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -48,7 +48,7 @@
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
-#include <bootloader_message_writer.h>
+#include <bootloader_message/bootloader_message.h>
#include <cutils/partition_utils.h>
#include <cutils/android_reboot.h>
#include <logwrap/logwrap.h>
@@ -346,6 +346,11 @@
return 0;
}
+/* umount <path> */
+static int do_umount(const std::vector<std::string>& args) {
+ return umount(args[1].c_str());
+}
+
static struct {
const char *name;
unsigned flag;
@@ -857,8 +862,12 @@
int ret = 0;
for (auto it = std::next(args.begin()); it != args.end(); ++it) {
- if (restorecon_recursive(it->c_str()) < 0)
+ /* The contents of CE paths are encrypted on FBE devices until user
+ * credentials are presented (filenames inside are mangled), so we need
+ * to delay restorecon of those until vold explicitly requests it. */
+ if (restorecon_recursive_skipce(it->c_str()) < 0) {
ret = -errno;
+ }
}
return ret;
}
@@ -956,6 +965,7 @@
{"mkdir", {1, 4, do_mkdir}},
{"mount_all", {1, kMax, do_mount_all}},
{"mount", {3, kMax, do_mount}},
+ {"umount", {1, 1, do_umount}},
{"powerctl", {1, 1, do_powerctl}},
{"restart", {1, 1, do_restart}},
{"restorecon", {1, kMax, do_restorecon}},
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 1cfdd80..3dbb2f0 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -78,11 +78,13 @@
if (adb_enabled == "running") {
Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
if (svc) {
- LOG(INFO) << "Starting service " << svc->name() << " from keychord...";
+ LOG(INFO) << "Starting service " << svc->name() << " from keychord " << id;
svc->Start();
} else {
- LOG(ERROR) << "service for keychord " << id << " not found";
+ LOG(ERROR) << "Service for keychord " << id << " not found";
}
+ } else {
+ LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
}
}
diff --git a/init/readme.txt b/init/readme.txt
index 4c04f17..25b53ec 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -366,6 +366,9 @@
Trigger an event. Used to queue an action from another
action.
+umount <path>
+ Unmount the filesystem mounted at that path.
+
verity_load_state
Internal implementation detail used to load dm-verity state.
diff --git a/init/util.cpp b/init/util.cpp
index 10ab1c7..c1750d2 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -362,6 +362,12 @@
return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
}
+int restorecon_recursive_skipce(const char* pathname)
+{
+ return selinux_android_restorecon(pathname,
+ SELINUX_ANDROID_RESTORECON_RECURSE | SELINUX_ANDROID_RESTORECON_SKIPCE);
+}
+
/*
* Writes hex_len hex characters (1/2 byte) to hex from bytes.
*/
diff --git a/init/util.h b/init/util.h
index f020da8..29d0497 100644
--- a/init/util.h
+++ b/init/util.h
@@ -59,6 +59,7 @@
int make_dir(const char *path, mode_t mode);
int restorecon(const char *pathname);
int restorecon_recursive(const char *pathname);
+int restorecon_recursive_skipce(const char *pathname);
std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
bool is_dir(const char* pathname);
bool expand_props(const std::string& src, std::string* dst);
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 840ac86..9acfa58 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -91,6 +91,7 @@
{ 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest" },
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64" },
+ { 00775, AID_ROOT, AID_ROOT, 0, "data/preloads" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
{ 00755, AID_ROOT, AID_SYSTEM, 0, "mnt" },
{ 00755, AID_ROOT, AID_ROOT, 0, "root" },
@@ -142,6 +143,9 @@
{ 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
{ 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },
+ /* Support FIFO scheduling mode in SurfaceFlinger. */
+ { 00755, AID_SYSTEM, AID_GRAPHICS, CAP_MASK_LONG(CAP_SYS_NICE), "system/bin/surfaceflinger" },
+
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 32e6c25..0a8346b 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -63,9 +63,12 @@
static int bg_cpuset_fd = -1;
static int fg_cpuset_fd = -1;
static int ta_cpuset_fd = -1; // special cpuset for top app
+#endif
+
+// File descriptors open to /dev/stune/../tasks, setup by initialize, or -1 on error
static int bg_schedboost_fd = -1;
static int fg_schedboost_fd = -1;
-#endif
+static int ta_schedboost_fd = -1;
/* Add tid to the scheduling group defined by the policy */
static int add_tid_to_cgroup(int tid, int fd)
@@ -135,9 +138,11 @@
ta_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
#ifdef USE_SCHEDBOOST
+ filename = "/dev/stune/top-app/tasks";
+ ta_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
filename = "/dev/stune/foreground/tasks";
fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/stune/tasks";
+ filename = "/dev/stune/background/tasks";
bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
#endif
}
@@ -295,11 +300,10 @@
break;
case SP_TOP_APP :
fd = ta_cpuset_fd;
- boost_fd = fg_schedboost_fd;
+ boost_fd = ta_schedboost_fd;
break;
case SP_SYSTEM:
fd = system_bg_cpuset_fd;
- boost_fd = bg_schedboost_fd;
break;
default:
boost_fd = fd = -1;
@@ -311,10 +315,12 @@
return -errno;
}
+#ifdef USE_SCHEDBOOST
if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
if (errno != ESRCH && errno != ENOENT)
return -errno;
}
+#endif
return 0;
#endif
@@ -386,19 +392,26 @@
#endif
if (__sys_supports_schedgroups) {
- int fd;
+ int fd = -1;
+ int boost_fd = -1;
switch (policy) {
case SP_BACKGROUND:
fd = bg_cgroup_fd;
+ boost_fd = bg_schedboost_fd;
break;
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
+ fd = fg_cgroup_fd;
+ boost_fd = fg_schedboost_fd;
+ break;
case SP_TOP_APP:
fd = fg_cgroup_fd;
+ boost_fd = ta_schedboost_fd;
break;
default:
fd = -1;
+ boost_fd = -1;
break;
}
@@ -407,6 +420,13 @@
if (errno != ESRCH && errno != ENOENT)
return -errno;
}
+
+#ifdef USE_SCHEDBOOST
+ if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
+ if (errno != ESRCH && errno != ENOENT)
+ return -errno;
+ }
+#endif
} else {
struct sched_param param;
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
index 1da1942..b082a64 100644
--- a/logcat/logcatd.rc
+++ b/logcat/logcatd.rc
@@ -35,7 +35,8 @@
# all exec/services are called with umask(077), so no gain beyond 0700
mkdir /data/misc/logd 0700 logd log
# logd for write to /data/misc/logd, log group for read from pstore (-L)
- exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
+ # b/28788401 b/30041146 b/30612424
+ # exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
start logcatd
# stop logcatd service and clear data
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index ef6c1ae..c7506ef 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -402,7 +402,32 @@
}
}
-pid_t LogKlog::sniffPid(const char *cp, size_t len) {
+pid_t LogKlog::sniffPid(const char **buf, size_t len) {
+ const char *cp = *buf;
+ // HTC kernels with modified printk "c0 1648 "
+ if ((len > 9) &&
+ (cp[0] == 'c') &&
+ isdigit(cp[1]) &&
+ (isdigit(cp[2]) || (cp[2] == ' ')) &&
+ (cp[3] == ' ')) {
+ bool gotDigit = false;
+ int i;
+ for (i = 4; i < 9; ++i) {
+ if (isdigit(cp[i])) {
+ gotDigit = true;
+ } else if (gotDigit || (cp[i] != ' ')) {
+ break;
+ }
+ }
+ if ((i == 9) && (cp[i] == ' ')) {
+ int pid = 0;
+ char dummy;
+ if (sscanf(cp + 4, "%d%c", &pid, &dummy) == 2) {
+ *buf = cp + 10; // skip-it-all
+ return pid;
+ }
+ }
+ }
while (len) {
// Mediatek kernels with modified printk
if (*cp == '[') {
@@ -588,7 +613,7 @@
}
// Parse pid, tid and uid
- const pid_t pid = sniffPid(p, len - (p - buf));
+ const pid_t pid = sniffPid(&p, len - (p - buf));
const pid_t tid = pid;
uid_t uid = AID_ROOT;
if (pid) {
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index ee73b71..a4f871e 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -51,7 +51,7 @@
protected:
void sniffTime(log_time &now, const char **buf, size_t len, bool reverse);
- pid_t sniffPid(const char *buf, size_t len);
+ pid_t sniffPid(const char **buf, size_t len);
void calculateCorrection(const log_time &monotonic,
const char *real_string, size_t len);
virtual bool onDataAvailable(SocketClient *cli);
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e060a2c..aa5a520 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -26,6 +26,7 @@
#######################################
# asan.options
ifneq ($(filter address,$(SANITIZE_TARGET)),)
+
include $(CLEAR_VARS)
LOCAL_MODULE := asan.options
@@ -34,6 +35,72 @@
LOCAL_MODULE_PATH := $(TARGET_OUT)
include $(BUILD_PREBUILT)
+
+# Modules for asan.options.X files.
+
+ASAN_OPTIONS_FILES :=
+
+define create-asan-options-module
+include $$(CLEAR_VARS)
+LOCAL_MODULE := asan.options.$(1)
+ASAN_OPTIONS_FILES += asan.options.$(1)
+LOCAL_MODULE_CLASS := ETC
+# The asan.options.off.template tries to turn off as much of ASAN as is possible.
+LOCAL_SRC_FILES := asan.options.off.template
+LOCAL_MODULE_PATH := $(TARGET_OUT)
+include $$(BUILD_PREBUILT)
+endef
+
+# Pretty comprehensive set of native services. This list is helpful if all that's to be checked is an
+# app.
+ifeq ($(SANITIZE_LITE),true)
+SANITIZE_ASAN_OPTIONS_FOR := \
+ adbd \
+ ATFWD-daemon \
+ audioserver \
+ bridgemgrd \
+ cameraserver \
+ cnd \
+ debuggerd \
+ debuggerd64 \
+ dex2oat \
+ drmserver \
+ fingerprintd \
+ gatekeeperd \
+ installd \
+ keystore \
+ lmkd \
+ logcat \
+ logd \
+ lowi-server \
+ media.codec \
+ mediadrmserver \
+ media.extractor \
+ mediaserver \
+ mm-qcamera-daemon \
+ mpdecision \
+ netmgrd \
+ perfd \
+ perfprofd \
+ qmuxd \
+ qseecomd \
+ rild \
+ sdcard \
+ servicemanager \
+ slim_daemon \
+ surfaceflinger \
+ thermal-engine \
+ time_daemon \
+ update_engine \
+ vold \
+ wpa_supplicant \
+ zip
+endif
+
+ifneq ($(SANITIZE_ASAN_OPTIONS_FOR),)
+ $(foreach binary, $(SANITIZE_ASAN_OPTIONS_FOR), $(eval $(call create-asan-options-module,$(binary))))
+endif
+
endif
#######################################
@@ -47,14 +114,14 @@
EXPORT_GLOBAL_ASAN_OPTIONS :=
ifneq ($(filter address,$(SANITIZE_TARGET)),)
EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS include=/system/asan.options
- LOCAL_REQUIRED_MODULES := asan.options
+ LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES)
endif
# Put it here instead of in init.rc module definition,
# because init.rc is conditionally included.
#
# create some directories (some are mount points) and symlinks
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
- sbin dev proc sys system data oem acct cache config storage mnt root $(BOARD_ROOT_EXTRA_FOLDERS)); \
+ sbin dev proc sys system data oem acct config storage mnt root $(BOARD_ROOT_EXTRA_FOLDERS)); \
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
@@ -63,6 +130,11 @@
else
LOCAL_POST_INSTALL_CMD += ; ln -sf /system/vendor $(TARGET_ROOT_OUT)/vendor
endif
+ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
+ LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
+else
+ LOCAL_POST_INSTALL_CMD += ; ln -sf /data/cache $(TARGET_ROOT_OUT)/cache
+endif
ifdef BOARD_ROOT_EXTRA_SYMLINKS
# BOARD_ROOT_EXTRA_SYMLINKS is a list of <target>:<link_name>.
LOCAL_POST_INSTALL_CMD += $(foreach s, $(BOARD_ROOT_EXTRA_SYMLINKS),\
diff --git a/rootdir/asan.options b/rootdir/asan.options
index 43896a1..d728f12 100644
--- a/rootdir/asan.options
+++ b/rootdir/asan.options
@@ -3,3 +3,5 @@
alloc_dealloc_mismatch=0
allocator_may_return_null=1
detect_container_overflow=0
+abort_on_error=1
+include_if_exists=/system/asan.options.%b
diff --git a/rootdir/asan.options.off.template b/rootdir/asan.options.off.template
new file mode 100644
index 0000000..59a1249
--- /dev/null
+++ b/rootdir/asan.options.off.template
@@ -0,0 +1,7 @@
+quarantine_size_mb=0
+max_redzone=16
+poison_heap=false
+poison_partial=false
+poison_array_cookie=false
+alloc_dealloc_mismatch=false
+new_delete_type_mismatch=false
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a68cb78..f276b55 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -50,12 +50,20 @@
mkdir /dev/stune
mount cgroup none /dev/stune schedtune
mkdir /dev/stune/foreground
+ mkdir /dev/stune/background
+ mkdir /dev/stune/top-app
chown system system /dev/stune
chown system system /dev/stune/foreground
+ chown system system /dev/stune/background
+ chown system system /dev/stune/top-app
chown system system /dev/stune/tasks
chown system system /dev/stune/foreground/tasks
+ chown system system /dev/stune/background/tasks
+ chown system system /dev/stune/top-app/tasks
chmod 0664 /dev/stune/tasks
chmod 0664 /dev/stune/foreground/tasks
+ chmod 0664 /dev/stune/background/tasks
+ chmod 0664 /dev/stune/top-app/tasks
# Mount staging areas for devices managed by vold
# See storage config details at http://source.android.com/tech/storage/
@@ -134,16 +142,17 @@
chown system system /dev/cpuctl
chown system system /dev/cpuctl/tasks
chmod 0666 /dev/cpuctl/tasks
- write /dev/cpuctl/cpu.rt_runtime_us 800000
write /dev/cpuctl/cpu.rt_period_us 1000000
+ write /dev/cpuctl/cpu.rt_runtime_us 950000
mkdir /dev/cpuctl/bg_non_interactive
chown system system /dev/cpuctl/bg_non_interactive/tasks
chmod 0666 /dev/cpuctl/bg_non_interactive/tasks
# 5.0 %
write /dev/cpuctl/bg_non_interactive/cpu.shares 52
- write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 700000
write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000
+ # active FIFO threads will never be in BG
+ write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 10000
# sets up initial cpusets for ActivityManager
mkdir /dev/cpuset
@@ -225,6 +234,8 @@
# expecting it to point to /proc/self/fd
symlink /proc/self/fd /dev/fd
+ export DOWNLOAD_CACHE /data/cache
+
# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
@@ -394,6 +405,10 @@
# create the A/B OTA directory, so as to enforce our permissions
mkdir /data/ota 0771 root root
+ # create the OTA package directory. It will be accessed by GmsCore (cache
+ # group), update_engine and update_verifier.
+ mkdir /data/ota_package 0770 system cache
+
# create resource-cache and double-check the perms
mkdir /data/resource-cache 0771 system system
chown system system /data/resource-cache
@@ -438,6 +453,11 @@
mkdir /data/media 0770 media_rw media_rw
mkdir /data/media/obb 0770 media_rw media_rw
+ mkdir /data/cache 0770 system cache
+ mkdir /data/cache/recovery 0770 system cache
+ mkdir /data/cache/backup_stage 0700 system system
+ mkdir /data/cache/backup 0700 system system
+
init_user0
# Set SELinux security contexts on upgrade or policy update.
@@ -546,7 +566,7 @@
on nonencrypted
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier nonencrypted
+ exec - root cache -- /system/bin/update_verifier nonencrypted
class_start main
class_start late_start
@@ -569,12 +589,12 @@
on property:vold.decrypt=trigger_restart_min_framework
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier trigger_restart_min_framework
+ exec - root cache -- /system/bin/update_verifier trigger_restart_min_framework
class_start main
on property:vold.decrypt=trigger_restart_framework
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier trigger_restart_framework
+ exec - root cache -- /system/bin/update_verifier trigger_restart_framework
class_start main
class_start late_start
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 1fd1e2a..915d159 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -103,7 +103,7 @@
# Used to set USB configuration at boot and to switch the configuration
# when changing the default configuration
-on property:persist.sys.usb.config=*
+on boot && property:persist.sys.usb.config=*
setprop sys.usb.config ${persist.sys.usb.config}
#
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 807f9bc..2d7d5c2 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -8,4 +8,4 @@
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
- writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 10fa915..a5e32c2 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -8,11 +8,11 @@
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
- writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
priority -20
socket zygote_secondary stream 660 root system
onrestart restart zygote
- writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 13ffd7e..8584cbb 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -8,4 +8,4 @@
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
- writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 1164ac5..4a32097 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -8,11 +8,11 @@
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
- writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
priority -20
socket zygote_secondary stream 660 root system
onrestart restart zygote
- writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks