Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 37d7d67c authored by Tianjie Xu's avatar Tianjie Xu
Browse files

DO NOT MERGE Report uncrypt errors in details

Add the error codes for uncrypt and report the failure details in
uncrypt_status.

Test: uncrypt_error logs correctly in last_install
Bug: 31603820
Change-Id: I8e0de845ce1707b6f8f5ae84564c5e93fd5f5ef5
(cherry picked from commit da44cf18)
parent a8c0d0b4
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -44,4 +44,26 @@ enum CauseCode {
    kVendorFailure = 200
};

enum UncryptErrorCode {
    kUncryptNoError = -1,
    kUncryptErrorPlaceholder = 50,
    kUncryptTimeoutError = 100,
    kUncryptFileRemoveError,
    kUncryptFileOpenError,
    kUncryptSocketOpenError,
    kUncryptSocketWriteError,
    kUncryptSocketListenError,
    kUncryptSocketAcceptError,
    kUncryptFstabReadError,
    kUncryptFileStatError,
    kUncryptBlockOpenError,
    kUncryptIoctlError,
    kUncryptReadError,
    kUncryptWriteError,
    kUncryptFileSyncError,
    kUncryptFileCloseError,
    kUncryptFileRenameError,
    kUncryptPackageMissingError,
};

#endif
+1 −1
Original line number Diff line number Diff line
@@ -532,7 +532,7 @@ install_package(const char* path, bool* wipe_cache, const char* install_file,
        std::string uncrypt_status;
        if (!android::base::ReadFileToString(UNCRYPT_STATUS, &uncrypt_status)) {
            LOGW("failed to read uncrypt status: %s\n", strerror(errno));
        } else if (!android::base::StartsWith(uncrypt_status, "uncrypt_time:")) {
        } else if (!android::base::StartsWith(uncrypt_status, "uncrypt_")) {
            LOGW("corrupted uncrypt_status: %s: %s\n", uncrypt_status.c_str(), strerror(errno));
        } else {
            log_buffer.push_back(android::base::Trim(uncrypt_status));
+52 −39
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@
#define LOG_TAG "uncrypt"
#include <log/log.h>

#include "error_code.h"
#include "unique_fd.h"

#define WINDOW_SIZE 5
@@ -235,25 +236,25 @@ static int produce_block_map(const char* path, const char* map_file, const char*
    std::string err;
    if (!android::base::RemoveFileIfExists(map_file, &err)) {
        ALOGE("failed to remove the existing map file %s: %s", map_file, err.c_str());
        return -1;
        return kUncryptFileRemoveError;
    }
    std::string tmp_map_file = std::string(map_file) + ".tmp";
    unique_fd mapfd(open(tmp_map_file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR));
    if (!mapfd) {
        ALOGE("failed to open %s: %s\n", tmp_map_file.c_str(), strerror(errno));
        return -1;
        return kUncryptFileOpenError;
    }

    // Make sure we can write to the socket.
    if (!write_status_to_socket(0, socket)) {
        ALOGE("failed to write to socket %d\n", socket);
        return -1;
        return kUncryptSocketWriteError;
    }

    struct stat sb;
    if (stat(path, &sb) != 0) {
        ALOGE("failed to stat %s", path);
        return -1;
        return kUncryptFileStatError;
    }

    ALOGI(" block size: %ld bytes", static_cast<long>(sb.st_blksize));
@@ -267,7 +268,7 @@ static int produce_block_map(const char* path, const char* map_file, const char*
                       blk_dev, sb.st_size, static_cast<long>(sb.st_blksize));
    if (!android::base::WriteStringToFd(s, mapfd.get())) {
        ALOGE("failed to write %s: %s", tmp_map_file.c_str(), strerror(errno));
        return -1;
        return kUncryptWriteError;
    }

    std::vector<std::vector<unsigned char>> buffers;
@@ -280,7 +281,7 @@ static int produce_block_map(const char* path, const char* map_file, const char*
    unique_fd fd(open(path, O_RDONLY));
    if (!fd) {
        ALOGE("failed to open %s for reading: %s", path, strerror(errno));
        return -1;
        return kUncryptFileOpenError;
    }

    unique_fd wfd(-1);
@@ -288,7 +289,7 @@ static int produce_block_map(const char* path, const char* map_file, const char*
        wfd = open(blk_dev, O_WRONLY);
        if (!wfd) {
            ALOGE("failed to open fd for writing: %s", strerror(errno));
            return -1;
            return kUncryptBlockOpenError;
        }
    }

@@ -307,13 +308,13 @@ static int produce_block_map(const char* path, const char* map_file, const char*
            int block = head_block;
            if (ioctl(fd.get(), FIBMAP, &block) != 0) {
                ALOGE("failed to find block %d", head_block);
                return -1;
                return kUncryptIoctlError;
            }
            add_block_to_ranges(ranges, block);
            if (encrypted) {
                if (write_at_offset(buffers[head].data(), sb.st_blksize, wfd.get(),
                        static_cast<off64_t>(sb.st_blksize) * block) != 0) {
                    return -1;
                    return kUncryptWriteError;
                }
            }
            head = (head + 1) % WINDOW_SIZE;
@@ -326,7 +327,7 @@ static int produce_block_map(const char* path, const char* map_file, const char*
                    std::min(static_cast<off64_t>(sb.st_blksize), sb.st_size - pos));
            if (!android::base::ReadFully(fd.get(), buffers[tail].data(), to_read)) {
                ALOGE("failed to read: %s", strerror(errno));
                return -1;
                return kUncryptReadError;
            }
            pos += to_read;
        } else {
@@ -343,13 +344,13 @@ static int produce_block_map(const char* path, const char* map_file, const char*
        int block = head_block;
        if (ioctl(fd.get(), FIBMAP, &block) != 0) {
            ALOGE("failed to find block %d", head_block);
            return -1;
            return kUncryptIoctlError;
        }
        add_block_to_ranges(ranges, block);
        if (encrypted) {
            if (write_at_offset(buffers[head].data(), sb.st_blksize, wfd.get(),
                    static_cast<off64_t>(sb.st_blksize) * block) != 0) {
                return -1;
                return kUncryptWriteError;
            }
        }
        head = (head + 1) % WINDOW_SIZE;
@@ -359,41 +360,41 @@ static int produce_block_map(const char* path, const char* map_file, const char*
    if (!android::base::WriteStringToFd(
            android::base::StringPrintf("%zu\n", ranges.size() / 2), mapfd.get())) {
        ALOGE("failed to write %s: %s", tmp_map_file.c_str(), strerror(errno));
        return -1;
        return kUncryptWriteError;
    }
    for (size_t i = 0; i < ranges.size(); i += 2) {
        if (!android::base::WriteStringToFd(
                android::base::StringPrintf("%d %d\n", ranges[i], ranges[i+1]), mapfd.get())) {
            ALOGE("failed to write %s: %s", tmp_map_file.c_str(), strerror(errno));
            return -1;
            return kUncryptWriteError;
        }
    }

    if (fsync(mapfd.get()) == -1) {
        ALOGE("failed to fsync \"%s\": %s", tmp_map_file.c_str(), strerror(errno));
        return -1;
        return kUncryptFileSyncError;
    }
    if (close(mapfd.get()) == -1) {
        ALOGE("failed to close %s: %s", tmp_map_file.c_str(), strerror(errno));
        return -1;
        return kUncryptFileCloseError;
    }
    mapfd = -1;

    if (encrypted) {
        if (fsync(wfd.get()) == -1) {
            ALOGE("failed to fsync \"%s\": %s", blk_dev, strerror(errno));
            return -1;
            return kUncryptFileSyncError;
        }
        if (close(wfd.get()) == -1) {
            ALOGE("failed to close %s: %s", blk_dev, strerror(errno));
            return -1;
            return kUncryptFileCloseError;
        }
        wfd = -1;
    }

    if (rename(tmp_map_file.c_str(), map_file) == -1) {
        ALOGE("failed to rename %s to %s: %s", tmp_map_file.c_str(), map_file, strerror(errno));
        return -1;
        return kUncryptFileRenameError;
    }
    // Sync dir to make rename() result written to disk.
    std::string file_name = map_file;
@@ -401,15 +402,15 @@ static int produce_block_map(const char* path, const char* map_file, const char*
    unique_fd dfd(open(dir_name.c_str(), O_RDONLY | O_DIRECTORY));
    if (!dfd) {
        ALOGE("failed to open dir %s: %s", dir_name.c_str(), strerror(errno));
        return -1;
        return kUncryptFileOpenError;
    }
    if (fsync(dfd.get()) == -1) {
        ALOGE("failed to fsync %s: %s", dir_name.c_str(), strerror(errno));
        return -1;
        return kUncryptFileSyncError;
    }
    if (close(dfd.get()) == -1) {
        ALOGE("failed to close %s: %s", dir_name.c_str(), strerror(errno));
        return -1;
        return kUncryptFileCloseError;
    }
    dfd = -1;
    return 0;
@@ -449,46 +450,54 @@ static int uncrypt(const char* input_path, const char* map_file, const int socke
    // and /sdcard we leave the file alone.
    if (strncmp(path, "/data/", 6) == 0) {
        ALOGI("writing block map %s", map_file);
        if (produce_block_map(path, map_file, blk_dev, encrypted, socket) != 0) {
            return 1;
        }
        return produce_block_map(path, map_file, blk_dev, encrypted, socket);
    }

    return 0;
}

static void log_uncrypt_error_code(UncryptErrorCode error_code) {
    if (!android::base::WriteStringToFile(android::base::StringPrintf(
            "uncrypt_error: %d\n", error_code), UNCRYPT_STATUS)) {
        ALOGW("failed to write to %s: %s", UNCRYPT_STATUS.c_str(), strerror(errno));
    }
}

static bool uncrypt_wrapper(const char* input_path, const char* map_file, const int socket) {
    // Initialize the uncrypt error to kUncryptErrorPlaceholder.
    log_uncrypt_error_code(kUncryptErrorPlaceholder);

    std::string package;
    if (input_path == nullptr) {
        if (!find_uncrypt_package(UNCRYPT_PATH_FILE, &package)) {
            write_status_to_socket(-1, socket);
            // Overwrite the error message.
            log_uncrypt_error_code(kUncryptPackageMissingError);
            return false;
        }
        input_path = package.c_str();
    }
    CHECK(map_file != nullptr);

#define UNCRYPT_TIME_HOLDER 0x7FFFFFFF
    // Intialize the uncrypt time cost to a huge number so that we can tell from
    // the statistics if an uncrypt fails to finish.
    if (!android::base::WriteStringToFile(android::base::StringPrintf(
            "uncrypt_time: %d\n", UNCRYPT_TIME_HOLDER), UNCRYPT_STATUS)) {
        PLOG(WARNING) << "failed to write to " << UNCRYPT_STATUS;
    }

    auto start = std::chrono::system_clock::now();
    int status = uncrypt(input_path, map_file, socket);
    std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
    int count = static_cast<int>(duration.count());

    std::string uncrypt_message = android::base::StringPrintf("uncrypt_time: %d\n", count);
    if (status != 0) {
        // Log the time cost and error code if uncrypt fails.
        uncrypt_message += android::base::StringPrintf("uncrypt_error: %d\n", status);
        if (!android::base::WriteStringToFile(uncrypt_message, UNCRYPT_STATUS)) {
            ALOGW("failed to write to %s: %s", UNCRYPT_STATUS.c_str(), strerror(errno));
        }

        write_status_to_socket(-1, socket);
        return false;
    }

    std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
    int count = static_cast<int>(duration.count());
    // Overwrite the uncrypt_time if uncrypt finishes successfully.
    if (!android::base::WriteStringToFile(
            android::base::StringPrintf("uncrypt_time: %d\n", count), UNCRYPT_STATUS)) {
        PLOG(WARNING) << "failed to write to " << UNCRYPT_STATUS;
    if (!android::base::WriteStringToFile(uncrypt_message, UNCRYPT_STATUS)) {
        ALOGW("failed to write to %s: %s", UNCRYPT_STATUS.c_str(), strerror(errno));
    }

    write_status_to_socket(100, socket);
@@ -582,6 +591,7 @@ int main(int argc, char** argv) {
    }

    if ((fstab = read_fstab()) == nullptr) {
        log_uncrypt_error_code(kUncryptFstabReadError);
        return 1;
    }

@@ -590,18 +600,21 @@ int main(int argc, char** argv) {
    unique_fd service_socket(android_get_control_socket(UNCRYPT_SOCKET.c_str()));
    if (!service_socket) {
        ALOGE("failed to open socket \"%s\": %s", UNCRYPT_SOCKET.c_str(), strerror(errno));
        log_uncrypt_error_code(kUncryptSocketOpenError);
        return 1;
    }
    fcntl(service_socket.get(), F_SETFD, FD_CLOEXEC);

    if (listen(service_socket.get(), 1) == -1) {
        ALOGE("failed to listen on socket %d: %s", service_socket.get(), strerror(errno));
        log_uncrypt_error_code(kUncryptSocketListenError);
        return 1;
    }

    unique_fd socket_fd(accept4(service_socket.get(), nullptr, nullptr, SOCK_CLOEXEC));
    if (!socket_fd) {
        ALOGE("failed to accept on socket %d: %s", service_socket.get(), strerror(errno));
        log_uncrypt_error_code(kUncryptSocketAcceptError);
        return 1;
    }