Merge "fastboot should fail if it runs out of space while unzipping."
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 7ed5b2b..121197c 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -51,6 +51,14 @@
ASSERT_EQ("bar", parts[2]);
}
+TEST(strings, split_with_trailing_empty_part) {
+ std::vector<std::string> parts = android::base::Split("foo,bar,", ",");
+ ASSERT_EQ(3U, parts.size());
+ ASSERT_EQ("foo", parts[0]);
+ ASSERT_EQ("bar", parts[1]);
+ ASSERT_EQ("", parts[2]);
+}
+
TEST(strings, split_null_char) {
std::vector<std::string> parts =
android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1));
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 209e81b..c1d5430 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -194,10 +194,12 @@
sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
then
+ sleep 1
break
fi
if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]
then
+ sleep 1
break
fi
fi
@@ -239,7 +241,8 @@
[ "USAGE: EXPECT_PROPERTY <prop> <value> [--allow_failure]
-Returns true if current return (regex) value is true and the result matches" ]
+Returns true (0) if current return (regex) value is true and the result matches
+and the incoming return value is true as well (wired-or)" ]
EXPECT_PROPERTY() {
save_ret=${?}
property="${1}"
@@ -287,6 +290,7 @@
bootstat: Battery level at shutdown 100%
bootstat: Battery level at startup 100%
init : Parsing file /system/etc/init/bootstat.rc...
+init : Parsing file /system/etc/init/bootstat-debug.rc...
init : processing action (persist.test.boot.reason=*) from (/system/etc/init/bootstat-debug.rc:
init : Command 'setprop ro.boot.bootreason \${persist.test.boot.reason}' action=persist.test.boot.reason=* (/system/etc/init/bootstat-debug.rc:
init : processing action (post-fs-data) from (/system/etc/init/bootstat.rc
@@ -566,6 +570,8 @@
esac
adb reboot ${TEST}
wait_for_screen
+ bootloader_reason=`validate_property ro.boot.bootreason`
+ EXPECT_PROPERTY ro.boot.bootreason ${bootloader_reason}
EXPECT_PROPERTY sys.boot.reason ${reason}
EXPECT_PROPERTY persist.sys.boot.reason ${reason}
report_bootstat_logs ${reason}
@@ -623,8 +629,13 @@
adb reboot-bootloader
fi
fastboot format userdata >&2
+ save_ret=${?}
+ if [ 0 != ${save_ret} ]; then
+ echo "ERROR: fastboot can not format userdata" >&2
+ fi
fastboot reboot >&2
wait_for_screen
+ ( exit ${save_ret} ) # because one can not just do ?=${save_ret}
EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
EXPECT_PROPERTY persist.sys.boot.reason ""
report_bootstat_logs reboot,factory_reset bootloader \
@@ -868,17 +879,30 @@
- NB: should report reboot,its_just_so_hard
- NB: expect log \"... I bootstat: Unknown boot reason: reboot,its_just_so_hard\"" ]
test_Its_Just_So_Hard_reboot() {
- duration_test
+ if isDebuggable; then # see below
+ duration_test
+ else
+ duration_test `expr ${DURATION_DEFAULT} + ${DURATION_DEFAULT}`
+ fi
adb shell 'reboot "Its Just So Hard"'
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
EXPECT_PROPERTY persist.sys.boot.reason "reboot,Its Just So Hard"
- adb shell su root setprop persist.sys.boot.reason reboot,its_just_so_hard
- if checkDebugBuild; then
- flag=""
+ # Do not leave this test with an illegal value in persist.sys.boot.reason
+ save_ret=${?} # hold on to error code from above two lines
+ if isDebuggable; then # can do this easy, or we can do this hard.
+ adb shell su root setprop persist.sys.boot.reason reboot,its_just_so_hard
+ ( exit ${save_ret} ) # because one can not just do ?=${save_ret}
else
- flag="--allow_failure"
+ report_bootstat_logs reboot,its_just_so_hard # report what we have so far
+ # user build mitigation
+ adb shell reboot its_just_so_hard
+ wait_for_screen
+ ( exit ${save_ret} ) # because one can not just do ?=${save_ret}
+ EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
fi
+ # Ensure persist.sys.boot.reason now valid, failure here acts as a signal
+ # that we could choke up following tests. For example test_properties.
EXPECT_PROPERTY persist.sys.boot.reason reboot,its_just_so_hard ${flag}
report_bootstat_logs reboot,its_just_so_hard
}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 2270133..10753ce 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -223,6 +223,10 @@
{"2sec_reboot", 83},
{"reboot,by_key", 84},
{"reboot,longkey", 85},
+ {"reboot,2sec", 86},
+ {"shutdown,thermal,battery", 87},
+ {"reboot,its_just_so_hard", 88}, // produced by boot_reason_test
+ {"reboot,Its Just So Hard", 89}, // produced by boot_reason_test
};
// Converts a string value representing the reason the system booted to an
@@ -324,7 +328,105 @@
return android::base::ReadFileToString("/sys/fs/pstore/console-ramoops", &console);
}
-bool addKernelPanicSubReason(const std::string& console, std::string& ret) {
+// Implement a variant of std::string::rfind that is resilient to errors in
+// the data stream being inspected.
+class pstoreConsole {
+ private:
+ const size_t kBitErrorRate = 8; // number of bits per error
+ const std::string& console;
+
+ // Number of bits that differ between the two arguments l and r.
+ // Returns zero if the values for l and r are identical.
+ size_t numError(uint8_t l, uint8_t r) const { return std::bitset<8>(l ^ r).count(); }
+
+ // A string comparison function, reports the number of errors discovered
+ // in the match to a maximum of the bitLength / kBitErrorRate, at that
+ // point returning npos to indicate match is too poor.
+ //
+ // Since called in rfind which works backwards, expect cache locality will
+ // help if we check in reverse here as well for performance.
+ //
+ // Assumption: l (from console.c_str() + pos) is long enough to house
+ // _r.length(), checked in rfind caller below.
+ //
+ size_t numError(size_t pos, const std::string& _r) const {
+ const char* l = console.c_str() + pos;
+ const char* r = _r.c_str();
+ size_t n = _r.length();
+ const uint8_t* le = reinterpret_cast<const uint8_t*>(l) + n;
+ const uint8_t* re = reinterpret_cast<const uint8_t*>(r) + n;
+ size_t count = 0;
+ n = 0;
+ do {
+ // individual character bit error rate > threshold + slop
+ size_t num = numError(*--le, *--re);
+ if (num > ((8 + kBitErrorRate) / kBitErrorRate)) return std::string::npos;
+ // total bit error rate > threshold + slop
+ count += num;
+ ++n;
+ if (count > ((n * 8 + kBitErrorRate - (n > 2)) / kBitErrorRate)) {
+ return std::string::npos;
+ }
+ } while (le != reinterpret_cast<const uint8_t*>(l));
+ return count;
+ }
+
+ public:
+ explicit pstoreConsole(const std::string& console) : console(console) {}
+ // scope of argument must be equal to or greater than scope of pstoreConsole
+ explicit pstoreConsole(const std::string&& console) = delete;
+ explicit pstoreConsole(std::string&& console) = delete;
+
+ // Our implementation of rfind, use exact match first, then resort to fuzzy.
+ size_t rfind(const std::string& needle) const {
+ size_t pos = console.rfind(needle); // exact match?
+ if (pos != std::string::npos) return pos;
+
+ // Check to make sure needle fits in console string.
+ pos = console.length();
+ if (needle.length() > pos) return std::string::npos;
+ pos -= needle.length();
+ // fuzzy match to maximum kBitErrorRate
+ do {
+ if (numError(pos, needle) != std::string::npos) return pos;
+ } while (pos-- != 0);
+ return std::string::npos;
+ }
+
+ // Our implementation of find, use only fuzzy match.
+ size_t find(const std::string& needle, size_t start = 0) const {
+ // Check to make sure needle fits in console string.
+ if (needle.length() > console.length()) return std::string::npos;
+ const size_t last_pos = console.length() - needle.length();
+ // fuzzy match to maximum kBitErrorRate
+ for (size_t pos = start; pos <= last_pos; ++pos) {
+ if (numError(pos, needle) != std::string::npos) return pos;
+ }
+ return std::string::npos;
+ }
+};
+
+// If bit error match to needle, correct it.
+// Return true if any corrections were discovered and applied.
+bool correctForBer(std::string& reason, const std::string& needle) {
+ bool corrected = false;
+ if (reason.length() < needle.length()) return corrected;
+ const pstoreConsole console(reason);
+ const size_t last_pos = reason.length() - needle.length();
+ for (size_t pos = 0; pos <= last_pos; pos += needle.length()) {
+ pos = console.find(needle, pos);
+ if (pos == std::string::npos) break;
+
+ // exact match has no malice
+ if (needle == reason.substr(pos, needle.length())) continue;
+
+ corrected = true;
+ reason = reason.substr(0, pos) + needle + reason.substr(pos + needle.length());
+ }
+ return corrected;
+}
+
+bool addKernelPanicSubReason(const pstoreConsole& console, std::string& ret) {
// Check for kernel panic types to refine information
if (console.rfind("SysRq : Trigger a crash") != std::string::npos) {
// Can not happen, except on userdebug, during testing/debugging.
@@ -343,16 +445,28 @@
return false;
}
+bool addKernelPanicSubReason(const std::string& content, std::string& ret) {
+ return addKernelPanicSubReason(pstoreConsole(content), ret);
+}
+
// std::transform Helper callback functions:
// Converts a string value representing the reason the system booted to a
// string complying with Android system standard reason.
char tounderline(char c) {
return ::isblank(c) ? '_' : c;
}
+
char toprintable(char c) {
return ::isprint(c) ? c : '?';
}
+// Cleanup boot_reason regarding acceptable character set
+void transformReason(std::string& reason) {
+ std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
+ std::transform(reason.begin(), reason.end(), reason.begin(), tounderline);
+ std::transform(reason.begin(), reason.end(), reason.begin(), toprintable);
+}
+
const char system_reboot_reason_property[] = "sys.boot.reason";
const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";
@@ -366,10 +480,7 @@
// If sys.boot.reason == ro.boot.bootreason, let's re-evaluate
if (reason == ret) ret = "";
- // Cleanup boot_reason regarding acceptable character set
- std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
- std::transform(reason.begin(), reason.end(), reason.begin(), tounderline);
- std::transform(reason.begin(), reason.end(), reason.begin(), toprintable);
+ transformReason(reason);
// Is the current system boot reason sys.boot.reason valid?
if (!isKnownRebootReason(ret)) ret = "";
@@ -406,6 +517,7 @@
{"shutdown,thermal", "thermal"},
{"warm,s3_wakeup", "s3_wakeup"},
{"hard,hw_reset", "hw_reset"},
+ {"reboot,2sec", "2sec_reboot"},
{"bootloader", ""},
};
@@ -441,9 +553,10 @@
// Check to see if last klog has some refinement hints.
std::string content;
if (readPstoreConsole(content)) {
+ const pstoreConsole console(content);
// The toybox reboot command used directly (unlikely)? But also
// catches init's response to Android's more controlled reboot command.
- if (content.rfind("reboot: Power down") != std::string::npos) {
+ if (console.rfind("reboot: Power down") != std::string::npos) {
ret = "shutdown"; // Still too blunt, but more accurate.
// ToDo: init should record the shutdown reason to kernel messages ala:
// init: shutdown system with command 'last_reboot_reason'
@@ -452,32 +565,46 @@
}
static const char cmd[] = "reboot: Restarting system with command '";
- size_t pos = content.rfind(cmd);
+ size_t pos = console.rfind(cmd);
if (pos != std::string::npos) {
pos += strlen(cmd);
std::string subReason(content.substr(pos, max_reason_length));
+ // Correct against any known strings that Bit Error Match
+ for (const auto& s : knownReasons) {
+ correctForBer(subReason, s);
+ }
+ for (const auto& m : kBootReasonMap) {
+ if (m.first.length() <= strlen("cold")) continue; // too short?
+ if (correctForBer(subReason, m.first + "'")) continue;
+ if (m.first.length() <= strlen("reboot,cold")) continue; // short?
+ if (!android::base::StartsWith(m.first, "reboot,")) continue;
+ correctForBer(subReason, m.first.substr(strlen("reboot,")) + "'");
+ }
for (pos = 0; pos < subReason.length(); ++pos) {
- char c = tounderline(subReason[pos]);
- if (!::isprint(c) || (c == '\'')) {
+ char c = subReason[pos];
+ // #, &, %, / are common single bit error for ' that we can block
+ if (!::isprint(c) || (c == '\'') || (c == '#') || (c == '&') || (c == '%') || (c == '/')) {
subReason.erase(pos);
break;
}
- subReason[pos] = ::tolower(c);
}
+ transformReason(subReason);
if (subReason != "") { // Will not land "reboot" as that is too blunt.
if (isKernelRebootReason(subReason)) {
ret = "reboot," + subReason; // User space can't talk kernel reasons.
- } else {
+ } else if (isKnownRebootReason(subReason)) {
ret = subReason;
+ } else {
+ ret = "reboot," + subReason; // legitimize unknown reasons
}
}
}
// Check for kernel panics, allowed to override reboot command.
- if (!addKernelPanicSubReason(content, ret) &&
+ if (!addKernelPanicSubReason(console, ret) &&
// check for long-press power down
- ((content.rfind("Power held for ") != std::string::npos) ||
- (content.rfind("charger: [") != std::string::npos))) {
+ ((console.rfind("Power held for ") != std::string::npos) ||
+ (console.rfind("charger: [") != std::string::npos))) {
ret = "cold";
}
}
@@ -493,14 +620,33 @@
// Really a hail-mary pass to find it in last klog content ...
static const int battery_dead_threshold = 2; // percent
static const char battery[] = "healthd: battery l=";
- size_t pos = content.rfind(battery); // last one
+ const pstoreConsole console(content);
+ size_t pos = console.rfind(battery); // last one
std::string digits;
if (pos != std::string::npos) {
- digits = content.substr(pos + strlen(battery));
+ digits = content.substr(pos + strlen(battery), strlen("100 "));
+ // correct common errors
+ correctForBer(digits, "100 ");
+ if (digits[0] == '!') digits[0] = '1';
+ if (digits[1] == '!') digits[1] = '1';
}
- char* endptr = NULL;
- unsigned long long level = strtoull(digits.c_str(), &endptr, 10);
- if ((level <= 100) && (endptr != digits.c_str()) && (*endptr == ' ')) {
+ const char* endptr = digits.c_str();
+ unsigned level = 0;
+ while (::isdigit(*endptr)) {
+ level *= 10;
+ level += *endptr++ - '0';
+ // make sure no leading zeros, except zero itself, and range check.
+ if ((level == 0) || (level > 100)) break;
+ }
+ // example bit error rate issues for 10%
+ // 'l=10 ' no bits in error
+ // 'l=00 ' single bit error (fails above)
+ // 'l=1 ' single bit error
+ // 'l=0 ' double bit error
+ // There are others, not typically critical because of 2%
+ // battery_dead_threshold. KISS check, make sure second
+ // character after digit sequence is not a space.
+ if ((level <= 100) && (endptr != digits.c_str()) && (endptr[0] == ' ') && (endptr[1] != ' ')) {
LOG(INFO) << "Battery level at shutdown " << level << "%";
if (level <= battery_dead_threshold) {
ret = "shutdown,battery";
@@ -540,10 +686,16 @@
pos = content.find(match); // The first one it finds.
if (pos != std::string::npos) {
- digits = content.substr(pos + strlen(match));
+ digits = content.substr(pos + strlen(match), strlen("100 "));
}
- endptr = NULL;
- level = strtoull(digits.c_str(), &endptr, 10);
+ endptr = digits.c_str();
+ level = 0;
+ while (::isdigit(*endptr)) {
+ level *= 10;
+ level += *endptr++ - '0';
+ // make sure no leading zeros, except zero itself, and range check.
+ if ((level == 0) || (level > 100)) break;
+ }
if ((level <= 100) && (endptr != digits.c_str()) && (*endptr == ' ')) {
LOG(INFO) << "Battery level at startup " << level << "%";
if (level <= battery_dead_threshold) {
@@ -560,10 +712,7 @@
// Content buffer no longer will have console data. Beware if more
// checks added below, that depend on parsing console content.
content = GetProperty(last_reboot_reason_property);
- // Cleanup last_boot_reason regarding acceptable character set
- std::transform(content.begin(), content.end(), content.begin(), ::tolower);
- std::transform(content.begin(), content.end(), content.begin(), tounderline);
- std::transform(content.begin(), content.end(), content.begin(), toprintable);
+ transformReason(content);
// Anything in last is better than 'super-blunt' reboot or shutdown.
if ((ret == "") || (ret == "reboot") || (ret == "shutdown") || !isBluntRebootReason(content)) {
diff --git a/debuggerd/NOTICE b/debuggerd/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/debuggerd/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/debuggerd/signal_sender.cpp b/debuggerd/signal_sender.cpp
deleted file mode 100644
index 42a8e77..0000000
--- a/debuggerd/signal_sender.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "debuggerd-signal"
-
-#include <errno.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "signal_sender.h"
-
-static int signal_fd = -1;
-static pid_t signal_pid;
-struct signal_message {
- pid_t pid;
- pid_t tid;
- int signal;
-};
-
-static void set_signal_sender_process_name() {
-#if defined(__LP64__)
- static constexpr char long_process_name[] = "debuggerd64:signaller";
- static constexpr char short_process_name[] = "debuggerd64:sig";
- static_assert(sizeof(long_process_name) <= sizeof("/system/bin/debuggerd64"), "");
-#else
- static constexpr char long_process_name[] = "debuggerd:signaller";
- static constexpr char short_process_name[] = "debuggerd:sig";
- static_assert(sizeof(long_process_name) <= sizeof("/system/bin/debuggerd"), "");
-#endif
-
- // pthread_setname_np has a maximum length of 16 chars, including null terminator.
- static_assert(sizeof(short_process_name) <= 16, "");
- pthread_setname_np(pthread_self(), short_process_name);
-
- char* progname = const_cast<char*>(getprogname());
- if (strlen(progname) <= strlen(long_process_name)) {
- ALOGE("debuggerd: unexpected progname %s", progname);
- return;
- }
-
- memset(progname, 0, strlen(progname));
- strcpy(progname, long_process_name);
-}
-
-// Fork a process to send signals for the worker processes to use after they've dropped privileges.
-bool start_signal_sender() {
- if (signal_pid != 0) {
- ALOGE("debuggerd: attempted to start signal sender multiple times");
- return false;
- }
-
- int sfd[2];
- if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sfd) != 0) {
- ALOGE("debuggerd: failed to create socketpair for signal sender: %s", strerror(errno));
- return false;
- }
-
- pid_t parent = getpid();
- pid_t fork_pid = fork();
- if (fork_pid == -1) {
- ALOGE("debuggerd: failed to initialize signal sender: fork failed: %s", strerror(errno));
- return false;
- } else if (fork_pid == 0) {
- close(sfd[1]);
-
- set_signal_sender_process_name();
-
- while (true) {
- signal_message msg;
- int rc = TEMP_FAILURE_RETRY(read(sfd[0], &msg, sizeof(msg)));
- if (rc < 0) {
- ALOGE("debuggerd: signal sender failed to read from socket");
- break;
- } else if (rc != sizeof(msg)) {
- ALOGE("debuggerd: signal sender read unexpected number of bytes: %d", rc);
- break;
- }
-
- // Report success after sending a signal
- int err = 0;
- if (msg.tid > 0) {
- if (syscall(SYS_tgkill, msg.pid, msg.tid, msg.signal) != 0) {
- err = errno;
- }
- } else {
- if (kill(msg.pid, msg.signal) != 0) {
- err = errno;
- }
- }
-
- if (TEMP_FAILURE_RETRY(write(sfd[0], &err, sizeof(err))) < 0) {
- ALOGE("debuggerd: signal sender failed to write: %s", strerror(errno));
- }
- }
-
- // Our parent proably died, but if not, kill them.
- if (getppid() == parent) {
- kill(parent, SIGKILL);
- }
- _exit(1);
- } else {
- close(sfd[0]);
- signal_fd = sfd[1];
- signal_pid = fork_pid;
- return true;
- }
-}
-
-bool stop_signal_sender() {
- if (signal_pid <= 0) {
- return false;
- }
-
- if (kill(signal_pid, SIGKILL) != 0) {
- ALOGE("debuggerd: failed to kill signal sender: %s", strerror(errno));
- return false;
- }
-
- close(signal_fd);
- signal_fd = -1;
-
- int status;
- waitpid(signal_pid, &status, 0);
- signal_pid = 0;
-
- return true;
-}
-
-bool send_signal(pid_t pid, pid_t tid, int signal) {
- if (signal_fd == -1) {
- ALOGE("debuggerd: attempted to send signal before signal sender was started");
- errno = EHOSTUNREACH;
- return false;
- }
-
- signal_message msg = {.pid = pid, .tid = tid, .signal = signal };
- if (TEMP_FAILURE_RETRY(write(signal_fd, &msg, sizeof(msg))) < 0) {
- ALOGE("debuggerd: failed to send message to signal sender: %s", strerror(errno));
- errno = EHOSTUNREACH;
- return false;
- }
-
- int response;
- ssize_t rc = TEMP_FAILURE_RETRY(read(signal_fd, &response, sizeof(response)));
- if (rc == 0) {
- ALOGE("debuggerd: received EOF from signal sender");
- errno = EHOSTUNREACH;
- return false;
- } else if (rc < 0) {
- ALOGE("debuggerd: failed to receive response from signal sender: %s", strerror(errno));
- errno = EHOSTUNREACH;
- return false;
- }
-
- if (response == 0) {
- return true;
- }
-
- errno = response;
- return false;
-}
diff --git a/init/service.cpp b/init/service.cpp
index 765b61e..12acfc6 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -101,8 +101,22 @@
// It's OK to LOG(FATAL) in this function since it's running in the first
// child process.
- if (mount("", "/proc", "proc", kSafeFlags | MS_REMOUNT, "") == -1) {
- PLOG(FATAL) << "couldn't remount(/proc) for " << service_name;
+
+ // Recursively remount / as slave like zygote does so unmounting and mounting /proc
+ // doesn't interfere with the parent namespace's /proc mount. This will also
+ // prevent any other mounts/unmounts initiated by the service from interfering
+ // with the parent namespace but will still allow mount events from the parent
+ // namespace to propagate to the child.
+ if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
+ PLOG(FATAL) << "couldn't remount(/) recursively as slave for " << service_name;
+ }
+ // umount() then mount() /proc.
+ // Note that it is not sufficient to mount with MS_REMOUNT.
+ if (umount("/proc") == -1) {
+ PLOG(FATAL) << "couldn't umount(/proc) for " << service_name;
+ }
+ if (mount("", "/proc", "proc", kSafeFlags, "") == -1) {
+ PLOG(FATAL) << "couldn't mount(/proc) for " << service_name;
}
if (prctl(PR_SET_NAME, service_name.c_str()) == -1) {
@@ -706,14 +720,20 @@
}
Result<Success> Service::Start() {
+ bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
// Running processes require no additional work --- if they're in the
// process of exiting, we've ensured that they will immediately restart
- // on exit, unless they are ONESHOT.
+ // on exit, unless they are ONESHOT. For ONESHOT service, if it's in
+ // stopping status, we just set SVC_RESTART flag so it will get restarted
+ // in Reap().
if (flags_ & SVC_RUNNING) {
+ if ((flags_ & SVC_ONESHOT) && disabled) {
+ flags_ |= SVC_RESTART;
+ }
// It is not an error to try to start a service that is already running.
return Success();
}
@@ -940,6 +960,13 @@
} else {
flags_ |= how;
}
+ // Make sure it's in right status when a restart immediately follow a
+ // stop/reset or vice versa.
+ if (how == SVC_RESTART) {
+ flags_ &= (~(SVC_DISABLED | SVC_RESET));
+ } else {
+ flags_ &= (~SVC_RESTART);
+ }
if (pid_) {
KillProcessGroup(SIGKILL);
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 4c0c1a8..62e453f 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -45,12 +45,12 @@
bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) {
- static std::set<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
+ static std::vector<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
auto process_memory = stack_map->process_memory();
unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
regs, stack_map->process_memory());
- unwinder.Unwind(&skip_names);
+ unwinder.Unwind(&skip_names, &stack_map->GetSuffixesToIgnore());
if (num_ignore_frames >= unwinder.NumFrames()) {
frames->resize(0);
@@ -64,7 +64,7 @@
auto frame = &unwinder_frames[i];
backtrace_frame_data_t* back_frame = &frames->at(cur_frame);
- back_frame->num = frame->num;
+ back_frame->num = frame->num - num_ignore_frames;
back_frame->rel_pc = frame->rel_pc;
back_frame->pc = frame->pc;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index e5eb9e3..c3e5da0 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -1844,6 +1844,22 @@
UnwindThroughSignal(true, Backtrace::CreateNew, BacktraceMap::CreateNew);
}
+static void TestFrameSkipNumbering(create_func_t create_func, map_create_func_t map_create_func) {
+ std::unique_ptr<BacktraceMap> map(map_create_func(getpid(), false));
+ std::unique_ptr<Backtrace> backtrace(create_func(getpid(), gettid(), map.get()));
+ backtrace->Unwind(1);
+ ASSERT_NE(0U, backtrace->NumFrames());
+ ASSERT_EQ(0U, backtrace->GetFrame(0)->num);
+}
+
+TEST(libbacktrace, unwind_frame_skip_numbering) {
+ TestFrameSkipNumbering(Backtrace::Create, BacktraceMap::Create);
+}
+
+TEST(libbacktrace, unwind_frame_skip_numbering_new) {
+ TestFrameSkipNumbering(Backtrace::CreateNew, BacktraceMap::CreateNew);
+}
+
#if defined(ENABLE_PSS_TESTS)
#include "GetPss.h"
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index e176c78..84e7132 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -107,13 +107,20 @@
return map.end > 0;
}
-protected:
+ void SetSuffixesToIgnore(std::vector<std::string> suffixes) {
+ suffixes_to_ignore_.insert(suffixes_to_ignore_.end(), suffixes.begin(), suffixes.end());
+ }
+
+ const std::vector<std::string>& GetSuffixesToIgnore() { return suffixes_to_ignore_; }
+
+ protected:
BacktraceMap(pid_t pid);
virtual bool ParseLine(const char* line, backtrace_map_t* map);
- std::deque<backtrace_map_t> maps_;
pid_t pid_;
+ std::deque<backtrace_map_t> maps_;
+ std::vector<std::string> suffixes_to_ignore_;
};
class ScopedBacktraceMapIteratorLock {
diff --git a/liblog/tests/log_read_test.cpp b/liblog/tests/log_read_test.cpp
index 6ed568a..444a5ac 100644
--- a/liblog/tests/log_read_test.cpp
+++ b/liblog/tests/log_read_test.cpp
@@ -100,9 +100,13 @@
EXPECT_LT(0, get_log_size);
// crash buffer is allowed to be empty, that is actually healthy!
// kernel buffer is allowed to be empty on "user" builds
+ // stats buffer is allowed to be empty TEMPORARILY.
+ // TODO: remove stats buffer from here once we start to use it in
+ // framework (b/68266385).
EXPECT_LE( // boolean 1 or 0 depending on expected content or empty
!!((strcmp("crash", name) != 0) &&
- ((strcmp("kernel", name) != 0) || __android_log_is_debuggable())),
+ ((strcmp("kernel", name) != 0) || __android_log_is_debuggable()) &&
+ (strcmp("stats", name) != 0)),
android_logger_get_log_readable_size(logger));
} else {
EXPECT_NE(0, get_log_size);
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index f1580a4..2190711 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -22,6 +22,8 @@
#include <sys/types.h>
#include <unistd.h>
+#include <algorithm>
+
#include <android-base/stringprintf.h>
#include <unwindstack/Elf.h>
@@ -64,7 +66,8 @@
}
}
-static bool ShouldStop(const std::set<std::string>* map_suffixes_to_ignore, std::string& map_name) {
+static bool ShouldStop(const std::vector<std::string>* map_suffixes_to_ignore,
+ std::string& map_name) {
if (map_suffixes_to_ignore == nullptr) {
return false;
}
@@ -72,11 +75,13 @@
if (pos == std::string::npos) {
return false;
}
- return map_suffixes_to_ignore->find(map_name.substr(pos + 1)) != map_suffixes_to_ignore->end();
+
+ return std::find(map_suffixes_to_ignore->begin(), map_suffixes_to_ignore->end(),
+ map_name.substr(pos + 1)) != map_suffixes_to_ignore->end();
}
-void Unwinder::Unwind(const std::set<std::string>* initial_map_names_to_skip,
- const std::set<std::string>* map_suffixes_to_ignore) {
+void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
+ const std::vector<std::string>* map_suffixes_to_ignore) {
frames_.clear();
bool return_address_attempt = false;
@@ -97,8 +102,8 @@
}
if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
- initial_map_names_to_skip->find(basename(map_info->name.c_str())) ==
- initial_map_names_to_skip->end()) {
+ std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
+ basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
FillInFrame(map_info, elf, rel_pc, adjust_pc);
// Once a frame is added, stop skipping frames.
initial_map_names_to_skip = nullptr;
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index ca5933d..37a76b2 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -21,7 +21,6 @@
#include <sys/types.h>
#include <memory>
-#include <set>
#include <string>
#include <vector>
@@ -60,8 +59,8 @@
}
~Unwinder() = default;
- void Unwind(const std::set<std::string>* initial_map_names_to_skip = nullptr,
- const std::set<std::string>* map_suffixes_to_ignore = nullptr);
+ void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
+ const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
size_t NumFrames() { return frames_.size(); }
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 8384473..8a90bae 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -308,8 +308,8 @@
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
- std::set<std::string> skip_set{"libunwind.so", "libanother.so"};
- unwinder.Unwind(&skip_set);
+ std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
+ unwinder.Unwind(&skip_libs);
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -572,7 +572,7 @@
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
- std::set<std::string> suffixes{"oat"};
+ std::vector<std::string> suffixes{"oat"};
unwinder.Unwind(nullptr, &suffixes);
ASSERT_EQ(2U, unwinder.NumFrames());
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index e3faee3..075fb86 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -86,19 +86,6 @@
},
}
-// Also provide libziparchive-host until everything is switched over to using libziparchive
-cc_library {
- name: "libziparchive-host",
- host_supported: true,
- device_supported: false,
- defaults: [
- "libziparchive_defaults",
- "libziparchive_flags",
- ],
- shared_libs: ["libz"],
- static_libs: ["libutils"],
-}
-
// Tests.
cc_test {
name: "ziparchive-tests",
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 73ae68d..dd463d1 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -230,4 +230,44 @@
ProcessZipEntryFunction func, void* cookie);
#endif
+namespace zip_archive {
+
+class Writer {
+ public:
+ virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
+ virtual ~Writer();
+
+ protected:
+ Writer() = default;
+
+ private:
+ Writer(const Writer&) = delete;
+ void operator=(const Writer&) = delete;
+};
+
+class Reader {
+ public:
+ virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const = 0;
+ virtual ~Reader();
+
+ protected:
+ Reader() = default;
+
+ private:
+ Reader(const Reader&) = delete;
+ void operator=(const Reader&) = delete;
+};
+
+/*
+ * Inflates the first |compressed_length| bytes of |reader| to a given |writer|.
+ * |crc_out| is set to the CRC32 checksum of the uncompressed data.
+ *
+ * Returns 0 on success and negative values on failure, for example if |reader|
+ * cannot supply the right amount of data, or if the number of bytes written to
+ * data does not match |uncompressed_length|.
+ */
+int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
+ const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out);
+} // namespace zip_archive
+
#endif // LIBZIPARCHIVE_ZIPARCHIVE_H_
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 7f47adb..a4b5dc5 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -725,22 +725,10 @@
return kIterationEnd;
}
-class Writer {
- public:
- virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
- virtual ~Writer() {}
-
- protected:
- Writer() = default;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Writer);
-};
-
// A Writer that writes data to a fixed size memory region.
// The size of the memory region must be equal to the total size of
// the data appended to it.
-class MemoryWriter : public Writer {
+class MemoryWriter : public zip_archive::Writer {
public:
MemoryWriter(uint8_t* buf, size_t size) : Writer(), buf_(buf), size_(size), bytes_written_(0) {}
@@ -764,7 +752,7 @@
// A Writer that appends data to a file |fd| at its current position.
// The file will be truncated to the end of the written data.
-class FileWriter : public Writer {
+class FileWriter : public zip_archive::Writer {
public:
// Creates a FileWriter for |fd| and prepare to write |entry| to it,
// guaranteeing that the file descriptor is valid and that there's enough
@@ -848,6 +836,22 @@
size_t total_bytes_written_;
};
+class EntryReader : public zip_archive::Reader {
+ public:
+ EntryReader(const MappedZipFile& zip_file, const ZipEntry* entry)
+ : Reader(), zip_file_(zip_file), entry_(entry) {}
+
+ virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ return zip_file_.ReadAtOffset(buf, len, entry_->offset + offset);
+ }
+
+ virtual ~EntryReader() {}
+
+ private:
+ const MappedZipFile& zip_file_;
+ const ZipEntry* entry_;
+};
+
// This method is using libz macros with old-style-casts
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
@@ -856,8 +860,14 @@
}
#pragma GCC diagnostic pop
-static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
- Writer* writer, uint64_t* crc_out) {
+namespace zip_archive {
+
+// Moved out of line to avoid -Wweak-vtables.
+Reader::~Reader() {}
+Writer::~Writer() {}
+
+int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
+ const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out) {
const size_t kBufSize = 32768;
std::vector<uint8_t> read_buf(kBufSize);
std::vector<uint8_t> write_buf(kBufSize);
@@ -898,25 +908,23 @@
std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
- const uint32_t uncompressed_length = entry->uncompressed_length;
-
uint64_t crc = 0;
- uint32_t compressed_length = entry->compressed_length;
+ uint32_t remaining_bytes = compressed_length;
do {
/* read as much as we can */
if (zstream.avail_in == 0) {
- const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
- off64_t offset = entry->offset + (entry->compressed_length - compressed_length);
+ const size_t read_size = (remaining_bytes > kBufSize) ? kBufSize : remaining_bytes;
+ const uint32_t offset = (compressed_length - remaining_bytes);
// Make sure to read at offset to ensure concurrent access to the fd.
- if (!mapped_zip.ReadAtOffset(read_buf.data(), getSize, offset)) {
- ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
+ if (!reader.ReadAtOffset(read_buf.data(), read_size, offset)) {
+ ALOGW("Zip: inflate read failed, getSize = %zu: %s", read_size, strerror(errno));
return kIoError;
}
- compressed_length -= getSize;
+ remaining_bytes -= read_size;
zstream.next_in = &read_buf[0];
- zstream.avail_in = getSize;
+ zstream.avail_in = read_size;
}
/* uncompress the data */
@@ -952,7 +960,7 @@
// the same manner that we have above.
*crc_out = crc;
- if (zstream.total_out != uncompressed_length || compressed_length != 0) {
+ if (zstream.total_out != uncompressed_length || remaining_bytes != 0) {
ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")", zstream.total_out,
uncompressed_length);
return kInconsistentInformation;
@@ -960,9 +968,18 @@
return 0;
}
+} // namespace zip_archive
-static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, Writer* writer,
- uint64_t* crc_out) {
+static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
+ zip_archive::Writer* writer, uint64_t* crc_out) {
+ const EntryReader reader(mapped_zip, entry);
+
+ return zip_archive::Inflate(reader, entry->compressed_length, entry->uncompressed_length, writer,
+ crc_out);
+}
+
+static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
+ zip_archive::Writer* writer, uint64_t* crc_out) {
static const uint32_t kBufSize = 32768;
std::vector<uint8_t> buf(kBufSize);
@@ -995,7 +1012,7 @@
return 0;
}
-int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, Writer* writer) {
+int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, zip_archive::Writer* writer) {
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
const uint16_t method = entry->method;
@@ -1025,12 +1042,12 @@
}
int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size) {
- std::unique_ptr<Writer> writer(new MemoryWriter(begin, size));
+ std::unique_ptr<zip_archive::Writer> writer(new MemoryWriter(begin, size));
return ExtractToWriter(handle, entry, writer.get());
}
int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd) {
- std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry));
+ std::unique_ptr<zip_archive::Writer> writer(FileWriter::Create(fd, entry));
if (writer.get() == nullptr) {
return kIoError;
}
@@ -1063,7 +1080,7 @@
}
#if !defined(_WIN32)
-class ProcessWriter : public Writer {
+class ProcessWriter : public zip_archive::Writer {
public:
ProcessWriter(ProcessZipEntryFunction func, void* cookie)
: Writer(), proc_function_(func), cookie_(cookie) {}
@@ -1118,7 +1135,7 @@
}
// Attempts to read |len| bytes into |buf| at offset |off|.
-bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) {
+bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const {
if (has_fd_) {
if (!android::base::ReadFullyAtOffset(fd_, buf, len, off)) {
ALOGE("Zip: failed to read at offset %" PRId64 "\n", off);
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 174aa3f..18e0229 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -106,7 +106,7 @@
off64_t GetFileLength() const;
- bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off);
+ bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const;
private:
// If has_fd_ is true, fd is valid and we'll read contents of a zip archive
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 21f24f2..f75036d 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -62,7 +62,6 @@
cameraserver \
cnd \
debuggerd \
- debuggerd64 \
dex2oat \
drmserver \
fingerprintd \
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 917e99d..96eb6f3 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -166,9 +166,6 @@
mkdir /dev/cpuset/foreground
copy /dev/cpuset/cpus /dev/cpuset/foreground/cpus
copy /dev/cpuset/mems /dev/cpuset/foreground/mems
- mkdir /dev/cpuset/foreground/boost
- copy /dev/cpuset/cpus /dev/cpuset/foreground/boost/cpus
- copy /dev/cpuset/mems /dev/cpuset/foreground/boost/mems
mkdir /dev/cpuset/background
copy /dev/cpuset/cpus /dev/cpuset/background/cpus
copy /dev/cpuset/mems /dev/cpuset/background/mems
@@ -187,13 +184,11 @@
# change permissions for all cpusets we'll touch at runtime
chown system system /dev/cpuset
chown system system /dev/cpuset/foreground
- chown system system /dev/cpuset/foreground/boost
chown system system /dev/cpuset/background
chown system system /dev/cpuset/system-background
chown system system /dev/cpuset/top-app
chown system system /dev/cpuset/tasks
chown system system /dev/cpuset/foreground/tasks
- chown system system /dev/cpuset/foreground/boost/tasks
chown system system /dev/cpuset/background/tasks
chown system system /dev/cpuset/system-background/tasks
chown system system /dev/cpuset/top-app/tasks
@@ -202,7 +197,6 @@
chmod 0775 /dev/cpuset/system-background
chmod 0664 /dev/cpuset/foreground/tasks
- chmod 0664 /dev/cpuset/foreground/boost/tasks
chmod 0664 /dev/cpuset/background/tasks
chmod 0664 /dev/cpuset/system-background/tasks
chmod 0664 /dev/cpuset/top-app/tasks