30 Sep 2014
在Eclipse下编译AIDL基本不用做什么特殊的工作,Eclipse都帮你完成了。但是如果需要在Android Source下编译AIDL,就需要你在Android.mk中加上AIDL文件声明。
LOCAL_SRC_FILES = \
$(call all-java-files-under, src) \
src/net/lnmcc/service/IMyService.aidl
29 Sep 2014
Low Memory Killer(LMK)
在用户空间中指定了一组内存临界值,当其中的某个值与进程描述中的oom_adj
值在同一范围时,该进程将被Kill掉。
LMK的策略记录在下面两个文件中:
- /sys/module/lowmemorykiller/parameters/adj
这个文件指定了发生LMK时,需要kill掉的进程号区间。
- /sys/module/lowmemorykiller/parameters/minfree
这个文件中储存了将导致调用LMK的空闲页面数量值。
看一个例子
adj文件的内容为:
0,58,117,176,529,1000
minfree文件的内容为:
12288,15360,18432,21504,24576,30720
这里些数组的具体含义是指:
当一个进程的空闲空间下降到了30720个页面时,系统将kill掉进程号 >= 1000的进程;
当一个进程的空闲空间下降到了24587个页面时,系统将kill掉进程号 >= 529的进程;
… …
怎样让你的App不被KML
你可以在AndroidManifest.xml
中的Application中增加属性
android:persistent="true"
这个属性会把你的APP提升为Android核心级别,在这个级别上的APP,即使你用ps -9也无法kill掉它(它会立刻重启)。
但是这个方法有一个限制,就是你的APP需要是系统APP,也就是说需要被push到/system/app/或者/system/priv-app/
下,否则android:persistent="true"
这个属性不会生效。
当你为你的APP设置了persistent后,查看一下你的APP的oom_adj值:
cat /proc/3730/oom_adj #3730为你APP的PID
我的APP的oom_adj值为-12,从上面的LMK策略可以看到LMK将永远不会kill一个oom_adj < 0
的进程,实际上它是一个CORE_SERVICE_ADJ
.
(ps:源码路径frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
)
27 Sep 2014
默认情况下vim使用的贪婪匹配,但是有时候我们需要的是最小匹配,通过 :h non-greedy
查看文档发现vim可以通过下面的方式来启用最小匹配:
使用 " \{-} "来替代通配符 "*"
比如有一个文件内容如下:
(a + b) + c)
现在需要把(a + b)替换成 x
贪婪匹配
:1,$s/(.*)/x/g
上面的命令会把文件内容替换成了:
x
因为是贪婪匹配,所有这里的表达式 (.*) 匹配到了第二个右括号。
最小匹配
:1,$s/(.\{-})/x/g
结果文件内容变成了:
x + c)
可以看出这里表达式 (.{-} 只匹配了第一个右括号。
22 Sep 2014
objective-c中对一个类的扩展除了使用常见的继承外还提供了一种独特的方法:分类(Category)。
先看一个使用分类扩展类的小例子:
将被扩展的类:
#import <Foundation/Foundation.h>
@interface Fraction : NSObject
{
int numerator;
int denominator;
}
@property int numerator, denominator;
-(void) setTo: (int)n over: (int)d;
-(void) print;
@end
@implementation Fraction
-(void) setTo:(int)n over:(int)d
{
numerator = n;
denominator = d;
}
-(void) print
{
NSLog(@"%d / %d", numerator, denominator);
}
@end
使用obj-c的分类语法扩展Fraction类:
#import <Foundation/Foundation.h>
#import "Fraction.h"
@interface Fraction (MathOps)
-(Fraction*) add: (Fraction*)f;
-(Fraction*) mul: (Fraction*)f;
-(Fraction*) sub: (Fraction*)f;
-(Fraction*) div: (Fraction*)f;
@end
@implementation Fraction (MathOps)
-(Fraction*) add:(Fraction *)f
{
Fraction *result = [[Fraction alloc]init];
int resultNum, resultDenom;
resultNum = (numerator * f->denominator) + (denominator * f->numerator);
resultDenom = denominator * f->denominator;
[result setTo:resultNum over:resultDenom];
return result;
}
@end
分类的特点:
- 只能扩展类的方法,不能扩展变量,否则还得用继承
- 一个类一旦被分类扩展了,也会影响他的所有子类
- 不要使用分类去重写被扩展类的方法,一旦这样做了,你将再也不能访问到原方法了,并不像继承那样可以使用super来访问原方法
- 可以不必实现全部的分类方法,上例中的mul,sub,div没有实现,仅仅是声明一下,可以留待以后去实现
20 Sep 2014
接上文 「Android电源管理-Healthd (1)」
adb shell进入到/sys/class/power_supply
目录,我们可以看到power_supply驱动创建的一些运行时文件(我的设备是Nuxus 7, Android 4.4.2, kernel 3.4.0):
adb root
adb shell
cd /sys/class/power_supply
ll
输出如下:
lrwxrwxrwx root root 2014-09-19 14:30 ac -> ../../devices/i2c-0/0-0055/power_supply/ac
lrwxrwxrwx root root 2014-09-19 14:30 battery -> ../../devices/i2c-0/0-0055/power_supply/battery
lrwxrwxrwx root root 2014-09-19 14:30 usb -> ../../devices/i2c-0/0-0055/power_supply/usb
lrwxrwxrwx root root 2014-09-19 14:30 wireless -> ../../devices/i2c-0/0-0055/power_supply/wireless
看文件名称就能知道其含义,但是问题是这里一下子列出了4种电源类型,Android系统究竟是怎么判断当前使用的是那一种呢?要回答这个问题,我们不妨进入其中任一个文件夹,看看里面记录的是些什么。
cd usb
ls
输出如下:
lrwxrwxrwx root root 2014-09-20 22:03 device -> ../../../0-0055
-r--r--r-- root root 4096 2014-09-19 14:30 online
drwxr-xr-x root root 2014-09-20 22:03 power
lrwxrwxrwx root root 2014-09-20 22:03 subsystem -> ../../../../../class/power_supply
-r--r--r-- root root 4096 2014-09-19 18:24 type
-rw-r--r-- root root 4096 2014-09-20 22:03 uevent
查看online文件,发现里面的值为1,这是因为我的设备正在使用USB电源,此时如果查看ac或者wireless文件夹中的online文件,你会发现其值为0;
再查看type文件,发现里面的值为USB,这个文件记录了对于的名称。
所以Android系统对当前电源类型的判别逻辑是这样的:
-
遍历所有系统支持的电源方式
-
查看online的值,值为1即是当前电源方式
回到代码,我们看看是不是真的这样做的呢
查看system/core/healthd/BatteryMonitor.cpp
关注下面的片段:
for (i = 0; i < mChargerNames.size(); i++) {
String8 path;
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
if (readFromFile(path, buf, SIZE) > 0) {
if (buf[0] != '0') {
path.clear();
path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
switch(readPowerSupplyType(path)) {
case ANDROID_POWER_SUPPLY_TYPE_AC:
props.chargerAcOnline = true;
break;
case ANDROID_POWER_SUPPLY_TYPE_USB:
props.chargerUsbOnline = true;
break;
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
props.chargerWirelessOnline = true;
break;
default:
KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
mChargerNames[i].string());
}
}
}
}
其中POWER_SUPPLY_SYSFS_PATH的定义为:
#define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
上面的代码很容易理解,当遍历所有支持的电源类型(存储在mChargerNames),当发现其中online文件记录的值不为0的时候,再通过其type文件读取其类型名,并把props结构体中对应的字段设置成true
。
注意这个props变量很关键,它的类型为BatteryProperties,它记录并传递关于电源的许多信息。
BatteryProperties的定义在frameworks/native/include/batteryservice/BatteryService.h
,下回就看看这个文件。