diff options
-rw-r--r-- | ext4_utils/ext2simg.c | 63 | ||||
-rw-r--r-- | ext4_utils/ext4_utils.c | 93 | ||||
-rw-r--r-- | ext4_utils/ext4_utils.h | 14 | ||||
-rw-r--r-- | ext4_utils/ext4fixup.c | 135 | ||||
-rw-r--r-- | ext4_utils/make_ext4fs.c | 44 | ||||
-rw-r--r-- | ext4_utils/make_ext4fs_main.c | 10 | ||||
-rwxr-xr-x | ext4_utils/mkuserimg.sh | 17 | ||||
-rw-r--r-- | taskstats/Android.mk | 19 | ||||
-rw-r--r-- | taskstats/MODULE_LICENSE_APACHE2 | 0 | ||||
-rw-r--r-- | taskstats/NOTICE | 190 | ||||
-rw-r--r-- | taskstats/taskstats.c | 378 | ||||
-rw-r--r-- | tests/audio/Android.mk | 17 | ||||
-rw-r--r-- | tests/audio/alsa/Android.mk | 27 | ||||
-rw-r--r-- | tests/audio/alsa/pcmtest.cpp | 224 | ||||
-rw-r--r-- | verity/Android.mk | 50 | ||||
-rw-r--r-- | verity/VeritySigner.java | 79 | ||||
-rw-r--r-- | verity/VeritySigner.mf | 1 | ||||
-rwxr-xr-x | verity/build_verity_metadata.py | 78 | ||||
-rwxr-xr-x | verity/build_verity_tree.py | 87 | ||||
-rw-r--r-- | verity/generate_verity_key.c | 165 | ||||
-rw-r--r-- | verity/syspatch.c | 61 | ||||
-rwxr-xr-x | verity/verity_signer | 8 |
22 files changed, 1555 insertions, 205 deletions
diff --git a/ext4_utils/ext2simg.c b/ext4_utils/ext2simg.c index 1531f0bb..e5b36c49 100644 --- a/ext4_utils/ext2simg.c +++ b/ext4_utils/ext2simg.c @@ -22,7 +22,6 @@ #include <sys/types.h> #include <sys/mman.h> #include <fcntl.h> -#include <inttypes.h> #include <libgen.h> #include <unistd.h> @@ -54,66 +53,6 @@ static void usage(char *path) fprintf(stderr, " -S don't use sparse output format\n"); } -static int read_ext(int fd) -{ - off64_t ret; - struct ext4_super_block sb; - - ret = lseek64(fd, 1024, SEEK_SET); - if (ret < 0) - critical_error_errno("failed to seek to superblock"); - - ret = read(fd, &sb, sizeof(sb)); - if (ret < 0) - critical_error_errno("failed to read superblock"); - if (ret != sizeof(sb)) - critical_error("failed to read all of superblock"); - - ext4_parse_sb_info(&sb); - - ret = lseek64(fd, info.len, SEEK_SET); - if (ret < 0) - critical_error_errno("failed to seek to end of input image"); - - ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET); - if (ret < 0) - critical_error_errno("failed to seek to block group descriptors"); - - ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks); - if (ret < 0) - critical_error_errno("failed to read block group descriptors"); - if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks) - critical_error("failed to read all of block group descriptors"); - - if (verbose) { - printf("Found filesystem with parameters:\n"); - printf(" Size: %"PRIu64"\n", info.len); - printf(" Block size: %d\n", info.block_size); - printf(" Blocks per group: %d\n", info.blocks_per_group); - printf(" Inodes per group: %d\n", info.inodes_per_group); - printf(" Inode size: %d\n", info.inode_size); - printf(" Label: %s\n", info.label); - printf(" Blocks: %"PRIu64"\n", aux_info.len_blocks); - printf(" Block groups: %d\n", aux_info.groups); - printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks); - printf(" Used %d/%d inodes and %d/%d blocks\n", - aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count, - aux_info.sb->s_inodes_count, - aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo, - aux_info.sb->s_blocks_count_lo); - } - - return 0; -} - -static int bitmap_get_bit(u8 *bitmap, u32 bit) -{ - if (bitmap[bit / 8] & 1 << (bit % 8)) - return 1; - - return 0; -} - static int build_sparse_ext(int fd, const char *filename) { unsigned int i; @@ -229,7 +168,7 @@ int main(int argc, char **argv) if (infd < 0) critical_error_errno("failed to open input image"); - read_ext(infd); + read_ext(infd, verbose); ext4_sparse_file = sparse_file_new(info.block_size, info.len); diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c index 3755fee1..e83f055d 100644 --- a/ext4_utils/ext4_utils.c +++ b/ext4_utils/ext4_utils.c @@ -23,6 +23,7 @@ #include <sparse/sparse.h> #include <fcntl.h> +#include <inttypes.h> #include <sys/stat.h> #include <sys/types.h> #include <stddef.h> @@ -60,6 +61,21 @@ static int is_power_of(int a, int b) return (a == b) ? 1 : 0; } +int bitmap_get_bit(u8 *bitmap, u32 bit) +{ + if (bitmap[bit / 8] & (1 << (bit % 8))) + return 1; + + return 0; +} + +void bitmap_clear_bit(u8 *bitmap, u32 bit) +{ + bitmap[bit / 8] &= ~(1 << (bit % 8)); + + return; +} + /* Returns 1 if the bg contains a backup superblock. On filesystems with the sparse_super feature, only block groups 0, 1, and powers of 3, 5, and 7 have backup superblocks. Otherwise, all block groups have backup @@ -79,6 +95,38 @@ int ext4_bg_has_super_block(int bg) return 0; } +/* Function to read the primary superblock */ +void read_sb(int fd, struct ext4_super_block *sb) +{ + off64_t ret; + + ret = lseek64(fd, 1024, SEEK_SET); + if (ret < 0) + critical_error_errno("failed to seek to superblock"); + + ret = read(fd, sb, sizeof(*sb)); + if (ret < 0) + critical_error_errno("failed to read superblock"); + if (ret != sizeof(*sb)) + critical_error("failed to read all of superblock"); +} + +/* Function to write a primary or backup superblock at a given offset */ +void write_sb(int fd, unsigned long long offset, struct ext4_super_block *sb) +{ + off64_t ret; + + ret = lseek64(fd, offset, SEEK_SET); + if (ret < 0) + critical_error_errno("failed to seek to superblock"); + + ret = write(fd, sb, sizeof(*sb)); + if (ret < 0) + critical_error_errno("failed to write superblock"); + if (ret != sizeof(*sb)) + critical_error("failed to write all of superblock"); +} + /* Write the filesystem image to a file */ void write_ext4_image(int fd, int gz, int sparse, int crc) { @@ -435,3 +483,48 @@ u64 parse_num(const char *arg) return num; } + +int read_ext(int fd, int verbose) +{ + off64_t ret; + struct ext4_super_block sb; + + read_sb(fd, &sb); + + ext4_parse_sb_info(&sb); + + ret = lseek64(fd, info.len, SEEK_SET); + if (ret < 0) + critical_error_errno("failed to seek to end of input image"); + + ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET); + if (ret < 0) + critical_error_errno("failed to seek to block group descriptors"); + + ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks); + if (ret < 0) + critical_error_errno("failed to read block group descriptors"); + if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks) + critical_error("failed to read all of block group descriptors"); + + if (verbose) { + printf("Found filesystem with parameters:\n"); + printf(" Size: %"PRIu64"\n", info.len); + printf(" Block size: %d\n", info.block_size); + printf(" Blocks per group: %d\n", info.blocks_per_group); + printf(" Inodes per group: %d\n", info.inodes_per_group); + printf(" Inode size: %d\n", info.inode_size); + printf(" Label: %s\n", info.label); + printf(" Blocks: %"PRIu64"\n", aux_info.len_blocks); + printf(" Block groups: %d\n", aux_info.groups); + printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks); + printf(" Used %d/%d inodes and %d/%d blocks\n", + aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count, + aux_info.sb->s_inodes_count, + aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo, + aux_info.sb->s_blocks_count_lo); + } + + return 0; +} + diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h index 447d4161..f87a0de7 100644 --- a/ext4_utils/ext4_utils.h +++ b/ext4_utils/ext4_utils.h @@ -130,7 +130,11 @@ static inline int log_2(int j) return i - 1; } +int bitmap_get_bit(u8 *bitmap, u32 bit); +void bitmap_clear_bit(u8 *bitmap, u32 bit); int ext4_bg_has_super_block(int bg); +void read_sb(int fd, struct ext4_super_block *sb); +void write_sb(int fd, unsigned long long offset, struct ext4_super_block *sb); void write_ext4_image(int fd, int gz, int sparse, int crc); void ext4_create_fs_aux_info(void); void ext4_free_fs_aux_info(void); @@ -146,14 +150,16 @@ void ext4_parse_sb_info(struct ext4_super_block *sb); u16 ext4_crc16(u16 crc_in, const void *buf, int size); typedef void (*fs_config_func_t)(const char *path, int dir, unsigned *uid, unsigned *gid, - unsigned *mode, uint64_t *capabilities); + unsigned *mode, uint64_t *capabilities); struct selabel_handle; int make_ext4fs_internal(int fd, const char *directory, - const char *mountpoint, fs_config_func_t fs_config_func, int gzip, - int sparse, int crc, int wipe, - struct selabel_handle *sehnd, int verbose); + const char *mountpoint, fs_config_func_t fs_config_func, int gzip, + int sparse, int crc, int wipe, + struct selabel_handle *sehnd, int verbose, time_t fixed_time); + +int read_ext(int fd, int verbose); #ifdef __cplusplus } diff --git a/ext4_utils/ext4fixup.c b/ext4_utils/ext4fixup.c index 7beeefbe..0e517655 100644 --- a/ext4_utils/ext4fixup.c +++ b/ext4_utils/ext4fixup.c @@ -25,7 +25,6 @@ #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> -#include <inttypes.h> #include <unistd.h> #ifndef USE_MINGW @@ -84,42 +83,6 @@ static int compute_new_inum(unsigned int old_inum) return (group * new_inodes_per_group) + offset + 1; } -/* Function to read the primary superblock */ -static void read_sb(int fd, struct ext4_super_block *sb) -{ - off64_t ret; - - ret = lseek64(fd, 1024, SEEK_SET); - if (ret < 0) - critical_error_errno("failed to seek to superblock"); - - ret = read(fd, sb, sizeof(*sb)); - if (ret < 0) - critical_error_errno("failed to read superblock"); - if (ret != sizeof(*sb)) - critical_error("failed to read all of superblock"); -} - -/* Function to write a primary or backup superblock at a given offset */ -static void write_sb(int fd, unsigned long long offset, struct ext4_super_block *sb) -{ - off64_t ret; - - if (no_write) { - return; - } - - ret = lseek64(fd, offset, SEEK_SET); - if (ret < 0) - critical_error_errno("failed to seek to superblock"); - - ret = write(fd, sb, sizeof(*sb)); - if (ret < 0) - critical_error_errno("failed to write superblock"); - if (ret != sizeof(*sb)) - critical_error("failed to write all of superblock"); -} - static int get_fs_fixup_state(int fd) { unsigned long long magic; @@ -192,64 +155,9 @@ static int set_fs_fixup_state(int fd, int state) /* we are done, so make the filesystem mountable again */ sb.s_desc_size &= ~1; } - write_sb(fd, 1024, &sb); - - return 0; -} - -static int read_ext(int fd) -{ - off64_t ret; - struct ext4_super_block sb; - - read_sb(fd, &sb); - - ext4_parse_sb_info(&sb); - - if (info.feat_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) { - critical_error("Filesystem needs recovery first, mount and unmount to do that\n"); - } - - /* Clear the low bit which is set while this tool is in progress. - * If the tool crashes, it will still be set when we restart. - * The low bit is set to make the filesystem unmountable while - * it is being fixed up. Also allow 0, which means the old ext2 - * size is in use. - */ - if (((sb.s_desc_size & ~1) != sizeof(struct ext2_group_desc)) && - ((sb.s_desc_size & ~1) != 0)) - critical_error("error: bg_desc_size != sizeof(struct ext2_group_desc)\n"); - - ret = lseek64(fd, info.len, SEEK_SET); - if (ret < 0) - critical_error_errno("failed to seek to end of input image"); - - ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET); - if (ret < 0) - critical_error_errno("failed to seek to block group descriptors"); - - ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks); - if (ret < 0) - critical_error_errno("failed to read block group descriptors"); - if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks) - critical_error("failed to read all of block group descriptors"); - if (verbose) { - printf("Found filesystem with parameters:\n"); - printf(" Size: %"PRIu64"\n", info.len); - printf(" Block size: %d\n", info.block_size); - printf(" Blocks per group: %d\n", info.blocks_per_group); - printf(" Inodes per group: %d\n", info.inodes_per_group); - printf(" Inode size: %d\n", info.inode_size); - printf(" Label: %s\n", info.label); - printf(" Blocks: %"PRIu64"\n", aux_info.len_blocks); - printf(" Block groups: %d\n", aux_info.groups); - printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks); - printf(" Used %d/%d inodes and %d/%d blocks\n", - aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count, - aux_info.sb->s_inodes_count, - aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo, - aux_info.sb->s_blocks_count_lo); + if (!no_write) { + write_sb(fd, 1024, &sb); } return 0; @@ -321,21 +229,6 @@ static int write_block(int fd, unsigned long long block_num, void *block) return 0; } -static int bitmap_get_bit(u8 *bitmap, u32 bit) -{ - if (bitmap[bit / 8] & (1 << (bit % 8))) - return 1; - - return 0; -} - -static void bitmap_clear_bit(u8 *bitmap, u32 bit) -{ - bitmap[bit / 8] &= ~(1 << (bit % 8)); - - return; -} - static void check_inode_bitmap(int fd, unsigned int bg_num) { unsigned int inode_bitmap_block_num; @@ -426,7 +319,13 @@ static int update_superblocks_and_bg_desc(int fd, int state) sb.s_desc_size &= ~1; } - write_sb(fd, (unsigned long long)i * info.blocks_per_group * info.block_size + sb_offset, &sb); + if (!no_write) { + write_sb(fd, + (unsigned long long)i + * info.blocks_per_group * info.block_size + + sb_offset, + &sb); + } ret = lseek64(fd, ((unsigned long long)i * info.blocks_per_group * info.block_size) + (info.block_size * (aux_info.first_data_block + 1)), SEEK_SET); @@ -806,7 +705,21 @@ int ext4fixup_internal(char *fsdev, int v_flag, int n_flag, if (fd < 0) critical_error_errno("failed to open filesystem image"); - read_ext(fd); + read_ext(fd, verbose); + + if (info.feat_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) { + critical_error("Filesystem needs recovery first, mount and unmount to do that\n"); + } + + /* Clear the low bit which is set while this tool is in progress. + * If the tool crashes, it will still be set when we restart. + * The low bit is set to make the filesystem unmountable while + * it is being fixed up. Also allow 0, which means the old ext2 + * size is in use. + */ + if (((aux_info.sb->s_desc_size & ~1) != sizeof(struct ext2_group_desc)) && + ((aux_info.sb->s_desc_size & ~1) != 0)) + critical_error("error: bg_desc_size != sizeof(struct ext2_group_desc)\n"); if ((info.feat_incompat & EXT4_FEATURE_INCOMPAT_FILETYPE) == 0) { critical_error("Expected filesystem to have filetype flag set\n"); diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c index 0cb5bae9..1c254571 100644 --- a/ext4_utils/make_ext4fs.c +++ b/ext4_utils/make_ext4fs.c @@ -110,7 +110,7 @@ static u32 build_default_directory_structure() if the image were mounted at the specified mount point */ static u32 build_directory_structure(const char *full_path, const char *dir_path, u32 dir_inode, fs_config_func_t fs_config_func, - struct selabel_handle *sehnd, int verbose) + struct selabel_handle *sehnd, int verbose, time_t fixed_time) { int entries = 0; struct dentry *dentries; @@ -164,7 +164,11 @@ static u32 build_directory_structure(const char *full_path, const char *dir_path dentries[i].size = stat.st_size; dentries[i].mode = stat.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); - dentries[i].mtime = stat.st_mtime; + if (fixed_time == -1) { + dentries[i].mtime = stat.st_mtime; + } else { + dentries[i].mtime = fixed_time; + } uint64_t capabilities; if (fs_config_func != NULL) { #ifdef ANDROID @@ -257,7 +261,7 @@ static u32 build_directory_structure(const char *full_path, const char *dir_path if (ret < 0) critical_error_errno("asprintf"); entry_inode = build_directory_structure(subdir_full_path, - subdir_dir_path, inode, fs_config_func, sehnd, verbose); + subdir_dir_path, inode, fs_config_func, sehnd, verbose, fixed_time); free(subdir_full_path); free(subdir_dir_path); } else if (dentries[i].file_type == EXT4_FT_SYMLINK) { @@ -358,28 +362,28 @@ static u32 compute_bg_desc_reserve_blocks() } void reset_ext4fs_info() { - // Reset all the global data structures used by make_ext4fs so it - // can be called again. - memset(&info, 0, sizeof(info)); - memset(&aux_info, 0, sizeof(aux_info)); - - if (ext4_sparse_file) { - sparse_file_destroy(ext4_sparse_file); - ext4_sparse_file = NULL; - } + // Reset all the global data structures used by make_ext4fs so it + // can be called again. + memset(&info, 0, sizeof(info)); + memset(&aux_info, 0, sizeof(aux_info)); + + if (ext4_sparse_file) { + sparse_file_destroy(ext4_sparse_file); + ext4_sparse_file = NULL; + } } int make_ext4fs_sparse_fd(int fd, long long len, - const char *mountpoint, struct selabel_handle *sehnd) + const char *mountpoint, struct selabel_handle *sehnd) { reset_ext4fs_info(); info.len = len; - return make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 1, 0, 0, sehnd, 0); + return make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 1, 0, 0, sehnd, 0, -1); } int make_ext4fs(const char *filename, long long len, - const char *mountpoint, struct selabel_handle *sehnd) + const char *mountpoint, struct selabel_handle *sehnd) { int fd; int status; @@ -393,7 +397,7 @@ int make_ext4fs(const char *filename, long long len, return EXIT_FAILURE; } - status = make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 0, 0, 1, sehnd, 0); + status = make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 0, 0, 1, sehnd, 0, -1); close(fd); return status; @@ -457,9 +461,9 @@ static char *canonicalize_rel_slashes(const char *str) } int make_ext4fs_internal(int fd, const char *_directory, - const char *_mountpoint, fs_config_func_t fs_config_func, int gzip, - int sparse, int crc, int wipe, - struct selabel_handle *sehnd, int verbose) + const char *_mountpoint, fs_config_func_t fs_config_func, int gzip, + int sparse, int crc, int wipe, + struct selabel_handle *sehnd, int verbose, time_t fixed_time) { u32 root_inode_num; u16 root_mode; @@ -568,7 +572,7 @@ int make_ext4fs_internal(int fd, const char *_directory, #else if (directory) root_inode_num = build_directory_structure(directory, mountpoint, 0, - fs_config_func, sehnd, verbose); + fs_config_func, sehnd, verbose, fixed_time); else root_inode_num = build_default_directory_structure(); #endif diff --git a/ext4_utils/make_ext4fs_main.c b/ext4_utils/make_ext4fs_main.c index 754e51f0..91635068 100644 --- a/ext4_utils/make_ext4fs_main.c +++ b/ext4_utils/make_ext4fs_main.c @@ -52,7 +52,7 @@ static void usage(char *path) fprintf(stderr, "%s [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]\n", basename(path)); fprintf(stderr, " [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]\n"); fprintf(stderr, " [ -L <label> ] [ -f ] [ -a <android mountpoint> ]\n"); - fprintf(stderr, " [ -S file_contexts ]\n"); + fprintf(stderr, " [ -S file_contexts ] [ -T timestamp ]\n"); fprintf(stderr, " [ -z | -s ] [ -w ] [ -c ] [ -J ] [ -v ]\n"); fprintf(stderr, " <filename> [<directory>]\n"); } @@ -71,12 +71,13 @@ int main(int argc, char **argv) int fd; int exitcode; int verbose = 0; + time_t fixed_time = -1; struct selabel_handle *sehnd = NULL; #ifndef USE_MINGW struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } }; #endif - while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:S:fwzJsctv")) != -1) { + while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:S:T:fwzJsctv")) != -1) { switch (opt) { case 'l': info.len = parse_num(optarg); @@ -143,6 +144,9 @@ int main(int argc, char **argv) case 'v': verbose = 1; break; + case 'T': + fixed_time = strtoll(optarg, NULL, 0); + break; default: /* '?' */ usage(argv[0]); exit(EXIT_FAILURE); @@ -201,7 +205,7 @@ int main(int argc, char **argv) } exitcode = make_ext4fs_internal(fd, directory, mountpoint, fs_config_func, gzip, - sparse, crc, wipe, sehnd, verbose); + sparse, crc, wipe, sehnd, verbose, fixed_time); close(fd); if (exitcode && strcmp(filename, "-")) unlink(filename); diff --git a/ext4_utils/mkuserimg.sh b/ext4_utils/mkuserimg.sh index c44129e7..6ef0294c 100755 --- a/ext4_utils/mkuserimg.sh +++ b/ext4_utils/mkuserimg.sh @@ -1,11 +1,11 @@ -#!/bin/bash -x +#!/bin/bash # # To call this script, make sure make_ext4fs is somewhere in PATH function usage() { cat<<EOT Usage: -mkuserimg.sh [-s] SRC_DIR OUTPUT_FILE EXT_VARIANT MOUNT_POINT SIZE [FILE_CONTEXTS] +mkuserimg.sh [-s] SRC_DIR OUTPUT_FILE EXT_VARIANT MOUNT_POINT SIZE [-T TIMESTAMP] [FILE_CONTEXTS] EOT } @@ -17,7 +17,7 @@ if [ "$1" = "-s" ]; then shift fi -if [ $# -ne 5 -a $# -ne 6 ]; then +if [ $# -lt 5 -o $# -gt 8 ]; then usage exit 1 fi @@ -32,7 +32,14 @@ OUTPUT_FILE=$2 EXT_VARIANT=$3 MOUNT_POINT=$4 SIZE=$5 -FC=$6 +shift; shift; shift; shift; shift + +TIMESTAMP=-1 +if [[ "$1" == "-T" ]]; then + TIMESTAMP=$2 + shift; shift +fi +FC=$1 case $EXT_VARIANT in ext4) ;; @@ -53,7 +60,7 @@ if [ -n "$FC" ]; then FCOPT="-S $FC" fi -MAKE_EXT4FS_CMD="make_ext4fs $ENABLE_SPARSE_IMAGE $FCOPT -l $SIZE -a $MOUNT_POINT $OUTPUT_FILE $SRC_DIR" +MAKE_EXT4FS_CMD="make_ext4fs $ENABLE_SPARSE_IMAGE -T $TIMESTAMP $FCOPT -l $SIZE -a $MOUNT_POINT $OUTPUT_FILE $SRC_DIR" echo $MAKE_EXT4FS_CMD $MAKE_EXT4FS_CMD if [ $? -ne 0 ]; then diff --git a/taskstats/Android.mk b/taskstats/Android.mk new file mode 100644 index 00000000..0ddba234 --- /dev/null +++ b/taskstats/Android.mk @@ -0,0 +1,19 @@ +# Copyright 2013 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + taskstats.c + +LOCAL_C_INCLUDES := \ + external/libnl-headers + +LOCAL_STATIC_LIBRARIES := \ + libnl_2 + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) +LOCAL_MODULE_TAGS := debug +LOCAL_MODULE:= taskstats + +include $(BUILD_EXECUTABLE) diff --git a/taskstats/MODULE_LICENSE_APACHE2 b/taskstats/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/taskstats/MODULE_LICENSE_APACHE2 diff --git a/taskstats/NOTICE b/taskstats/NOTICE new file mode 100644 index 00000000..c5b1efa7 --- /dev/null +++ b/taskstats/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/taskstats/taskstats.c b/taskstats/taskstats.c new file mode 100644 index 00000000..66cc0c5e --- /dev/null +++ b/taskstats/taskstats.c @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2013 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. + */ + +/* + * Linux task stats reporting tool. Queries and prints out the kernel's + * taskstats structure for a given process or thread group id. See + * https://www.kernel.org/doc/Documentation/accounting/ for more information + * about the reported fields. + */ + +#include <errno.h> +#include <getopt.h> +#include <netlink-types.h> +#include <netlink/attr.h> +#include <netlink/genl/genl.h> +#include <netlink/handlers.h> +#include <netlink/msg.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +#include <linux/taskstats.h> + +struct TaskStatistics { + int pid; + int tgid; + struct taskstats stats; +}; + +int send_command(struct nl_sock* netlink_socket, uint16_t nlmsg_type, + uint32_t nlmsg_pid, uint8_t genl_cmd, uint16_t nla_type, + void* nla_data, int nla_len) { + struct nl_msg* message = nlmsg_alloc(); + int seq = 0; + int version = 1; + int header_length = 0; + int flags = NLM_F_REQUEST; + genlmsg_put(message, nlmsg_pid, seq, nlmsg_type, header_length, flags, + genl_cmd, version); + nla_put(message, nla_type, nla_len, nla_data); + + /* Override the header flags since we don't want NLM_F_ACK. */ + struct nlmsghdr* header = nlmsg_hdr(message); + header->nlmsg_flags = flags; + + int result = nl_send(netlink_socket, message); + nlmsg_free(message); + return result; +} + +int print_receive_error(struct sockaddr_nl* address, struct nlmsgerr* error, + void* arg) { + fprintf(stderr, "Netlink receive error: %s\n", strerror(-error->error)); + return NL_STOP; +} + +int parse_family_id(struct nl_msg* msg, void* arg) { + struct genlmsghdr* gnlh = (struct genlmsghdr*)nlmsg_data(nlmsg_hdr(msg)); + struct nlattr* attr = genlmsg_attrdata(gnlh, 0); + int remaining = genlmsg_attrlen(gnlh, 0); + + do { + if (attr->nla_type == CTRL_ATTR_FAMILY_ID) { + *((int*)arg) = nla_get_u16(attr); + return NL_STOP; + } + } while ((attr = nla_next(attr, &remaining))); + return NL_OK; +} + +int get_family_id(struct nl_sock* netlink_socket, const char* name) { + if (send_command(netlink_socket, GENL_ID_CTRL, getpid(), + CTRL_CMD_GETFAMILY, + CTRL_ATTR_FAMILY_NAME, + (void*)name, strlen(name) + 1) < 0) { + return 0; + } + + int family_id = 0; + struct nl_cb* callbacks = nl_cb_get(nl_cb_alloc(NL_CB_VALID)); + nl_cb_set(callbacks, NL_CB_VALID, NL_CB_DEFAULT, &parse_family_id, + &family_id); + nl_cb_err(callbacks, NL_CB_DEFAULT, &print_receive_error, NULL); + + if (nl_recvmsgs(netlink_socket, callbacks) < 0) { + return 0; + } + nl_cb_put(callbacks); + return family_id; +} + +void parse_aggregate_task_stats(struct nlattr* attr, int attr_size, + struct TaskStatistics* stats) { + do { + switch (attr->nla_type) { + case TASKSTATS_TYPE_PID: + stats->pid = nla_get_u32(attr); + break; + case TASKSTATS_TYPE_TGID: + stats->tgid = nla_get_u32(attr); + break; + case TASKSTATS_TYPE_STATS: + nla_memcpy(&stats->stats, attr, sizeof(stats->stats)); + break; + default: + break; + } + } while ((attr = nla_next(attr, &attr_size))); +} + +int parse_task_stats(struct nl_msg* msg, void* arg) { + struct TaskStatistics* stats = (struct TaskStatistics*)arg; + struct genlmsghdr* gnlh = (struct genlmsghdr*)nlmsg_data(nlmsg_hdr(msg)); + struct nlattr* attr = genlmsg_attrdata(gnlh, 0); + int remaining = genlmsg_attrlen(gnlh, 0); + + do { + switch (attr->nla_type) { + case TASKSTATS_TYPE_AGGR_PID: + case TASKSTATS_TYPE_AGGR_TGID: + parse_aggregate_task_stats(nla_data(attr), nla_len(attr), + stats); + break; + default: + break; + } + } while ((attr = nla_next(attr, &remaining))); + return NL_STOP; +} + +int query_task_stats(struct nl_sock* netlink_socket, int family_id, + int command_type, int parameter, + struct TaskStatistics* stats) { + memset(stats, 0, sizeof(*stats)); + int result = send_command(netlink_socket, family_id, getpid(), + TASKSTATS_CMD_GET, command_type, ¶meter, + sizeof(parameter)); + if (result < 0) { + return result; + } + + struct nl_cb* callbacks = nl_cb_get(nl_cb_alloc(NL_CB_VALID)); + nl_cb_set(callbacks, NL_CB_VALID, NL_CB_DEFAULT, &parse_task_stats, stats); + nl_cb_err(callbacks, NL_CB_DEFAULT, &print_receive_error, &family_id); + + result = nl_recvmsgs(netlink_socket, callbacks); + if (result < 0) { + return result; + } + nl_cb_put(callbacks); + return stats->pid || stats->tgid; +} + +double average_ms(uint64_t total, uint64_t count) { + if (!count) { + return 0; + } + return ((double)total) / count / 1e6; +} + +uint64_t average_ns(uint64_t total, uint64_t count) { + if (!count) { + return 0; + } + return total / count; +} + +void print_task_stats(const struct TaskStatistics* stats, + int human_readable) { + const struct taskstats* s = &stats->stats; + printf("Basic task statistics\n"); + printf("---------------------\n"); + printf("%-25s%d\n", "Stats version:", s->version); + printf("%-25s%d\n", "Exit code:", s->ac_exitcode); + printf("%-25s0x%x\n", "Flags:", s->ac_flag); + printf("%-25s%d\n", "Nice value:", s->ac_nice); + printf("%-25s%s\n", "Command name:", s->ac_comm); + printf("%-25s%d\n", "Scheduling discipline:", s->ac_sched); + printf("%-25s%d\n", "UID:", s->ac_uid); + printf("%-25s%d\n", "GID:", s->ac_gid); + printf("%-25s%d\n", "PID:", s->ac_pid); + printf("%-25s%d\n", "PPID:", s->ac_ppid); + + if (human_readable) { + time_t begin_time = s->ac_btime; + printf("%-25s%s", "Begin time:", ctime(&begin_time)); + } else { + printf("%-25s%d sec\n", "Begin time:", s->ac_btime); + } + printf("%-25s%llu usec\n", "Elapsed time:", s->ac_etime); + printf("%-25s%llu usec\n", "User CPU time:", s->ac_utime); + printf("%-25s%llu\n", "Minor page faults:", s->ac_minflt); + printf("%-25s%llu\n", "Major page faults:", s->ac_majflt); + printf("%-25s%llu usec\n", "Scaled user time:", s->ac_utimescaled); + printf("%-25s%llu usec\n", "Scaled system time:", s->ac_stimescaled); + + printf("\nDelay accounting\n"); + printf("----------------\n"); + printf(" %15s%15s%15s%15s%15s%15s\n", + "Count", + human_readable ? "Delay (ms)" : "Delay (ns)", + "Average delay", + "Real delay", + "Scaled real", + "Virtual delay"); + + if (!human_readable) { + printf("CPU %15llu%15llu%15llu%15llu%15llu%15llu\n", + s->cpu_count, + s->cpu_delay_total, + average_ns(s->cpu_delay_total, s->cpu_count), + s->cpu_run_real_total, + s->cpu_scaled_run_real_total, + s->cpu_run_virtual_total); + printf("IO %15llu%15llu%15llu\n", + s->blkio_count, + s->blkio_delay_total, + average_ns(s->blkio_delay_total, s->blkio_count)); + printf("Swap %15llu%15llu%15llu\n", + s->swapin_count, + s->swapin_delay_total, + average_ns(s->swapin_delay_total, s->swapin_count)); + printf("Reclaim%15llu%15llu%15llu\n", + s->freepages_count, + s->freepages_delay_total, + average_ns(s->freepages_delay_total, s->freepages_count)); + } else { + const double ms_per_ns = 1e6; + printf("CPU %15llu%15.3f%15.3f%15.3f%15.3f%15.3f\n", + s->cpu_count, + s->cpu_delay_total / ms_per_ns, + average_ms(s->cpu_delay_total, s->cpu_count), + s->cpu_run_real_total / ms_per_ns, + s->cpu_scaled_run_real_total / ms_per_ns, + s->cpu_run_virtual_total / ms_per_ns); + printf("IO %15llu%15.3f%15.3f\n", + s->blkio_count, + s->blkio_delay_total / ms_per_ns, + average_ms(s->blkio_delay_total, s->blkio_count)); + printf("Swap %15llu%15.3f%15.3f\n", + s->swapin_count, + s->swapin_delay_total / ms_per_ns, + average_ms(s->swapin_delay_total, s->swapin_count)); + printf("Reclaim%15llu%15.3f%15.3f\n", + s->freepages_count, + s->freepages_delay_total / ms_per_ns, + average_ms(s->freepages_delay_total, s->freepages_count)); + } + + printf("\nExtended accounting fields\n"); + printf("--------------------------\n"); + if (human_readable && s->ac_stime) { + printf("%-25s%.3f MB\n", "Average RSS usage:", + (double)s->coremem / s->ac_stime); + printf("%-25s%.3f MB\n", "Average VM usage:", + (double)s->virtmem / s->ac_stime); + } else { + printf("%-25s%llu MB\n", "Accumulated RSS usage:", s->coremem); + printf("%-25s%llu MB\n", "Accumulated VM usage:", s->virtmem); + } + printf("%-25s%llu KB\n", "RSS high water mark:", s->hiwater_rss); + printf("%-25s%llu KB\n", "VM high water mark:", s->hiwater_vm); + printf("%-25s%llu\n", "IO bytes read:", s->read_char); + printf("%-25s%llu\n", "IO bytes written:", s->write_char); + printf("%-25s%llu\n", "IO read syscalls:", s->read_syscalls); + printf("%-25s%llu\n", "IO write syscalls:", s->write_syscalls); + + printf("\nPer-task/thread statistics\n"); + printf("--------------------------\n"); + printf("%-25s%llu\n", "Voluntary switches:", s->nvcsw); + printf("%-25s%llu\n", "Involuntary switches:", s->nivcsw); +} + +void print_usage() { + printf("Linux task stats reporting tool\n" + "\n" + "Usage: taskstats [options]\n" + "\n" + "Options:\n" + " --help This text\n" + " --pid PID Print stats for the process id PID\n" + " --tgid TGID Print stats for the thread group id TGID\n" + " --raw Print raw numbers instead of human readable units\n" + "\n" + "Either PID or TGID must be specified. For more documentation about " + "the reported fields, see\n" + "https://www.kernel.org/doc/Documentation/accounting/" + "taskstats-struct.txt\n"); +} + +int main(int argc, char** argv) { + int command_type = 0; + int pid = 0; + int human_readable = 1; + + const struct option long_options[] = { + {"help", no_argument, 0, 0}, + {"pid", required_argument, 0, 0}, + {"tgid", required_argument, 0, 0}, + {"raw", no_argument, 0, 0}, + {0, 0, 0, 0} + }; + + while (1) { + int option_index; + int option_char = getopt_long_only(argc, argv, "", long_options, + &option_index); + if (option_char == -1) { + break; + } + switch (option_index) { + case 0: + print_usage(); + return EXIT_SUCCESS; + case 1: + command_type = TASKSTATS_CMD_ATTR_PID; + pid = atoi(optarg); + break; + case 2: + command_type = TASKSTATS_CMD_ATTR_TGID; + pid = atoi(optarg); + break; + case 3: + human_readable = 0; + break; + default: + break; + }; + } + + if (!pid) { + printf("Either PID or TGID must be specified\n"); + return EXIT_FAILURE; + } + + struct nl_sock* netlink_socket = nl_socket_alloc(); + if (!netlink_socket || genl_connect(netlink_socket) < 0) { + perror("Unable to open netlink socket (are you root?)"); + goto error; + } + + int family_id = get_family_id(netlink_socket, TASKSTATS_GENL_NAME); + if (!family_id) { + perror("Unable to determine taskstats family id " + "(does your kernel support taskstats?)"); + goto error; + } + struct TaskStatistics stats; + if (query_task_stats(netlink_socket, family_id, command_type, pid, + &stats) < 0) { + perror("Failed to query taskstats"); + goto error; + } + print_task_stats(&stats, human_readable); + + nl_socket_free(netlink_socket); + return EXIT_SUCCESS; + +error: + if (netlink_socket) { + nl_socket_free(netlink_socket); + } + return EXIT_FAILURE; +} diff --git a/tests/audio/Android.mk b/tests/audio/Android.mk new file mode 100644 index 00000000..f69a2fc5 --- /dev/null +++ b/tests/audio/Android.mk @@ -0,0 +1,17 @@ +# +# Copyright (C) 2013 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 $(call all-subdir-makefiles) diff --git a/tests/audio/alsa/Android.mk b/tests/audio/alsa/Android.mk new file mode 100644 index 00000000..c6e5a8af --- /dev/null +++ b/tests/audio/alsa/Android.mk @@ -0,0 +1,27 @@ +# +# Copyright (C) 2013 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE := pcmtest +LOCAL_SRC_FILES := pcmtest.cpp +LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libtinyalsa +LOCAL_STATIC_LIBRARIES += libtestUtil +LOCAL_C_INCLUDES += system/extras/tests/include external/tinyalsa/include + +include $(BUILD_NATIVE_TEST) diff --git a/tests/audio/alsa/pcmtest.cpp b/tests/audio/alsa/pcmtest.cpp new file mode 100644 index 00000000..b8bc5f28 --- /dev/null +++ b/tests/audio/alsa/pcmtest.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2013 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 requied 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 <assert.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <gtest/gtest.h> +#include <linux/ioctl.h> +#define __force +#define __bitwise +#define __user +#include <sound/asound.h> +#include <sys/types.h> +#include <tinyalsa/asoundlib.h> + +#define LOG_TAG "pcmtest" +#include <utils/Log.h> +#include <testUtil.h> + +#define PCM_PREFIX "pcm" +#define MIXER_PREFIX "control" +#define TIMER_PREFIX "timer" + +const char kSoundDir[] = "/dev/snd"; + +typedef struct PCM_NODE { + unsigned int card; + unsigned int device; + unsigned int flags; +} pcm_node_t; + +static pcm_node_t *pcmnodes; + +static unsigned int pcms; +static unsigned int cards; +static unsigned int mixers; +static unsigned int timers; + +int getPcmNodes(void) +{ + DIR *d; + struct dirent *de; + unsigned int pcount = 0; + + d = opendir(kSoundDir); + if (d == 0) + return 0; + while ((de = readdir(d)) != NULL) { + if (de->d_name[0] == '.') + continue; + if (strstr(de->d_name, PCM_PREFIX)) + pcount++; + } + closedir(d); + return pcount; +} + +int getSndDev(unsigned int pcmdevs) +{ + DIR *d; + struct dirent *de; + unsigned int prevcard = -1; + + d = opendir(kSoundDir); + if (d == 0) + return -ENXIO; + pcmnodes = (pcm_node_t *)malloc(pcmdevs * sizeof(pcm_node_t)); + if (!pcmnodes) + return -ENOMEM; + pcms = 0; + while ((de = readdir(d)) != NULL) { + if (de->d_name[0] == '.') + continue; + /* printf("%s\n", de->d_name); */ + if (strstr(de->d_name, PCM_PREFIX)) { + char flags; + + EXPECT_LE(pcms, pcmdevs) << "Too many PCMs"; + if (pcms >= pcmdevs) + continue; + sscanf(de->d_name, PCM_PREFIX "C%uD%u", &(pcmnodes[pcms].card), + &(pcmnodes[pcms].device)); + flags = de->d_name[strlen(de->d_name)-1]; + if (flags == 'c') { + pcmnodes[pcms].flags = PCM_IN; + } else if(flags == 'p') { + pcmnodes[pcms].flags = PCM_OUT; + } else { + pcmnodes[pcms].flags = -1; + testPrintI("Unknown PCM type = %c", flags); + } + if (prevcard != pcmnodes[pcms].card) + cards++; + prevcard = pcmnodes[pcms].card; + pcms++; + continue; + } + if (strstr(de->d_name, MIXER_PREFIX)) { + unsigned int mixer = -1; + sscanf(de->d_name, MIXER_PREFIX "C%u", &mixer); + mixers++; + continue; + } + if (strstr(de->d_name, TIMER_PREFIX)) { + timers++; + continue; + } + } + closedir(d); + return 0; +} + +int getPcmParams(unsigned int i) +{ + struct pcm_params *params; + unsigned int min; + unsigned int max; + + params = pcm_params_get(pcmnodes[i].card, pcmnodes[i].device, + pcmnodes[i].flags); + if (params == NULL) + return -ENODEV; + + min = pcm_params_get_min(params, PCM_PARAM_RATE); + max = pcm_params_get_max(params, PCM_PARAM_RATE); + EXPECT_LE(min, max); + /* printf(" Rate:\tmin=%uHz\tmax=%uHz\n", min, max); */ + min = pcm_params_get_min(params, PCM_PARAM_CHANNELS); + max = pcm_params_get_max(params, PCM_PARAM_CHANNELS); + EXPECT_LE(min, max); + /* printf(" Channels:\tmin=%u\t\tmax=%u\n", min, max); */ + min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS); + max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS); + EXPECT_LE(min, max); + /* printf(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max); */ + min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE); + max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE); + EXPECT_LE(min, max); + /* printf(" Period size:\tmin=%u\t\tmax=%u\n", min, max); */ + min = pcm_params_get_min(params, PCM_PARAM_PERIODS); + max = pcm_params_get_max(params, PCM_PARAM_PERIODS); + EXPECT_LE(min, max); + /* printf("Period count:\tmin=%u\t\tmax=%u\n", min, max); */ + + pcm_params_free(params); + return 0; +} + +TEST(pcmtest, CheckAudioDir) { + pcms = getPcmNodes(); + ASSERT_GT(pcms, 0); +} + +TEST(pcmtest, GetSoundDevs) { + int err = getSndDev(pcms); + testPrintI(" DEVICES = PCMS:%u CARDS:%u MIXERS:%u TIMERS:%u", + pcms, cards, mixers, timers); + ASSERT_EQ(0, err); +} + +TEST(pcmtest, CheckPcmSanity0) { + ASSERT_NE(0, pcms); +} + +TEST(pcmtest, CheckPcmSanity1) { + EXPECT_NE(1, pcms % 2); +} + +TEST(pcmtests, CheckMixerSanity) { + ASSERT_NE(0, mixers); + ASSERT_EQ(mixers, cards); +} + +TEST(pcmtest, CheckTimesSanity0) { + ASSERT_NE(0, timers); +} + +TEST(pcmtest, CheckTimesSanity1) { + EXPECT_EQ(1, timers); +} + +TEST(pcmtest, CheckPcmDevices) { + for (unsigned int i = 0; i < pcms; i++) { + EXPECT_EQ(0, getPcmParams(i)); + } + free(pcmnodes); +} + +TEST(pcmtest, CheckMixerDevices) { + struct mixer *mixer; + for (unsigned int i = 0; i < mixers; i++) { + mixer = mixer_open(i); + EXPECT_TRUE(mixer != NULL); + if (mixer) + mixer_close(mixer); + } +} + +TEST(pcmtest, CheckTimer) { + int ver = 0; + int fd = open("/dev/snd/timer", O_RDWR | O_NONBLOCK); + ASSERT_GE(fd, 0); + int ret = ioctl(fd, SNDRV_TIMER_IOCTL_PVERSION, &ver); + EXPECT_EQ(0, ret); + testPrintI(" Timer Version = 0x%x", ver); + close(fd); +} diff --git a/verity/Android.mk b/verity/Android.mk new file mode 100644 index 00000000..68fe0ef9 --- /dev/null +++ b/verity/Android.mk @@ -0,0 +1,50 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := generate_verity_key +LOCAL_SRC_FILES := generate_verity_key.c +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_TAGS := optional +LOCAL_SHARED_LIBRARIES := libcrypto-host +LOCAL_C_INCLUDES += external/openssl/include +include $(BUILD_HOST_EXECUTABLE) + +#include $(CLEAR_VARS) +#LOCAL_MODULE := generate_block_patch +#LOCAL_SRC_FILES := generate_block_patch.c +#LOCAL_MODULE_CLASS := EXECUTABLES +#LOCAL_MODULE_TAGS := optional +#LOCAL_SHARED_LIBRARIES := libminibsdiff +#include $(BUILD_HOST_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := VeritySigner.java +LOCAL_MODULE := VeritySigner +LOCAL_JAR_MANIFEST := VeritySigner.mf +LOCAL_MODULE_TAGS := optional +include $(BUILD_HOST_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := verity_signer +LOCAL_MODULE := verity_signer +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_IS_HOST_MODULE := true +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_MODULE := build_verity_tree.py +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_SRC_FILES := build_verity_tree.py +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_IS_HOST_MODULE := true +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_MODULE := build_verity_metadata.py +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_SRC_FILES := build_verity_metadata.py +LOCAL_IS_HOST_MODULE := true +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) diff --git a/verity/VeritySigner.java b/verity/VeritySigner.java new file mode 100644 index 00000000..f1d95c82 --- /dev/null +++ b/verity/VeritySigner.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013 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. + */ + +package com.android.verity; + +import sun.misc.BASE64Decoder; +import sun.misc.BASE64Encoder; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.spec.PKCS8EncodedKeySpec; + +class VeritySigner { + + private static byte[] sign(PrivateKey privateKey, byte[] input) throws Exception { + Signature signer = Signature.getInstance("SHA1withRSA"); + signer.initSign(privateKey); + signer.update(input); + return signer.sign(); + } + + private static PKCS8EncodedKeySpec pemToDer(String pem) throws Exception { + pem = pem.replaceAll("^-.*", ""); + String base64_der = pem.replaceAll("-.*$", ""); + BASE64Decoder decoder = new BASE64Decoder(); + byte[] der = decoder.decodeBuffer(base64_der); + return new PKCS8EncodedKeySpec(der); + } + + private static PrivateKey loadPrivateKey(String pem) throws Exception { + PKCS8EncodedKeySpec keySpec = pemToDer(pem); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return (PrivateKey) keyFactory.generatePrivate(keySpec); + } + + private static byte[] read(String path) throws Exception { + File contentFile = new File(path); + byte[] content = new byte[(int)contentFile.length()]; + FileInputStream fis = new FileInputStream(contentFile); + fis.read(content); + fis.close(); + return content; + } + + private static void writeOutput(String path, byte[] output) throws Exception { + FileOutputStream fos = new FileOutputStream(path); + fos.write(output); + fos.close(); + } + + // USAGE: + // VeritySigner <contentfile> <key.pem> <sigfile> + // To verify that this has correct output: + // openssl rsautl -raw -inkey <key.pem> -encrypt -in <sigfile> > /tmp/dump + public static void main(String[] args) throws Exception { + byte[] content = read(args[0]); + PrivateKey privateKey = loadPrivateKey(new String(read(args[1]))); + byte[] signature = sign(privateKey, content); + writeOutput(args[2], signature); + } +} diff --git a/verity/VeritySigner.mf b/verity/VeritySigner.mf new file mode 100644 index 00000000..b36c1982 --- /dev/null +++ b/verity/VeritySigner.mf @@ -0,0 +1 @@ +Main-Class: com.android.verity.VeritySigner diff --git a/verity/build_verity_metadata.py b/verity/build_verity_metadata.py new file mode 100755 index 00000000..547e6060 --- /dev/null +++ b/verity/build_verity_metadata.py @@ -0,0 +1,78 @@ +#! /usr/bin/env python + +import os +import sys +import struct +import tempfile +import commands + +VERSION = 0 +MAGIC_NUMBER = 0xb001b001 +BLOCK_SIZE = 4096 +METADATA_SIZE = BLOCK_SIZE * 8 + +def run(cmd): + status, output = commands.getstatusoutput(cmd) + print output + if status: + exit(-1) + +def get_verity_metadata_size(data_size): + return METADATA_SIZE + +def build_metadata_block(verity_table, signature): + table_len = len(verity_table) + block = struct.pack("II256sI", MAGIC_NUMBER, VERSION, signature, table_len) + block += verity_table + block = block.ljust(METADATA_SIZE, '\x00') + return block + +def sign_verity_table(table, signer_path, key_path): + with tempfile.NamedTemporaryFile(suffix='.table') as table_file: + with tempfile.NamedTemporaryFile(suffix='.sig') as signature_file: + table_file.write(table) + table_file.flush() + cmd = " ".join((signer_path, table_file.name, key_path, signature_file.name)) + print cmd + run(cmd) + return signature_file.read() + +def build_verity_table(block_device, data_blocks, root_hash, salt): + table = "1 %s %s %s %s %s %s sha256 %s %s" + table %= ( block_device, + block_device, + BLOCK_SIZE, + BLOCK_SIZE, + data_blocks, + data_blocks + (METADATA_SIZE / BLOCK_SIZE), + root_hash, + salt) + return table + +def build_verity_metadata(data_blocks, metadata_image, root_hash, + salt, block_device, signer_path, signing_key): + # build the verity table + verity_table = build_verity_table(block_device, data_blocks, root_hash, salt) + # build the verity table signature + signature = sign_verity_table(verity_table, signer_path, signing_key) + # build the metadata block + metadata_block = build_metadata_block(verity_table, signature) + # write it to the outfile + with open(metadata_image, "wb") as f: + f.write(metadata_block) + +if __name__ == "__main__": + if len(sys.argv) == 3 and sys.argv[1] == "-s": + print get_verity_metadata_size(int(sys.argv[2])) + elif len(sys.argv) == 8: + data_image_blocks = int(sys.argv[1]) / 4096 + metadata_image = sys.argv[2] + root_hash = sys.argv[3] + salt = sys.argv[4] + block_device = sys.argv[5] + signer_path = sys.argv[6] + signing_key = sys.argv[7] + build_verity_metadata(data_image_blocks, metadata_image, root_hash, + salt, block_device, signer_path, signing_key) + else: + exit(-1) diff --git a/verity/build_verity_tree.py b/verity/build_verity_tree.py new file mode 100755 index 00000000..970d8c01 --- /dev/null +++ b/verity/build_verity_tree.py @@ -0,0 +1,87 @@ +#! /usr/bin/env python + +import os +import sys +import math +import hashlib +import binascii + +HASH_FUNCTION = "SHA256" +HASH_FUNCTION_SIZE = 32 +BLOCK_SIZE = 4096 +HASHES_PER_BLOCK = BLOCK_SIZE / HASH_FUNCTION_SIZE + +def generate_salt(): + return os.urandom(HASH_FUNCTION_SIZE) + +def get_hash_image_blocks(data_image_size): + data_image_blocks = data_image_size / BLOCK_SIZE + return data_image_blocks / (HASH_FUNCTION_SIZE * 2) + +def get_hash_image_size(data_image_size): + return get_hash_image_blocks(data_image_size) * BLOCK_SIZE + +def blockify(data): + blocks = [] + for i in range(0, len(data), BLOCK_SIZE): + chunk = data[i:i+BLOCK_SIZE] + blocks.append(chunk) + return blocks + +def read_blocks(image_path): + image = open(image_path, "rb").read() + return blockify(image) + +def hash_block(data, salt): + hasher = hashlib.new(HASH_FUNCTION) + hasher.update(salt) + hasher.update(data) + return hasher.digest() + +def block_align(level): + pad_size = (BLOCK_SIZE - (len(level) % BLOCK_SIZE)) % BLOCK_SIZE + pad = '\x00' * pad_size + return level + pad + +def generate_hashes(data_blocks, salt): + levels = [] + root_hash = '' + while True: + hashes = [hash_block(b, salt) for b in data_blocks] + if len(hashes) == 1: + root_hash = hashes[0] + break + else: + level = ''.join(hashes) + level = block_align(level) + levels.insert(0, level) + data_blocks = blockify(level) + return root_hash, ''.join(levels) + +def write_hashes(hashes, hash_image, hash_image_size): + hashes = hashes.ljust(hash_image_size, '\x00') + with open(hash_image, 'wb+') as hash_file: + hash_file.write(hashes) + +def generate_hash_image(data_image, hash_image, hash_image_size, salt): + blocks = read_blocks(data_image) + root_hash, hashes = generate_hashes(blocks, salt) + write_hashes(hashes, hash_image, hash_image_size) + return root_hash + +def build_verity_tree(data_image, hash_image, data_image_size): + salt = generate_salt() + hash_image_size = get_hash_image_size(data_image_size) + root_hash = generate_hash_image(data_image, hash_image, hash_image_size, salt) + print binascii.hexlify(root_hash), binascii.hexlify(salt) + +if __name__ == "__main__": + if len(sys.argv) == 3 and sys.argv[1] == "-s": + print get_hash_image_size(int(sys.argv[2])) + elif len(sys.argv) == 4: + data_image = sys.argv[1] + hash_image = sys.argv[2] + data_image_size = int(sys.argv[3]) + build_verity_tree(data_image, hash_image, data_image_size) + else: + exit(-1) diff --git a/verity/generate_verity_key.c b/verity/generate_verity_key.c new file mode 100644 index 00000000..7414af58 --- /dev/null +++ b/verity/generate_verity_key.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2013 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 <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +/* HACK: we need the RSAPublicKey struct + * but RSA_verify conflits with openssl */ +#define RSA_verify RSA_verify_mincrypt +#include "mincrypt/rsa.h" +#undef RSA_verify + +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/pem.h> +#include <openssl/rsa.h> +#include <openssl/sha.h> + +// Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format. +// Lifted from secure adb's mincrypt key generation. +static int convert_to_mincrypt_format(RSA *rsa, RSAPublicKey *pkey) +{ + int ret = -1; + unsigned int i; + + if (RSA_size(rsa) != RSANUMBYTES) + goto out; + + BN_CTX* ctx = BN_CTX_new(); + BIGNUM* r32 = BN_new(); + BIGNUM* rr = BN_new(); + BIGNUM* r = BN_new(); + BIGNUM* rem = BN_new(); + BIGNUM* n = BN_new(); + BIGNUM* n0inv = BN_new(); + + BN_set_bit(r32, 32); + BN_copy(n, rsa->n); + BN_set_bit(r, RSANUMWORDS * 32); + BN_mod_sqr(rr, r, n, ctx); + BN_div(NULL, rem, n, r32, ctx); + BN_mod_inverse(n0inv, rem, r32, ctx); + + pkey->len = RSANUMWORDS; + pkey->n0inv = 0 - BN_get_word(n0inv); + for (i = 0; i < RSANUMWORDS; i++) { + BN_div(rr, rem, rr, r32, ctx); + pkey->rr[i] = BN_get_word(rem); + BN_div(n, rem, n, r32, ctx); + pkey->n[i] = BN_get_word(rem); + } + pkey->exponent = BN_get_word(rsa->e); + + ret = 0; + + BN_free(n0inv); + BN_free(n); + BN_free(rem); + BN_free(r); + BN_free(rr); + BN_free(r32); + BN_CTX_free(ctx); + +out: + return ret; +} + +static int write_public_keyfile(RSA *private_key, const char *private_key_path) +{ + RSAPublicKey pkey; + BIO *bfile = NULL; + char *path = NULL; + int ret = -1; + + if (asprintf(&path, "%s.pub", private_key_path) < 0) + goto out; + + if (convert_to_mincrypt_format(private_key, &pkey) < 0) + goto out; + + bfile = BIO_new_file(path, "w"); + if (!bfile) + goto out; + + BIO_write(bfile, &pkey, sizeof(pkey)); + BIO_flush(bfile); + + ret = 0; +out: + BIO_free_all(bfile); + free(path); + return ret; +} + +static int generate_key(const char *file) +{ + int ret = -1; + FILE *f = NULL; + RSA* rsa = RSA_new(); + BIGNUM* exponent = BN_new(); + EVP_PKEY* pkey = EVP_PKEY_new(); + + if (!pkey || !exponent || !rsa) { + printf("Failed to allocate key\n"); + goto out; + } + + BN_set_word(exponent, RSA_F4); + RSA_generate_key_ex(rsa, 2048, exponent, NULL); + EVP_PKEY_set1_RSA(pkey, rsa); + + f = fopen(file, "w"); + if (!f) { + printf("Failed to open '%s'\n", file); + goto out; + } + + if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) { + printf("Failed to write key\n"); + goto out; + } + + if (write_public_keyfile(rsa, file) < 0) { + printf("Failed to write public key\n"); + goto out; + } + + ret = 0; + +out: + if (f) + fclose(f); + EVP_PKEY_free(pkey); + RSA_free(rsa); + BN_free(exponent); + return ret; +} + +static void usage(){ + printf("Usage: generate_verity_key <path-to-key>"); +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + usage(); + exit(-1); + } + return generate_key(argv[1]); +}
\ No newline at end of file diff --git a/verity/syspatch.c b/verity/syspatch.c new file mode 100644 index 00000000..7e3909de --- /dev/null +++ b/verity/syspatch.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 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 <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "LzmaDec.h" + +void usage() +{ + fprintf(stderr, "Usage: syspatch <patch> <target>\n"); +} + +int main(int argc, char *argv[]) +{ + char *patch_path; + char *target_path; + + int patch_fd; + int target_fd; + + if (argc == 3) { + patch_path = argv[1]; + target_path = argv[2]; + } else { + usage(); + exit(-1); + } + + patch_fd = open(patch_path, O_RDONLY); + if (patch_fd < 0) { + fprintf(stderr, "Couldn't open patch file (%s)\n", strerror(errno)); + exit(-1); + } + + target_fd = open(target_path, O_RDWR); + if (target_fd < 0) { + fprintf(stderr, "Couldn't open target file (%s)\n", strerror(errno)); + exit(-1); + } + + close(patch_fd); + close(target_fd); + exit(0); +} diff --git a/verity/verity_signer b/verity/verity_signer new file mode 100755 index 00000000..a4f337ae --- /dev/null +++ b/verity/verity_signer @@ -0,0 +1,8 @@ +#! /bin/sh + +# Start-up script for VeritySigner + +VERITYSIGNER_HOME=`dirname "$0"` +VERITYSIGNER_HOME=`dirname "$VERITYSIGNER_HOME"` + +java -Xmx512M -jar "$VERITYSIGNER_HOME"/framework/VeritySigner.jar "$@"
\ No newline at end of file |