Merge changes from topic "move_bionic_to_apex3" am: a15f385821
am: 90b7095cf5
am: 7ce93d2d0d
Change-Id: I670493883a18e604bb3cbc80979c76d0a725c0ef
This commit is contained in:
commit
7b9a913497
3 changed files with 125 additions and 0 deletions
|
@ -25,6 +25,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
@ -209,6 +210,22 @@ done:
|
|||
return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
|
||||
}
|
||||
|
||||
static bool is_mountpoint(const std::string& path, pid_t tid) {
|
||||
const std::string mountinfo_path = "/proc/" + std::to_string(tid) + "/mountinfo";
|
||||
std::string mountinfo;
|
||||
if (!android::base::ReadFileToString(mountinfo_path, &mountinfo)) {
|
||||
PLOG(ERROR) << "Failed to open " << mountinfo_path;
|
||||
return false;
|
||||
}
|
||||
std::vector<std::string> lines = android::base::Split(mountinfo, "\n");
|
||||
return std::find_if(lines.begin(), lines.end(), [&path](const auto& line) {
|
||||
auto tokens = android::base::Split(line, " ");
|
||||
// line format is ...
|
||||
// mountid parentmountid major:minor sourcepath targetpath option ...
|
||||
return tokens.size() >= 4 && tokens[4] == path;
|
||||
}) != lines.end();
|
||||
}
|
||||
|
||||
// Make sure that SendFail from adb_io.cpp isn't accidentally used in this file.
|
||||
#pragma GCC poison SendFail
|
||||
|
||||
|
@ -415,6 +432,18 @@ static bool do_send(int s, const std::string& spec, std::vector<char>& buffer) {
|
|||
struct stat st;
|
||||
bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) ||
|
||||
(S_ISLNK(st.st_mode) && !S_ISLNK(mode));
|
||||
|
||||
// If the path is a file that is a mount point, don't unlink it, but instead
|
||||
// truncate to zero. If unlinked, existing mounts on the path is all
|
||||
// unmounted
|
||||
if (S_ISREG(st.st_mode) && is_mountpoint(path, getpid())) {
|
||||
do_unlink = false;
|
||||
if (truncate(path.c_str(), 0) == -1) {
|
||||
SendSyncFail(s, "truncate to zero failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_unlink) {
|
||||
adb_unlink(path.c_str());
|
||||
}
|
||||
|
@ -546,7 +575,64 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) {
|
|||
return true;
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
class FileSyncPreparer {
|
||||
public:
|
||||
FileSyncPreparer() : saved_ns_fd_(-1), rooted_(getuid() == 0) {
|
||||
const std::string namespace_path = "/proc/" + std::to_string(gettid()) + "/ns/mnt";
|
||||
const int ns_fd = adb_open(namespace_path.c_str(), O_RDONLY | O_CLOEXEC);
|
||||
if (ns_fd == -1) {
|
||||
if (rooted_) PLOG(ERROR) << "Failed to save mount namespace";
|
||||
return;
|
||||
}
|
||||
saved_ns_fd_.reset(ns_fd);
|
||||
|
||||
// Note: this is for the current thread only
|
||||
if (unshare(CLONE_NEWNS) != 0) {
|
||||
if (rooted_) PLOG(ERROR) << "Failed to clone mount namespace";
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the propagation type of / to private so that unmount below is
|
||||
// not propagated to other mount namespaces.
|
||||
if (mount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr) == -1) {
|
||||
if (rooted_) PLOG(ERROR) << "Could not change propagation type of / to MS_PRIVATE";
|
||||
return;
|
||||
}
|
||||
|
||||
// unmount /bionic which is bind-mount to itself by init. Under /bionic,
|
||||
// there are other bind mounts for the bionic files. By unmounting this,
|
||||
// we unmount them all thus revealing the raw file system that is the
|
||||
// same as the local file system seen by the adb client.
|
||||
if (umount2("/bionic", MNT_DETACH) == -1 && errno != ENOENT) {
|
||||
if (rooted_) PLOG(ERROR) << "Could not unmount /bionic to reveal raw filesystem";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
~FileSyncPreparer() {
|
||||
if (saved_ns_fd_.get() != -1) {
|
||||
// In fact, this is not strictly required because this thread for file
|
||||
// sync service will be destroyed after the current transfer is all
|
||||
// done. However, let's restore the ns in case the same thread is
|
||||
// reused by multiple transfers in the future refactoring.
|
||||
if (setns(saved_ns_fd_, CLONE_NEWNS) == -1) {
|
||||
PLOG(ERROR) << "Failed to restore saved mount namespace";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
unique_fd saved_ns_fd_;
|
||||
bool rooted_;
|
||||
};
|
||||
#endif
|
||||
|
||||
void file_sync_service(unique_fd fd) {
|
||||
#if defined(__ANDROID__)
|
||||
FileSyncPreparer preparer;
|
||||
#endif
|
||||
|
||||
std::vector<char> buffer(SYNC_DATA_MAX);
|
||||
|
||||
while (handle_sync_command(fd.get(), buffer)) {
|
||||
|
|
|
@ -230,6 +230,23 @@ static void reboot_for_remount(int fd, bool need_fsck) {
|
|||
android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd.c_str());
|
||||
}
|
||||
|
||||
static void try_unmount_bionic(int fd) {
|
||||
static constexpr const char* kBionic = "/bionic";
|
||||
struct statfs buf;
|
||||
if (statfs(kBionic, &buf) == -1) {
|
||||
WriteFdFmt(fd, "statfs of the %s mount failed: %s.\n", kBionic, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (buf.f_flags & ST_RDONLY) {
|
||||
// /bionic is on a read-only partition; can happen for
|
||||
// non-system-as-root-devices. Don' try to unmount.
|
||||
return;
|
||||
}
|
||||
// Success/Fail of the actual remount will be reported by the function.
|
||||
remount_partition(fd, kBionic);
|
||||
return;
|
||||
}
|
||||
|
||||
void remount_service(unique_fd fd, const std::string& cmd) {
|
||||
bool user_requested_reboot = cmd == "-R";
|
||||
|
||||
|
@ -323,6 +340,8 @@ void remount_service(unique_fd fd, const std::string& cmd) {
|
|||
return;
|
||||
}
|
||||
|
||||
try_unmount_bionic(fd.get());
|
||||
|
||||
if (!success) {
|
||||
WriteFdExactly(fd.get(), "remount failed\n");
|
||||
} else {
|
||||
|
|
|
@ -569,6 +569,18 @@ B="`adb_cat /vendor/hello`" ||
|
|||
die "vendor hello"
|
||||
check_eq "${A}" "${B}" /vendor before reboot
|
||||
|
||||
# download libc.so, append some gargage, push back, and check if the file is updated.
|
||||
tempdir="`mktemp -d`"
|
||||
cleanup() {
|
||||
rm -rf ${tempdir}
|
||||
}
|
||||
adb pull /system/lib/bootstrap/libc.so ${tempdir} || die "pull libc.so from device"
|
||||
garbage="`hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random`"
|
||||
echo ${garbage} >> ${tempdir}/libc.so
|
||||
adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so || die "push libc.so to device"
|
||||
adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice || die "pull libc.so from device"
|
||||
diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
|
||||
|
||||
echo "${GREEN}[ RUN ]${NORMAL} reboot to confirm content persistent" >&2
|
||||
|
||||
adb_reboot &&
|
||||
|
@ -607,6 +619,14 @@ adb_root &&
|
|||
check_eq "${A}" "${B}" vendor after reboot
|
||||
echo "${GREEN}[ OK ]${NORMAL} /vendor content remains after reboot" >&2
|
||||
|
||||
# check if the updated libc.so is persistent after reboot
|
||||
adb_root &&
|
||||
adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice ||
|
||||
die "pull libc.so from device"
|
||||
diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
|
||||
rm -r ${tempdir}
|
||||
echo "${GREEN}[ OK ]${NORMAL} /system/lib/bootstrap/libc.so content remains after reboot" >&2
|
||||
|
||||
echo "${GREEN}[ RUN ]${NORMAL} flash vendor, confirm its content disappears" >&2
|
||||
|
||||
H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
|
||||
|
|
Loading…
Reference in a new issue