打开调试信息
需要打开logcat的日志,在所有头文件前面添加(后面的头文件会包含< utils/Log.h > ,其中会根据以下宏的取值打开或者关闭打印):
#define LOG_TAG “AndroidRuntime”
#undef NDEBUG //打开LOGV/LOGI/LOGD
#define LOG_NDEBUG 0 //打开LOGV,为1时表示禁止
#define LOG_NIDEBUG 0 //打开LOGI,为1时表示禁止
#define LOG_NDDEBUG 0 //打开LOGD,为1时表示禁止
对于安卓源码中需要打印到/proc/kmsg(dmesg)中的日志,比如uenvent.c中的日志,需要修改
system/core/include/cutils/klog.h文件中的打印等级,且打印等级必须高于内核中/kernel/printk.c的设置等级:
#define KLOG_DEFAULT_LEVEL 3
驱动设备测试
可以通过在/sys下添加读写测试节点测试驱动好坏:
struct pn544_dev *g_pn544_dev;
static ssize_t pn544_test_write(struct kobject *kobj,struct kobj_attribute *attr,
const char *buf, size_t n)
{
unsigned char count,i;
unsigned char getdata[10];
ssize_t ret;
const char *buftmp = buf;
sscanf(buftmp, "%x %x %x %x %x %x %x %x %x %x %x", &count,
&getdata[0], &getdata[1], &getdata[2], &getdata[3],&getdata[4],
&getdata[5], &getdata[6], &getdata[7], &getdata[8],&getdata[9]);
ret = i2c_master_send(g_pn544_dev->client, getdata, count);
if (ret != count)
{
pr_err("%s : i2c_master_send returned %d\n", __func__, ret);
ret = -EIO;
return ret;
}
printk("write %d bytes success:", count);
for(i = 0 ; i < count ; i++)
printk("%x ", getdata[i]);
printk("\n");
return n;
}
static ssize_t pn544_test_read(struct kobject *kobj, struct kobj_attribute *attr,char *buf)
{
unsigned char i;
unsigned char getdata[10];
ssize_t ret;
ret = i2c_master_recv(g_pn544_dev->client, getdata, 10);
if (ret < 0)
{
pr_err("%s: i2c_master_recv returned %d\n", __func__, ret);
return ret;
}
if (ret > 10)
{
pr_err("%s: received too many bytes from i2c (%d)\n", __func__, ret);
ret = -EIO;
return ret;
}
printk("read %d bytes success:", ret);
for(i = 0 ; i < ret ; i++)
printk("%x ", getdata[i]);
printk("\n");
sprintf(buf, "Read %d bytes success :%x %x %x %x %x %x x %x %x %x %x\n", ret ,
getdata[0], getdata[1], getdata[2], getdata[3], getdata[4],
getdata[5], getdata[6], getdata[7], getdata[8], getdata[9]);
return ret;
}
static struct kobject *pn544_kobj;
struct pn544_attribute {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n);
};
static struct pn544_attribute pn544_attrs[] = {
/* node_name permision show_func store_func */
__ATTR(pn544_test, S_IRUSR | S_IWUSR, pn544_test_read, pn544_test_write),
};
/* probe函数中添加: */
g_pn544_dev = pn544_dev;
pn544_kobj = kobject_create_and_add("pn544_test", NULL);
if (!pn544_kobj)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(pn544_attrs); i++) {
ret = sysfs_create_file(pn544_kobj, &pn544_attrs[i].attr);
if (ret != 0) {
printk("create index %d error\n", i);
return ret;
}
}
mm -jn单独编译模块(重新编译用mm -B -jn,自动编译依赖使用mma -B -jn)
单独编译模块,可以打开Android.mk查看目标模块的名字,以找到模块对应的.jar或者.so
当存在多个模块名的时候,请注意模块所包含的源文件和编译最后的Install命令,看产生了什么.jar或者.so
如果Android.mk中没有LOCAL_MODULE,或者mm之后没有产生Install文件,说明需要在上一级目录编译
生成的.jar或者.so可以通过以下命令进行推送调试
adb root
adb remount rw(失败时可以先进入shell,执行mount -o remount rw /)
注意remount后的分区必须为ext格式才能使用chmod更改权限,其他如fat32分区虽然不报错,也不会有效果
adb push a.jar /system/lib/…
adb reboot
make snod 可以重新打包system.img
编译清理
严格性依次为
make clean-module_name 清除单个模块
make installclean 删除out目录下的install文件,由于system.img文件大部分并非通过依赖关系生成,而是通过打包生成,因此改动了编译mk规则之后,经常需要清除out目录下的目标文件,重新make
make clean 清理,不解释
make clobber 清理包括编译配置信息,更加彻底
清理之后需要 lunch来进行编译项选择
lunch命令选项
user
仅安装标签为 user 的模块
设定属性 ro.secure=1,打开安全功能
设定属性 ro.adb.secure=1,需要adb调试身份校验
设定属性 ro.debuggable=0,关闭应用调试功能,不允许通过adb root获取root权限
默认关闭 adb 功能
打开 Proguard 混淆器
打开 DEXPREOPT 预先编译优化
userdebug
安装标签为 user、debug 的模块
设定属性 ro.secure=1,打开安全功能
设定属性 ro.adb.secure=1,需要adb调试身份校验
设定属性 ro.debuggable=1,启用应用调试功能,即允许adb通过adb root获取root权限
默认打开 adb 功能
打开 Proguard 混淆器
打开 DEXPREOPT 预先编译优化
eng
安装标签为 user、debug、eng 的模块
设定属性 ro.secure=0,关闭安全功能,即默认adb使用root权限
设定属性 ro.adb.secure=1,需要adb调试身份校验
设定属性 ro.debuggable=1,启用应用调试功能
设定属性 ro.kernel.android.checkjni=1,启用 JNI 调用检查
默认打开 adb 功能
关闭 Proguard 混淆器
关闭 DEXPREOPT 预先编译优化
adb中的中文显示问题
1.打开cmd,输入chcp查看当前字符编码,一般为GBK936;
2.输入“chcp 65001”更改char codepage为utf-8;
3.在cmd的默认值属性中,将字体设置为中文字体,如"新宋体"。
常用路径
frameworks/native/services/inputflinger
frameworks/base/services/core/jni
frameworks/base/core/java/android/app
frameworks/base/core/java/android/hardware/display
system/displayd
source build/envsetup.sh后的命令
mma 可以根据模块依赖关系,编译所有与当前目录下的模块关联的程序。
cgrep 只查找C、C++文件
ggrep 只查找Gradle文件
jgrep 只查找Java文件
resgrep 只查找res/*.xml文件
mangrep 只查找AndroidManifest.xml文件
sepgrep 只查找sepolicy文件
sgrep 查找所有源文件
croot 返回源码根目录
godir 进入包含源码文件名的目录
命令行启动APP
am start -n {包名(package)}/{包名}.{活动名称(activity)}
程序的入口类可以从每个应用的AndroidManifest.xml的文件中得到,以计算器(calculator)为例,它的
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.calculator2">
<application
android:icon="@mipmap/ic_launcher_calculator"
android:label="@string/app_name"
android:theme="@style/CalculatorTheme">
<activity
android:name=".Calculator"
android:label="@string/app_name"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.APP_CALCULATOR" />
</intent-filter>
</activity>
</application>
</manifest>
由此计算器(calculator)的启动方法为:# am start -n com.android.calculator2/com.android.calculator2.Calculator
提取内置安装包
1.adb shell pm list packages找到要提取apk的包名
2.adb shell pm path 定位apk所在系统路径
3.adb pull [] 从手机把apk pull下来
Android.mk
LOCAL_MODULE_TAGS :=user eng tests optional
user: 指该模块只在user版本下才编译,高版本AOSP不可直接使用,优选optional
eng: 指该模块只在eng版本下才编译
tests: 指该模块只在tests版本下才编译
optional:指该模块在所有版本下都编译,根目录下make,该模块仅编译,但不会install,需要在PRODUCT_PACKAGES 中添加报名才会自动安装到system.img