diff options
-rw-r--r-- | adb_install.cpp | 2 | ||||
-rw-r--r-- | applypatch/applypatch.c | 53 | ||||
-rw-r--r-- | device.h | 17 | ||||
-rw-r--r-- | fuse_sdcard_provider.c | 16 | ||||
-rw-r--r-- | fuse_sideload.c | 16 | ||||
-rw-r--r-- | minadbd/Android.mk | 3 | ||||
-rw-r--r-- | minadbd/adb_main.cpp | 6 | ||||
-rw-r--r-- | minadbd/fuse_adb_provider.cpp | 21 | ||||
-rw-r--r-- | minadbd/services.cpp | 19 | ||||
-rw-r--r-- | minui/Android.mk | 2 | ||||
-rw-r--r-- | minui/events.cpp | 3 | ||||
-rw-r--r-- | minui/graphics.cpp | 5 | ||||
-rw-r--r-- | minui/graphics.h | 1 | ||||
-rw-r--r-- | minui/graphics_drm.cpp | 476 | ||||
-rw-r--r-- | minzip/SysUtil.c | 10 | ||||
-rw-r--r-- | minzip/Zip.c | 6 | ||||
-rw-r--r-- | mtdutils/flash_image.c | 8 | ||||
-rw-r--r-- | mtdutils/mtdutils.c | 54 | ||||
-rw-r--r-- | mtdutils/mtdutils.h | 2 | ||||
-rw-r--r-- | recovery.cpp | 196 | ||||
-rw-r--r-- | screen_ui.cpp | 110 | ||||
-rw-r--r-- | screen_ui.h | 15 | ||||
-rw-r--r-- | tools/ota/check-lost+found.c | 2 | ||||
-rw-r--r-- | ui.cpp | 2 | ||||
-rw-r--r-- | uncrypt/Android.mk | 4 | ||||
-rw-r--r-- | uncrypt/uncrypt.cpp (renamed from uncrypt/uncrypt.c) | 283 | ||||
-rw-r--r-- | updater/blockimg.c | 79 |
27 files changed, 969 insertions, 442 deletions
diff --git a/adb_install.cpp b/adb_install.cpp index ebd4cac00..e3b94ea59 100644 --- a/adb_install.cpp +++ b/adb_install.cpp @@ -42,7 +42,7 @@ set_usb_driver(bool enabled) { ui->Print("failed to open driver control: %s\n", strerror(errno)); return; } - if (write(fd, enabled ? "1" : "0", 1) < 0) { + if (TEMP_FAILURE_RETRY(write(fd, enabled ? "1" : "0", 1)) == -1) { ui->Print("failed to set driver control: %s\n", strerror(errno)); } if (close(fd) < 0) { diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c index 2c86e0984..2358d4292 100644 --- a/applypatch/applypatch.c +++ b/applypatch/applypatch.c @@ -422,20 +422,19 @@ int WriteToPartition(unsigned char* data, size_t len, int attempt; for (attempt = 0; attempt < 2; ++attempt) { - lseek(fd, start, SEEK_SET); + if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { + printf("failed seek on %s: %s\n", + partition, strerror(errno)); + return -1; + } while (start < len) { size_t to_write = len - start; if (to_write > 1<<20) to_write = 1<<20; - ssize_t written = write(fd, data+start, to_write); - if (written < 0) { - if (errno == EINTR) { - written = 0; - } else { - printf("failed write writing to %s (%s)\n", - partition, strerror(errno)); - return -1; - } + ssize_t written = TEMP_FAILURE_RETRY(write(fd, data+start, to_write)); + if (written == -1) { + printf("failed write writing to %s: %s\n", partition, strerror(errno)); + return -1; } start += written; } @@ -460,13 +459,20 @@ int WriteToPartition(unsigned char* data, size_t len, // won't just be reading the cache. sync(); int dc = open("/proc/sys/vm/drop_caches", O_WRONLY); - write(dc, "3\n", 2); + if (TEMP_FAILURE_RETRY(write(dc, "3\n", 2)) == -1) { + printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); + } else { + printf(" caches dropped\n"); + } close(dc); sleep(1); - printf(" caches dropped\n"); // verify - lseek(fd, 0, SEEK_SET); + if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { + printf("failed to seek back to beginning of %s: %s\n", + partition, strerror(errno)); + return -1; + } unsigned char buffer[4096]; start = len; size_t p; @@ -476,15 +482,12 @@ int WriteToPartition(unsigned char* data, size_t len, size_t so_far = 0; while (so_far < to_read) { - ssize_t read_count = read(fd, buffer+so_far, to_read-so_far); - if (read_count < 0) { - if (errno == EINTR) { - read_count = 0; - } else { - printf("verify read error %s at %zu: %s\n", - partition, p, strerror(errno)); - return -1; - } + ssize_t read_count = + TEMP_FAILURE_RETRY(read(fd, buffer+so_far, to_read-so_far)); + if (read_count == -1) { + printf("verify read error %s at %zu: %s\n", + partition, p, strerror(errno)); + return -1; } if ((size_t)read_count < to_read) { printf("short verify read %s at %zu: %zd %zu %s\n", @@ -625,8 +628,8 @@ ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) { ssize_t done = 0; ssize_t wrote; while (done < (ssize_t) len) { - wrote = write(fd, data+done, len-done); - if (wrote <= 0) { + wrote = TEMP_FAILURE_RETRY(write(fd, data+done, len-done)); + if (wrote == -1) { printf("error writing %d bytes: %s\n", (int)(len-done), strerror(errno)); return done; } @@ -659,7 +662,7 @@ size_t FreeSpaceForFile(const char* filename) { printf("failed to statfs %s: %s\n", filename, strerror(errno)); return -1; } - return sf.f_bsize * sf.f_bfree; + return sf.f_bsize * sf.f_bavail; } int CacheSizeCheck(size_t bytes) { @@ -91,13 +91,16 @@ class Device { static const int kHighlightDown = -3; static const int kInvokeItem = -4; - // Called when we do a wipe data/factory reset operation (either via a - // reboot from the main system with the --wipe_data flag, or when the - // user boots into recovery manually and selects the option from the - // menu.) Can perform whatever device-specific wiping actions are - // needed. Return 0 on success. The userdata and cache partitions - // are erased AFTER this returns (whether it returns success or not). - virtual int WipeData() { return 0; } + // Called before and after we do a wipe data/factory reset operation, + // either via a reboot from the main system with the --wipe_data flag, + // or when the user boots into recovery image manually and selects the + // option from the menu, to perform whatever device-specific wiping + // actions are needed. + // Return true on success; returning false from PreWipeData will prevent + // the regular wipe, and returning false from PostWipeData will cause + // the wipe to be considered a failure. + virtual bool PreWipeData() { return true; } + virtual bool PostWipeData() { return true; } private: RecoveryUI* ui_; diff --git a/fuse_sdcard_provider.c b/fuse_sdcard_provider.c index ca8c914f9..4565c7b5b 100644 --- a/fuse_sdcard_provider.c +++ b/fuse_sdcard_provider.c @@ -36,19 +36,17 @@ struct file_data { static int read_block_file(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size) { struct file_data* fd = (struct file_data*)cookie; - if (lseek(fd->fd, block * fd->block_size, SEEK_SET) < 0) { - printf("seek on sdcard failed: %s\n", strerror(errno)); + off64_t offset = ((off64_t) block) * fd->block_size; + if (TEMP_FAILURE_RETRY(lseek64(fd->fd, offset, SEEK_SET)) == -1) { + fprintf(stderr, "seek on sdcard failed: %s\n", strerror(errno)); return -EIO; } while (fetch_size > 0) { - ssize_t r = read(fd->fd, buffer, fetch_size); - if (r < 0) { - if (r != -EINTR) { - printf("read on sdcard failed: %s\n", strerror(errno)); - return -EIO; - } - r = 0; + ssize_t r = TEMP_FAILURE_RETRY(read(fd->fd, buffer, fetch_size)); + if (r == -1) { + fprintf(stderr, "read on sdcard failed: %s\n", strerror(errno)); + return -EIO; } fetch_size -= r; buffer += r; diff --git a/fuse_sideload.c b/fuse_sideload.c index 1dd84e97a..48e6cc53a 100644 --- a/fuse_sideload.c +++ b/fuse_sideload.c @@ -442,14 +442,12 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, } uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX*8]; for (;;) { - ssize_t len = read(fd.ffd, request_buffer, sizeof(request_buffer)); - if (len < 0) { - if (errno != EINTR) { - perror("read request"); - if (errno == ENODEV) { - result = -1; - break; - } + ssize_t len = TEMP_FAILURE_RETRY(read(fd.ffd, request_buffer, sizeof(request_buffer))); + if (len == -1) { + perror("read request"); + if (errno == ENODEV) { + result = -1; + break; } continue; } @@ -508,7 +506,7 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, outhdr.len = sizeof(outhdr); outhdr.error = result; outhdr.unique = hdr->unique; - write(fd.ffd, &outhdr, sizeof(outhdr)); + TEMP_FAILURE_RETRY(write(fd.ffd, &outhdr, sizeof(outhdr))); } } diff --git a/minadbd/Android.mk b/minadbd/Android.mk index cbfd76e4e..a7a3e087d 100644 --- a/minadbd/Android.mk +++ b/minadbd/Android.mk @@ -20,6 +20,7 @@ LOCAL_CFLAGS := $(minadbd_cflags) LOCAL_CONLY_FLAGS := -Wimplicit-function-declaration LOCAL_C_INCLUDES := bootable/recovery system/core/adb LOCAL_WHOLE_STATIC_LIBRARIES := libadbd +LOCAL_STATIC_LIBRARIES := libbase include $(BUILD_STATIC_LIBRARY) @@ -31,6 +32,6 @@ LOCAL_SRC_FILES := fuse_adb_provider_test.cpp LOCAL_CFLAGS := $(minadbd_cflags) LOCAL_C_INCLUDES := $(LOCAL_PATH) system/core/adb LOCAL_STATIC_LIBRARIES := libminadbd -LOCAL_SHARED_LIBRARIES := liblog +LOCAL_SHARED_LIBRARIES := liblog libbase libcutils include $(BUILD_NATIVE_TEST) diff --git a/minadbd/adb_main.cpp b/minadbd/adb_main.cpp index f6e240108..7fae99a9a 100644 --- a/minadbd/adb_main.cpp +++ b/minadbd/adb_main.cpp @@ -19,11 +19,12 @@ #include <stdio.h> #include <stdlib.h> -#define TRACE_TAG TRACE_ADB +#define TRACE_TAG TRACE_ADB #include "sysdeps.h" #include "adb.h" +#include "adb_auth.h" #include "transport.h" int adb_main(int is_daemon, int server_port) @@ -35,6 +36,9 @@ int adb_main(int is_daemon, int server_port) // No SIGCHLD. Let the service subproc handle its children. signal(SIGPIPE, SIG_IGN); + // We can't require authentication for sideloading. http://b/22025550. + auth_required = false; + init_transport_registration(); usb_init(); diff --git a/minadbd/fuse_adb_provider.cpp b/minadbd/fuse_adb_provider.cpp index 5da7fd76c..d71807dfb 100644 --- a/minadbd/fuse_adb_provider.cpp +++ b/minadbd/fuse_adb_provider.cpp @@ -26,13 +26,10 @@ #include "fuse_adb_provider.h" #include "fuse_sideload.h" -int read_block_adb(void* cookie, uint32_t block, uint8_t* buffer, - uint32_t fetch_size) { - struct adb_data* ad = (struct adb_data*)cookie; +int read_block_adb(void* data, uint32_t block, uint8_t* buffer, uint32_t fetch_size) { + adb_data* ad = reinterpret_cast<adb_data*>(data); - char buf[10]; - snprintf(buf, sizeof(buf), "%08u", block); - if (!WriteStringFully(ad->sfd, buf)) { + if (!WriteFdFmt(ad->sfd, "%08u", block)) { fprintf(stderr, "failed to write to adb host: %s\n", strerror(errno)); return -EIO; } @@ -45,20 +42,18 @@ int read_block_adb(void* cookie, uint32_t block, uint8_t* buffer, return 0; } -static void close_adb(void* cookie) { - struct adb_data* ad = (struct adb_data*)cookie; - - WriteStringFully(ad->sfd, "DONEDONE"); +static void close_adb(void* data) { + adb_data* ad = reinterpret_cast<adb_data*>(data); + WriteFdExactly(ad->sfd, "DONEDONE"); } int run_adb_fuse(int sfd, uint64_t file_size, uint32_t block_size) { - struct adb_data ad; - struct provider_vtab vtab; - + adb_data ad; ad.sfd = sfd; ad.file_size = file_size; ad.block_size = block_size; + provider_vtab vtab; vtab.read_block = read_block_adb; vtab.close = close_adb; diff --git a/minadbd/services.cpp b/minadbd/services.cpp index a83256796..dd1fd7c4b 100644 --- a/minadbd/services.cpp +++ b/minadbd/services.cpp @@ -43,15 +43,16 @@ void* service_bootstrap_func(void* x) { return 0; } -static void sideload_host_service(int sfd, void* cookie) { - char* saveptr; - const char* s = adb_strtok_r(reinterpret_cast<char*>(cookie), ":", &saveptr); - uint64_t file_size = strtoull(s, NULL, 10); - s = adb_strtok_r(NULL, ":", &saveptr); - uint32_t block_size = strtoul(s, NULL, 10); - - printf("sideload-host file size %" PRIu64 " block size %" PRIu32 "\n", - file_size, block_size); +static void sideload_host_service(int sfd, void* data) { + const char* args = reinterpret_cast<const char*>(data); + int file_size; + int block_size; + if (sscanf(args, "%d:%d", &file_size, &block_size) != 2) { + printf("bad sideload-host arguments: %s\n", args); + exit(1); + } + + printf("sideload-host file size %d block size %d\n", file_size, block_size); int result = run_adb_fuse(sfd, file_size, block_size); diff --git a/minui/Android.mk b/minui/Android.mk index 52f066256..97724fbf0 100644 --- a/minui/Android.mk +++ b/minui/Android.mk @@ -5,10 +5,12 @@ LOCAL_SRC_FILES := \ events.cpp \ graphics.cpp \ graphics_adf.cpp \ + graphics_drm.cpp \ graphics_fbdev.cpp \ resources.cpp \ LOCAL_WHOLE_STATIC_LIBRARIES += libadf +LOCAL_WHOLE_STATIC_LIBRARIES += libdrm LOCAL_STATIC_LIBRARIES += libpng LOCAL_MODULE := libminui diff --git a/minui/events.cpp b/minui/events.cpp index 2d47a587f..3b2262a4b 100644 --- a/minui/events.cpp +++ b/minui/events.cpp @@ -15,6 +15,7 @@ */ #include <dirent.h> +#include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> @@ -165,7 +166,7 @@ void ev_dispatch(void) { int ev_get_input(int fd, uint32_t epevents, input_event* ev) { if (epevents & EPOLLIN) { - ssize_t r = read(fd, ev, sizeof(*ev)); + ssize_t r = TEMP_FAILURE_RETRY(read(fd, ev, sizeof(*ev))); if (r == sizeof(*ev)) { return 0; } diff --git a/minui/graphics.cpp b/minui/graphics.cpp index f09f1c6b0..c0eea9e38 100644 --- a/minui/graphics.cpp +++ b/minui/graphics.cpp @@ -369,6 +369,11 @@ int gr_init(void) } if (!gr_draw) { + gr_backend = open_drm(); + gr_draw = gr_backend->init(gr_backend); + } + + if (!gr_draw) { gr_backend = open_fbdev(); gr_draw = gr_backend->init(gr_backend); if (gr_draw == NULL) { diff --git a/minui/graphics.h b/minui/graphics.h index 81a923383..52968eb10 100644 --- a/minui/graphics.h +++ b/minui/graphics.h @@ -38,5 +38,6 @@ struct minui_backend { minui_backend* open_fbdev(); minui_backend* open_adf(); +minui_backend* open_drm(); #endif diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp new file mode 100644 index 000000000..03e33b775 --- /dev/null +++ b/minui/graphics_drm.cpp @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2015 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. + */ + +#include <drm_fourcc.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/cdefs.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include "minui.h" +#include "graphics.h" + +#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A))) + +struct drm_surface { + GRSurface base; + uint32_t fb_id; + uint32_t handle; +}; + +static drm_surface *drm_surfaces[2]; +static int current_buffer; + +static drmModeCrtc *main_monitor_crtc; +static drmModeConnector *main_monitor_connector; + +static int drm_fd = -1; + +static void drm_disable_crtc(int drm_fd, drmModeCrtc *crtc) { + if (crtc) { + drmModeSetCrtc(drm_fd, crtc->crtc_id, + 0, // fb_id + 0, 0, // x,y + NULL, // connectors + 0, // connector_count + NULL); // mode + } +} + +static void drm_enable_crtc(int drm_fd, drmModeCrtc *crtc, + struct drm_surface *surface) { + int32_t ret; + + ret = drmModeSetCrtc(drm_fd, crtc->crtc_id, + surface->fb_id, + 0, 0, // x,y + &main_monitor_connector->connector_id, + 1, // connector_count + &main_monitor_crtc->mode); + + if (ret) + printf("drmModeSetCrtc failed ret=%d\n", ret); +} + +static void drm_blank(minui_backend* backend __unused, bool blank) { + if (blank) + drm_disable_crtc(drm_fd, main_monitor_crtc); + else + drm_enable_crtc(drm_fd, main_monitor_crtc, + drm_surfaces[current_buffer]); +} + +static void drm_destroy_surface(struct drm_surface *surface) { + struct drm_gem_close gem_close; + int ret; + + if(!surface) + return; + + if (surface->base.data) + munmap(surface->base.data, + surface->base.row_bytes * surface->base.height); + + if (surface->fb_id) { + ret = drmModeRmFB(drm_fd, surface->fb_id); + if (ret) + printf("drmModeRmFB failed ret=%d\n", ret); + } + + if (surface->handle) { + memset(&gem_close, 0, sizeof(gem_close)); + gem_close.handle = surface->handle; + + ret = drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close); + if (ret) + printf("DRM_IOCTL_GEM_CLOSE failed ret=%d\n", ret); + } + + free(surface); +} + +static int drm_format_to_bpp(uint32_t format) { + switch(format) { + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_XRGB8888: + return 32; + case DRM_FORMAT_RGB565: + return 16; + default: + printf("Unknown format %d\n", format); + return 32; + } +} + +static drm_surface *drm_create_surface(int width, int height) { + struct drm_surface *surface; + struct drm_mode_create_dumb create_dumb; + uint32_t format; + int ret; + + surface = (struct drm_surface*)calloc(1, sizeof(*surface)); + if (!surface) { + printf("Can't allocate memory\n"); + return NULL; + } + +#if defined(RECOVERY_ABGR) + format = DRM_FORMAT_RGBA8888; +#elif defined(RECOVERY_BGRA) + format = DRM_FORMAT_ARGB8888; +#elif defined(RECOVERY_RGBX) + format = DRM_FORMAT_XBGR8888; +#else + format = DRM_FORMAT_RGB565; +#endif + + memset(&create_dumb, 0, sizeof(create_dumb)); + create_dumb.height = height; + create_dumb.width = width; + create_dumb.bpp = drm_format_to_bpp(format); + create_dumb.flags = 0; + + ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb); + if (ret) { + printf("DRM_IOCTL_MODE_CREATE_DUMB failed ret=%d\n",ret); + drm_destroy_surface(surface); + return NULL; + } + surface->handle = create_dumb.handle; + + uint32_t handles[4], pitches[4], offsets[4]; + + handles[0] = surface->handle; + pitches[0] = create_dumb.pitch; + offsets[0] = 0; + + ret = drmModeAddFB2(drm_fd, width, height, + format, handles, pitches, offsets, + &(surface->fb_id), 0); + if (ret) { + printf("drmModeAddFB2 failed ret=%d\n", ret); + drm_destroy_surface(surface); + return NULL; + } + + struct drm_mode_map_dumb map_dumb; + memset(&map_dumb, 0, sizeof(map_dumb)); + map_dumb.handle = create_dumb.handle; + ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb); + if (ret) { + printf("DRM_IOCTL_MODE_MAP_DUMB failed ret=%d\n",ret); + drm_destroy_surface(surface); + return NULL;; + } + + surface->base.height = height; + surface->base.width = width; + surface->base.row_bytes = create_dumb.pitch; + surface->base.pixel_bytes = create_dumb.bpp / 8; + surface->base.data = (unsigned char*) + mmap(NULL, + surface->base.height * surface->base.row_bytes, + PROT_READ | PROT_WRITE, MAP_SHARED, + drm_fd, map_dumb.offset); + if (surface->base.data == MAP_FAILED) { + perror("mmap() failed"); + drm_destroy_surface(surface); + return NULL; + } + + return surface; +} + +static drmModeCrtc *find_crtc_for_connector(int fd, + drmModeRes *resources, + drmModeConnector *connector) { + int i, j; + drmModeEncoder *encoder; + int32_t crtc; + + /* + * Find the encoder. If we already have one, just use it. + */ + if (connector->encoder_id) + encoder = drmModeGetEncoder(fd, connector->encoder_id); + else + encoder = NULL; + + if (encoder && encoder->crtc_id) { + crtc = encoder->crtc_id; + drmModeFreeEncoder(encoder); + return drmModeGetCrtc(fd, crtc); + } + + /* + * Didn't find anything, try to find a crtc and encoder combo. + */ + crtc = -1; + for (i = 0; i < connector->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, connector->encoders[i]); + + if (encoder) { + for (j = 0; j < resources->count_crtcs; j++) { + if (!(encoder->possible_crtcs & (1 << j))) + continue; + crtc = resources->crtcs[j]; + break; + } + if (crtc >= 0) { + drmModeFreeEncoder(encoder); + return drmModeGetCrtc(fd, crtc); + } + } + } + + return NULL; +} + +static drmModeConnector *find_used_connector_by_type(int fd, + drmModeRes *resources, + unsigned type) { + int i; + for (i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(fd, resources->connectors[i]); + if (connector) { + if ((connector->connector_type == type) && + (connector->connection == DRM_MODE_CONNECTED) && + (connector->count_modes > 0)) + return connector; + + drmModeFreeConnector(connector); + } + } + return NULL; +} + +static drmModeConnector *find_first_connected_connector(int fd, + drmModeRes *resources) { + int i; + for (i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(fd, resources->connectors[i]); + if (connector) { + if ((connector->count_modes > 0) && + (connector->connection == DRM_MODE_CONNECTED)) + return connector; + + drmModeFreeConnector(connector); + } + } + return NULL; +} + +static drmModeConnector *find_main_monitor(int fd, drmModeRes *resources, + uint32_t *mode_index) { + unsigned i = 0; + int modes; + /* Look for LVDS/eDP/DSI connectors. Those are the main screens. */ + unsigned kConnectorPriority[] = { + DRM_MODE_CONNECTOR_LVDS, + DRM_MODE_CONNECTOR_eDP, + DRM_MODE_CONNECTOR_DSI, + }; + + drmModeConnector *main_monitor_connector = NULL; + do { + main_monitor_connector = find_used_connector_by_type(fd, + resources, + kConnectorPriority[i]); + i++; + } while (!main_monitor_connector && i < ARRAY_SIZE(kConnectorPriority)); + + /* If we didn't find a connector, grab the first one that is connected. */ + if (!main_monitor_connector) + main_monitor_connector = + find_first_connected_connector(fd, resources); + + /* If we still didn't find a connector, give up and return. */ + if (!main_monitor_connector) + return NULL; + + *mode_index = 0; + for (modes = 0; modes < main_monitor_connector->count_modes; modes++) { + if (main_monitor_connector->modes[modes].type & + DRM_MODE_TYPE_PREFERRED) { + *mode_index = modes; + break; + } + } + + return main_monitor_connector; +} + +static void disable_non_main_crtcs(int fd, + drmModeRes *resources, + drmModeCrtc* main_crtc) { + int i; + drmModeCrtc* crtc; + + for (i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(fd, resources->connectors[i]); + crtc = find_crtc_for_connector(fd, resources, connector); + if (crtc->crtc_id != main_crtc->crtc_id) + drm_disable_crtc(fd, crtc); + drmModeFreeCrtc(crtc); + } +} + +static GRSurface* drm_init(minui_backend* backend __unused) { + drmModeRes *res = NULL; + uint32_t selected_mode; + char *dev_name; + int width, height; + int ret, i; + + /* Consider DRM devices in order. */ + for (i = 0; i < DRM_MAX_MINOR; i++) { + uint64_t cap = 0; + + ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i); + if (ret < 0) + continue; + + drm_fd = open(dev_name, O_RDWR, 0); + free(dev_name); + if (drm_fd < 0) + continue; + + /* We need dumb buffers. */ + ret = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &cap); + if (ret || cap == 0) { + close(drm_fd); + continue; + } + + res = drmModeGetResources(drm_fd); + if (!res) { + close(drm_fd); + continue; + } + + /* Use this device if it has at least one connected monitor. */ + if (res->count_crtcs > 0 && res->count_connectors > 0) + if (find_first_connected_connector(drm_fd, res)) + break; + + drmModeFreeResources(res); + close(drm_fd); + res = NULL; + } + + if (drm_fd < 0 || res == NULL) { + perror("cannot find/open a drm device"); + return NULL; + } + + main_monitor_connector = find_main_monitor(drm_fd, + res, &selected_mode); + + if (!main_monitor_connector) { + printf("main_monitor_connector not found\n"); + drmModeFreeResources(res); + close(drm_fd); + return NULL; + } + + main_monitor_crtc = find_crtc_for_connector(drm_fd, res, + main_monitor_connector); + + if (!main_monitor_crtc) { + printf("main_monitor_crtc not found\n"); + drmModeFreeResources(res); + close(drm_fd); + return NULL; + } + + disable_non_main_crtcs(drm_fd, + res, main_monitor_crtc); + + main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode]; + + width = main_monitor_crtc->mode.hdisplay; + height = main_monitor_crtc->mode.vdisplay; + + drmModeFreeResources(res); + + drm_surfaces[0] = drm_create_surface(width, height); + drm_surfaces[1] = drm_create_surface(width, height); + if (!drm_surfaces[0] || !drm_surfaces[1]) { + drm_destroy_surface(drm_surfaces[0]); + drm_destroy_surface(drm_surfaces[1]); + drmModeFreeResources(res); + close(drm_fd); + return NULL; + } + + current_buffer = 0; + + drm_enable_crtc(drm_fd, main_monitor_crtc, drm_surfaces[1]); + + return &(drm_surfaces[0]->base); +} + +static GRSurface* drm_flip(minui_backend* backend __unused) { + int ret; + + ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id, + drm_surfaces[current_buffer]->fb_id, 0, NULL); + if (ret < 0) { + printf("drmModePageFlip failed ret=%d\n", ret); + return NULL; + } + current_buffer = 1 - current_buffer; + return &(drm_surfaces[current_buffer]->base); +} + +static void drm_exit(minui_backend* backend __unused) { + drm_disable_crtc(drm_fd, main_monitor_crtc); + drm_destroy_surface(drm_surfaces[0]); + drm_destroy_surface(drm_surfaces[1]); + drmModeFreeCrtc(main_monitor_crtc); + drmModeFreeConnector(main_monitor_connector); + close(drm_fd); + drm_fd = -1; +} + +static minui_backend drm_backend = { + .init = drm_init, + .flip = drm_flip, + .blank = drm_blank, + .exit = drm_exit, +}; + +minui_backend* open_drm() { + return &drm_backend; +} diff --git a/minzip/SysUtil.c b/minzip/SysUtil.c index ac6f5c33f..b160c9e3d 100644 --- a/minzip/SysUtil.c +++ b/minzip/SysUtil.c @@ -27,11 +27,13 @@ static int getFileStartAndLength(int fd, off_t *start_, size_t *length_) assert(start_ != NULL); assert(length_ != NULL); - start = lseek(fd, 0L, SEEK_CUR); - end = lseek(fd, 0L, SEEK_END); - (void) lseek(fd, start, SEEK_SET); + // TODO: isn't start always 0 for the single call site? just use fstat instead? - if (start == (off_t) -1 || end == (off_t) -1) { + start = TEMP_FAILURE_RETRY(lseek(fd, 0L, SEEK_CUR)); + end = TEMP_FAILURE_RETRY(lseek(fd, 0L, SEEK_END)); + + if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1 || + start == (off_t) -1 || end == (off_t) -1) { LOGE("could not determine length of file\n"); return -1; } diff --git a/minzip/Zip.c b/minzip/Zip.c index d3ff79be6..40712e03a 100644 --- a/minzip/Zip.c +++ b/minzip/Zip.c @@ -675,13 +675,11 @@ static bool writeProcessFunction(const unsigned char *data, int dataLen, } ssize_t soFar = 0; while (true) { - ssize_t n = write(fd, data+soFar, dataLen-soFar); + ssize_t n = TEMP_FAILURE_RETRY(write(fd, data+soFar, dataLen-soFar)); if (n <= 0) { LOGE("Error writing %zd bytes from zip file from %p: %s\n", dataLen-soFar, data+soFar, strerror(errno)); - if (errno != EINTR) { - return false; - } + return false; } else if (n > 0) { soFar += n; if (soFar == dataLen) return true; diff --git a/mtdutils/flash_image.c b/mtdutils/flash_image.c index 5657dfc82..36ffa1314 100644 --- a/mtdutils/flash_image.c +++ b/mtdutils/flash_image.c @@ -72,7 +72,7 @@ int main(int argc, char **argv) { if (fd < 0) die("error opening %s", argv[2]); char header[HEADER_SIZE]; - int headerlen = read(fd, header, sizeof(header)); + int headerlen = TEMP_FAILURE_RETRY(read(fd, header, sizeof(header))); if (headerlen <= 0) die("error reading %s header", argv[2]); MtdReadContext *in = mtd_read_partition(partition); @@ -104,7 +104,7 @@ int main(int argc, char **argv) { if (wrote != headerlen) die("error writing %s", argv[1]); int len; - while ((len = read(fd, buf, sizeof(buf))) > 0) { + while ((len = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)))) > 0) { wrote = mtd_write_data(out, buf, len); if (wrote != len) die("error writing %s", argv[1]); } @@ -125,13 +125,13 @@ int main(int argc, char **argv) { if (mtd_partition_info(partition, NULL, &block_size, NULL)) die("error getting %s block size", argv[1]); - if (lseek(fd, headerlen, SEEK_SET) != headerlen) + if (TEMP_FAILURE_RETRY(lseek(fd, headerlen, SEEK_SET)) != headerlen) die("error rewinding %s", argv[2]); int left = block_size - headerlen; while (left < 0) left += block_size; while (left > 0) { - len = read(fd, buf, left > (int)sizeof(buf) ? (int)sizeof(buf) : left); + len = TEMP_FAILURE_RETRY(read(fd, buf, left > (int)sizeof(buf) ? (int)sizeof(buf) : left)); if (len <= 0) die("error reading %s", argv[2]); if (mtd_write_data(out, buf, len) != len) die("error writing %s", argv[1]); diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c index 9a17e38d8..cc3033444 100644 --- a/mtdutils/mtdutils.c +++ b/mtdutils/mtdutils.c @@ -108,7 +108,7 @@ mtd_scan_partitions() if (fd < 0) { goto bail; } - nbytes = read(fd, buf, sizeof(buf) - 1); + nbytes = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf) - 1)); close(fd); if (nbytes < 0) { goto bail; @@ -279,12 +279,6 @@ MtdReadContext *mtd_read_partition(const MtdPartition *partition) return ctx; } -// Seeks to a location in the partition. Don't mix with reads of -// anything other than whole blocks; unpredictable things will result. -void mtd_read_skip_to(const MtdReadContext* ctx, size_t offset) { - lseek64(ctx->fd, offset, SEEK_SET); -} - static int read_block(const MtdPartition *partition, int fd, char *data) { struct mtd_ecc_stats before, after; @@ -293,13 +287,18 @@ static int read_block(const MtdPartition *partition, int fd, char *data) return -1; } - loff_t pos = lseek64(fd, 0, SEEK_CUR); + loff_t pos = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR)); + if (pos == -1) { + printf("mtd: read_block: couldn't SEEK_CUR: %s\n", strerror(errno)); + return -1; + } ssize_t size = partition->erase_size; int mgbb; while (pos + size <= (int) partition->size) { - if (lseek64(fd, pos, SEEK_SET) != pos || read(fd, data, size) != size) { + if (TEMP_FAILURE_RETRY(lseek64(fd, pos, SEEK_SET)) != pos || + TEMP_FAILURE_RETRY(read(fd, data, size)) != size) { printf("mtd: read error at 0x%08llx (%s)\n", pos, strerror(errno)); } else if (ioctl(fd, ECCGETSTATS, &after)) { @@ -409,8 +408,11 @@ static int write_block(MtdWriteContext *ctx, const char *data) const MtdPartition *partition = ctx->partition; int fd = ctx->fd; - off_t pos = lseek(fd, 0, SEEK_CUR); - if (pos == (off_t) -1) return 1; + off_t pos = TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_CUR)); + if (pos == (off_t) -1) { + printf("mtd: write_block: couldn't SEEK_CUR: %s\n", strerror(errno)); + return -1; + } ssize_t size = partition->erase_size; while (pos + size <= (int) partition->size) { @@ -435,15 +437,15 @@ static int write_block(MtdWriteContext *ctx, const char *data) pos, strerror(errno)); continue; } - if (lseek(fd, pos, SEEK_SET) != pos || - write(fd, data, size) != size) { + if (TEMP_FAILURE_RETRY(lseek(fd, pos, SEEK_SET)) != pos || + TEMP_FAILURE_RETRY(write(fd, data, size)) != size) { printf("mtd: write error at 0x%08lx (%s)\n", pos, strerror(errno)); } char verify[size]; - if (lseek(fd, pos, SEEK_SET) != pos || - read(fd, verify, size) != size) { + if (TEMP_FAILURE_RETRY(lseek(fd, pos, SEEK_SET)) != pos || + TEMP_FAILURE_RETRY(read(fd, verify, size)) != size) { printf("mtd: re-read error at 0x%08lx (%s)\n", pos, strerror(errno)); continue; @@ -512,8 +514,11 @@ off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks) ctx->stored = 0; } - off_t pos = lseek(ctx->fd, 0, SEEK_CUR); - if ((off_t) pos == (off_t) -1) return pos; + off_t pos = TEMP_FAILURE_RETRY(lseek(ctx->fd, 0, SEEK_CUR)); + if ((off_t) pos == (off_t) -1) { + printf("mtd_erase_blocks: couldn't SEEK_CUR: %s\n", strerror(errno)); + return -1; + } const int total = (ctx->partition->size - pos) / ctx->partition->erase_size; if (blocks < 0) blocks = total; @@ -554,18 +559,3 @@ int mtd_write_close(MtdWriteContext *ctx) free(ctx); return r; } - -/* Return the offset of the first good block at or after pos (which - * might be pos itself). - */ -off_t mtd_find_write_start(MtdWriteContext *ctx, off_t pos) { - int i; - for (i = 0; i < ctx->bad_block_count; ++i) { - if (ctx->bad_block_offsets[i] == pos) { - pos += ctx->partition->erase_size; - } else if (ctx->bad_block_offsets[i] > pos) { - return pos; - } - } - return pos; -} diff --git a/mtdutils/mtdutils.h b/mtdutils/mtdutils.h index 2708c4318..8059d6a4d 100644 --- a/mtdutils/mtdutils.h +++ b/mtdutils/mtdutils.h @@ -49,12 +49,10 @@ typedef struct MtdWriteContext MtdWriteContext; MtdReadContext *mtd_read_partition(const MtdPartition *); ssize_t mtd_read_data(MtdReadContext *, char *data, size_t data_len); void mtd_read_close(MtdReadContext *); -void mtd_read_skip_to(const MtdReadContext *, size_t offset); MtdWriteContext *mtd_write_partition(const MtdPartition *); ssize_t mtd_write_data(MtdWriteContext *, const char *data, size_t data_len); off_t mtd_erase_blocks(MtdWriteContext *, int blocks); /* 0 ok, -1 for all */ -off_t mtd_find_write_start(MtdWriteContext *ctx, off_t pos); int mtd_write_close(MtdWriteContext *); #ifdef __cplusplus diff --git a/recovery.cpp b/recovery.cpp index 4dd827919..b7a545898 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -31,6 +31,9 @@ #include <time.h> #include <unistd.h> +#include <base/file.h> +#include <base/stringprintf.h> + #include "bootloader.h" #include "common.h" #include "cutils/properties.h" @@ -65,8 +68,6 @@ static const struct option OPTIONS[] = { { NULL, 0, NULL, 0 }, }; -#define LAST_LOG_FILE "/cache/recovery/last_log" - static const char *CACHE_LOG_DIR = "/cache/recovery"; static const char *COMMAND_FILE = "/cache/recovery/command"; static const char *INTENT_FILE = "/cache/recovery/intent"; @@ -78,9 +79,8 @@ static const char *SDCARD_ROOT = "/sdcard"; static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log"; static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install"; static const char *LAST_KMSG_FILE = "/cache/recovery/last_kmsg"; -#define KLOG_DEFAULT_LEN (64 * 1024) - -#define KEEP_LOG_COUNT 10 +static const char *LAST_LOG_FILE = "/cache/recovery/last_log"; +static const int KEEP_LOG_COUNT = 10; RecoveryUI* ui = NULL; char* locale = NULL; @@ -267,72 +267,55 @@ set_sdcard_update_bootloader_message() { set_bootloader_message(&boot); } -// read from kernel log into buffer and write out to file -static void -save_kernel_log(const char *destination) { - int n; - char *buffer; - int klog_buf_len; - FILE *log; - - klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0); +// Read from kernel log into buffer and write out to file. +static void save_kernel_log(const char* destination) { + int klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0); if (klog_buf_len <= 0) { - LOGE("Error getting klog size (%s), using default\n", strerror(errno)); - klog_buf_len = KLOG_DEFAULT_LEN; - } - - buffer = (char *)malloc(klog_buf_len); - if (!buffer) { - LOGE("Can't alloc %d bytes for klog buffer\n", klog_buf_len); - return; - } - - n = klogctl(KLOG_READ_ALL, buffer, klog_buf_len); - if (n < 0) { - LOGE("Error in reading klog (%s)\n", strerror(errno)); - free(buffer); + LOGE("Error getting klog size: %s\n", strerror(errno)); return; } - log = fopen_path(destination, "w"); - if (log == NULL) { - LOGE("Can't open %s\n", destination); - free(buffer); + std::string buffer(klog_buf_len, 0); + int n = klogctl(KLOG_READ_ALL, &buffer[0], klog_buf_len); + if (n == -1) { + LOGE("Error in reading klog: %s\n", strerror(errno)); return; } - fwrite(buffer, n, 1, log); - check_and_fclose(log, destination); - free(buffer); + buffer.resize(n); + android::base::WriteStringToFile(buffer, destination); } // How much of the temp log we have copied to the copy in cache. static long tmplog_offset = 0; -static void -copy_log_file(const char* source, const char* destination, int append) { - FILE *log = fopen_path(destination, append ? "a" : "w"); - if (log == NULL) { +static void copy_log_file(const char* source, const char* destination, bool append) { + FILE* dest_fp = fopen_path(destination, append ? "a" : "w"); + if (dest_fp == nullptr) { LOGE("Can't open %s\n", destination); } else { - FILE *tmplog = fopen(source, "r"); - if (tmplog != NULL) { + FILE* source_fp = fopen(source, "r"); + if (source_fp != nullptr) { if (append) { - fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write + fseek(source_fp, tmplog_offset, SEEK_SET); // Since last write } char buf[4096]; - while (fgets(buf, sizeof(buf), tmplog)) fputs(buf, log); + size_t bytes; + while ((bytes = fread(buf, 1, sizeof(buf), source_fp)) != 0) { + fwrite(buf, 1, bytes, dest_fp); + } if (append) { - tmplog_offset = ftell(tmplog); + tmplog_offset = ftell(source_fp); } - check_and_fclose(tmplog, source); + check_and_fclose(source_fp, source); } - check_and_fclose(log, destination); + check_and_fclose(dest_fp, destination); } } -// Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max -// Overwrites any existing last_log.$max. -static void rotate_last_logs(int max) { +// Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max. +// Similarly rename last_kmsg -> last_kmsg.1 -> ... -> last_kmsg.$max. +// Overwrite any existing last_log.$max and last_kmsg.$max. +static void rotate_logs(int max) { // Logs should only be rotated once. static bool rotated = false; if (rotated) { @@ -340,14 +323,19 @@ static void rotate_last_logs(int max) { } rotated = true; ensure_path_mounted(LAST_LOG_FILE); + ensure_path_mounted(LAST_KMSG_FILE); - char oldfn[256]; - char newfn[256]; for (int i = max-1; i >= 0; --i) { - snprintf(oldfn, sizeof(oldfn), (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i); - snprintf(newfn, sizeof(newfn), LAST_LOG_FILE ".%d", i+1); - // ignore errors - rename(oldfn, newfn); + std::string old_log = android::base::StringPrintf((i == 0) ? "%s" : "%s.%d", + LAST_LOG_FILE, i); + std::string new_log = android::base::StringPrintf("%s.%d", LAST_LOG_FILE, i+1); + // Ignore errors if old_log doesn't exist. + rename(old_log.c_str(), new_log.c_str()); + + std::string old_kmsg = android::base::StringPrintf((i == 0) ? "%s" : "%s.%d", + LAST_KMSG_FILE, i); + std::string new_kmsg = android::base::StringPrintf("%s.%d", LAST_KMSG_FILE, i+1); + rename(old_kmsg.c_str(), new_kmsg.c_str()); } } @@ -360,7 +348,7 @@ static void copy_logs() { return; } - rotate_last_logs(KEEP_LOG_COUNT); + rotate_logs(KEEP_LOG_COUNT); // Copy logs to cache so the system can find out what happened. copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); @@ -429,8 +417,7 @@ typedef struct _saved_log_file { struct _saved_log_file* next; } saved_log_file; -static int -erase_volume(const char *volume) { +static bool erase_volume(const char* volume) { bool is_cache = (strcmp(volume, CACHE_ROOT) == 0); ui->SetBackground(RecoveryUI::ERASING); @@ -439,9 +426,10 @@ erase_volume(const char *volume) { saved_log_file* head = NULL; if (is_cache) { - // If we're reformatting /cache, we load any - // "/cache/recovery/last*" files into memory, so we can restore - // them after the reformat. + // If we're reformatting /cache, we load any past logs + // (i.e. "/cache/recovery/last_*") and the current log + // ("/cache/recovery/log") into memory, so we can restore them after + // the reformat. ensure_path_mounted(volume); @@ -454,7 +442,7 @@ erase_volume(const char *volume) { strcat(path, "/"); int path_len = strlen(path); while ((de = readdir(d)) != NULL) { - if (strncmp(de->d_name, "last", 4) == 0) { + if (strncmp(de->d_name, "last_", 5) == 0 || strcmp(de->d_name, "log") == 0) { saved_log_file* p = (saved_log_file*) malloc(sizeof(saved_log_file)); strcpy(path+path_len, de->d_name); p->name = strdup(path); @@ -510,7 +498,7 @@ erase_volume(const char *volume) { copy_logs(); } - return result; + return (result == 0); } static int @@ -684,13 +672,13 @@ static bool wipe_data(int should_confirm, Device* device) { modified_flash = true; ui->Print("\n-- Wiping data...\n"); - if (device->WipeData() == 0 && erase_volume("/data") == 0 && erase_volume("/cache") == 0) { - ui->Print("Data wipe complete.\n"); - return true; - } else { - ui->Print("Data wipe failed.\n"); - return false; - } + bool success = + device->PreWipeData() && + erase_volume("/data") && + erase_volume("/cache") && + device->PostWipeData(); + ui->Print("Data wipe %s.\n", success ? "complete" : "failed"); + return success; } // Return true on success. @@ -702,52 +690,51 @@ static bool wipe_cache(bool should_confirm, Device* device) { modified_flash = true; ui->Print("\n-- Wiping cache...\n"); - if (erase_volume("/cache") == 0) { - ui->Print("Cache wipe complete.\n"); - return true; - } else { - ui->Print("Cache wipe failed.\n"); - return false; - } + bool success = erase_volume("/cache"); + ui->Print("Cache wipe %s.\n", success ? "complete" : "failed"); + return success; } static void choose_recovery_file(Device* device) { - unsigned int i; - unsigned int n; - static const char** title_headers = NULL; - char *filename; - // "Go back" + LAST_KMSG_FILE + KEEP_LOG_COUNT + terminating NULL entry - char* entries[KEEP_LOG_COUNT + 3]; + // "Back" + KEEP_LOG_COUNT * 2 + terminating nullptr entry + char* entries[1 + KEEP_LOG_COUNT * 2 + 1]; memset(entries, 0, sizeof(entries)); - n = 0; - entries[n++] = strdup("Go back"); - - // Add kernel kmsg file if available - if ((ensure_path_mounted(LAST_KMSG_FILE) == 0) && (access(LAST_KMSG_FILE, R_OK) == 0)) { - entries[n++] = strdup(LAST_KMSG_FILE); - } + unsigned int n = 0; // Add LAST_LOG_FILE + LAST_LOG_FILE.x - for (i = 0; i < KEEP_LOG_COUNT; i++) { - char *filename; - if (asprintf(&filename, (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i) == -1) { + // Add LAST_KMSG_FILE + LAST_KMSG_FILE.x + for (int i = 0; i < KEEP_LOG_COUNT; i++) { + char* log_file; + if (asprintf(&log_file, (i == 0) ? "%s" : "%s.%d", LAST_LOG_FILE, i) == -1) { // memory allocation failure - return early. Should never happen. return; } - if ((ensure_path_mounted(filename) != 0) || (access(filename, R_OK) == -1)) { - free(filename); - entries[n++] = NULL; - break; + if ((ensure_path_mounted(log_file) != 0) || (access(log_file, R_OK) == -1)) { + free(log_file); + } else { + entries[n++] = log_file; + } + + char* kmsg_file; + if (asprintf(&kmsg_file, (i == 0) ? "%s" : "%s.%d", LAST_KMSG_FILE, i) == -1) { + // memory allocation failure - return early. Should never happen. + return; + } + if ((ensure_path_mounted(kmsg_file) != 0) || (access(kmsg_file, R_OK) == -1)) { + free(kmsg_file); + } else { + entries[n++] = kmsg_file; } - entries[n++] = filename; } - const char* headers[] = { "Select file to view", NULL }; + entries[n++] = strdup("Back"); + + const char* headers[] = { "Select file to view", nullptr }; while (true) { int chosen_item = get_menu_selection(headers, entries, 1, 0, device); - if (chosen_item == 0) break; + if (strcmp(entries[chosen_item], "Back") == 0) break; // TODO: do we need to redirect? ShowFile could just avoid writing to stdio. redirect_stdio("/dev/null"); @@ -755,7 +742,7 @@ static void choose_recovery_file(Device* device) { redirect_stdio(TEMPORARY_LOG_FILE); } - for (i = 0; i < (sizeof(entries) / sizeof(*entries)); i++) { + for (size_t i = 0; i < (sizeof(entries) / sizeof(*entries)); i++) { free(entries[i]); } } @@ -1086,6 +1073,13 @@ main(int argc, char **argv) { } else if (!just_exit) { status = INSTALL_NONE; // No command specified ui->SetBackground(RecoveryUI::NO_COMMAND); + + // http://b/17489952 + // If this is an eng or userdebug build, automatically turn on the + // text display if no command is specified. + if (is_ro_debuggable()) { + ui->ShowText(true); + } } if (!sideload_auto_reboot && (status == INSTALL_ERROR || status == INSTALL_CORRUPT)) { diff --git a/screen_ui.cpp b/screen_ui.cpp index 5e73d37c4..ff9591514 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -58,18 +58,19 @@ ScreenRecoveryUI::ScreenRecoveryUI() : progressScopeSize(0), progress(0), pagesIdentical(false), - text(nullptr), - text_cols(0), - text_rows(0), - text_col(0), - text_row(0), - text_top(0), + text_cols_(0), + text_rows_(0), + text_(nullptr), + text_col_(0), + text_row_(0), + text_top_(0), show_text(false), show_text_ever(false), - menu(nullptr), + menu_(nullptr), show_menu(false), menu_items(0), menu_sel(0), + file_viewer_text_(nullptr), animation_fps(20), installing_frames(-1), stage(-1), @@ -255,7 +256,7 @@ void ScreenRecoveryUI::draw_screen_locked() { DrawTextLines(&y, HasThreeButtons() ? REGULAR_HELP : LONG_PRESS_HELP); SetColor(HEADER); - DrawTextLines(&y, menu_headers); + DrawTextLines(&y, menu_headers_); SetColor(MENU); DrawHorizontalRule(&y); @@ -267,10 +268,10 @@ void ScreenRecoveryUI::draw_screen_locked() { gr_fill(0, y - 2, gr_fb_width(), y + char_height + 2); // Bold white text for the selected item. SetColor(MENU_SEL_FG); - gr_text(4, y, menu[i], true); + gr_text(4, y, menu_[i], true); SetColor(MENU); } else { - gr_text(4, y, menu[i], false); + gr_text(4, y, menu_[i], false); } y += char_height + 4; } @@ -281,14 +282,14 @@ void ScreenRecoveryUI::draw_screen_locked() { // screen, the bottom of the menu, or we've displayed the // entire text buffer. SetColor(LOG); - int row = (text_top+text_rows-1) % text_rows; + int row = (text_top_ + text_rows_ - 1) % text_rows_; size_t count = 0; for (int ty = gr_fb_height() - char_height; - ty >= y && count < text_rows; + ty >= y && count < text_rows_; ty -= char_height, ++count) { - gr_text(0, ty, text[row], false); + gr_text(0, ty, text_[row], false); --row; - if (row < 0) row = text_rows-1; + if (row < 0) row = text_rows_ - 1; } } } @@ -391,14 +392,15 @@ void ScreenRecoveryUI::Init() { gr_init(); gr_font_size(&char_width, &char_height); - text_rows = gr_fb_height() / char_height; - text_cols = gr_fb_width() / char_width; + text_rows_ = gr_fb_height() / char_height; + text_cols_ = gr_fb_width() / char_width; - text = Alloc2d(text_rows, text_cols + 1); - menu = Alloc2d(text_rows, text_cols + 1); + text_ = Alloc2d(text_rows_, text_cols_ + 1); + file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1); + menu_ = Alloc2d(text_rows_, text_cols_ + 1); - text_col = text_row = 0; - text_top = 1; + text_col_ = text_row_ = 0; + text_top_ = 1; backgroundIcon[NONE] = nullptr; LoadBitmapArray("icon_installing", &installing_frames, &installation); @@ -514,17 +516,17 @@ void ScreenRecoveryUI::Print(const char *fmt, ...) { fputs(buf, stdout); pthread_mutex_lock(&updateMutex); - if (text_rows > 0 && text_cols > 0) { + if (text_rows_ > 0 && text_cols_ > 0) { for (const char* ptr = buf; *ptr != '\0'; ++ptr) { - if (*ptr == '\n' || text_col >= text_cols) { - text[text_row][text_col] = '\0'; - text_col = 0; - text_row = (text_row + 1) % text_rows; - if (text_row == text_top) text_top = (text_top + 1) % text_rows; + if (*ptr == '\n' || text_col_ >= text_cols_) { + text_[text_row_][text_col_] = '\0'; + text_col_ = 0; + text_row_ = (text_row_ + 1) % text_rows_; + if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_; } - if (*ptr != '\n') text[text_row][text_col++] = *ptr; + if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr; } - text[text_row][text_col] = '\0'; + text_[text_row_][text_col_] = '\0'; update_screen_locked(); } pthread_mutex_unlock(&updateMutex); @@ -532,21 +534,23 @@ void ScreenRecoveryUI::Print(const char *fmt, ...) { void ScreenRecoveryUI::PutChar(char ch) { pthread_mutex_lock(&updateMutex); - if (ch != '\n') text[text_row][text_col++] = ch; - if (ch == '\n' || text_col >= text_cols) { - text_col = 0; - ++text_row; + if (ch != '\n') text_[text_row_][text_col_++] = ch; + if (ch == '\n' || text_col_ >= text_cols_) { + text_col_ = 0; + ++text_row_; + + if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_; } pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::ClearText() { pthread_mutex_lock(&updateMutex); - text_col = 0; - text_row = 0; - text_top = 1; - for (size_t i = 0; i < text_rows; ++i) { - memset(text[i], 0, text_cols + 1); + text_col_ = 0; + text_row_ = 0; + text_top_ = 1; + for (size_t i = 0; i < text_rows_; ++i) { + memset(text_[i], 0, text_cols_ + 1); } pthread_mutex_unlock(&updateMutex); } @@ -590,12 +594,11 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) { int ch = getc(fp); if (ch == EOF) { - text_row = text_top = text_rows - 2; + while (text_row_ < text_rows_ - 1) PutChar('\n'); show_prompt = true; } else { PutChar(ch); - if (text_col == 0 && text_row >= text_rows - 2) { - text_top = text_row; + if (text_col_ == 0 && text_row_ >= text_rows_ - 1) { show_prompt = true; } } @@ -608,19 +611,34 @@ void ScreenRecoveryUI::ShowFile(const char* filename) { Print(" Unable to open %s: %s\n", filename, strerror(errno)); return; } + + char** old_text = text_; + size_t old_text_col = text_col_; + size_t old_text_row = text_row_; + size_t old_text_top = text_top_; + + // Swap in the alternate screen and clear it. + text_ = file_viewer_text_; + ClearText(); + ShowFile(fp); fclose(fp); + + text_ = old_text; + text_col_ = old_text_col; + text_row_ = old_text_row; + text_top_ = old_text_top; } void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const * items, int initial_selection) { pthread_mutex_lock(&updateMutex); - if (text_rows > 0 && text_cols > 0) { - menu_headers = headers; + if (text_rows_ > 0 && text_cols_ > 0) { + menu_headers_ = headers; size_t i = 0; - for (; i < text_rows && items[i] != nullptr; ++i) { - strncpy(menu[i], items[i], text_cols-1); - menu[i][text_cols-1] = '\0'; + for (; i < text_rows_ && items[i] != nullptr; ++i) { + strncpy(menu_[i], items[i], text_cols_ - 1); + menu_[i][text_cols_ - 1] = '\0'; } menu_items = i; show_menu = true; @@ -649,7 +667,7 @@ int ScreenRecoveryUI::SelectMenu(int sel) { void ScreenRecoveryUI::EndMenu() { pthread_mutex_lock(&updateMutex); - if (show_menu && text_rows > 0 && text_cols > 0) { + if (show_menu && text_rows_ > 0 && text_cols_ > 0) { show_menu = false; update_screen_locked(); } diff --git a/screen_ui.h b/screen_ui.h index 46165d90c..ea05bf15f 100644 --- a/screen_ui.h +++ b/screen_ui.h @@ -89,18 +89,23 @@ class ScreenRecoveryUI : public RecoveryUI { // true when both graphics pages are the same (except for the progress bar). bool pagesIdentical; + size_t text_cols_, text_rows_; + // Log text overlay, displayed when a magic key is pressed. - char** text; - size_t text_cols, text_rows; - size_t text_col, text_row, text_top; + char** text_; + size_t text_col_, text_row_, text_top_; + bool show_text; bool show_text_ever; // has show_text ever been true? - char** menu; - const char* const* menu_headers; + char** menu_; + const char* const* menu_headers_; bool show_menu; int menu_items, menu_sel; + // An alternate text screen, swapped with 'text_' when we're viewing a log file. + char** file_viewer_text_; + pthread_t progress_thread_; int animation_fps; diff --git a/tools/ota/check-lost+found.c b/tools/ota/check-lost+found.c index cbf792629..8ce12d39f 100644 --- a/tools/ota/check-lost+found.c +++ b/tools/ota/check-lost+found.c @@ -78,7 +78,7 @@ int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) snprintf(fn, sizeof(fn), "%s/%s", kPartitions[i], "dirty"); fd = open(fn, O_WRONLY|O_CREAT, 0444); if (fd >= 0) { // Don't sweat it if we can't write the file. - write(fd, fn, sizeof(fn)); // write, you know, some data + TEMP_FAILURE_RETRY(write(fd, fn, sizeof(fn))); // write, you know, some data close(fd); unlink(fn); } @@ -251,7 +251,7 @@ bool RecoveryUI::IsUsbConnected() { char buf; // USB is connected if android_usb state is CONNECTED or CONFIGURED. - int connected = (read(fd, &buf, 1) == 1) && (buf == 'C'); + int connected = (TEMP_FAILURE_RETRY(read(fd, &buf, 1)) == 1) && (buf == 'C'); if (close(fd) < 0) { printf("failed to close /sys/class/android_usb/android0/state: %s\n", strerror(errno)); diff --git a/uncrypt/Android.mk b/uncrypt/Android.mk index 878d2757e..c7d4d3746 100644 --- a/uncrypt/Android.mk +++ b/uncrypt/Android.mk @@ -16,10 +16,10 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := uncrypt.c +LOCAL_SRC_FILES := uncrypt.cpp LOCAL_MODULE := uncrypt -LOCAL_STATIC_LIBRARIES := libfs_mgr liblog libcutils +LOCAL_STATIC_LIBRARIES := libbase liblog libfs_mgr libcutils include $(BUILD_EXECUTABLE) diff --git a/uncrypt/uncrypt.c b/uncrypt/uncrypt.cpp index aa75210b0..1db3013c6 100644 --- a/uncrypt/uncrypt.c +++ b/uncrypt/uncrypt.cpp @@ -40,37 +40,42 @@ // file data to use as an update package. #include <errno.h> +#include <fcntl.h> +#include <linux/fs.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <stdarg.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <linux/fs.h> #include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> -#define LOG_TAG "uncrypt" -#include <log/log.h> +#include <base/file.h> +#include <base/strings.h> #include <cutils/properties.h> #include <fs_mgr.h> +#define LOG_TAG "uncrypt" +#include <log/log.h> #define WINDOW_SIZE 5 -#define RECOVERY_COMMAND_FILE "/cache/recovery/command" -#define RECOVERY_COMMAND_FILE_TMP "/cache/recovery/command.tmp" -#define CACHE_BLOCK_MAP "/cache/recovery/block.map" + +static const std::string cache_block_map = "/cache/recovery/block.map"; +static const std::string status_file = "/cache/recovery/uncrypt_status"; +static const std::string uncrypt_file = "/cache/recovery/uncrypt_file"; static struct fstab* fstab = NULL; -static int write_at_offset(unsigned char* buffer, size_t size, - int wfd, off64_t offset) -{ - lseek64(wfd, offset, SEEK_SET); +static int write_at_offset(unsigned char* buffer, size_t size, int wfd, off64_t offset) { + if (TEMP_FAILURE_RETRY(lseek64(wfd, offset, SEEK_SET)) == -1) { + ALOGE("error seeking to offset %lld: %s\n", offset, strerror(errno)); + return -1; + } size_t written = 0; while (written < size) { - ssize_t wrote = write(wfd, buffer + written, size - written); - if (wrote < 0) { - ALOGE("error writing offset %lld: %s\n", offset, strerror(errno)); + ssize_t wrote = TEMP_FAILURE_RETRY(write(wfd, buffer + written, size - written)); + if (wrote == -1) { + ALOGE("error writing offset %lld: %s\n", (offset + written), strerror(errno)); return -1; } written += wrote; @@ -78,8 +83,7 @@ static int write_at_offset(unsigned char* buffer, size_t size, return 0; } -void add_block_to_ranges(int** ranges, int* range_alloc, int* range_used, int new_block) -{ +static void add_block_to_ranges(int** ranges, int* range_alloc, int* range_used, int new_block) { // If the current block start is < 0, set the start to the new // block. (This only happens for the very first block of the very // first range.) @@ -98,7 +102,7 @@ void add_block_to_ranges(int** ranges, int* range_alloc, int* range_used, int ne // If there isn't enough room in the array, we need to expand it. if (*range_used >= *range_alloc) { *range_alloc *= 2; - *ranges = realloc(*ranges, *range_alloc * 2 * sizeof(int)); + *ranges = reinterpret_cast<int*>(realloc(*ranges, *range_alloc * 2 * sizeof(int))); } ++*range_used; @@ -107,8 +111,7 @@ void add_block_to_ranges(int** ranges, int* range_alloc, int* range_used, int ne } } -static struct fstab* read_fstab() -{ +static struct fstab* read_fstab() { fstab = NULL; // The fstab path is always "/fstab.${ro.hardware}". @@ -127,26 +130,26 @@ static struct fstab* read_fstab() return fstab; } -const char* find_block_device(const char* path, int* encryptable, int* encrypted) -{ +static const char* find_block_device(const char* path, bool* encryptable, bool* encrypted) { // Look for a volume whose mount point is the prefix of path and // return its block device. Set encrypted if it's currently // encrypted. - int i; - for (i = 0; i < fstab->num_entries; ++i) { + for (int i = 0; i < fstab->num_entries; ++i) { struct fstab_rec* v = &fstab->recs[i]; - if (!v->mount_point) continue; + if (!v->mount_point) { + continue; + } int len = strlen(v->mount_point); if (strncmp(path, v->mount_point, len) == 0 && (path[len] == '/' || path[len] == 0)) { - *encrypted = 0; - *encryptable = 0; + *encrypted = false; + *encryptable = false; if (fs_mgr_is_encryptable(v)) { - *encryptable = 1; + *encryptable = true; char buffer[PROPERTY_VALUE_MAX+1]; if (property_get("ro.crypto.state", buffer, "") && strcmp(buffer, "encrypted") == 0) { - *encrypted = 1; + *encrypted = true; } } return v->blk_device; @@ -156,56 +159,37 @@ const char* find_block_device(const char* path, int* encryptable, int* encrypted return NULL; } -char* parse_recovery_command_file() +// Parse uncrypt_file to find the update package name. +static bool find_uncrypt_package(std::string& package_name) { - char* fn = NULL; - int count = 0; - char temp[1024]; - - FILE* f = fopen(RECOVERY_COMMAND_FILE, "r"); - if (f == NULL) { - return NULL; - } - int fd = open(RECOVERY_COMMAND_FILE_TMP, O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR); - if (fd < 0) { - ALOGE("failed to open %s\n", RECOVERY_COMMAND_FILE_TMP); - return NULL; + if (!android::base::ReadFileToString(uncrypt_file, &package_name)) { + ALOGE("failed to open \"%s\": %s\n", uncrypt_file.c_str(), strerror(errno)); + return false; } - FILE* fo = fdopen(fd, "w"); - while (fgets(temp, sizeof(temp), f)) { - printf("read: %s", temp); - if (strncmp(temp, "--update_package=/data/", strlen("--update_package=/data/")) == 0) { - fn = strdup(temp + strlen("--update_package=")); - strcpy(temp, "--update_package=@" CACHE_BLOCK_MAP "\n"); - } - fputs(temp, fo); - } - fclose(f); - fsync(fd); - fclose(fo); + // Remove the trailing '\n' if present. + package_name = android::base::Trim(package_name); - if (fn) { - char* newline = strchr(fn, '\n'); - if (newline) *newline = 0; - } - return fn; + return true; } -int produce_block_map(const char* path, const char* map_file, const char* blk_dev, - int encrypted) -{ - struct stat sb; - int ret; - +static int produce_block_map(const char* path, const char* map_file, const char* blk_dev, + bool encrypted, int status_fd) { int mapfd = open(map_file, O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR); - if (mapfd < 0) { + if (mapfd == -1) { ALOGE("failed to open %s\n", map_file); return -1; } FILE* mapf = fdopen(mapfd, "w"); - ret = stat(path, &sb); + // Make sure we can write to the status_file. + if (!android::base::WriteStringToFd("0\n", status_fd)) { + ALOGE("failed to update \"%s\"\n", status_file.c_str()); + return -1; + } + + struct stat sb; + int ret = stat(path, &sb); if (ret != 0) { ALOGE("failed to stat %s\n", path); return -1; @@ -216,20 +200,18 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de int blocks = ((sb.st_size-1) / sb.st_blksize) + 1; ALOGI(" file size: %lld bytes, %d blocks\n", (long long)sb.st_size, blocks); - int* ranges; int range_alloc = 1; int range_used = 1; - ranges = malloc(range_alloc * 2 * sizeof(int)); + int* ranges = reinterpret_cast<int*>(malloc(range_alloc * 2 * sizeof(int))); ranges[0] = -1; ranges[1] = -1; fprintf(mapf, "%s\n%lld %lu\n", blk_dev, (long long)sb.st_size, (unsigned long)sb.st_blksize); unsigned char* buffers[WINDOW_SIZE]; - int i; if (encrypted) { - for (i = 0; i < WINDOW_SIZE; ++i) { - buffers[i] = malloc(sb.st_blksize); + for (size_t i = 0; i < WINDOW_SIZE; ++i) { + buffers[i] = reinterpret_cast<unsigned char*>(malloc(sb.st_blksize)); } } int head_block = 0; @@ -241,7 +223,6 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de ALOGE("failed to open fd for reading: %s\n", strerror(errno)); return -1; } - fsync(fd); int wfd = -1; if (encrypted) { @@ -252,7 +233,15 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de } } + int last_progress = 0; while (pos < sb.st_size) { + // Update the status file, progress must be between [0, 99]. + int progress = static_cast<int>(100 * (double(pos) / double(sb.st_size))); + if (progress > last_progress) { + last_progress = progress; + android::base::WriteStringToFd(std::to_string(progress) + "\n", status_fd); + } + if ((tail+1) % WINDOW_SIZE == head) { // write out head buffer int block = head_block; @@ -263,7 +252,8 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de } add_block_to_ranges(&ranges, &range_alloc, &range_used, block); if (encrypted) { - if (write_at_offset(buffers[head], sb.st_blksize, wfd, (off64_t)sb.st_blksize * block) != 0) { + if (write_at_offset(buffers[head], sb.st_blksize, wfd, + (off64_t)sb.st_blksize * block) != 0) { return -1; } } @@ -275,8 +265,9 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de if (encrypted) { size_t so_far = 0; while (so_far < sb.st_blksize && pos < sb.st_size) { - ssize_t this_read = read(fd, buffers[tail] + so_far, sb.st_blksize - so_far); - if (this_read < 0) { + ssize_t this_read = + TEMP_FAILURE_RETRY(read(fd, buffers[tail] + so_far, sb.st_blksize - so_far)); + if (this_read == -1) { ALOGE("failed to read: %s\n", strerror(errno)); return -1; } @@ -302,7 +293,8 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de } add_block_to_ranges(&ranges, &range_alloc, &range_used, block); if (encrypted) { - if (write_at_offset(buffers[head], sb.st_blksize, wfd, (off64_t)sb.st_blksize * block) != 0) { + if (write_at_offset(buffers[head], sb.st_blksize, wfd, + (off64_t)sb.st_blksize * block) != 0) { return -1; } } @@ -311,25 +303,30 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de } fprintf(mapf, "%d\n", range_used); - for (i = 0; i < range_used; ++i) { + for (int i = 0; i < range_used; ++i) { fprintf(mapf, "%d %d\n", ranges[i*2], ranges[i*2+1]); } - fsync(mapfd); + if (fsync(mapfd) == -1) { + ALOGE("failed to fsync \"%s\": %s\n", map_file, strerror(errno)); + return -1; + } fclose(mapf); close(fd); if (encrypted) { - fsync(wfd); + if (fsync(wfd) == -1) { + ALOGE("failed to fsync \"%s\": %s\n", blk_dev, strerror(errno)); + return -1; + } close(wfd); } return 0; } -void wipe_misc() { +static void wipe_misc() { ALOGI("removing old commands from misc"); - int i; - for (i = 0; i < fstab->num_entries; ++i) { + for (int i = 0; i < fstab->num_entries; ++i) { struct fstab_rec* v = &fstab->recs[i]; if (!v->mount_point) continue; if (strcmp(v->mount_point, "/misc") == 0) { @@ -340,72 +337,49 @@ void wipe_misc() { size_t written = 0; size_t size = sizeof(zeroes); while (written < size) { - ssize_t w = write(fd, zeroes, size-written); - if (w < 0 && errno != EINTR) { + ssize_t w = TEMP_FAILURE_RETRY(write(fd, zeroes, size-written)); + if (w == -1) { ALOGE("zero write failed: %s\n", strerror(errno)); return; } else { written += w; } } - fsync(fd); + if (fsync(fd) == -1) { + ALOGE("failed to fsync \"%s\": %s\n", v->blk_device, strerror(errno)); + close(fd); + return; + } close(fd); } } } -void reboot_to_recovery() { +static void reboot_to_recovery() { ALOGI("rebooting to recovery"); property_set("sys.powerctl", "reboot,recovery"); sleep(10); ALOGE("reboot didn't succeed?"); } -int main(int argc, char** argv) -{ - const char* input_path; - const char* map_file; - int do_reboot = 1; +int uncrypt(const char* input_path, const char* map_file, int status_fd) { - if (argc != 1 && argc != 3) { - fprintf(stderr, "usage: %s [<transform_path> <map_file>]\n", argv[0]); - return 2; - } - - if (argc == 3) { - // when command-line args are given this binary is being used - // for debugging; don't reboot to recovery at the end. - input_path = argv[1]; - map_file = argv[2]; - do_reboot = 0; - } else { - input_path = parse_recovery_command_file(); - if (input_path == NULL) { - // if we're rebooting to recovery without a package (say, - // to wipe data), then we don't need to do anything before - // going to recovery. - ALOGI("no recovery command file or no update package arg"); - reboot_to_recovery(); - return 1; - } - map_file = CACHE_BLOCK_MAP; - } - - ALOGI("update package is %s", input_path); + ALOGI("update package is \"%s\"", input_path); // Turn the name of the file we're supposed to convert into an // absolute path, so we can find what filesystem it's on. char path[PATH_MAX+1]; if (realpath(input_path, path) == NULL) { - ALOGE("failed to convert %s to absolute path: %s", input_path, strerror(errno)); + ALOGE("failed to convert \"%s\" to absolute path: %s", input_path, strerror(errno)); return 1; } - int encryptable; - int encrypted; if (read_fstab() == NULL) { return 1; } + + bool encryptable; + bool encrypted; const char* blk_dev = find_block_device(path, &encryptable, &encrypted); if (blk_dev == NULL) { ALOGE("failed to find block device for %s", path); @@ -425,18 +399,67 @@ int main(int argc, char** argv) // On /data we want to convert the file to a block map so that we // can read the package without mounting the partition. On /cache // and /sdcard we leave the file alone. - if (strncmp(path, "/data/", 6) != 0) { - // path does not start with "/data/"; leave it alone. - unlink(RECOVERY_COMMAND_FILE_TMP); - } else { + if (strncmp(path, "/data/", 6) == 0) { ALOGI("writing block map %s", map_file); - if (produce_block_map(path, map_file, blk_dev, encrypted) != 0) { + if (produce_block_map(path, map_file, blk_dev, encrypted, status_fd) != 0) { return 1; } } - wipe_misc(); - rename(RECOVERY_COMMAND_FILE_TMP, RECOVERY_COMMAND_FILE); - if (do_reboot) reboot_to_recovery(); + return 0; +} + +int main(int argc, char** argv) { + const char* input_path; + const char* map_file; + + if (argc != 3 && argc != 1 && (argc == 2 && strcmp(argv[1], "--reboot") != 0)) { + fprintf(stderr, "usage: %s [--reboot] [<transform_path> <map_file>]\n", argv[0]); + return 2; + } + + // When uncrypt is started with "--reboot", it wipes misc and reboots. + // Otherwise it uncrypts the package and writes the block map. + if (argc == 2) { + if (read_fstab() == NULL) { + return 1; + } + wipe_misc(); + reboot_to_recovery(); + } else { + // The pipe has been created by the system server. + int status_fd = open(status_file.c_str(), O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR); + if (status_fd == -1) { + ALOGE("failed to open pipe \"%s\": %s\n", status_file.c_str(), strerror(errno)); + return 1; + } + + if (argc == 3) { + // when command-line args are given this binary is being used + // for debugging. + input_path = argv[1]; + map_file = argv[2]; + } else { + std::string package; + if (!find_uncrypt_package(package)) { + android::base::WriteStringToFd("-1\n", status_fd); + close(status_fd); + return 1; + } + input_path = package.c_str(); + map_file = cache_block_map.c_str(); + } + + int status = uncrypt(input_path, map_file, status_fd); + if (status != 0) { + android::base::WriteStringToFd("-1\n", status_fd); + close(status_fd); + return 1; + } + + android::base::WriteStringToFd("100\n", status_fd); + close(status_fd); + } + return 0; } diff --git a/updater/blockimg.c b/updater/blockimg.c index d5344f991..b006d10c5 100644 --- a/updater/blockimg.c +++ b/updater/blockimg.c @@ -19,6 +19,7 @@ #include <dirent.h> #include <fcntl.h> #include <inttypes.h> +#include <libgen.h> #include <pthread.h> #include <stdarg.h> #include <stdio.h> @@ -101,7 +102,7 @@ static int range_overlaps(RangeSet* r1, RangeSet* r2) { r2_0 = r2->pos[j * 2]; r2_1 = r2->pos[j * 2 + 1]; - if (!(r2_0 > r1_1 || r1_0 > r2_1)) { + if (!(r2_0 >= r1_1 || r1_0 >= r2_1)) { return 1; } } @@ -113,13 +114,12 @@ static int range_overlaps(RangeSet* r1, RangeSet* r2) { static int read_all(int fd, uint8_t* data, size_t size) { size_t so_far = 0; while (so_far < size) { - ssize_t r = read(fd, data+so_far, size-so_far); - if (r < 0 && errno != EINTR) { + ssize_t r = TEMP_FAILURE_RETRY(read(fd, data+so_far, size-so_far)); + if (r == -1) { fprintf(stderr, "read failed: %s\n", strerror(errno)); return -1; - } else { - so_far += r; } + so_far += r; } return 0; } @@ -127,13 +127,12 @@ static int read_all(int fd, uint8_t* data, size_t size) { static int write_all(int fd, const uint8_t* data, size_t size) { size_t written = 0; while (written < size) { - ssize_t w = write(fd, data+written, size-written); - if (w < 0 && errno != EINTR) { + ssize_t w = TEMP_FAILURE_RETRY(write(fd, data+written, size-written)); + if (w == -1) { fprintf(stderr, "write failed: %s\n", strerror(errno)); return -1; - } else { - written += w; } + written += w; } if (fsync(fd) == -1) { @@ -144,19 +143,13 @@ static int write_all(int fd, const uint8_t* data, size_t size) { return 0; } -static int check_lseek(int fd, off64_t offset, int whence) { - while (true) { - off64_t ret = lseek64(fd, offset, whence); - if (ret < 0) { - if (errno != EINTR) { - fprintf(stderr, "lseek64 failed: %s\n", strerror(errno)); - return -1; - } - } else { - break; - } +static bool check_lseek(int fd, off64_t offset, int whence) { + off64_t rc = TEMP_FAILURE_RETRY(lseek64(fd, offset, whence)); + if (rc == -1) { + fprintf(stderr, "lseek64 failed: %s\n", strerror(errno)); + return false; } - return 0; + return true; } static void allocate(size_t size, uint8_t** buffer, size_t* buffer_alloc) { @@ -213,8 +206,8 @@ static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) { rss->p_remain = (rss->tgt->pos[rss->p_block * 2 + 1] - rss->tgt->pos[rss->p_block * 2]) * BLOCKSIZE; - if (check_lseek(rss->fd, (off64_t)rss->tgt->pos[rss->p_block*2] * BLOCKSIZE, - SEEK_SET) == -1) { + if (!check_lseek(rss->fd, (off64_t)rss->tgt->pos[rss->p_block*2] * BLOCKSIZE, + SEEK_SET)) { break; } } else { @@ -306,7 +299,7 @@ static int ReadBlocks(RangeSet* src, uint8_t* buffer, int fd) { } for (i = 0; i < src->count; ++i) { - if (check_lseek(fd, (off64_t) src->pos[i * 2] * BLOCKSIZE, SEEK_SET) == -1) { + if (!check_lseek(fd, (off64_t) src->pos[i * 2] * BLOCKSIZE, SEEK_SET)) { return -1; } @@ -332,7 +325,7 @@ static int WriteBlocks(RangeSet* tgt, uint8_t* buffer, int fd) { } for (i = 0; i < tgt->count; ++i) { - if (check_lseek(fd, (off64_t) tgt->pos[i * 2] * BLOCKSIZE, SEEK_SET) == -1) { + if (!check_lseek(fd, (off64_t) tgt->pos[i * 2] * BLOCKSIZE, SEEK_SET)) { return -1; } @@ -624,7 +617,7 @@ static int LoadStash(const char* base, const char* id, int verify, int* blocks, lsout: if (fd != -1) { - TEMP_FAILURE_RETRY(close(fd)); + close(fd); } if (fn) { @@ -640,6 +633,7 @@ static int WriteStash(const char* base, const char* id, int blocks, uint8_t* buf char *cn = NULL; int fd = -1; int rc = -1; + int dfd = -1; int res; struct stat st; @@ -698,11 +692,29 @@ static int WriteStash(const char* base, const char* id, int blocks, uint8_t* buf goto wsout; } + const char* dname; + dname = dirname(cn); + dfd = TEMP_FAILURE_RETRY(open(dname, O_RDONLY | O_DIRECTORY)); + + if (dfd == -1) { + fprintf(stderr, "failed to open \"%s\" failed: %s\n", dname, strerror(errno)); + goto wsout; + } + + if (fsync(dfd) == -1) { + fprintf(stderr, "fsync \"%s\" failed: %s\n", dname, strerror(errno)); + goto wsout; + } + rc = 0; wsout: if (fd != -1) { - TEMP_FAILURE_RETRY(close(fd)); + close(fd); + } + + if (dfd != -1) { + close(dfd); } if (fn) { @@ -1217,7 +1229,7 @@ static int PerformCommandZero(CommandParameters* params) { if (params->canwrite) { for (i = 0; i < tgt->count; ++i) { - if (check_lseek(params->fd, (off64_t) tgt->pos[i * 2] * BLOCKSIZE, SEEK_SET) == -1) { + if (!check_lseek(params->fd, (off64_t) tgt->pos[i * 2] * BLOCKSIZE, SEEK_SET)) { goto pczout; } @@ -1271,7 +1283,7 @@ static int PerformCommandNew(CommandParameters* params) { rss.p_block = 0; rss.p_remain = (tgt->pos[1] - tgt->pos[0]) * BLOCKSIZE; - if (check_lseek(params->fd, (off64_t) tgt->pos[0] * BLOCKSIZE, SEEK_SET) == -1) { + if (!check_lseek(params->fd, (off64_t) tgt->pos[0] * BLOCKSIZE, SEEK_SET)) { goto pcnout; } @@ -1367,7 +1379,7 @@ static int PerformCommandDiff(CommandParameters* params) { rss.p_block = 0; rss.p_remain = (tgt->pos[1] - tgt->pos[0]) * BLOCKSIZE; - if (check_lseek(params->fd, (off64_t) tgt->pos[0] * BLOCKSIZE, SEEK_SET) == -1) { + if (!check_lseek(params->fd, (off64_t) tgt->pos[0] * BLOCKSIZE, SEEK_SET)) { goto pcdout; } @@ -1432,7 +1444,6 @@ static int PerformCommandErase(CommandParameters* params) { if (!S_ISBLK(st.st_mode)) { fprintf(stderr, "not a block device; skipping erase\n"); - rc = 0; goto pceout; } @@ -1456,7 +1467,7 @@ static int PerformCommandErase(CommandParameters* params) { if (ioctl(params->fd, BLKDISCARD, &blocks) == -1) { fprintf(stderr, "BLKDISCARD ioctl failed: %s\n", strerror(errno)); - // Continue anyway, nothing we can do + goto pceout; } } } @@ -1740,7 +1751,7 @@ pbiudone: if (fsync(params.fd) == -1) { fprintf(stderr, "fsync failed: %s\n", strerror(errno)); } - TEMP_FAILURE_RETRY(close(params.fd)); + close(params.fd); } if (logcmd) { @@ -1906,7 +1917,7 @@ Value* RangeSha1Fn(const char* name, State* state, int argc, Expr* argv[]) { int i, j; for (i = 0; i < rs->count; ++i) { - if (check_lseek(fd, (off64_t)rs->pos[i*2] * BLOCKSIZE, SEEK_SET) == -1) { + if (!check_lseek(fd, (off64_t)rs->pos[i*2] * BLOCKSIZE, SEEK_SET)) { ErrorAbort(state, "failed to seek %s: %s", blockdev_filename->data, strerror(errno)); goto done; |