if (!android::base::WriteFully(fd, message, kMinadbdMessageSize)) {
PLOG(ERROR) << "Failed to write message " << message; returnfalse;
} returntrue;
}
// Blocks and reads the command status from |fd|. Returns false if the received message has a // format error. staticbool WaitForCommandStatus(int fd, MinadbdCommandStatus* status) { char buffer[kMinadbdMessageSize]; if (!android::base::ReadFully(fd, buffer, kMinadbdMessageSize)) {
PLOG(ERROR) << "Failed to response status from socket"; exit(kMinadbdSocketIOError);
}
std::string message(buffer, buffer + kMinadbdMessageSize); if (!android::base::StartsWith(message, kMinadbdStatusPrefix)) {
LOG(ERROR) << "Failed to parse status in " << message; returnfalse;
}
if (!WriteCommandToFd(MinadbdCommand::kInstall, minadbd_socket)) { return kMinadbdSocketIOError;
}
auto adb_data_reader = std::make_unique<FuseAdbDataProvider>(sfd, file_size, block_size); if (int result = run_fuse_sideload(std::move(adb_data_reader), sideload_mount_point.c_str());
result != 0) {
LOG(ERROR) << "Failed to start fuse"; return kMinadbdFuseStartError;
}
if (!WaitForCommandStatus(minadbd_socket, status)) { return kMinadbdMessageFormatError;
}
// Signal host-side adb to stop. For sideload mode, we always send kMinadbdServicesExitSuccess // (i.e. "DONEDONE") regardless of the install result. For rescue mode, we send failure message on // install error. if (!rescue_mode || *status == MinadbdCommandStatus::kSuccess) { if (!android::base::WriteFully(sfd, kMinadbdServicesExitSuccess,
strlen(kMinadbdServicesExitSuccess))) { return kMinadbdHostSocketIOError;
}
} else { if (!android::base::WriteFully(sfd, kMinadbdServicesExitFailure,
strlen(kMinadbdServicesExitFailure))) { return kMinadbdHostSocketIOError;
}
}
return kMinadbdSuccess;
}
staticbool WaitForSocketClose(int fd, std::chrono::milliseconds timeout) { constauto begin = std::chrono::steady_clock::now(); constauto end = begin + timeout; while (std::chrono::steady_clock::now() < end) { // We don't care about reading the socket, we just want to wait until // socket closes. In this case .events = 0 will tell the kernel to wait // for close events. struct pollfd pfd = { .fd = fd, .events = 0 }; auto timeout_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
end - std::chrono::steady_clock::now())
.count(); int rc = TEMP_FAILURE_RETRY(adb_poll(&pfd, 1, timeout_ms)); if (rc == 1) {
LOG(INFO) << "revents: " << pfd.revents; if (pfd.revents & (POLLHUP | POLLRDHUP)) { returntrue;
}
} else {
PLOG(ERROR) << "poll() failed"; // poll failed, almost definitely due to timeout // If not, you're screwed anyway, because it probably means the kernel ran // out of memory. returnfalse;
}
} returnfalse;
}
// Sideload service always exits after serving an install command. staticvoid SideloadHostService(unique_fd sfd, const std::string& args) { usingnamespace std::chrono_literals;
MinadbdCommandStatus status; auto error = RunAdbFuseSideload(sfd.get(), args, &status); // No need to wait if the socket is already closed, meaning the other end // already exited for some reason. if (error != kMinadbdHostSocketIOError) { // We sleep for a little bit just to wait for the host to receive last // "DONEDONE" message. However minadbd process is likely to get terminated // early due to exit_on_close
WaitForSocketClose(sfd, 3000ms);
} exit(error);
}
// Rescue service waits for the next command after an install command. staticvoid RescueInstallHostService(unique_fd sfd, const std::string& args) {
MinadbdCommandStatus status; if (auto result = RunAdbFuseSideload(sfd.get(), args, &status); result != kMinadbdSuccess) { exit(result);
}
}
// Answers the query on a given property |prop|, by writing the result to the given |sfd|. The // result will be newline-terminated, so nonexistent or nonallowed query will be answered with "\n". // If given an empty string, dumps all the supported properties (analogous to `adb shell getprop`) // in lines, e.g. "[prop]: [value]". staticvoid RescueGetpropHostService(unique_fd sfd, const std::string& prop) {
constexpr constchar* kRescueBatteryLevelProp = "rescue.battery_level"; staticconst std::set<std::string> kGetpropAllowedProps = { // clang-format off
kRescueBatteryLevelProp, "ro.build.date.utc", "ro.build.fingerprint", "ro.build.flavor", "ro.build.id", "ro.build.product", "ro.build.tags", "ro.build.version.incremental", "ro.product.device", "ro.product.vendor.device", // clang-format on
};
auto query_prop = [](const std::string& key) { if (key == kRescueBatteryLevelProp) { auto battery_info = GetBatteryInfo(); return std::to_string(battery_info.capacity);
} return android::base::GetProperty(key, "");
};
std::string result; if (prop.empty()) { for (constauto& key : kGetpropAllowedProps) { auto value = query_prop(key); if (value.empty()) { continue;
}
result += "[" + key + "]: [" + value + "]\n";
}
} elseif (kGetpropAllowedProps.contains(prop)) {
result = query_prop(prop) + "\n";
} if (result.empty()) {
result = "\n";
} if (!android::base::WriteFully(sfd, result.data(), result.size())) { exit(kMinadbdHostSocketIOError);
}
// Send heartbeat signal to keep the rescue service alive. if (!WriteCommandToFd(MinadbdCommand::kNoOp, minadbd_socket)) { exit(kMinadbdSocketIOError);
} if (MinadbdCommandStatus status; !WaitForCommandStatus(minadbd_socket, &status)) { exit(kMinadbdMessageFormatError);
}
}
// Reboots into the given target. We don't reboot directly from minadbd, but going through recovery // instead. This allows recovery to finish all the pending works (clear BCB, save logs etc) before // the reboot. staticvoid RebootHostService(unique_fd /* sfd */, const std::string& target) {
MinadbdCommand command; if (target == "bootloader") {
command = MinadbdCommand::kRebootBootloader;
} elseif (target == "rescue") {
command = MinadbdCommand::kRebootRescue;
} elseif (target == "recovery") {
command = MinadbdCommand::kRebootRecovery;
} elseif (target == "fastboot") {
command = MinadbdCommand::kRebootFastboot;
} else {
command = MinadbdCommand::kRebootAndroid;
} if (!WriteCommandToFd(command, minadbd_socket)) { exit(kMinadbdSocketIOError);
}
MinadbdCommandStatus status; if (!WaitForCommandStatus(minadbd_socket, &status)) { exit(kMinadbdMessageFormatError);
}
}
unique_fd daemon_service_to_fd(std::string_view name, atransport* /* transport */) { // Common services that are supported both in sideload and rescue modes. if (android::base::ConsumePrefix(&name, "reboot:")) { // "reboot:<target>", where target must be one of the following.
std::string args(name); if (args.empty() || args == "bootloader" || args == "rescue" || args == "recovery" ||
args == "fastboot") { return create_service_thread("reboot",
std::bind(RebootHostService, std::placeholders::_1, args));
} return unique_fd{};
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.