Awesome Open Source
Awesome Open Source

Monitor

CPU SDK

iOS SDK iOS CPU FPSSDK SDK

Wedjat****Wedjat SDK

CPU

A CPU chip is designed for portable computers, it is typically housed in a smaller chip package, but more importantly, in order to run cooler, it uses lower voltages than its desktop counterpart and has more "sleep mode" capability. A mobile processor can be throttled down to different power levels or sections of the chip can be turned off entirely when not in use. Further, the clock frequency may be stepped down under low processor loads. This stepping down conserves power and prolongs battery life.

CPU CPU

APP CPU

CPU iOS CPU CPU CPU

iOS Apple Darwin kernelXNU Runtime XNU Darwin X is not UNIX Mach BSD Mach BSD

OS X Internal: A System Approach Mac OS X Mac OS X iOS Mach Mach thread_basic_info

struct thread_basic_info {
        time_value_t    user_time;      /* user run time */
        time_value_t    system_time;    /* system run time */
        integer_t       cpu_usage;      /* scaled cpu usage percentage */
        policy_t        policy;         /* scheduling policy in effect */
        integer_t       run_state;      /* run state (see below) */
        integer_t       flags;          /* various flags (see below) */
        integer_t       suspend_count;  /* suspend count for thread */
        integer_t       sleep_time;     /* number of seconds that thread
                                           has been sleeping */
};

taskcontainerMach Mach BSD 11 BSD OS X Mach

OS X and iOS Kernel Programming Mach task Mach task thread task task_threads API task thread_info API thread_info API thread_act.h

kern_return_t task_threads
(
	task_t target_task,
	thread_act_array_t *act_list,
	mach_msg_type_number_t *act_listCnt
);

task_threads target_task act_list act_listCnt

kern_return_t thread_info
(
	thread_act_t target_act,
	thread_flavor_t flavor,
	thread_info_t thread_info_out,
	mach_msg_type_number_t *thread_info_outCnt
);

thread_info flavor thread thread_info_outCnt thread_info_out

CPU

#import <mach/mach.h>
#import <assert.h>

+ (CGFloat)appCpuUsage {
    kern_return_t kr;
    task_info_data_t tinfo;
    mach_msg_type_number_t task_info_count;
    
    task_info_count = TASK_INFO_MAX;
    kr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)tinfo, &task_info_count);
    if (kr != KERN_SUCCESS) {
        return -1;
    }
    
    thread_array_t         thread_list;
    mach_msg_type_number_t thread_count;
    
    thread_info_data_t     thinfo;
    mach_msg_type_number_t thread_info_count;
    
    thread_basic_info_t basic_info_th;
    
    // get threads in the task
    kr = task_threads(mach_task_self(), &thread_list, &thread_count);
    if (kr != KERN_SUCCESS) {
        return -1;
    }
    
    long total_time     = 0;
    long total_userTime = 0;
    CGFloat total_cpu   = 0;
    int j;
    
    // for each thread
    for (j = 0; j < (int)thread_count; j++) {
        thread_info_count = THREAD_INFO_MAX;
        kr = thread_info(thread_list[j], THREAD_BASIC_INFO,
                         (thread_info_t)thinfo, &thread_info_count);
        if (kr != KERN_SUCCESS) {
            return -1;
        }
        
        basic_info_th = (thread_basic_info_t)thinfo;
        
        if (!(basic_info_th->flags & TH_FLAGS_IDLE)) {
            total_time     = total_time + basic_info_th->user_time.seconds + basic_info_th->system_time.seconds;
            total_userTime = total_userTime + basic_info_th->user_time.microseconds + basic_info_th->system_time.microseconds;
            total_cpu      = total_cpu + basic_info_th->cpu_usage / (float)TH_USAGE_SCALE * kMaxPercent;
        }
    }
    
    kr = vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t));
    assert(kr == KERN_SUCCESS);
    
    return total_cpu;
}

task_threads API target_task mach_task_self() Mach task thread_info API flavor THREAD_BASIC_INFO thread_basic_info_t

vm_deallocate CPU GTInstruments

CPU CPU

GT App CPU

- (float)getCpuUsage
{
    kern_return_t           kr;
    thread_array_t          thread_list;
    mach_msg_type_number_t  thread_count;
    thread_info_data_t      thinfo;
    mach_msg_type_number_t  thread_info_count;
    thread_basic_info_t     basic_info_th;
    
    kr = task_threads(mach_task_self(), &thread_list, &thread_count);
    if (kr != KERN_SUCCESS) {
        return -1;
    }
    cpu_usage = 0;
    
    for (int i = 0; i < thread_count; i++)
    {
        thread_info_count = THREAD_INFO_MAX;
        kr = thread_info(thread_list[i], THREAD_BASIC_INFO,(thread_info_t)thinfo, &thread_info_count);
        if (kr != KERN_SUCCESS) {
            return -1;
        }
        
        basic_info_th = (thread_basic_info_t)thinfo;

        if (!(basic_info_th->flags & TH_FLAGS_IDLE))
        {
            cpu_usage += basic_info_th->cpu_usage;
        }
    }
    
    cpu_usage = cpu_usage / (float)TH_USAGE_SCALE * 100.0;
    
    vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t));
    
    return cpu_usage;
}

CPU

CPU

static NSUInteger const kMaxPercent = 100;

+ (CGFloat)cpuUsage {
    CGFloat cpuUsage = 0;
    processor_info_array_t _cpuInfo, _prevCPUInfo = nil;
    mach_msg_type_number_t _numCPUInfo, _numPrevCPUInfo = 0;
    unsigned _numCPUs;
    NSLock *_cpuUsageLock;
    
    int _mib[2U] = {CTL_HW, HW_NCPU};
    size_t _sizeOfNumCPUs = sizeof(_numCPUs);
    int _status = sysctl(_mib, 2U, &_numCPUs, &_sizeOfNumCPUs, NULL, 0U);
    if (_status)
        _numCPUs = 1;
    
    _cpuUsageLock = [[NSLock alloc] init];
    
    natural_t _numCPUsU = 0U;
    kern_return_t err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &_numCPUsU, &_cpuInfo, &_numCPUInfo);
    if (err == KERN_SUCCESS) {
        [_cpuUsageLock lock];
        
        for (unsigned i = 0U; i < _numCPUs; ++i) {
            CGFloat _inUse, _total = 0;
            if (_prevCPUInfo) {
                _inUse = (
                          (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER]   - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER])
                          + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM])
                          + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE]   - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE])
                          );
                _total = _inUse + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE]);
            } else {
                _inUse = _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE];
                _total = _inUse + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE];
            }
            
            if (_total != 0) {
                cpuUsage += _inUse / _total;
            }
        }
        
        [_cpuUsageLock unlock];
        if (_prevCPUInfo) {
            size_t prevCpuInfoSize = sizeof(integer_t) * _numPrevCPUInfo;
            vm_deallocate(mach_task_self(), (vm_address_t)_prevCPUInfo, prevCpuInfoSize);
        }
        return cpuUsage * kMaxPercent ;
    } else {
        return -1;
    }
}

CPU CPU CPU top CPU CPU

CPU YYCategories UIDevice YYAdd category CPU ySssssssss _prevCPUInfo _numPrevCPUInfo _prevCPUInfo _cpuInfo _prevCPUInfo


@implementation WDTDevice {
    processor_info_array_t _cpuInfo, _prevCPUInfo;
    mach_msg_type_number_t _numCPUInfo, _numPrevCPUInfo;
    NSLock *_cpuUsageLock;
}

- (CGFloat)cpuUsage {
    CGFloat cpuUsage = 0;
    unsigned _numCPUs;
    
    int _mib[2U] = {CTL_HW, HW_NCPU};
    size_t _sizeOfNumCPUs = sizeof(_numCPUs);
    int _status = sysctl(_mib, 2U, &_numCPUs, &_sizeOfNumCPUs, NULL, 0U);
    if (_status)
        _numCPUs = 1;
    
    _cpuUsageLock = [[NSLock alloc] init];
    
    natural_t _numCPUsU = 0U;
    kern_return_t err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &_numCPUsU, &_cpuInfo, &_numCPUInfo);
    if (err == KERN_SUCCESS) {
        [_cpuUsageLock lock];
        
        for (unsigned i = 0U; i < _numCPUs; ++i) {
            CGFloat _inUse, _total = 0;
            if (_prevCPUInfo) {
                _inUse = (
                          (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER]   - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER])
                          + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM])
                          + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE]   - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE])
                          );
                _total = _inUse + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE]);
            } else {
                _inUse = _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE];
                _total = _inUse + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE];
            }
            
            if (_total != 0) {
                cpuUsage += _inUse / _total;
            }
        }
        
        [_cpuUsageLock unlock];
        if (_prevCPUInfo) {
            size_t prevCpuInfoSize = sizeof(integer_t) * _numPrevCPUInfo;
            vm_deallocate(mach_task_self(), (vm_address_t)_prevCPUInfo, prevCpuInfoSize);
        }
        
        _prevCPUInfo = _cpuInfo;
        _numPrevCPUInfo = _numCPUInfo;
        
        _cpuInfo = NULL;
        _numCPUInfo = 0U;

        return cpuUsage * kMaxPercent ;
    } else {
        return -1;
    }
}

100%

host_statistics host_cpu_load_info cpu_ticks CPU cpu_ticks CPU_STATE_USER, CPU_STATE_SYSTEM, CPU_STATE_IDLE CPU_STATE_NICE

+ (CGFloat)cpuUsage {
    kern_return_t kr;
    mach_msg_type_number_t count;
    static host_cpu_load_info_data_t previous_info = {0, 0, 0, 0};
    host_cpu_load_info_data_t info;
    
    count = HOST_CPU_LOAD_INFO_COUNT;
    
    kr = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&info, &count);
    if (kr != KERN_SUCCESS) {
        return -1;
    }
    
    natural_t user   = info.cpu_ticks[CPU_STATE_USER] - previous_info.cpu_ticks[CPU_STATE_USER];
    natural_t nice   = info.cpu_ticks[CPU_STATE_NICE] - previous_info.cpu_ticks[CPU_STATE_NICE];
    natural_t system = info.cpu_ticks[CPU_STATE_SYSTEM] - previous_info.cpu_ticks[CPU_STATE_SYSTEM];
    natural_t idle   = info.cpu_ticks[CPU_STATE_IDLE] - previous_info.cpu_ticks[CPU_STATE_IDLE];
    natural_t total  = user + nice + system + idle;
    previous_info    = info;
    
    return (user + nice + system) * 100.0 / total;
}

info previous_info cpu_ticks idle CPU CPU

CPU iOS top iPhone 5s App Store CPU **** Battery Memory System Status Monitor

CPU

+ (NSUInteger)cpuNumber {
    return [NSProcessInfo processInfo].activeProcessorCount;
}

CPU

CPU CPU CPU 1 Hz

iOS CPU CPU CPU CPU

CPU CPU

+ (NSUInteger)getSysInfo:(uint)typeSpecifier {
    size_t size = sizeof(int);
    int results;
    int mib[2] = {CTL_HW, typeSpecifier};
    sysctl(mib, 2, &results, &size, NULL, 0);
    return (NSUInteger)results;
}

+ (NSUInteger)getCpuFrequency {
    return [self getSysInfo:HW_CPU_FREQ];
}

[self getSysInfo:0Xf] 0Xf HW_CPU_FREQ HW_CPU_FREQ 15.

CPU Apple CPU CPU CPU

static const NSUInteger CPUFrequencyTable[] = {
    [iPhone_1G]         = 412,
    [iPhone_3G]         = 620,
    [iPhone_3GS]        = 600,
    [iPhone_4]          = 800,
    [iPhone_4_Verizon]  = 800,
    [iPhone_4S]         = 800,
    [iPhone_5_GSM]      = 1300,
    [iPhone_5_CDMA]     = 1300,
    [iPhone_5C]         = 1000,
    [iPhone_5S]         = 1300,
    [iPhone_6]          = 1400,
    [iPhone_6_Plus]     = 1400,
    [iPhone_6S]         = 1850,
    [iPhone_6S_Plus]    = 1850,
    [iPod_Touch_1G]     = 400,
    [iPod_Touch_2G]     = 533,
    [iPod_Touch_3G]     = 600,
    [iPod_Touch_4G]     = 800,
    [iPod_Touch_5]      = 1000,
    [iPad_1]            = 1000,
    [iPad_2_CDMA]       = 1000,
    [iPad_2_GSM]        = 1000,
    [iPad_2_WiFi]       = 1000,
    [iPad_3_WiFi]       = 1000,
    [iPad_3_GSM]        = 1000,
    [iPad_3_CDMA]       = 1000,
    [iPad_4_WiFi]       = 1400,
    [iPad_4_GSM]        = 1400,
    [iPad_4_CDMA]       = 1400,
    [iPad_Air]          = 1400,
    [iPad_Air_Cellular] = 1400,
    [iPad_Air_2]        = 1500,
    [iPad_Air_2_Cellular] = 1500,
    [iPad_Pro]          = 2260,
    [iPad_Mini_WiFi]    = 1000,
    [iPad_Mini_GSM]     = 1000,
    [iPad_Mini_CDMA]    = 1000,
    [iPad_Mini_2]       = 1300,
    [iPad_Mini_2_Cellular] = 1300,
    [iPad_Mini_3]       = 1300,
    [iPad_Mini_3_Cellular] = 1300,
    [iUnknown]          = 0
};

MHZSystemMonitor

CPU

extern int freqTest(int cycles);

static double GetCPUFrequency(void)
{
    volatile NSTimeInterval times[500];
    
    int sum = 0;
    
    for(int i = 0; i < 500; i++)
    {
        times[i] = [[NSProcessInfo processInfo] systemUptime];
        sum += freqTest(10000);
        times[i] = [[NSProcessInfo processInfo] systemUptime] - times[i];
    }
    
    NSTimeInterval time = times[0];
    for(int i = 1; i < 500; i++)
    {
        if(time > times[i])
            time = times[i];
    }
    
    double freq = 1300000.0 / time;
    return freq;
}

freqTest cpuFreq.s s

.text
.align 4
.globl _freqTest    

_freqTest:

    push    {r4-r11, lr}

freqTest_LOOP:

    // loop 1
    add     r2, r2, r1
    add     r3, r3, r2
    add     r4, r4, r3
    add     r5, r5, r4
    add     r6, r6, r5
    add     r7, r7, r6
    add     r8, r8, r7
    add     r9, r9, r8
    add     r10, r10, r9
    add     r11, r11, r10
    add     r12, r12, r11
    add     r14, r14, r12
    add     r1, r1, r14

    // loop 2
    add     r2, r2, r1
    add     r3, r3, r2
    add     r4, r4, r3
    add     r5, r5, r4
    add     r6, r6, r5
    add     r7, r7, r6
    add     r8, r8, r7
    add     r9, r9, r8
    add     r10, r10, r9
    add     r11, r11, r10
    add     r12, r12, r11
    add     r14, r14, r12
    add     r1, r1, r14

    // loop 3
    add     r2, r2, r1
    add     r3, r3, r2
    add     r4, r4, r3
    add     r5, r5, r4
    add     r6, r6, r5
    add     r7, r7, r6
    add     r8, r8, r7
    add     r9, r9, r8
    add     r10, r10, r9
    add     r11, r11, r10
    add     r12, r12, r11
    add     r14, r14, r12
    add     r1, r1, r14

    // loop 4
    add     r2, r2, r1
    add     r3, r3, r2
    add     r4, r4, r3
    add     r5, r5, r4
    add     r6, r6, r5
    add     r7, r7, r6
    add     r8, r8, r7
    add     r9, r9, r8
    add     r10, r10, r9
    add     r11, r11, r10
    add     r12, r12, r11
    add     r14, r14, r12
    add     r1, r1, r14

    // loop 5
    add     r2, r2, r1
    add     r3, r3, r2
    add     r4, r4, r3
    add     r5, r5, r4
    add     r6, r6, r5
    add     r7, r7, r6
    add     r8, r8, r7
    add     r9, r9, r8
    add     r10, r10, r9
    add     r11, r11, r10
    add     r12, r12, r11
    add     r14, r14, r12
    add     r1, r1, r14

    // loop 6
    add     r2, r2, r1
    add     r3, r3, r2
    add     r4, r4, r3
    add     r5, r5, r4
    add     r6, r6, r5
    add     r7, r7, r6
    add     r8, r8, r7
    add     r9, r9, r8
    add     r10, r10, r9
    add     r11, r11, r10
    add     r12, r12, r11
    add     r14, r14, r12
    add     r1, r1, r14

    // loop 7
    add     r2, r2, r1
    add     r3, r3, r2
    add     r4, r4, r3
    add     r5, r5, r4
    add     r6, r6, r5
    add     r7, r7, r6
    add     r8, r8, r7
    add     r9, r9, r8
    add     r10, r10, r9
    add     r11, r11, r10
    add     r12, r12, r11
    add     r14, r14, r12
    add     r1, r1, r14

    // loop 8
    add     r2, r2, r1
    add     r3, r3, r2
    add     r4, r4, r3
    add     r5, r5, r4
    add     r6, r6, r5
    add     r7, r7, r6
    add     r8, r8, r7
    add     r9, r9, r8
    add     r10, r10, r9
    add     r11, r11, r10
    add     r12, r12, r11
    add     r14, r14, r12
    add     r1, r1, r14

    // loop 9
    add     r2, r2, r1
    add     r3, r3, r2
    add     r4, r4, r3
    add     r5, r5, r4
    add     r6, r6, r5
    add     r7, r7, r6
    add     r8, r8, r7
    add     r9, r9, r8
    add     r10, r10, r9
    add     r11, r11, r10
    add     r12, r12, r11
    add     r14, r14, r12
    add     r1, r1, r14

    // loop 10
    add     r2, r2, r1
    add     r3, r3, r2
    add     r4, r4, r3
    add     r5, r5, r4
    add     r6, r6, r5
    add     r7, r7, r6
    add     r8, r8, r7
    add     r9, r9, r8
    add     r10, r10, r9
    add     r11, r11, r10
    add     r12, r12, r11
    add     r14, r14, r12
    add     r1, r1, r14

    subs    r0, r0, #1
    bne     freqTest_LOOP
    pop     {r4-r11, pc}

armv7 armv7s 32 Arch64 64 build archive architecture only NO

iPhone 6 CPU 1391614727.725209 HZ 1400 MHZ

AppStore CPU DasherCPU-Dasher-for-iOS

CPU CPU sysctl``sysctl

static inline Boolean WDTCanGetSysCtlBySpecifier(char* specifier, size_t *size) {
    if (!specifier || strlen(specifier) == 0 ||
        sysctlbyname(specifier, NULL, size, NULL, 0) == -1 || size == -1) {
        return false;
    }
    return true;
}

static inline uint64_t WDTGetSysCtl64BySpecifier(char* specifier) {
    size_t size = -1;
    uint64_t val = 0;
    
    if (!WDTCanGetSysCtlBySpecifier(specifier, &size)) {
        return -1;
    }
    
    if (sysctlbyname(specifier, &val, &size, NULL, 0) == -1)
    {
        return -1;
    }

    return val;
}

+ (NSUInteger)cpuMaxFrequency {
    return (NSUInteger)WDTGetSysCtl64BySpecifier("hw.cpufrequency_max");
}

+ (NSUInteger)cpuMinFrequency {
    return (NSUInteger)WDTGetSysCtl64BySpecifier("hw.cpufrequency_min");
}

specifier hw.cpufrequency_max hw.cpufrequency_min sysctlbyname(specifier, NULL, size, NULL, 0)-12700000000HZ MBP 2.7GHZ iOS

CPU Type

iPhone ARM ARM ARMV7ARMV7S ARM64 NXGetLocalArchInfo() NXArchInfo

typedef struct {
    const char *name;
    cpu_type_t cputype;
    cpu_subtype_t cpusubtype;
    enum NXByteOrder byteorder;
    const char *description;
} NXArchInfo;

NXArchInfo cputype cpusubtype mach/machine.h int typedef

mach/machine.h CPU CPU

+ (NSInteger)cpuType {
    return (NSInteger)NXGetLocalArchInfo()->cputype;
}
+ (NSInteger)cpuSubtype {
    return (NSInteger)NXGetLocalArchInfo()->cpusubtype;
}
- (NSString *)p_stringFromCpuType:(NSInteger)cpuType {
    switch (cpuType) {
        case CPU_TYPE_VAX:          return @"VAX";          
        case CPU_TYPE_MC680x0:      return @"MC680x0";      
        case CPU_TYPE_X86:          return @"X86";          
        case CPU_TYPE_X86_64:       return @"X86_64";       
        case CPU_TYPE_MC98000:      return @"MC98000";      
        case CPU_TYPE_HPPA:         return @"HPPA";         
        case CPU_TYPE_ARM:          return @"ARM";          
        case CPU_TYPE_ARM64:        return @"ARM64";        
        case CPU_TYPE_MC88000:      return @"MC88000";      
        case CPU_TYPE_SPARC:        return @"SPARC";        
        case CPU_TYPE_I860:         return @"I860";         
        case CPU_TYPE_POWERPC:      return @"POWERPC";      
        case CPU_TYPE_POWERPC64:    return @"POWERPC64";    
        default:                    return @"Unknown";      
    }
}
- (NSString *)cpuTypeString {
    if (!_cpuTypeString) {
        _cpuTypeString = [self p_stringFromCpuType:[[self class] cpuType]];
    }
    
    return _cpuTypeString;
}

- (NSString *)cpuSubtypeString {
    if (!_cpuSubtypeString) {
        _cpuSubtypeString = [NSString stringWithUTF8String:NXGetLocalArchInfo()->description];
    }
    
    return _cpuSubtypeString;
}

NXArchInfo description CPU cpuSubtypeString cpuSubtype

Memory

RAM CPU - PC iOS iOS Jetsam RAM Jetsam Linux Out-Of-Memory(Killer)

App

mach_task_basic_info Mach task resident_size virtual_size

#define MACH_TASK_BASIC_INFO     20         /* always 64-bit basic info */
struct mach_task_basic_info {
        mach_vm_size_t  virtual_size;       /* virtual memory size (bytes) */
        mach_vm_size_t  resident_size;      /* resident memory size (bytes) */
        mach_vm_size_t  resident_size_max;  /* maximum resident memory size (bytes) */
        time_value_t    user_time;          /* total user run time for
                                               terminated threads */
        time_value_t    system_time;        /* total system run time for
                                               terminated threads */
        policy_t        policy;             /* default policy for new threads */
        integer_t       suspend_count;      /* suspend count for task */
};

task_basic_info mach_task_basic_info Apple task_basic_info

/* localized structure - cannot be safely passed between tasks of differing sizes */
/* Don't use this, use MACH_TASK_BASIC_INFO instead */
struct task_basic_info {
        integer_t       suspend_count;  /* suspend count for task */
        vm_size_t       virtual_size;   /* virtual memory size (bytes) */
        vm_size_t       resident_size;  /* resident memory size (bytes) */
        time_value_t    user_time;      /* total user run time for
                                           terminated threads */
        time_value_t    system_time;    /* total system run time for
                                           terminated threads */
	policy_t	policy;		/* default policy for new threads */
};

task_info API flavor target_task

kern_return_t task_info
(
	task_name_t target_task,
	task_flavor_t flavor,
	task_info_t task_info_out,
	mach_msg_type_number_t *task_info_outCnt
);

App Memory

- (NSUInteger)getResidentMemory
{
    struct mach_task_basic_info info;
    mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
	
	int r = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)& info, & count);
	if (r == KERN_SUCCESS)
	{
		return info.resident_size;
	}
	else
	{
		return -1;
	}
}

App RAM Xcode Debug Gauges memory Debug Gauges MB

WebKit MemoryFootprintCocoa.cpp

size_t memoryFootprint()
{
    task_vm_info_data_t vmInfo;
    mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
    kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
    if (result != KERN_SUCCESS)
        return 0;
    return static_cast<size_t>(vmInfo.phys_footprint);
}

resident_size phys_footprint``phys_footprint task_info

iOS JetSam JetSam kern_memorystatus.c

static boolean_t
memorystatus_kill_hiwat_proc(uint32_t *errors)
{
.....
		/* skip if no limit set */
		if (p->p_memstat_memlimit <= 0) {
			continue;
		}

		footprint_in_bytes = get_task_phys_footprint(p->task);
		memlimit_in_bytes  = (((uint64_t)p->p_memstat_memlimit) * 1024ULL * 1024ULL);	/* convert MB to bytes */
		skip = (footprint_in_bytes <= memlimit_in_bytes);
.....
	return killed;
}

resident_size phys_footprint Xcode Debug Gauges

- (NSUInteger)getApplicationUsedMemory
{
    struct mach_task_basic_info info;
    mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
	
	int r = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)& info, & count);
	if (r == KERN_SUCCESS)
	{
		return info.phys_footprint;
	}
	else
	{
		return -1;
	}
}

CPU task_info API target_task mach_task_self() Mach task flavor MACH_TASK_BASIC_INFO mach_task_basic_info target_task task

NSProcessInfo

[NSProcessInfo processInfo].physicalMemory

Memory

int64_t getUsedMemory()
{
    size_t length = 0;
    int mib[6] = {0};
    
    int pagesize = 0;
    mib[0] = CTL_HW;
    mib[1] = HW_PAGESIZE;
    length = sizeof(pagesize);
    if (sysctl(mib, 2, &pagesize, &length, NULL, 0) < 0)
    {
        return 0;
    }
    
    mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
    
    vm_statistics_data_t vmstat;
    
    if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat, &count) != KERN_SUCCESS)
    {
		return 0;
    }
    
    int wireMem = vmstat.wire_count * pagesize;
    int activeMem = vmstat.active_count * pagesize;
    return wireMem + activeMem;
}

Memory

+ (uint64_t)availableMemory {
    vm_statistics64_data_t vmStats;
    mach_msg_type_number_t infoCount = HOST_VM_INFO_COUNT;
    kern_return_t kernReturn = host_statistics(mach_host_self(),
                                               HOST_VM_INFO,
                                               (host_info_t)&vmStats,
                                               &infoCount);
    
    if (kernReturn != KERN_SUCCESS) {
        return NSNotFound;
    }
        
    return vm_page_size * (vmStats.free_count + vmStats.inactive_count);
}

vm_statistics_data_t 32 Apple 32 vm_statistics64_data_t 64

Startup Time

  • applicationDidFinishLaunching:withOptions:
  • ( Home ) applicationWillEnterForeground:

t(App ) = t1(main()) + t2(main())

t1 = dylib () App

t2 = main AppDelegate applicationDidFinishLaunching:withOptions:

main

CFAbsoluteTime StartTime;

int main(int argc, char * argv[]) {
    @autoreleasepool {
        StartTime = CFAbsoluteTimeGetCurrent();
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

extern CFAbsoluteTime StartTime;
 ...
 
//  applicationDidFinishLaunching:withOptions: 
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"Launched in %f sec", CFAbsoluteTimeGetCurrent() - StartTime);
});

CFAbsoluteTimeGetCurrent()``CFAbsoluteTimeGetCurrent()``NSDate GMT 2001000000CFAbsoluteTimeGetCurrent()s

mach_absolute_time() CPU ticksnsmach_absolute_time()

static uint64_t loadTime;
static uint64_t applicationRespondedTime = -1;
static mach_timebase_info_data_t timebaseInfo;

static inline NSTimeInterval MachTimeToSeconds(uint64_t machTime) {
    return ((machTime / 1e9) * timebaseInfo.numer) / timebaseInfo.denom;
}

@implementation XXStartupMeasurer

+ (void)load {
    loadTime = mach_absolute_time();
    mach_timebase_info(&timebaseInfo);
    
    @autoreleasepool {
        __block id<NSObject> obs;
        obs = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification
                                                                object:nil queue:nil
                                                            usingBlock:^(NSNotification *note) {
            dispatch_async(dispatch_get_main_queue(), ^{
                applicationRespondedTime = mach_absolute_time();
                NSLog(@"StartupMeasurer: it took %f seconds until the app could respond to user interaction.", MachTimeToSeconds(applicationRespondedTime - loadTime));
            });
            [[NSNotificationCenter defaultCenter] removeObserver:obs];
        }];
    }
}

+ load``main``+ load``UIApplicationDidFinishLaunchingNotification``main

FPS

wikipedia FPS(Frames Per Second)

Frame rate (expressed in frames per second or FPS) is the frequency (rate) at which consecutive images called frames are displayed in an animated display. The term applies equally to film and video cameras, computer graphics, and motion capture systems. Frame rate may also be called the frame frequency, and be expressed in hertz.

FPS FPS 50-60

FPS GitHub FPS

@implementation YYFPSLabel {
    CADisplayLink *_link;
    NSUInteger _count;
    NSTimeInterval _lastTime;    
}

- (id)init {
    self = [super init];
    if( self ){        
    _link = [CADisplayLink displayLinkWithTarget:[YYWeakProxy proxyWithTarget:self] selector:@selector(tick:)];
    [_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
        
    }
    return self;
}

- (void)dealloc {
    [_link invalidate];
}

- (void)tick:(CADisplayLink *)link {
    if (_lastTime == 0) {
        _lastTime = link.timestamp;
        return;
    }
    
    _count++;
    NSTimeInterval delta = link.timestamp - _lastTime;
    if (delta < 1) return;
    _lastTime = link.timestamp;
    float fps = _count / delta;
    _count = 0;    
}

YYText Demo YYFPSLabel``CADisplayLink``YYWeakProxy

CADisplayLink FPS FPSCADisplayLink FPS Core Animation RunLoop

Freezing/Lag

iPhone iOS CPUGPU CPU CPU GPUGPU V-Sync

V-Sync iPhone iPhone FrameBuffer GPU V-Sync V-Sync GPU V-Sync

iPhone iPhone CPU GPU V-Sync 1000/60=16.67ms CPU GPU V-Sync

  • FPS FPS FPS
  • RunLoop Hertz

FPS FPS FPS CPU Bugly

Hertz

kCFRunLoopBeforeSources kCFRunLoopAfterWaiting

static void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
    MyClass *object = (__bridge MyClass*)info;
    
    // 
    object->activity = activity;
    
    // 
    dispatch_semaphore_t semaphore = moniotr->semaphore;
    dispatch_semaphore_signal(semaphore);
}

- (void)registerObserver
{
    CFRunLoopObserverContext context = {0,(__bridge void*)self,NULL,NULL};
    CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
                                                            kCFRunLoopAllActivities,
                                                            YES,
                                                            0,
                                                            &runLoopObserverCallBack,
                                                            &context);
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
    
    // 
    semaphore = dispatch_semaphore_create(0);
    
    // 
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        while (YES)
        {
            // 550ms(250ms)
            long st = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 50*NSEC_PER_MSEC));
            if (st != 0)
            {
                if (activity==kCFRunLoopBeforeSources || activity==kCFRunLoopAfterWaiting)
                {
                    if (++timeoutCount < 5)
                        continue;
                    // 
                }
            }
            timeoutCount = 0;
        }
    });
}                                                 

timeoutCount 5

PLCrashReporter

PLCrashReporterConfig *config = [[PLCrashReporterConfig alloc] initWithSignalHandlerType:PLCrashReporterSignalHandlerTypeBSD
                                                                   symbolicationStrategy:PLCrashReporterSymbolicationStrategyAll];
PLCrashReporter *crashReporter = [[PLCrashReporter alloc] initWithConfiguration:config];
NSData *data = [crashReporter generateLiveReport];
PLCrashReport *reporter = [[PLCrashReport alloc] initWithData:data error:NULL];
NSString *report = [PLCrashReportTextFormatter stringValueForCrashReport:reporter
                                                          withTextFormat:PLCrashReportTextFormatiOS];                                                

Network

WIFI4G3G2.5G(Edge)2G WIFI/4G/3G/2.5G/2G Connection Migration DNS DNS App App

NSURLProtocol Hook NSURLProtocol NSURLProtocol URL Loading System FTPHTTPHTTPS CFNetwork

  • TCP
  • DNS
  • SSL
  • HTTP

NSURLProtocol

// canInitWithRequest  canonicalRequestForRequest 
static NSString * const HJHTTPHandledIdentifier = @"hujiang_http_handled";

@interface HJURLProtocol () <NSURLSessionTaskDelegate, NSURLSessionDataDelegate>

@property (nonatomic, strong) NSURLSessionDataTask *dataTask;
@property (nonatomic, strong) NSOperationQueue     *sessionDelegateQueue;
@property (nonatomic, strong) NSURLResponse        *response;
@property (nonatomic, strong) NSMutableData        *data;
@property (nonatomic, strong) NSDate               *startDate;
@property (nonatomic, strong) HJHTTPModel          *httpModel;

@end

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    if (![request.URL.scheme isEqualToString:@"http"] &&
        ![request.URL.scheme isEqualToString:@"https"]) {
        return NO;
    }
    
    if ([NSURLProtocol propertyForKey:HJHTTPHandledIdentifier inRequest:request] ) {
        return NO;
    }
    return YES;
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    
    NSMutableURLRequest *mutableReqeust = [request mutableCopy];
    [NSURLProtocol setProperty:@YES
                        forKey:HJHTTPHandledIdentifier
                     inRequest:mutableReqeust];
    return [mutableReqeust copy];
}

- (void)startLoading {
    self.startDate                                        = [NSDate date];
    self.data                                             = [NSMutableData data];
    NSURLSessionConfiguration *configuration              = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.sessionDelegateQueue                             = [[NSOperationQueue alloc] init];
    self.sessionDelegateQueue.maxConcurrentOperationCount = 1;
    self.sessionDelegateQueue.name                        = @"com.hujiang.wedjat.session.queue";
    NSURLSession *session                                 = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:self.sessionDelegateQueue];
    self.dataTask                                         = [session dataTaskWithRequest:self.request];
    [self.dataTask resume];

    httpModel                                             = [[NEHTTPModel alloc] init];
    httpModel.request                                     = self.request;
    httpModel.startDateString                             = [self stringWithDate:[NSDate date]];

    NSTimeInterval myID                                   = [[NSDate date] timeIntervalSince1970];
    double randomNum                                      = ((double)(arc4random() % 100))/10000;
    httpModel.myID                                        = myID+randomNum;
}

- (void)stopLoading {
    [self.dataTask cancel];
    self.dataTask           = nil;
    httpModel.response      = (NSHTTPURLResponse *)self.response;
    httpModel.endDateString = [self stringWithDate:[NSDate date]];
    NSString *mimeType      = self.response.MIMEType;
    
    //  response
}

#pragma mark - NSURLSessionTaskDelegate

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    if (!error) {
        [self.client URLProtocolDidFinishLoading:self];
    } else if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) {
    } else {
        [self.client URLProtocol:self didFailWithError:error];
    }
    self.dataTask = nil;
}

#pragma mark - NSURLSessionDataDelegate

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data {
    [self.client URLProtocol:self didLoadData:data];
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
    completionHandler(NSURLSessionResponseAllow);
    self.response = response;
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler {
    if (response != nil){
        self.response = response;
        [[self client] URLProtocol:self wasRedirectedToRequest:request redirectResponse:response];
    }
}

Hertz NSURLProtocol NSURLProtocol NSURLConnectionDelegate

Hook

Hook RUM: Real User Monitoring

AOP(Aspect Oriented Programming) OOP AOP AOP

iOS AOP Objective-C Runtime Hook Method Swizzling****NSProxy Fishhook Objective-C NSURLConnection NSURLSession Fishhook C CFNetwork

hook

Method Swizzling

Method swizzling Objective-C Runtime Class Dispatch Table Dispatch Table SEL IMP C Method Swizzling SEL IMP

Method swizzling

NSProxy

NSProxy is an abstract superclass defining an API for objects that act as stand-ins for other objects or for objects that dont exist yet. Typically, a message to a proxy is forwarded to the real object or causes the proxy to load (or transform itself into) the real object. Subclasses of NSProxy can be used to implement transparent distributed messaging (for example, NSDistantObject) or for lazy instantiation of objects that are expensive to create.

Apple NSProxy NSProxy NSObject -forwardInvocation: -methodSignatureForSelector: NSProxy target

Method swizzling NSURLConnectionDelegate NSURLSessionDelegate Method swizzling NSProxy proxy delegate NSURLConnection NSURLSession delegate proxy delegate hook proxy proxy delegate hook delegate

Fishhook

fishhook Facebook C fishhook C CFNetwork CoreFoundation CFNetwork

iOS hook NSURLConnection``NSURLSession CFNetwork

NSURLConnection

NSURLSession

CFNetwork

NeteaseAPM CFNetwork CoreFoundation Framework CFStream Proxy Stream CFStream Original Stream

CFNetwork C C Hook Dynamic Loader Hook - fishhook

Dynamic Loaderdyld Mach-O Runtime C fishhook __DATA segment __nl_symbol_ptr __la_symbol_ptr section Indirect Symbol TableSymbol Table String Table hook

CFNetwork CFReadStreamRef hook read read stream hook

HTTP CFReadStream CFReadStreamNeteaseAPM HTTP Stream NSInputStream ProxyStream CFReadStream HTTP Stream

NSObject NSInputStream Proxy NSInputStream OriginalStream Proxy OriginalStream NSInputStream read:maxLength: stream XXInputStreamProxy

- (instancetype)initWithStream:(id)stream {
    if (self = [super init]) {
        _stream = stream;
    }
    return self;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [_stream methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    [anInvocation invokeWithTarget:_stream];
}
                                                        

NSInputStream read:maxLength:

- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len {
    NSInteger readSize = [_stream read:buffer maxLength:len];
    //  readSize
    return readSize;
}                                                   

XX_CFReadStreamCreateForHTTPRequest CFReadStreamCreateForHTTPRequest


static CFReadStreamRef (*original_CFReadStreamCreateForHTTPRequest)(CFAllocatorRef __nullable alloc,
                                                                    CFHTTPMessageRef request);
                         
/**
 XXInputStreamProxy  original CFReadStreamRef original CFReadStreamRef
  read 
 */
static CFReadStreamRef XX_CFReadStreamCreateForHTTPRequest(CFAllocatorRef alloc,
                                                           CFHTTPMessageRef request) {
    // 
    CFReadStreamRef originalCFStream = original_CFReadStreamCreateForHTTPRequest(alloc, request);
    //  CFReadStreamRef  NSInputStream XXInputStreamProxy CFReadStreamRef
    NSInputStream *stream = (__bridge NSInputStream *)originalCFStream;
    XXInputStreamProxy *outStream = [[XXInputStreamProxy alloc] initWithClient:stream];
    CFRelease(originalCFStream);
    CFReadStreamRef result = (__bridge_retained CFReadStreamRef)outStream;
    return result;
}                                                             
                                                        

fishhook

void save_original_symbols() {
    original_CFReadStreamCreateForHTTPRequest = dlsym(RTLD_DEFAULT, "CFReadStreamCreateForHTTPRequest");
}                                                      
rebind_symbols((struct rebinding[1]){{"CFReadStreamCreateForHTTPRequest", XX_CFReadStreamCreateForHTTPRequest, (void *)& original_CFReadStreamCreateForHTTPRequest}}, 1);                                                    

CFNetwork API fishhook Proxy Stream C

NSURLSessionTaskMetrics/NSURLSessionTaskTransactionMetrics

Apple iOS 10 NSURLSessionTaskDelegate -URLSession: task:didFinishCollectingMetrics: NSURLSessionTaskMetrics DNS /TCP /TLS /

/*
 * Sent when complete statistics information has been collected for the task.
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

NSURLSessionTaskMetrics

NSURLSessionTaskMetrics session task NSURLSessionTaskMetrics taskInterval redirectCount /

  • transactionMetrics:transactionMetrics /

     /*
      * transactionMetrics array contains the metrics collected for every request/response transaction created during the task execution.
      */
     @property (copy, readonly) NSArray<NSURLSessionTaskTransactionMetrics *> *transactionMetrics;
    
  • taskInterval:

     /*
      * Interval from the task creation time to the task completion time.
      * Task creation time is the time when the task was instantiated.
      * Task completion time is the time when the task is about to change its internal state to completed.
      */
     @property (copy, readonly) NSDateInterval *taskInterval;
    
  • redirectCount:

     /*
      * redirectCount is the number of redirects that were recorded.
      */
     @property (assign, readonly) NSUInteger redirectCount;
    

NSURLSessionTaskTransactionMetrics

NSURLSessionTaskTransactionMetrics request response HTTP fetchStartDate responseEndDate networkProtocolName resourceFetchType

  • request:

     /*
      * Represents the transaction request.
      */
     @property (copy, readonly) NSURLRequest *request;
    
  • response:response nil

     /*
      * Represents the transaction response. Can be nil if error occurred and no response was generated.
      */
     @property (nullable, copy, readonly) NSURLResponse *response;
    
  • networkProtocolName: ALPN h2, http/1.1, spdy/3.1

     @property (nullable, copy, readonly) NSString *networkProtocolName;
    
  • isProxyConnection:

     /*
      * This property is set to YES if a proxy connection was used to fetch the resource.
      */
     @property (assign, readonly, getter=isProxyConnection) BOOL proxyConnection;
    
  • isReusedConnection:

     /*
      * This property is set to YES if a persistent connection was used to fetch the resource.
      */
     @property (assign, readonly, getter=isReusedConnection) BOOL reusedConnection;
    
  • resourceFetchType:NSURLSessionTaskMetricsResourceFetchType

     /*
      * Indicates whether the resource was loaded, pushed or retrieved from the local cache.
      */
     @property (assign, readonly) NSURLSessionTaskMetricsResourceFetchType resourceFetchType;
    

NSDate EndDate nil DNS domainLookupStartDate domainLookupEndDate nil

HTTP

nil

  • domainLookupStartDate

  • domainLookupEndDate

  • connectStartDate

  • connectEndDate

  • secureConnectionStartDate

  • secureConnectionEndDate

  • fetchStartDate:

     @property (nullable, copy, readonly) NSDate *fetchStartDate;
    
  • domainLookupStartDate:DNS Domain -> IP

     /*
      * domainLookupStartDate returns the time immediately before the user agent started the name lookup for the resource.
      */
     @property (nullable, copy, readonly) NSDate *domainLookupStartDate;
    
  • domainLookupEndDate:DNS IP

     /*
      * domainLookupEndDate returns the time after the name lookup was completed.
      */
     @property (nullable, copy, readonly) NSDate *domainLookupEndDate;
    
  • connectStartDate: TCP

     /*
      * connectStartDate is the time immediately before the user agent started establishing the connection to the server.
      *
      * For example, this would correspond to the time immediately before the user agent started trying to establish the TCP connection.
      */
     @property (nullable, copy, readonly) NSDate *connectStartDate;
    
    • secureConnectionStartDate:HTTPS TLS

       /*
        * If an encrypted connection was used, secureConnectionStartDate is the time immediately before the user agent started the security handshake to secure the current connection.
        *
        * For example, this would correspond to the time immediately before the user agent started the TLS handshake.
        *
        * If an encrypted connection was not used, this attribute is set to nil.
        */
       @property (nullable, copy, readonly) NSDate *secureConnectionStartDate;
      
    • secureConnectionEndDate:HTTPS TLS

       /*
        * If an encrypted connection was used, secureConnectionEndDate is the time immediately after the security handshake completed.
        *
        * If an encrypted connection was not used, this attribute is set to nil.
        */
       @property (nullable, copy, readonly) NSDate *secureConnectionEndDate;
      
  • connectEndDate: TCP TLS

     /*
      * connectEndDate is the time immediately after the user agent finished establishing the connection to the server, including completion of security-related and other handshakes.
      */
     @property (nullable, copy, readonly) NSDate *connectEndDate;
    
  • requestStartDate: HTTP header

     /*
      * requestStartDate is the time immediately before the user agent started requesting the source, regardless of whether the resource was retrieved from the server or local resources.
      *
      * For example, this would correspond to the time immediately before the user agent sent an HTTP GET request.
      */
     @property (nullable, copy, readonly) NSDate *requestStartDate;
    
  • requestEndDate:HTTP

     /*
      * requestEndDate is the time immediately after the user agent finished requesting the source, regardless of whether the resource was retrieved from the server or local resources.
      *
      * For example, this would correspond to the time immediately after the user agent finished sending the last byte of the request.
      */
     @property (nullable, copy, readonly) NSDate *requestEndDate;
    
  • responseStartDate:

     /*
      * responseStartDate is the time immediately after the user agent received the first byte of the response from the server or from local resources.
      *
      * For example, this would correspond to the time immediately after the user agent received the first byte of an HTTP response.
      */
     @property (nullable, copy, readonly) NSDate *responseStartDate;
    
  • responseEndDate:

     /*
      * responseEndDate is the time immediately after the user agent received the last byte of the resource.
      */
     @property (nullable, copy, readonly) NSDate *responseEndDate;
    

Traffic

APM

HTTP HTTP CR + LF

POST /q HTTP/1.1
Host: get.sogou.com
Content-Type: application/octet-stream
Connection: keep-alive
Accept: */*
User-Agent: SogouServices (unknown version) CFNetwork/811.5.4 Darwin/16.7.0 (x86_64)
Content-Length: 854
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate

u=pJcIsbkG1m3U+6MUE4njAru+inspyRuhE6TjK4eHiygLzcF9T84jjnLwJt4ZYhqdvoYRTmeMUgo4yiaDnuEn/w==&g=HqdloJ9a3HetZyhU87uuHeYXnFxb9z0PynKAvmO/s0iG3NiGKanztmA8ZLv82ILg1aZUFJwwvmfouA+DT2cYtg==&p=lf+gqqMorInY9pCBwEd+Ecy6akrYsRRLUaoToCFhmqlO5lsE9Am672UbGU9HanDWj44qFi+AMx+hnuWpMnZhe4xLTyItF8WH15TXYZ2+53t7VfzG/ORosrHkcU2vyMm2Z1lWiGnMZL9pDXqYaHDniE7fiDq0F3qfNvbOTPPNStroqv2UZPJWcX3ZCK5axd1/yBYq5Dhj8JREkO8MeO/qZNV/YY6mA7paq6nTnKKsJJQnSs7wpOCXosQKHOYtidziDmzf5vs+2e8vAGGOZmzlDlwyiaRFocYjPZ0Nxks9VQVCK67UKDNrZeU7xrebocq6&k=I1D5ztcMZZq/x3oJV9X43CxNhLfXXkln/ytlXa5LxKo1iFMjZtiuqbTDNA+jP4rCvlRdxdRwgvqpi6PvvZywfLS+KqGsik9csxxLgatJHkPhFXmGRQZlrl9vm8e2foTH7BmzUb/vhH/Y4s3FgBQylGj9l/A3/8VOuPFArCC2wzA=&v=ua/DxZwfrnDzy5Oo79+dblQ66uuUP3NmBKo7HbJwQIrvnlqw/lUcE54w310UB0VXpa6A8qZFJCeAa4vmAJRJaqkJfUkhX6z/kEE/kybSlqZaYl+KETwymNgVDvbf6On7tsGWU1HcxGZo/UN2aEnV3tWAAfhKGC3RliQfiwsTSFo=

iOS NSURLRequest allHTTPHeaderFields HTTPBody allHTTPHeaderFields Cookie Cookie CFNetwork framework CFNetwork HTTP HTTPMessage C++

int HTTPMessage::copySerializedMessage()() {
    edi = arg_0;
    esi = HTTPMessage::copySerializedHeaders(edi);
    ebx = 0x0;
    if (esi != 0x0) {
            eax = *(edi + 0x18);
            if (eax != 0x0) {
                    ebx = HTTPBodyData::getLength();
                    var_14 = ebx;
                    ebx = CFDataCreateMutableCopy(CFGetAllocator(edi + 0xfffffff8), CFDataGetLength(esi) + ebx, esi);
                    CFRelease(esi);
                    eax = HTTPBodyData::getBytePtr();
                    CFDataAppendBytes(ebx, eax, var_14);
            }
            else {
                    ebx = esi;
            }
    }
    eax = ebx;
    return eax;
}

HTTPMessage::copySerializedHeaders HTTPHeaderDict::serializeHeaders HTTPBodyData

allHTTPHeaderFields -[NSHTTPCookieStorage cookiesForURL:] URL Cookie -[NSHTTPCookie requestHeaderFieldsWithCookies:cookies] Cookie allHTTPHeaderFields

- (NSUInteger)p_getRequestLength {
    NSDictionary<NSString *, NSString *> *headerFields = _request.allHTTPHeaderFields;
    NSDictionary<NSString *, NSString *> *cookiesHeader = [self p_getCookies];
    if (cookiesHeader.count) {
        NSMutableDictionary *headerFieldsWithCookies = [NSMutableDictionary dictionaryWithDictionary:headerFields];
        [headerFieldsWithCookies addEntriesFromDictionary:cookiesHeader];
        headerFields = [headerFieldsWithCookies copy];
    }
    
    NSUInteger headersLength = [self p_getHeadersLength:headerFields];
    NSUInteger bodyLength = [_request.HTTPBody length];
    return headersLength + bodyLength;
}

- (NSUInteger)p_getHeadersLength:(NSDictionary *)headers {
    NSUInteger headersLength = 0;
    if (headers) {
        NSData *data = [NSJSONSerialization dataWithJSONObject:headers
                                                       options:NSJSONWritingPrettyPrinted
                                                         error:nil];
        headersLength = data.length;
    }
    
    return headersLength;
}

- (NSDictionary<NSString *, NSString *> *)p_getCookies {
    NSDictionary<NSString *, NSString *> *cookiesHeader;
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    NSArray<NSHTTPCookie *> *cookies = [cookieStorage cookiesForURL:_request.URL];
    if (cookies.count) {
         cookiesHeader = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
    }
    return cookiesHeader;
}

NSHTTPURLResponse allHeaderFields expectedContentLength expectedContentLength NSURLResponseUnknownLength(-1) Content-Length

- (int64_t)p_getResponseLength {
    int64_t responseLength = 0;
    if (_response && [_response isKindOfClass:[NSHTTPURLResponse class]]) {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)_response;
        NSDictionary<NSString *, NSString *> *headerFields = httpResponse.allHeaderFields;
        NSUInteger headersLength = [self p_getHeadersLength:headerFields];
        int64_t contentLength = (httpResponse.expectedContentLength != NSURLResponseUnknownLength) ?
        httpResponse.expectedContentLength :
        _dataLength;
        responseLength = headersLength + contentLength;
    }
    return responseLength;
}

expectedContentLength NSURLResponseUnknownLength expectedContentLength _dataLength``_dataLength

- (void)wtn_URLSession:(NSURLSession *)session
              dataTask:(NSURLSessionDataTask *)dataTask
        didReceiveData:(NSData *)data {
    WTNHTTPTransactionMetrics *httpTransaction = dataTask.httpTransaction;
    httpTransaction.dataLength += data.length;
    
    if ([self.originalDelegate respondsToSelector:@selector(URLSession:dataTask:didReceiveData:)]) {
        [(id)self.originalDelegate URLSession:session dataTask:dataTask didReceiveData:data];
    }
}


- (NSURLSessionDataTask *)wtn_dataTaskWithRequest:(NSURLRequest *)request
                                completionHandler:(void (^)(NSData * _Nullable data,
                                                            NSURLResponse * _Nullable response,
                                                            NSError * _Nullable error))completionHandler {
    WTNHTTPTransactionMetrics *httpTransaction = [WTNHTTPTransactionMetrics new];
    
    

    if (completionHandler) {
        wrappedCompletionHandler = ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            httpTransaction.dataLength = data.length;
        };
    }
    
    

    return dataTask;
}

wtn_URLSession:dataTask:didReceiveData hook +=``wtn_dataTaskWithRequest:completionHandler: hook wtn_uploadTaskWithRequest:fromData:completionHandler:``wtn_uploadTaskWithRequest:fromFile:completionHandler

Power consumption

iOS App

UIDevice API
IOKit

UIDevice

UIDevice batteryMonitoringEnabled YES batteryState batteryLevel

  • NO

    // default is NO             
    @property(nonatomic,getter=isBatteryMonitoringEnabled) BOOL batteryMonitoringEnabled NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED;                
    
  • 0-1.0 batteryState UIDeviceBatteryStateUnknown -1.0

    // 0 .. 1.0. -1.0 if UIDeviceBatteryStateUnknown
    @property(nonatomic,readonly) float batteryLevel NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED; 
    
  • UIDeviceBatteryState

    // UIDeviceBatteryStateUnknown if monitoring disabled
    @property(nonatomic,readonly) UIDeviceBatteryState batteryState NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED;  
    
    typedef NS_ENUM(NSInteger, UIDeviceBatteryState) {
        UIDeviceBatteryStateUnknown,
        UIDeviceBatteryStateUnplugged,   // on battery, discharging
        UIDeviceBatteryStateCharging,    // plugged in, less than 100%
        UIDeviceBatteryStateFull,        // plugged in, at 100%
    } __TVOS_PROHIBITED;              // available in iPhone 3.0
    
  [UIDevice currentDevice].batteryMonitoringEnabled = YES;
  [[NSNotificationCenter defaultCenter]
 addObserverForName:UIDeviceBatteryLevelDidChangeNotification
 object:nil queue:[NSOperationQueue mainQueue]
 usingBlock:^(NSNotification *notification) {
     // Level has changed
     NSLog(@"Battery Level Change");
     NSLog(@"%.2f", [UIDevice currentDevice].batteryLevel);
 }];                         

UIDevice iOS 8.0 batteryLevel 5% iOS 8.0 1%

IOKit

IOKit iOS 1%

- (double)getBatteryLevel {
    // returns a blob of power source information in an opaque CFTypeRef
    CFTypeRef blob = IOPSCopyPowerSourcesInfo();
    // returns a CFArray of power source handles, each of type CFTypeRef
    CFArrayRef sources = IOPSCopyPowerSourcesList(blob);
    CFDictionaryRef pSource = NULL;
    const void *psValue;
    // returns the number of values currently in an array
    int numOfSources = CFArrayGetCount(sources);
    // error in CFArrayGetCount
    if (numOfSources == 0) {
        NSLog(@"Error in CFArrayGetCount");
        return -1.0f;
    }

    // calculating the remaining energy
    for (int i=0; i<numOfSources; i++) {
        // returns a CFDictionary with readable information about the specific power source
        pSource = IOPSGetPowerSourceDescription(blob, CFArrayGetValueAtIndex(sources, i));
        if (!pSource) {
            NSLog(@"Error in IOPSGetPowerSourceDescription");
            return -1.0f;
        }
        psValue = (CFStringRef) CFDictionaryGetValue(pSource, CFSTR(kIOPSNameKey));

        int curCapacity = 0;
        int maxCapacity = 0;
        double percentage;

        psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSCurrentCapacityKey));
        CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);

        psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSMaxCapacityKey));
        CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);

        percentage = ((double) curCapacity / (double) maxCapacity * 100.0f);
        NSLog(@"curCapacity : %d / maxCapacity: %d , percentage: %.1f ", curCapacity, maxCapacity, percentage);
        return percentage;
    }
    return -1.0f;
}                                        

iOSDiagnosticsSupport Runtime MBSDevice copyPowerLogsToDir: PLBLMAccountingService_Aggregate_BLMAppEnergyBreakdown iOS iOS-Diagnostics

SQL

SELECT datetime(timestamp, 'unixepoch') AS TIME, BLMAppName FROM PLBLMAccountingService_Aggregate_BLMAppEnergyBreakdown WHERE BLMEnergy_BackgroundLocation > 0  ORDER BY TIME

iOSDiagnosticsSupport Framework iOS 10 DiagnosticsSupport MBSDevice

Author

Twitter: @aozhimin

Email: [email protected]


Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
Ios (18,917
Hooks (2,728
Monitor (1,050
Cpu (802
Memory (783
Fps (227
Related Projects