aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJed Estep2015-12-15 18:04:53 -0600
committerJed Estep2016-03-18 19:58:25 -0500
commitff6df890a2a01bf3bf56d3f430b17a5ef69055cf (patch)
treed639d516e51ec2df2f6e2e26b0643f982e6ae2b6 /otafault
parent9020e0f141d1c26dcf8b6fa4212ee94b7891d53f (diff)
downloadplatform-bootable-recovery-ff6df890a2a01bf3bf56d3f430b17a5ef69055cf.tar.gz
platform-bootable-recovery-ff6df890a2a01bf3bf56d3f430b17a5ef69055cf.tar.xz
platform-bootable-recovery-ff6df890a2a01bf3bf56d3f430b17a5ef69055cf.zip
Control fault injection with config files instead of build flags
Bug: 27724259 Change-Id: I65bdefed10b3fb85fcb9e1147eaf0687d7d438f4
Diffstat (limited to 'otafault')
-rw-r--r--otafault/Android.mk43
-rw-r--r--otafault/config.cpp70
-rw-r--r--otafault/config.h74
-rw-r--r--otafault/ota_io.cpp174
-rw-r--r--otafault/ota_io.h4
-rw-r--r--otafault/test.cpp6
6 files changed, 237 insertions, 134 deletions
diff --git a/otafault/Android.mk b/otafault/Android.mk
index 75617a14..7468de6c 100644
--- a/otafault/Android.mk
+++ b/otafault/Android.mk
@@ -1,10 +1,10 @@
1# Copyright 2015 The ANdroid Open Source Project 1# Copyright 2015 The Android Open Source Project
2# 2#
3# Licensed under the Apache License, Version 2.0 (the "License"); 3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License. 4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at 5# You may obtain a copy of the License at
6# 6#
7# http://www.apache.org/licenses/LICENSE-2.0 7# http://www.apache.org/licenses/LICENSE-2.0
8# 8#
9# Unless required by applicable law or agreed to in writing, software 9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, 10# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,45 +14,30 @@
14 14
15LOCAL_PATH := $(call my-dir) 15LOCAL_PATH := $(call my-dir)
16 16
17empty :=
18space := $(empty) $(empty)
19comma := ,
20
21ifneq ($(TARGET_INJECT_FAULTS),)
22TARGET_INJECT_FAULTS := $(subst $(comma),$(space),$(strip $(TARGET_INJECT_FAULTS)))
23endif
24
25include $(CLEAR_VARS) 17include $(CLEAR_VARS)
26 18
27LOCAL_SRC_FILES := ota_io.cpp 19otafault_static_libs := \
20 libminzip \
21 libz \
22 libselinux \
23
24LOCAL_SRC_FILES := config.cpp ota_io.cpp
28LOCAL_MODULE_TAGS := eng 25LOCAL_MODULE_TAGS := eng
29LOCAL_MODULE := libotafault 26LOCAL_MODULE := libotafault
30LOCAL_CLANG := true 27LOCAL_CLANG := true
31 28LOCAL_C_INCLUDES := bootable/recovery
32ifneq ($(TARGET_INJECT_FAULTS),) 29LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
33$(foreach ft,$(TARGET_INJECT_FAULTS),\ 30LOCAL_WHOLE_STATIC_LIBRARIES := $(otafault_static_libs)
34 $(eval LOCAL_CFLAGS += -DTARGET_$(ft)_FAULT=$(TARGET_$(ft)_FAULT_FILE)))
35LOCAL_CFLAGS += -Wno-unused-parameter
36LOCAL_CFLAGS += -DTARGET_INJECT_FAULTS
37endif
38
39LOCAL_STATIC_LIBRARIES := libc
40 31
41include $(BUILD_STATIC_LIBRARY) 32include $(BUILD_STATIC_LIBRARY)
42 33
43include $(CLEAR_VARS) 34include $(CLEAR_VARS)
44 35
45LOCAL_SRC_FILES := ota_io.cpp test.cpp 36LOCAL_SRC_FILES := config.cpp ota_io.cpp test.cpp
46LOCAL_MODULE_TAGS := tests 37LOCAL_MODULE_TAGS := tests
47LOCAL_MODULE := otafault_test 38LOCAL_MODULE := otafault_test
48LOCAL_STATIC_LIBRARIES := libc 39LOCAL_STATIC_LIBRARIES := $(otafault_static_libs)
40LOCAL_C_INCLUDES := bootable/recovery
49LOCAL_FORCE_STATIC_EXECUTABLE := true 41LOCAL_FORCE_STATIC_EXECUTABLE := true
50LOCAL_CFLAGS += -Wno-unused-parameter -Wno-writable-strings
51
52ifneq ($(TARGET_INJECT_FAULTS),)
53$(foreach ft,$(TARGET_INJECT_FAULTS),\
54 $(eval LOCAL_CFLAGS += -DTARGET_$(ft)_FAULT=$(TARGET_$(ft)_FAULT_FILE)))
55LOCAL_CFLAGS += -DTARGET_INJECT_FAULTS
56endif
57 42
58include $(BUILD_EXECUTABLE) 43include $(BUILD_EXECUTABLE)
diff --git a/otafault/config.cpp b/otafault/config.cpp
new file mode 100644
index 00000000..aa4b4d5c
--- /dev/null
+++ b/otafault/config.cpp
@@ -0,0 +1,70 @@
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <map>
18#include <string>
19
20#include <stdio.h>
21#include <unistd.h>
22
23#include "minzip/Zip.h"
24#include "config.h"
25#include "ota_io.h"
26
27#define OTAIO_MAX_FNAME_SIZE 128
28
29static ZipArchive* archive;
30static std::map<const char*, bool> should_inject_cache;
31
32static const char* get_type_path(const char* io_type) {
33 char* path = (char*)calloc(strlen(io_type) + strlen(OTAIO_BASE_DIR) + 2, sizeof(char));
34 sprintf(path, "%s/%s", OTAIO_BASE_DIR, io_type);
35 return path;
36}
37
38void ota_io_init(ZipArchive* za) {
39 archive = za;
40 ota_set_fault_files();
41}
42
43bool should_fault_inject(const char* io_type) {
44 // archive will be NULL if we used an entry point other
45 // than updater/updater.cpp:main
46 if (archive == NULL) {
47 return false;
48 }
49 if (should_inject_cache.find(io_type) != should_inject_cache.end()) {
50 return should_inject_cache[io_type];
51 }
52 const char* type_path = get_type_path(io_type);
53 const ZipEntry* entry = mzFindZipEntry(archive, type_path);
54 should_inject_cache[type_path] = entry != nullptr;
55 free((void*)type_path);
56 return entry != NULL;
57}
58
59bool should_hit_cache() {
60 return should_fault_inject(OTAIO_CACHE);
61}
62
63std::string fault_fname(const char* io_type) {
64 const char* type_path = get_type_path(io_type);
65 char* fname = (char*) calloc(OTAIO_MAX_FNAME_SIZE, sizeof(char));
66 const ZipEntry* entry = mzFindZipEntry(archive, type_path);
67 mzReadZipEntry(archive, entry, fname, OTAIO_MAX_FNAME_SIZE);
68 free((void*)type_path);
69 return std::string(fname);
70}
diff --git a/otafault/config.h b/otafault/config.h
new file mode 100644
index 00000000..4430be3f
--- /dev/null
+++ b/otafault/config.h
@@ -0,0 +1,74 @@
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Read configuration files in the OTA package to determine which files, if any, will trigger errors.
19 *
20 * OTA packages can be modified to trigger errors by adding a top-level
21 * directory called .libotafault, which may optionally contain up to three
22 * files called READ, WRITE, and FSYNC. Each one of these optional files
23 * contains the name of a single file on the device disk which will cause
24 * an IO error on the first call of the appropriate I/O action to that file.
25 *
26 * Example:
27 * ota.zip
28 * <normal package contents>
29 * .libotafault
30 * WRITE
31 *
32 * If the contents of the file WRITE were /system/build.prop, the first write
33 * action to /system/build.prop would fail with EIO. Note that READ and
34 * FSYNC files are absent, so these actions will not cause an error.
35 */
36
37#ifndef _UPDATER_OTA_IO_CFG_H_
38#define _UPDATER_OTA_IO_CFG_H_
39
40#include <string>
41
42#include <stdbool.h>
43
44#include "minzip/Zip.h"
45
46#define OTAIO_BASE_DIR ".libotafault"
47#define OTAIO_READ "READ"
48#define OTAIO_WRITE "WRITE"
49#define OTAIO_FSYNC "FSYNC"
50#define OTAIO_CACHE "CACHE"
51
52/*
53 * Initialize libotafault by providing a reference to the OTA package.
54 */
55void ota_io_init(ZipArchive* za);
56
57/*
58 * Return true if a config file is present for the given IO type.
59 */
60bool should_fault_inject(const char* io_type);
61
62/*
63 * Return true if an EIO should occur on the next hit to /cache/saved.file
64 * instead of the next hit to the specified file.
65 */
66bool should_hit_cache();
67
68/*
69 * Return the name of the file that should cause an error for the
70 * given IO type.
71 */
72std::string fault_fname(const char* io_type);
73
74#endif
diff --git a/otafault/ota_io.cpp b/otafault/ota_io.cpp
index 9434ebea..04458537 100644
--- a/otafault/ota_io.cpp
+++ b/otafault/ota_io.cpp
@@ -14,9 +14,7 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17#if defined (TARGET_INJECT_FAULTS)
18#include <map> 17#include <map>
19#endif
20 18
21#include <errno.h> 19#include <errno.h>
22#include <fcntl.h> 20#include <fcntl.h>
@@ -24,185 +22,155 @@
24#include <sys/stat.h> 22#include <sys/stat.h>
25#include <unistd.h> 23#include <unistd.h>
26 24
25#include "config.h"
27#include "ota_io.h" 26#include "ota_io.h"
28 27
29#if defined (TARGET_INJECT_FAULTS) 28static std::map<intptr_t, const char*> filename_cache;
30static std::map<int, const char*> FilenameCache; 29static std::string read_fault_file_name = "";
31static std::string FaultFileName = 30static std::string write_fault_file_name = "";
32#if defined (TARGET_READ_FAULT) 31static std::string fsync_fault_file_name = "";
33 TARGET_READ_FAULT; 32
34#elif defined (TARGET_WRITE_FAULT) 33static bool get_hit_file(const char* cached_path, std::string ffn) {
35 TARGET_WRITE_FAULT; 34 return should_hit_cache()
36#elif defined (TARGET_FSYNC_FAULT) 35 ? !strncmp(cached_path, OTAIO_CACHE_FNAME, strlen(cached_path))
37 TARGET_FSYNC_FAULT; 36 : !strncmp(cached_path, ffn.c_str(), strlen(cached_path));
38#endif // defined (TARGET_READ_FAULT) 37}
39#endif // defined (TARGET_INJECT_FAULTS) 38
39void ota_set_fault_files() {
40 if (should_fault_inject(OTAIO_READ)) {
41 read_fault_file_name = fault_fname(OTAIO_READ);
42 }
43 if (should_fault_inject(OTAIO_WRITE)) {
44 write_fault_file_name = fault_fname(OTAIO_WRITE);
45 }
46 if (should_fault_inject(OTAIO_FSYNC)) {
47 fsync_fault_file_name = fault_fname(OTAIO_FSYNC);
48 }
49}
40 50
41bool have_eio_error = false; 51bool have_eio_error = false;
42 52
43int ota_open(const char* path, int oflags) { 53int ota_open(const char* path, int oflags) {
44#if defined (TARGET_INJECT_FAULTS)
45 // Let the caller handle errors; we do not care if open succeeds or fails 54 // Let the caller handle errors; we do not care if open succeeds or fails
46 int fd = open(path, oflags); 55 int fd = open(path, oflags);
47 FilenameCache[fd] = path; 56 filename_cache[fd] = path;
48 return fd; 57 return fd;
49#else
50 return open(path, oflags);
51#endif
52} 58}
53 59
54int ota_open(const char* path, int oflags, mode_t mode) { 60int ota_open(const char* path, int oflags, mode_t mode) {
55#if defined (TARGET_INJECT_FAULTS)
56 int fd = open(path, oflags, mode); 61 int fd = open(path, oflags, mode);
57 FilenameCache[fd] = path; 62 filename_cache[fd] = path;
58 return fd; 63 return fd; }
59#else
60 return open(path, oflags, mode);
61#endif
62}
63 64
64FILE* ota_fopen(const char* path, const char* mode) { 65FILE* ota_fopen(const char* path, const char* mode) {
65#if defined (TARGET_INJECT_FAULTS)
66 FILE* fh = fopen(path, mode); 66 FILE* fh = fopen(path, mode);
67 FilenameCache[(intptr_t)fh] = path; 67 filename_cache[(intptr_t)fh] = path;
68 return fh; 68 return fh;
69#else
70 return fopen(path, mode);
71#endif
72} 69}
73 70
74int ota_close(int fd) { 71int ota_close(int fd) {
75#if defined (TARGET_INJECT_FAULTS) 72 // descriptors can be reused, so make sure not to leave them in the cache
76 // descriptors can be reused, so make sure not to leave them in the cahce 73 filename_cache.erase(fd);
77 FilenameCache.erase(fd);
78#endif
79 return close(fd); 74 return close(fd);
80} 75}
81 76
82int ota_fclose(FILE* fh) { 77int ota_fclose(FILE* fh) {
83#if defined (TARGET_INJECT_FAULTS) 78 filename_cache.erase((intptr_t)fh);
84 FilenameCache.erase((intptr_t)fh);
85#endif
86 return fclose(fh); 79 return fclose(fh);
87} 80}
88 81
89size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) { 82size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) {
90#if defined (TARGET_READ_FAULT) 83 if (should_fault_inject(OTAIO_READ)) {
91 if (FilenameCache.find((intptr_t)stream) != FilenameCache.end() 84 auto cached = filename_cache.find((intptr_t)stream);
92 && FilenameCache[(intptr_t)stream] == FaultFileName) { 85 const char* cached_path = cached->second;
93 FaultFileName = ""; 86 if (cached != filename_cache.end() &&
94 errno = EIO; 87 get_hit_file(cached_path, read_fault_file_name)) {
95 have_eio_error = true; 88 read_fault_file_name = "";
96 return 0; 89 errno = EIO;
97 } else {
98 size_t status = fread(ptr, size, nitems, stream);
99 // If I/O error occurs, set the retry-update flag.
100 if (status != nitems && errno == EIO) {
101 have_eio_error = true; 90 have_eio_error = true;
91 return 0;
102 } 92 }
103 return status;
104 } 93 }
105#else
106 size_t status = fread(ptr, size, nitems, stream); 94 size_t status = fread(ptr, size, nitems, stream);
107 if (status != nitems && errno == EIO) { 95 if (status != nitems && errno == EIO) {
108 have_eio_error = true; 96 have_eio_error = true;
109 } 97 }
110 return status; 98 return status;
111#endif
112} 99}
113 100
114ssize_t ota_read(int fd, void* buf, size_t nbyte) { 101ssize_t ota_read(int fd, void* buf, size_t nbyte) {
115#if defined (TARGET_READ_FAULT) 102 if (should_fault_inject(OTAIO_READ)) {
116 if (FilenameCache.find(fd) != FilenameCache.end() 103 auto cached = filename_cache.find(fd);
117 && FilenameCache[fd] == FaultFileName) { 104 const char* cached_path = cached->second;
118 FaultFileName = ""; 105 if (cached != filename_cache.end()
119 errno = EIO; 106 && get_hit_file(cached_path, read_fault_file_name)) {
120 have_eio_error = true; 107 read_fault_file_name = "";
121 return -1; 108 errno = EIO;
122 } else {
123 ssize_t status = read(fd, buf, nbyte);
124 if (status == -1 && errno == EIO) {
125 have_eio_error = true; 109 have_eio_error = true;
110 return -1;
126 } 111 }
127 return status;
128 } 112 }
129#else
130 ssize_t status = read(fd, buf, nbyte); 113 ssize_t status = read(fd, buf, nbyte);
131 if (status == -1 && errno == EIO) { 114 if (status == -1 && errno == EIO) {
132 have_eio_error = true; 115 have_eio_error = true;
133 } 116 }
134 return status; 117 return status;
135#endif
136} 118}
137 119
138size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) { 120size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) {
139#if defined (TARGET_WRITE_FAULT) 121 if (should_fault_inject(OTAIO_WRITE)) {
140 if (FilenameCache.find((intptr_t)stream) != FilenameCache.end() 122 auto cached = filename_cache.find((intptr_t)stream);
141 && FilenameCache[(intptr_t)stream] == FaultFileName) { 123 const char* cached_path = cached->second;
142 FaultFileName = ""; 124 if (cached != filename_cache.end() &&
143 errno = EIO; 125 get_hit_file(cached_path, write_fault_file_name)) {
144 have_eio_error = true; 126 write_fault_file_name = "";
145 return 0; 127 errno = EIO;
146 } else {
147 size_t status = fwrite(ptr, size, count, stream);
148 if (status != count && errno == EIO) {
149 have_eio_error = true; 128 have_eio_error = true;
129 return 0;
150 } 130 }
151 return status;
152 } 131 }
153#else
154 size_t status = fwrite(ptr, size, count, stream); 132 size_t status = fwrite(ptr, size, count, stream);
155 if (status != count && errno == EIO) { 133 if (status != count && errno == EIO) {
156 have_eio_error = true; 134 have_eio_error = true;
157 } 135 }
158 return status; 136 return status;
159#endif
160} 137}
161 138
162ssize_t ota_write(int fd, const void* buf, size_t nbyte) { 139ssize_t ota_write(int fd, const void* buf, size_t nbyte) {
163#if defined (TARGET_WRITE_FAULT) 140 if (should_fault_inject(OTAIO_WRITE)) {
164 if (FilenameCache.find(fd) != FilenameCache.end() 141 auto cached = filename_cache.find(fd);
165 && FilenameCache[fd] == FaultFileName) { 142 const char* cached_path = cached->second;
166 FaultFileName = ""; 143 if (cached != filename_cache.end() &&
167 errno = EIO; 144 get_hit_file(cached_path, write_fault_file_name)) {
168 have_eio_error = true; 145 write_fault_file_name = "";
169 return -1; 146 errno = EIO;
170 } else {
171 ssize_t status = write(fd, buf, nbyte);
172 if (status == -1 && errno == EIO) {
173 have_eio_error = true; 147 have_eio_error = true;
148 return -1;
174 } 149 }
175 return status;
176 } 150 }
177#else
178 ssize_t status = write(fd, buf, nbyte); 151 ssize_t status = write(fd, buf, nbyte);
179 if (status == -1 && errno == EIO) { 152 if (status == -1 && errno == EIO) {
180 have_eio_error = true; 153 have_eio_error = true;
181 } 154 }
182 return status; 155 return status;
183#endif
184} 156}
185 157
186int ota_fsync(int fd) { 158int ota_fsync(int fd) {
187#if defined (TARGET_FSYNC_FAULT) 159 if (should_fault_inject(OTAIO_FSYNC)) {
188 if (FilenameCache.find(fd) != FilenameCache.end() 160 auto cached = filename_cache.find(fd);
189 && FilenameCache[fd] == FaultFileName) { 161 const char* cached_path = cached->second;
190 FaultFileName = ""; 162 if (cached != filename_cache.end() &&
191 errno = EIO; 163 get_hit_file(cached_path, fsync_fault_file_name)) {
192 have_eio_error = true; 164 fsync_fault_file_name = "";
193 return -1; 165 errno = EIO;
194 } else {
195 int status = fsync(fd);
196 if (status == -1 && errno == EIO) {
197 have_eio_error = true; 166 have_eio_error = true;
167 return -1;
198 } 168 }
199 return status;
200 } 169 }
201#else
202 int status = fsync(fd); 170 int status = fsync(fd);
203 if (status == -1 && errno == EIO) { 171 if (status == -1 && errno == EIO) {
204 have_eio_error = true; 172 have_eio_error = true;
205 } 173 }
206 return status; 174 return status;
207#endif
208} 175}
176
diff --git a/otafault/ota_io.h b/otafault/ota_io.h
index 641a5ae0..84187a76 100644
--- a/otafault/ota_io.h
+++ b/otafault/ota_io.h
@@ -26,6 +26,10 @@
26#include <stdio.h> 26#include <stdio.h>
27#include <sys/stat.h> 27#include <sys/stat.h>
28 28
29#define OTAIO_CACHE_FNAME "/cache/saved.file"
30
31void ota_set_fault_files();
32
29int ota_open(const char* path, int oflags); 33int ota_open(const char* path, int oflags);
30 34
31int ota_open(const char* path, int oflags, mode_t mode); 35int ota_open(const char* path, int oflags, mode_t mode);
diff --git a/otafault/test.cpp b/otafault/test.cpp
index a0f73151..6514782b 100644
--- a/otafault/test.cpp
+++ b/otafault/test.cpp
@@ -17,16 +17,18 @@
17#include <errno.h> 17#include <errno.h>
18#include <fcntl.h> 18#include <fcntl.h>
19#include <stdio.h> 19#include <stdio.h>
20#include <unistd.h>
20 21
21#include "ota_io.h" 22#include "ota_io.h"
22 23
23int main(int argc, char **argv) { 24int main(int /* argc */, char** /* argv */) {
24 int fd = open("testdata/test.file", O_RDWR); 25 int fd = open("testdata/test.file", O_RDWR);
25 char buf[8]; 26 char buf[8];
26 char *out = "321"; 27 const char* out = "321";
27 int readv = ota_read(fd, buf, 4); 28 int readv = ota_read(fd, buf, 4);
28 printf("Read returned %d\n", readv); 29 printf("Read returned %d\n", readv);
29 int writev = ota_write(fd, out, 4); 30 int writev = ota_write(fd, out, 4);
30 printf("Write returned %d\n", writev); 31 printf("Write returned %d\n", writev);
32 close(fd);
31 return 0; 33 return 0;
32} 34}