diff options
-rw-r--r-- | adb/Android.mk | 15 | ||||
-rw-r--r-- | adb/adb.h | 1 | ||||
-rw-r--r-- | adb/commandline.c | 6 | ||||
-rw-r--r-- | adb/disable_verity_service.c | 199 | ||||
-rw-r--r-- | adb/services.c | 2 | ||||
-rw-r--r-- | fs_mgr/Android.mk | 4 | ||||
-rw-r--r-- | fs_mgr/fs_mgr.c | 26 | ||||
-rw-r--r-- | fs_mgr/fs_mgr_fstab.c | 5 | ||||
-rw-r--r-- | fs_mgr/fs_mgr_priv_verity.h | 5 | ||||
-rw-r--r-- | fs_mgr/fs_mgr_verity.c | 67 | ||||
-rw-r--r-- | fs_mgr/include/fs_mgr.h | 8 | ||||
-rw-r--r-- | libcutils/sched_policy.c | 26 | ||||
-rw-r--r-- | liblog/tests/Android.mk | 3 | ||||
-rw-r--r-- | logd/LogAudit.cpp | 34 | ||||
-rw-r--r-- | logd/LogBuffer.cpp | 33 | ||||
-rw-r--r-- | logd/LogBuffer.h | 9 | ||||
-rw-r--r-- | logd/LogStatistics.cpp | 107 | ||||
-rw-r--r-- | logd/LogStatistics.h | 14 | ||||
-rw-r--r-- | logd/README.property | 3 | ||||
-rw-r--r-- | logd/main.cpp | 9 | ||||
-rw-r--r-- | rootdir/init.environ.rc.in | 1 | ||||
-rw-r--r-- | rootdir/init.rc | 23 | ||||
-rw-r--r-- | toolbox/top.c | 47 |
23 files changed, 479 insertions, 168 deletions
diff --git a/adb/Android.mk b/adb/Android.mk index af7d7e5..b70c153 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -111,6 +111,7 @@ LOCAL_SRC_FILES := \ jdwp_service.c \ framebuffer_service.c \ remount_service.c \ + disable_verity_service.c \ usb_linux_client.c LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror @@ -120,13 +121,25 @@ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1 endif +ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT))) +LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1 +endif + LOCAL_MODULE := adbd LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) +LOCAL_C_INCLUDES += system/extras/ext4_utils system/core/fs_mgr/include + +LOCAL_STATIC_LIBRARIES := liblog \ + libfs_mgr \ + libcutils \ + libc \ + libmincrypt \ + libselinux \ + libext4_utils_static -LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt libselinux include $(BUILD_EXECUTABLE) @@ -329,6 +329,7 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri #if !ADB_HOST void framebuffer_service(int fd, void *cookie); void remount_service(int fd, void *cookie); +void disable_verity_service(int fd, void* cookie); #endif /* packet allocator */ diff --git a/adb/commandline.c b/adb/commandline.c index 05b4ef6..87baeb9 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -189,6 +189,7 @@ void help() "\n" " adb restore <file> - restore device contents from the <file> backup archive\n" "\n" + " adb disable-verity - disable dm-verity checking on USERDEBUG builds\n" " adb help - show this help message\n" " adb version - show version num\n" "\n" @@ -205,8 +206,7 @@ void help() " adb reboot-bootloader - reboots the device into the bootloader\n" " adb root - restarts the adbd daemon with root permissions\n" " adb usb - restarts the adbd daemon listening on USB\n" - " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port" - "\n" + " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port\n" "networking:\n" " adb ppp <tty> [parameters] - Run PPP over USB.\n" " Note: you should not automatically start a PPP connection.\n" @@ -1437,7 +1437,7 @@ top: if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot") || !strcmp(argv[0], "reboot-bootloader") || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb") - || !strcmp(argv[0], "root")) { + || !strcmp(argv[0], "root") || !strcmp(argv[0], "disable-verity")) { char command[100]; if (!strcmp(argv[0], "reboot-bootloader")) snprintf(command, sizeof(command), "reboot:bootloader"); diff --git a/adb/disable_verity_service.c b/adb/disable_verity_service.c new file mode 100644 index 0000000..ed3da52 --- /dev/null +++ b/adb/disable_verity_service.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2014 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 "sysdeps.h" + +#define TRACE_TAG TRACE_ADB +#include "adb.h" + +#include <stdio.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <inttypes.h> + +#include "cutils/properties.h" +#include "ext4_sb.h" +#include <fs_mgr.h> + +#define FSTAB_PREFIX "/fstab." +struct fstab *fstab; + +__attribute__((__format__(printf, 2, 3))) __nonnull((2)) +static void write_console(int fd, const char* format, ...) +{ + char buffer[256]; + va_list args; + va_start (args, format); + vsnprintf (buffer, sizeof(buffer), format, args); + va_end (args); + + adb_write(fd, buffer, strnlen(buffer, sizeof(buffer))); +} + +static int get_target_device_size(int fd, const char *blk_device, + uint64_t *device_size) +{ + int data_device; + struct ext4_super_block sb; + struct fs_info info; + + info.len = 0; /* Only len is set to 0 to ask the device for real size. */ + + data_device = adb_open(blk_device, O_RDONLY | O_CLOEXEC); + if (data_device < 0) { + write_console(fd, "Error opening block device (%s)\n", strerror(errno)); + return -1; + } + + if (lseek64(data_device, 1024, SEEK_SET) < 0) { + write_console(fd, "Error seeking to superblock\n"); + adb_close(data_device); + return -1; + } + + if (adb_read(data_device, &sb, sizeof(sb)) != sizeof(sb)) { + write_console(fd, "Error reading superblock\n"); + adb_close(data_device); + return -1; + } + + ext4_parse_sb(&sb, &info); + *device_size = info.len; + + adb_close(data_device); + return 0; +} + +static int disable_verity(int fd, const char *block_device, + const char* mount_point) +{ + uint32_t magic_number; + const uint32_t voff = VERITY_METADATA_MAGIC_DISABLE; + uint64_t device_length; + int device; + int retval = -1; + + device = adb_open(block_device, O_RDWR | O_CLOEXEC); + if (device == -1) { + write_console(fd, "Could not open block device %s (%s).\n", + block_device, strerror(errno)); + write_console(fd, "Maybe run adb remount?\n"); + goto errout; + } + + // find the start of the verity metadata + if (get_target_device_size(fd, (char*)block_device, &device_length) < 0) { + write_console(fd, "Could not get target device size.\n"); + goto errout; + } + + if (lseek64(device, device_length, SEEK_SET) < 0) { + write_console(fd, + "Could not seek to start of verity metadata block.\n"); + goto errout; + } + + // check the magic number + if (adb_read(device, &magic_number, sizeof(magic_number)) + != sizeof(magic_number)) { + write_console(fd, "Couldn't read magic number!\n"); + goto errout; + } + + if (magic_number == VERITY_METADATA_MAGIC_DISABLE) { + write_console(fd, "Verity already disabled on %s\n", mount_point); + goto errout; + } + + if (magic_number != VERITY_METADATA_MAGIC_NUMBER) { + write_console(fd, + "Couldn't find verity metadata at offset %"PRIu64"!\n", + device_length); + goto errout; + } + + if (lseek64(device, device_length, SEEK_SET) < 0) { + write_console(fd, + "Could not seek to start of verity metadata block.\n"); + goto errout; + } + + if (adb_write(device, &voff, sizeof(voff)) != sizeof(voff)) { + write_console(fd, "Could not set verity disabled flag on device %s\n", + block_device); + goto errout; + } + + write_console(fd, "Verity disabled on %s\n", mount_point); + retval = 0; +errout: + if (device != -1) + adb_close(device); + return retval; +} + +void disable_verity_service(int fd, void* cookie) +{ +#ifdef ALLOW_ADBD_DISABLE_VERITY + char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; + char propbuf[PROPERTY_VALUE_MAX]; + int i; + bool any_disabled = false; + + property_get("ro.secure", propbuf, "0"); + if (strcmp(propbuf, "1")) { + write_console(fd, "verity not enabled - ENG build\n"); + goto errout; + } + + property_get("ro.debuggable", propbuf, "0"); + if (strcmp(propbuf, "1")) { + write_console(fd, "verity cannot be disabled - USER build\n"); + goto errout; + } + + property_get("ro.hardware", propbuf, ""); + snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); + + fstab = fs_mgr_read_fstab(fstab_filename); + if (!fstab) { + write_console(fd, "Failed to open %s\nMaybe run adb root?\n", + fstab_filename); + goto errout; + } + + /* Loop through entries looking for ones that vold manages */ + for (i = 0; i < fstab->num_entries; i++) { + if(fs_mgr_is_verified(&fstab->recs[i])) { + if (!disable_verity(fd, fstab->recs[i].blk_device, + fstab->recs[i].mount_point)) { + any_disabled = true; + } + } + } + + if (any_disabled) { + write_console(fd, + "Now reboot your device for settings to take effect\n"); + } +#else + write_console(fd, "disable-verity only works for userdebug builds\n"); +#endif + +errout: + adb_close(fd); +} diff --git a/adb/services.c b/adb/services.c index e61371a..21b08dc 100644 --- a/adb/services.c +++ b/adb/services.c @@ -469,6 +469,8 @@ int service_to_fd(const char *name) free(cookie); } } + } else if(!strncmp(name, "disable-verity:", 15)) { + ret = create_service_thread(disable_verity_service, NULL); #endif } if (ret >= 0) { diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk index 7cffc37..61bf1ee 100644 --- a/fs_mgr/Android.mk +++ b/fs_mgr/Android.mk @@ -13,6 +13,10 @@ LOCAL_C_INCLUDES += system/extras/ext4_utils LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_CFLAGS := -Werror +ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT))) +LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1 +endif + include $(BUILD_STATIC_LIBRARY) diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c index 91e6c33..40878c1 100644 --- a/fs_mgr/fs_mgr.c +++ b/fs_mgr/fs_mgr.c @@ -245,6 +245,16 @@ static int device_is_debuggable() { return strcmp(value, "1") ? 0 : 1; } +static int device_is_secure() { + int ret = -1; + char value[PROP_VALUE_MAX]; + ret = __system_property_get("ro.secure", value); + /* If error, we want to fail secure */ + if (ret < 0) + return 1; + return strcmp(value, "0") ? 1 : 0; +} + /* * Tries to mount any of the consecutive fstab entries that match * the mountpoint of the one given by fstab->recs[start_idx]. @@ -350,9 +360,11 @@ int fs_mgr_mount_all(struct fstab *fstab) wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT); } - if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && - !device_is_debuggable()) { - if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) { + if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) { + int rc = fs_mgr_setup_verity(&fstab->recs[i]); + if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) { + INFO("Verity disabled"); + } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) { ERROR("Could not set up verified partition, skipping!\n"); continue; } @@ -467,9 +479,11 @@ int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device, fstab->recs[i].mount_point); } - if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && - !device_is_debuggable()) { - if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) { + if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) { + int rc = fs_mgr_setup_verity(&fstab->recs[i]); + if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) { + INFO("Verity disabled"); + } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) { ERROR("Could not set up verified partition, skipping!\n"); continue; } diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c index 3f84179..ab8f128 100644 --- a/fs_mgr/fs_mgr_fstab.c +++ b/fs_mgr/fs_mgr_fstab.c @@ -418,6 +418,11 @@ int fs_mgr_is_nonremovable(struct fstab_rec *fstab) return fstab->fs_mgr_flags & MF_NONREMOVABLE; } +int fs_mgr_is_verified(struct fstab_rec *fstab) +{ + return fstab->fs_mgr_flags & MF_VERIFY; +} + int fs_mgr_is_encryptable(struct fstab_rec *fstab) { return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT); diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_verity.h index 6193784..f90e596 100644 --- a/fs_mgr/fs_mgr_priv_verity.h +++ b/fs_mgr/fs_mgr_priv_verity.h @@ -14,4 +14,7 @@ * limitations under the License. */ -int fs_mgr_setup_verity(struct fstab_rec *fstab);
\ No newline at end of file +#define FS_MGR_SETUP_VERITY_DISABLED -2 +#define FS_MGR_SETUP_VERITY_FAIL -1 +#define FS_MGR_SETUP_VERITY_SUCCESS 0 +int fs_mgr_setup_verity(struct fstab_rec *fstab); diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c index b79a4a8..f5dcf3a 100644 --- a/fs_mgr/fs_mgr_verity.c +++ b/fs_mgr/fs_mgr_verity.c @@ -43,7 +43,6 @@ #include "fs_mgr_priv_verity.h" #define VERITY_METADATA_SIZE 32768 -#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001 #define VERITY_TABLE_RSA_KEY "/verity_key" extern struct fs_info info; @@ -155,7 +154,9 @@ static int read_verity_metadata(char *block_device, char **signature, char **tab uint64_t device_length; int protocol_version; FILE *device; - int retval = -1; + int retval = FS_MGR_SETUP_VERITY_FAIL; + *signature = 0; + *table = 0; device = fopen(block_device, "r"); if (!device) { @@ -178,8 +179,18 @@ static int read_verity_metadata(char *block_device, char **signature, char **tab ERROR("Couldn't read magic number!\n"); goto out; } + +#ifdef ALLOW_ADBD_DISABLE_VERITY + if (magic_number == VERITY_METADATA_MAGIC_DISABLE) { + retval = FS_MGR_SETUP_VERITY_DISABLED; + INFO("Attempt to cleanly disable verity - only works in USERDEBUG"); + goto out; + } +#endif + if (magic_number != VERITY_METADATA_MAGIC_NUMBER) { - ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", device_length); + ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", + device_length); goto out; } @@ -201,14 +212,12 @@ static int read_verity_metadata(char *block_device, char **signature, char **tab } if (!fread(*signature, RSANUMBYTES, 1, device)) { ERROR("Couldn't read signature from verity metadata!\n"); - free(*signature); goto out; } // get the size of the table if (!fread(&table_length, sizeof(int), 1, device)) { ERROR("Couldn't get the size of the verity table from metadata!\n"); - free(*signature); goto out; } @@ -221,16 +230,22 @@ static int read_verity_metadata(char *block_device, char **signature, char **tab } if (!fgets(*table, table_length, device)) { ERROR("Couldn't read the verity table from metadata!\n"); - free(*table); - free(*signature); goto out; } - retval = 0; + retval = FS_MGR_SETUP_VERITY_SUCCESS; out: if (device) fclose(device); + + if (retval != FS_MGR_SETUP_VERITY_SUCCESS) { + free(*table); + free(*signature); + *table = 0; + *signature = 0; + } + return retval; } @@ -358,10 +373,11 @@ static int set_verified_property(char *name) { int fs_mgr_setup_verity(struct fstab_rec *fstab) { int retval = -1; + int fd = -1; - char *verity_blk_name; - char *verity_table; - char *verity_table_signature; + char *verity_blk_name = 0; + char *verity_table = 0; + char *verity_table_signature = 0; char buffer[DM_BUF_SIZE]; struct dm_ioctl *io = (struct dm_ioctl *) buffer; @@ -378,11 +394,19 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { return retval; } + // read the verity block at the end of the block device + // send error code up the chain so we can detect attempts to disable verity + retval = read_verity_metadata(fstab->blk_device, + &verity_table_signature, + &verity_table); + if (retval < 0) { + goto out; + } + // get the device mapper fd - int fd; if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) { ERROR("Error opening device mapper (%s)", strerror(errno)); - return retval; + goto out; } // create the device @@ -397,13 +421,6 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { goto out; } - // read the verity block at the end of the block device - if (read_verity_metadata(fstab->blk_device, - &verity_table_signature, - &verity_table) < 0) { - goto out; - } - // verify the signature on the table if (verify_table(verity_table_signature, verity_table, @@ -424,6 +441,7 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { // assign the new verity block device as the block device free(fstab->blk_device); fstab->blk_device = verity_blk_name; + verity_blk_name = 0; // make sure we've set everything up properly if (test_access(fstab->blk_device) < 0) { @@ -434,6 +452,13 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { retval = set_verified_property(mount_point); out: - close(fd); + if (fd != -1) { + close(fd); + } + + free(verity_table); + free(verity_table_signature); + free(verity_blk_name); + return retval; } diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 0c7eb20..5e2ff41 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -20,6 +20,13 @@ #include <stdint.h> #include <linux/dm-ioctl.h> +// Magic number at start of verity metadata +#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001 + +// Replacement magic number at start of verity metadata to cleanly +// turn verity off in userdebug builds. +#define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF" + #ifdef __cplusplus extern "C" { #endif @@ -74,6 +81,7 @@ int fs_mgr_add_entry(struct fstab *fstab, struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path); int fs_mgr_is_voldmanaged(struct fstab_rec *fstab); int fs_mgr_is_nonremovable(struct fstab_rec *fstab); +int fs_mgr_is_verified(struct fstab_rec *fstab); int fs_mgr_is_encryptable(struct fstab_rec *fstab); int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab); int fs_mgr_swapon_all(struct fstab *fstab); diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c index 2acc3c3..493511e 100644 --- a/libcutils/sched_policy.c +++ b/libcutils/sched_policy.c @@ -45,8 +45,6 @@ static inline SchedPolicy _policy(SchedPolicy p) #define POLICY_DEBUG 0 -#define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM) - // This prctl is only available in Android kernels. #define PR_SET_TIMERSLACK_PID 41 @@ -60,9 +58,6 @@ static int __sys_supports_schedgroups = -1; // File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error. static int bg_cgroup_fd = -1; static int fg_cgroup_fd = -1; -#if CAN_SET_SP_SYSTEM -static int system_cgroup_fd = -1; -#endif /* Add tid to the scheduling group defined by the policy */ static int add_tid_to_cgroup(int tid, SchedPolicy policy) @@ -78,11 +73,6 @@ static int add_tid_to_cgroup(int tid, SchedPolicy policy) case SP_AUDIO_SYS: fd = fg_cgroup_fd; break; -#if CAN_SET_SP_SYSTEM - case SP_SYSTEM: - fd = system_cgroup_fd; - break; -#endif default: fd = -1; break; @@ -123,21 +113,13 @@ static void __initialize(void) { if (!access("/dev/cpuctl/tasks", F_OK)) { __sys_supports_schedgroups = 1; -#if CAN_SET_SP_SYSTEM filename = "/dev/cpuctl/tasks"; - system_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC); - if (system_cgroup_fd < 0) { - SLOGV("open of %s failed: %s\n", filename, strerror(errno)); - } -#endif - - filename = "/dev/cpuctl/apps/tasks"; fg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC); if (fg_cgroup_fd < 0) { SLOGE("open of %s failed: %s\n", filename, strerror(errno)); } - filename = "/dev/cpuctl/apps/bg_non_interactive/tasks"; + filename = "/dev/cpuctl/bg_non_interactive/tasks"; bg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC); if (bg_cgroup_fd < 0) { SLOGE("open of %s failed: %s\n", filename, strerror(errno)); @@ -233,11 +215,9 @@ int get_sched_policy(int tid, SchedPolicy *policy) if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0) return -1; if (grpBuf[0] == '\0') { - *policy = SP_SYSTEM; - } else if (!strcmp(grpBuf, "apps/bg_non_interactive")) { - *policy = SP_BACKGROUND; - } else if (!strcmp(grpBuf, "apps")) { *policy = SP_FOREGROUND; + } else if (!strcmp(grpBuf, "bg_non_interactive")) { + *policy = SP_BACKGROUND; } else { errno = ERANGE; return -1; diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk index 255dc2e..cd1bf33 100644 --- a/liblog/tests/Android.mk +++ b/liblog/tests/Android.mk @@ -59,7 +59,8 @@ test_c_flags := \ -g \ -Wall -Wextra \ -Werror \ - -fno-builtin + -fno-builtin \ + -std=gnu++11 test_src_files := \ liblog_test.cpp diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp index f8d6162..51feff3 100644 --- a/logd/LogAudit.cpp +++ b/logd/LogAudit.cpp @@ -22,15 +22,26 @@ #include <sys/klog.h> #include <sys/prctl.h> #include <sys/uio.h> +#include <syslog.h> #include "libaudit.h" #include "LogAudit.h" +#define KMSG_PRIORITY(PRI) \ + '<', \ + '0' + (LOG_AUTH | (PRI)) / 10, \ + '0' + (LOG_AUTH | (PRI)) % 10, \ + '>' + LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmsg) : SocketListener(getLogSocket(), false) , logbuf(buf) , reader(reader) , fdDmesg(-1) { + static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO), + 'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':', + ' ', 's', 't', 'a', 'r', 't', '\n' }; + write(fdDmsg, auditd_message, sizeof(auditd_message)); logDmesg(); fdDmesg = fdDmsg; } @@ -75,13 +86,19 @@ int LogAudit::logPrint(const char *fmt, ...) { memmove(cp, cp + 1, strlen(cp + 1) + 1); } + bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded "); if (fdDmesg >= 0) { - struct iovec iov[2]; - - iov[0].iov_base = str; - iov[0].iov_len = strlen(str); - iov[1].iov_base = const_cast<char *>("\n"); - iov[1].iov_len = 1; + struct iovec iov[3]; + static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) }; + static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) }; + + iov[0].iov_base = info ? const_cast<char *>(log_info) + : const_cast<char *>(log_warning); + iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning); + iov[1].iov_base = str; + iov[1].iov_len = strlen(str); + iov[2].iov_base = const_cast<char *>("\n"); + iov[2].iov_len = 1; writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0])); } @@ -175,10 +192,7 @@ int LogAudit::logPrint(const char *fmt, ...) { if (!newstr) { rc = -ENOMEM; } else { - *newstr = (strstr(str, " permissive=1") - || strstr(str, " policy loaded ")) - ? ANDROID_LOG_INFO - : ANDROID_LOG_WARN; + *newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN; strlcpy(newstr + 1, comm, l); strncpy(newstr + 1 + l, str, estr - str); strcpy(newstr + 1 + l + (estr - str), ecomm); diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index cd9ea20..8c1c344 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp @@ -93,9 +93,9 @@ static unsigned long property_get_size(const char *key) { } LogBuffer::LogBuffer(LastLogTimes *times) - : mTimes(*times) { + : dgramQlenStatistics(false) + , mTimes(*times) { pthread_mutex_init(&mLogElementsLock, NULL); - dgram_qlen_statistics = false; static const char global_tuneable[] = "persist.logd.size"; // Settings App static const char global_default[] = "ro.logd.size"; // BoardConfig.mk @@ -150,10 +150,10 @@ void LogBuffer::log(log_id_t log_id, log_time realtime, while (--it != mLogElements.begin()) { if ((*it)->getRealTime() <= realtime) { // halves the peak performance, use with caution - if (dgram_qlen_statistics) { + if (dgramQlenStatistics) { LogBufferElementCollection::iterator ib = it; unsigned short buckets, num = 1; - for (unsigned short i = 0; (buckets = stats.dgram_qlen(i)); ++i) { + for (unsigned short i = 0; (buckets = stats.dgramQlen(i)); ++i) { buckets -= num; num += buckets; while (buckets && (--ib != mLogElements.begin())) { @@ -267,8 +267,7 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { if (uid == caller_uid) { it = mLogElements.erase(it); - unsigned short len = e->getMsgLen(); - stats.subtract(len, id, uid, e->getPid()); + stats.subtract(e->getMsgLen(), id, uid, e->getPid()); delete e; pruneRows--; if (pruneRows == 0) { @@ -318,23 +317,19 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { uid_t uid = e->getUid(); - if (uid == worst) { + if ((uid == worst) || mPrune.naughty(e)) { // Worst or BlackListed it = mLogElements.erase(it); unsigned short len = e->getMsgLen(); - stats.subtract(len, id, worst, e->getPid()); - delete e; - kick = true; - pruneRows--; - if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) { - break; - } - worst_sizes -= len; - } else if (mPrune.naughty(e)) { // BlackListed - it = mLogElements.erase(it); - stats.subtract(e->getMsgLen(), id, uid, e->getPid()); + stats.subtract(len, id, uid, e->getPid()); delete e; pruneRows--; - if (pruneRows == 0) { + if (uid == worst) { + kick = true; + if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) { + break; + } + worst_sizes -= len; + } else if (pruneRows == 0) { break; } } else { diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h index 4b982a8..879baea 100644 --- a/logd/LogBuffer.h +++ b/logd/LogBuffer.h @@ -37,8 +37,7 @@ class LogBuffer { pthread_mutex_t mLogElementsLock; LogStatistics stats; - - bool dgram_qlen_statistics; + bool dgramQlenStatistics; PruneList mPrune; @@ -66,7 +65,11 @@ public: void enableDgramQlenStatistics() { stats.enableDgramQlenStatistics(); - dgram_qlen_statistics = true; + dgramQlenStatistics = true; + } + + void enableStatistics() { + stats.enableStatistics(); } int initPrune(char *cp) { return mPrune.init(cp); } diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp index a2f27c6..2a45590 100644 --- a/logd/LogStatistics.cpp +++ b/logd/LogStatistics.cpp @@ -51,11 +51,11 @@ PidStatistics::~PidStatistics() { } bool PidStatistics::pidGone() { - if (mGone) { + if (mGone || (pid == gone)) { return true; } - if (pid == gone) { - return true; + if (pid == 0) { + return false; } if (kill(pid, 0) && (errno != EPERM)) { mGone = true; @@ -90,9 +90,14 @@ void PidStatistics::addTotal(size_t size, size_t element) { } // must call free to release return value +// If only we could sniff our own logs for: +// <time> <pid> <pid> E AndroidRuntime: Process: <name>, PID: <pid> +// which debuggerd prints as a process is crashing. char *PidStatistics::pidToName(pid_t pid) { char *retval = NULL; - if (pid != gone) { + if (pid == 0) { // special case from auditd for kernel + retval = strdup("logd.auditd"); + } else if (pid != gone) { char buffer[512]; snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid); int fd = open(buffer, O_RDONLY); @@ -122,7 +127,7 @@ UidStatistics::~UidStatistics() { PidStatisticsCollection::iterator it; for (it = begin(); it != end();) { delete (*it); - it = Pids.erase(it); + it = erase(it); } } @@ -130,7 +135,7 @@ void UidStatistics::add(unsigned short size, pid_t pid) { mSizes += size; ++mElements; - PidStatistics *p; + PidStatistics *p = NULL; PidStatisticsCollection::iterator last; PidStatisticsCollection::iterator it; for (last = it = begin(); it != end(); last = it, ++it) { @@ -141,12 +146,12 @@ void UidStatistics::add(unsigned short size, pid_t pid) { } } // insert if the gone entry. - bool insert = (last != it) && (p->getPid() == p->gone); + bool insert_before_last = (last != it) && p && (p->getPid() == p->gone); p = new PidStatistics(pid, pidToName(pid)); - if (insert) { - Pids.insert(last, p); + if (insert_before_last) { + insert(last, p); } else { - Pids.push_back(p); + push_back(p); } p->add(size); } @@ -163,17 +168,17 @@ void UidStatistics::subtract(unsigned short size, pid_t pid) { size_t szsTotal = p->sizesTotal(); size_t elsTotal = p->elementsTotal(); delete p; - Pids.erase(it); + erase(it); it = end(); --it; if (it == end()) { p = new PidStatistics(p->gone); - Pids.push_back(p); + push_back(p); } else { p = *it; if (p->getPid() != p->gone) { p = new PidStatistics(p->gone); - Pids.push_back(p); + push_back(p); } } p->addTotal(szsTotal, elsTotal); @@ -194,8 +199,8 @@ void UidStatistics::sort() { PidStatistics *n = (*it); if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) { pass = true; - Pids.erase(it); - Pids.insert(lt, n); + erase(it); + insert(lt, n); it = lt; n = l; } @@ -302,6 +307,10 @@ void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) { } void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) { + if (uid == (uid_t) -1) { // init + uid = (uid_t) AID_ROOT; + } + UidStatisticsCollection::iterator it; for (it = begin(); it != end(); ++it) { UidStatistics *u = *it; @@ -384,24 +393,25 @@ size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) { } LogStatistics::LogStatistics() - : start(CLOCK_MONOTONIC) { + : mStatistics(false) + , dgramQlenStatistics(false) + , start(CLOCK_MONOTONIC) { log_id_for_each(i) { mSizes[i] = 0; mElements[i] = 0; } - dgram_qlen_statistics = false; - for(unsigned short bucket = 0; dgram_qlen(bucket); ++bucket) { + for(unsigned short bucket = 0; dgramQlen(bucket); ++bucket) { mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max; mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max; } } -// Each bucket below represents a dgram_qlen of log messages. By +// Each bucket below represents a dgramQlen of log messages. By // finding the minimum period of time from start to finish -// of each dgram_qlen, we can get a performance expectation for +// of each dgramQlen, we can get a performance expectation for // the user space logger. The net result is that the period -// of time divided by the dgram_qlen will give us the average time +// of time divided by the dgramQlen will give us the average time // between log messages; at the point where the average time // is greater than the throughput capability of the logger // we will not longer require the benefits of the FIFO formed @@ -412,7 +422,7 @@ LogStatistics::LogStatistics() // // for example (reformatted): // -// Minimum time between log events per dgram_qlen: +// Minimum time between log events per dgramQlen: // 1 2 3 5 10 20 30 50 100 200 300 400 500 600 // 5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5 // @@ -426,12 +436,12 @@ LogStatistics::LogStatistics() // a large engineering margin so the rule of thumb that lead us to 100 is // fine. // -// bucket dgram_qlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300 +// bucket dgramQlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300 const unsigned short LogStatistics::mBuckets[] = { 1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600 }; -unsigned short LogStatistics::dgram_qlen(unsigned short bucket) { +unsigned short LogStatistics::dgramQlen(unsigned short bucket) { if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) { return 0; } @@ -455,6 +465,9 @@ void LogStatistics::add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid) { mSizes[log_id] += size; ++mElements[log_id]; + if (!mStatistics) { + return; + } id(log_id).add(size, uid, pid); } @@ -462,6 +475,9 @@ void LogStatistics::subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid) { mSizes[log_id] -= size; --mElements[log_id]; + if (!mStatistics) { + return; + } id(log_id).subtract(size, uid, pid); } @@ -545,25 +561,28 @@ void LogStatistics::format(char **buf, spaces = 1; log_time t(CLOCK_MONOTONIC); - unsigned long long d = t.nsec() - start.nsec(); - string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu", + unsigned long long d; + if (mStatistics) { + d = t.nsec() - start.nsec(); + string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu", d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60, (d / NS_PER_SEC) % 60, d % NS_PER_SEC); - log_id_for_each(i) { - if (!(logMask & (1 << i))) { - continue; - } - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; + log_id_for_each(i) { + if (!(logMask & (1 << i))) { + continue; + } + oldLength = string.length(); + if (spaces < 0) { + spaces = 0; + } + string.appendFormat("%*s%zu/%zu", spaces, "", + sizesTotal(i), elementsTotal(i)); + spaces += spaces_total + oldLength - string.length(); } - string.appendFormat("%*s%zu/%zu", spaces, "", - sizesTotal(i), elementsTotal(i)); - spaces += spaces_total + oldLength - string.length(); + spaces = 1; } - spaces = 1; d = t.nsec() - oldest.nsec(); string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu", d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60, @@ -686,23 +705,23 @@ void LogStatistics::format(char **buf, pids.clear(); } - if (dgram_qlen_statistics) { + if (dgramQlenStatistics) { const unsigned short spaces_time = 6; const unsigned long long max_seconds = 100000; spaces = 0; - string.append("\n\nMinimum time between log events per dgram_qlen:\n"); - for(unsigned short i = 0; dgram_qlen(i); ++i) { + string.append("\n\nMinimum time between log events per max_dgram_qlen:\n"); + for(unsigned short i = 0; dgramQlen(i); ++i) { oldLength = string.length(); if (spaces < 0) { spaces = 0; } - string.appendFormat("%*s%u", spaces, "", dgram_qlen(i)); + string.appendFormat("%*s%u", spaces, "", dgramQlen(i)); spaces += spaces_time + oldLength - string.length(); } string.append("\n"); spaces = 0; unsigned short n; - for(unsigned short i = 0; (n = dgram_qlen(i)); ++i) { + for(unsigned short i = 0; (n = dgramQlen(i)); ++i) { unsigned long long duration = minimum(i); if (duration) { duration /= n; @@ -724,8 +743,8 @@ void LogStatistics::format(char **buf, / (NS_PER_SEC / 1000)); } else if (duration >= (NS_PER_SEC / (1000000 / 10))) { string.appendFormat("%lluu", - (duration + (NS_PER_SEC / 2 / 1000000)) - / (NS_PER_SEC / 1000000)); + (duration + (NS_PER_SEC / 2 / 1000000)) + / (NS_PER_SEC / 1000000)); } else { string.appendFormat("%llun", duration); } diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h index 3733137..f6c4329 100644 --- a/logd/LogStatistics.h +++ b/logd/LogStatistics.h @@ -72,6 +72,10 @@ class UidStatistics { PidStatisticsCollection Pids; + void insert(PidStatisticsCollection::iterator i, PidStatistics *p) + { Pids.insert(i, p); } + void push_back(PidStatistics *p) { Pids.push_back(p); } + size_t mSizes; size_t mElements; @@ -81,6 +85,8 @@ public: PidStatisticsCollection::iterator begin() { return Pids.begin(); } PidStatisticsCollection::iterator end() { return Pids.end(); } + PidStatisticsCollection::iterator erase(PidStatisticsCollection::iterator i) + { return Pids.erase(i); } uid_t getUid() { return uid; } @@ -138,7 +144,8 @@ class LogStatistics { size_t mSizes[LOG_ID_MAX]; size_t mElements[LOG_ID_MAX]; - bool dgram_qlen_statistics; + bool mStatistics; + bool dgramQlenStatistics; static const unsigned short mBuckets[14]; log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])]; @@ -150,8 +157,9 @@ public: LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; } - void enableDgramQlenStatistics() { dgram_qlen_statistics = true; } - static unsigned short dgram_qlen(unsigned short bucket); + void enableDgramQlenStatistics() { dgramQlenStatistics = true; } + void enableStatistics() { mStatistics = true; } + static unsigned short dgramQlen(unsigned short bucket); unsigned long long minimum(unsigned short bucket); void recordDiff(log_time diff, unsigned short bucket); diff --git a/logd/README.property b/logd/README.property index f4b3c3c..b7fcece 100644 --- a/logd/README.property +++ b/logd/README.property @@ -4,6 +4,9 @@ name type default description logd.auditd bool true Enable selinux audit daemon logd.auditd.dmesg bool true selinux audit messages duplicated and sent on to dmesg log +logd.statistics bool depends Enable logcat -S statistics. +ro.config.low_ram bool false if true, logd.statistics default false +ro.build.type string if user, logd.statistics default false logd.statistics.dgram_qlen bool false Record dgram_qlen statistics. This represents a performance impact and is used to determine the platform's diff --git a/logd/main.cpp b/logd/main.cpp index 1e1a718..54da7e3 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -152,6 +152,15 @@ int main() { if (property_get_bool("logd.statistics.dgram_qlen", false)) { logBuf->enableDgramQlenStatistics(); } + { + char property[PROPERTY_VALUE_MAX]; + property_get("ro.build.type", property, ""); + if (property_get_bool("logd.statistics", + !!strcmp(property, "user") + && !property_get_bool("ro.config.low_ram", false))) { + logBuf->enableStatistics(); + } + } // LogReader listens on /dev/socket/logdr. When a client // connects, log entries in the LogBuffer are written to the client. diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in index 67222d7..30bef46 100644 --- a/rootdir/init.environ.rc.in +++ b/rootdir/init.environ.rc.in @@ -10,4 +10,3 @@ on init export LOOP_MOUNTPOINT /mnt/obb export BOOTCLASSPATH %BOOTCLASSPATH% export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH% - export LD_PRELOAD libsigchain.so diff --git a/rootdir/init.rc b/rootdir/init.rc index 8ba7c10..89f9aa6 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -119,25 +119,18 @@ on init mount cgroup none /dev/cpuctl cpu chown system system /dev/cpuctl chown system system /dev/cpuctl/tasks - chmod 0660 /dev/cpuctl/tasks + chmod 0666 /dev/cpuctl/tasks write /dev/cpuctl/cpu.shares 1024 - write /dev/cpuctl/cpu.rt_runtime_us 950000 + write /dev/cpuctl/cpu.rt_runtime_us 800000 write /dev/cpuctl/cpu.rt_period_us 1000000 - mkdir /dev/cpuctl/apps - chown system system /dev/cpuctl/apps/tasks - chmod 0666 /dev/cpuctl/apps/tasks - write /dev/cpuctl/apps/cpu.shares 1024 - write /dev/cpuctl/apps/cpu.rt_runtime_us 800000 - write /dev/cpuctl/apps/cpu.rt_period_us 1000000 - - mkdir /dev/cpuctl/apps/bg_non_interactive - chown system system /dev/cpuctl/apps/bg_non_interactive/tasks - chmod 0666 /dev/cpuctl/apps/bg_non_interactive/tasks + mkdir /dev/cpuctl/bg_non_interactive + chown system system /dev/cpuctl/bg_non_interactive/tasks + chmod 0666 /dev/cpuctl/bg_non_interactive/tasks # 5.0 % - write /dev/cpuctl/apps/bg_non_interactive/cpu.shares 52 - write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_runtime_us 700000 - write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_period_us 1000000 + write /dev/cpuctl/bg_non_interactive/cpu.shares 52 + write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 700000 + write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000 # qtaguid will limit access to specific data based on group memberships. # net_bw_acct grants impersonation of socket owners. diff --git a/toolbox/top.c b/toolbox/top.c index 280a032..b1a275c 100644 --- a/toolbox/top.c +++ b/toolbox/top.c @@ -32,6 +32,7 @@ #include <ctype.h> #include <dirent.h> #include <grp.h> +#include <inttypes.h> #include <pwd.h> #include <stdio.h> #include <stdlib.h> @@ -59,13 +60,13 @@ struct proc_info { char name[PROC_NAME_LEN]; char tname[THREAD_NAME_LEN]; char state; - long unsigned utime; - long unsigned stime; - long unsigned delta_utime; - long unsigned delta_stime; - long unsigned delta_time; - long vss; - long rss; + uint64_t utime; + uint64_t stime; + uint64_t delta_utime; + uint64_t delta_stime; + uint64_t delta_time; + uint64_t vss; + uint64_t rss; int prs; int num_threads; char policy[POLICY_NAME_LEN]; @@ -344,10 +345,19 @@ static int read_stat(char *filename, struct proc_info *proc) { proc->tname[THREAD_NAME_LEN-1] = 0; /* Scan rest of string. */ - sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " - "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld " - "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d", - &proc->state, &proc->utime, &proc->stime, &proc->vss, &proc->rss, &proc->prs); + sscanf(close_paren + 1, + " %c " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " + "%" SCNu64 + "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d " + "%" SCNu64 + "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " + "%d", + &proc->state, + &proc->utime, + &proc->stime, + &proc->vss, + &proc->rss, + &proc->prs); return 0; } @@ -470,12 +480,15 @@ static void print_procs(void) { snprintf(user_buf, 20, "%d", proc->uid); user_str = user_buf; } - if (!threads) - printf("%5d %2d %3ld%% %c %5d %6ldK %6ldK %3s %-8.8s %s\n", proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads, - proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname); - else - printf("%5d %5d %2d %3ld%% %c %6ldK %6ldK %3s %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, - proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name); + if (!threads) { + printf("%5d %2d %3" PRIu64 "%% %c %5d %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %s\n", + proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads, + proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname); + } else { + printf("%5d %5d %2d %3" PRIu64 "%% %c %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %-15s %s\n", + proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, + proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name); + } } } |