summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--adb_install.cpp2
-rw-r--r--applypatch/applypatch.c53
-rw-r--r--device.h17
-rw-r--r--fuse_sdcard_provider.c16
-rw-r--r--fuse_sideload.c16
-rw-r--r--minadbd/Android.mk3
-rw-r--r--minadbd/adb_main.cpp6
-rw-r--r--minadbd/fuse_adb_provider.cpp21
-rw-r--r--minadbd/services.cpp19
-rw-r--r--minui/Android.mk2
-rw-r--r--minui/events.cpp3
-rw-r--r--minui/graphics.cpp5
-rw-r--r--minui/graphics.h1
-rw-r--r--minui/graphics_drm.cpp476
-rw-r--r--minzip/SysUtil.c10
-rw-r--r--minzip/Zip.c6
-rw-r--r--mtdutils/flash_image.c8
-rw-r--r--mtdutils/mtdutils.c54
-rw-r--r--mtdutils/mtdutils.h2
-rw-r--r--recovery.cpp196
-rw-r--r--screen_ui.cpp110
-rw-r--r--screen_ui.h15
-rw-r--r--tools/ota/check-lost+found.c2
-rw-r--r--ui.cpp2
-rw-r--r--uncrypt/Android.mk4
-rw-r--r--uncrypt/uncrypt.cpp (renamed from uncrypt/uncrypt.c)283
-rw-r--r--updater/blockimg.c79
27 files changed, 969 insertions, 442 deletions
diff --git a/adb_install.cpp b/adb_install.cpp
index ebd4cac..e3b94ea 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 2c86e09..2358d42 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) {
diff --git a/device.h b/device.h
index dad8ccd..f74b6b0 100644
--- a/device.h
+++ b/device.h
@@ -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 ca8c914..4565c7b 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 1dd84e9..48e6cc5 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 cbfd76e..a7a3e08 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 f6e2401..7fae99a 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 5da7fd7..d71807d 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 a832567..dd1fd7c 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 52f0662..97724fb 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 2d47a58..3b2262a 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 f09f1c6..c0eea9e 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 81a9233..52968eb 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 0000000..03e33b7
--- /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 ac6f5c3..b160c9e 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 d3ff79b..40712e0 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 5657dfc..36ffa13 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 9a17e38..cc30334 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 2708c43..8059d6a 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 4dd8279..b7a5458 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 5e73d37..ff95915 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 46165d9..ea05bf1 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 cbf7926..8ce12d3 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);
}
diff --git a/ui.cpp b/ui.cpp
index dca325f..1a0b079 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -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 878d275..c7d4d37 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 aa75210..1db3013 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 d5344f9..b006d10 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;