Android初步笔记

================================Android=====================================
$$ Android中对java编写的应用放在system/app,而C/C++的放在system/bin


$$mk文件功能:
这个比较复杂一点,但是简单地说:找到mk中的一些定义的变量,要选择要编译什么?怎么编译?或是要拷贝什么?怎么拷贝?等等方面的问题。简而言之就是熟悉mk规则。
PRODUCT_COPY_FILES: src:dst  #当编译时,源路径上的文件会被复制到目标路径上去,具体的复制规则在config/Makefile中定义。


$$ Android property属性定义。
system/buid.pro生产过程:
build.prop的生成是由make系统解析build/core/Makefile完成。
1)      Makefile中首先定义各种变量,这在下一步执行时会用到。比如:
...
PRODUCT_DEFAULT_LANGUAGE="$(calldefault-locale-language,$(PRODUCT_LOCALES))" \
PRODUCT_DEFAULT_REGION="$(calldefault-locale-region,$(PRODUCT_LOCALES))" \
...
2)      Makefile中调用build/tools/buildinfo.sh执行脚本,并输出到build.prop
Buildinfo.sh很简单,只是echo一些属性,比如:
...
echo"ro.product.locale.language=$PRODUCT_DEFAULT_LANGUAGE"
echo"ro.product.locale.region=$PRODUCT_DEFAULT_REGION"
...
而,ro.product.locale.language/ ro.product.locale.region就是些属性,等号后面是值。
3)      Makefile中直接把$(TARGET_DEVICE_DIR)/system.prop的内容追加到build.prop中。
4)      收集ADDITIONAL_BUILD_PROPERTIES中的属性,追加到build.prop中。
ADDITIONAL_BUILD_PROPERTIES又会收集PRODUCT_PROPERTY_OVERRIDES中定义的属性
ADDITIONAL_BUILD_PROPERTIES:= \
        $(ADDITIONAL_BUILD_PROPERTIES)\
        $(PRODUCT_PROPERTY_OVERRIDES)

$$ ramdisk.img是Android系统的根文件系统,linux系统启动后将其挂载在内存中,并将之后的system和data以及sddata等分区挂载到ramdisk的相应节点上(目录)
注意:有些Android系统编译生产的并没有ramdisk.img,那基本就是ramdisk被编译进内核镜像中了。
如何配置编进内核???
答:不是配置编进内核了,而是用外部工具mkbootimg进行了打包。 将ramdisk和kernel镜像打包在一起了,fastboot在加载内的时候能检测到initrd的存在,
并在bootargs后面增加字段initrd=0x4000000,0x4FDCA,这就是为何bootatgs中没有指定init=xx的原因。


$$ Android的recovery是啥玩意??
Android开机后,会先运行 bootloader。Bootloader 会根据某些判定条件(比如按某个特殊键)决定是否进入 recovery模式。
Recovery模式会装载recovery 分区,该分区包含recovery.img。recovery.img包含了标准内核(和boot.img中的内核相同)以及recovery根文件系统。
 
$$ Android上报的键值都是已经通过转换的标准键值。
@wangjie: hexdump /dev/input/event0
|offset| second  |    us   |type|code|  value |
0000000 895f 4779 452a 000a 0001 0069 0001 0000
0000010 895f 4779 452a 000a 0000 0000 0000 0000
0000020 895f 4779 45bf 000a 0001 0069 0000 0000
0000030 895f 4779 45bf 000a 0000 0000 0000 0000


数据结构:linux/input.h
struct input_event {


         struct timeval time; //事件发生的时间


         __u16 type; //事件类类型:按键和移动鼠标就是不同类型


         __u16 code; //键值


         __s32 value; //事件值:是按下还是松开或者其他事件


};


$$ Android中添加product.即在Android源码根目录执行lunch会出现的候选配置。
一个配置其实就是对于device或者vendor下的一个product(注意Android官方已经建议放弃在vendor中建立product了)
   通常,对于一个产品的定义通常至少会包括四个文件:AndroidProducts.mk,产品版本定义文件,BoardConfig.mk 以及 verndorsetup.sh,分别介绍:
1, AndroidProducts.mk:该文文件中的内容很简单,其中只需要定义一个变量,名称为“PRODUCT_MAKEFILES”,该变量的值为产品版本定义文件名的列表,例如:
PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/Hi3796MV100.mk

2,产品版本定义文件:顾名思义,该文件中包含了对于特定产品版本的定义。该文件可能不只一个,因为同一个产品可能会有多种版本
(例如,面向中国地区一个版本,面向美国地区一个版本)。该文件中可以定义的变量以及含义说明如表 6 所示:
包含一些需要定义的类似PRODUCT_XX的变量:
PRODUCT_NAME 最终用户将看到的完整产品名,会出现在“关于手机”信息中。
PRODUCT_MODEL 产品的型号,这也是最终用户将看到的。
PRODUCT_LOCALES 该产品支持的地区,以空格分格,例如:en_GB de_DE es_ES fr_CA。
PRODUCT_PACKAGES 该产品版本中包含的 APK 应用程序,以空格分格,例如:Calendar Contacts。
PRODUCT_DEVICE 该产品的工业设计的名称。
PRODUCT_MANUFACTURER 制造商的名称。
PRODUCT_BRAND 该产品专门定义的商标(如果有的话)。
PRODUCT_PROPERTY_OVERRIDES 对于商品属性的定义。
PRODUCT_COPY_FILES 编译该产品时需要拷贝的文件,以“源路径 : 目标路径”的形式。
PRODUCT_OTA_PUBLIC_KEYS 对于该产品的 OTA 公开 key 的列表。
PRODUCT_POLICY 产品使用的策略。
PRODUCT_PACKAGE_OVERLAYS 指出是否要使用默认的资源或添加产品特定定义来覆盖。
PRODUCT_CONTRIBUTORS_FILE HTML 文件,其中包含项目的贡献者。
PRODUCT_TAGS 该产品的标签,以空格分格。

通常情况下,我们并不需要定义所有这些变量。Build 系统的已经预先定义好了一些组合,它们都位于 /build/target/product 下,
每个文件定义了一个组合,我们只要继承这些预置的定义,然后再覆盖自己想要的变量定义即可。例如:
# 继承 full_base.mk 文件中的定义
$(call inherit-product, $(SRC_TARGET_DIR)/product/full_base.mk) 
# 覆盖其中已经定义的一些变量
PRODUCT_NAME := full_lt26 
PRODUCT_DEVICE := lt26 
PRODUCT_BRAND := Android 
PRODUCT_MODEL := Full Android on LT26
 
3,BoardConfig.mk:该文件用来配置硬件主板,它其中定义的都是设备底层的硬件特性。
例如:该设备的主板相关信息,Wifi 相关信息,还有 bootloader,内核,radioimage 等信息。对于该文件的示例,请参看 Android 源码树已经有的文件。

4,vendorsetup.sh:该文件中作用是通过 add_lunch_combo 函数在 lunch 函数中添加一个菜单选项。该函数的参数是产品名称加上编译类型,中间以“-”连接,
例如:add_lunch_combo full_lt26-userdebug。/build/envsetup.sh 会扫描所有 device 和 vender 二 级目 录下的名称 为"vendorsetup.sh"文件,
并根据其中的内容来确定 lunch 函数的 菜单选项。


$$ Android的jni实现原个人总结:
----> java层需要做的事:
1, 加载对应的JNI库。:System.loadLibrary("media_jni");
2, 声明由关键字native修饰的所有需要调用的函数:private static native final void native_init(); private native void processFile(String path, String mimeType,MediaScannerClient client);

----> native层需要做的事:
1, 绑定java函数和native函数。(一般采用动态绑定方式,更加灵活)
a,背景:在JNI技术中,用来记录这种一一对应关系的,是一个叫JNINativeMethod的结构,其定义如下:
typedef struct {
  //Java中native函数的名字,不用携带包的路径。例如“native_init“。
constchar* name;    
//Java函数的签名信息,用字符串表示,是参数类型和返回值类型的组合。
const char* signature;
  void*       fnPtr;  //JNI层对应函数的函数指针,注意它是void*类型。
} JNINativeMethod;
b,方法:在native中定义该结构组成的数组,分别填充相应元素实现java和C/C++函数的一一对应关系。
//I,定义一个JNINativeMethod数组,其成员就是MS中所有native函数的一一对应关系。
static JNINativeMethod gMethods[] = {
......
{
"processFile" //Java中native函数的函数名。
//processFile的签名信息,当参数的类型是引用类型时,其格式是”L包名。签名是反的,即从左到右依次为(参数,...)返回值
"(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V", //javap –s -p xx.class生产签名信息 
(void*)android_media_MediaScanner_processFile //JNI层对应函数指针。
},
......
 
{
"native_init",       
"()V",                     
(void *)android_media_MediaScanner_native_init
},
 ......
};
//II,通过JNI_OnLoad注册进系统。当Java层通过System.loadLibrary加载完JNI动态库后,紧接着会查找该库中一个叫JNI_OnLoad的函数,如果有,就调用它,而动态注册的工作就是在这里完成的。
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
  //该函数的第一个参数类型为JavaVM,这可是虚拟机在JNI层的代表喔,每个Java进程只有一个
 //这样的JavaVM
  JNIEnv* env = NULL;
jintresult = -1;
 
if(vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
gotobail;
}
(*env)->RegisterNatives(env, clazz, gMethods,numMethods);//动态注册MediaScanner的JNI函数。第二个参数表明是Java中的哪个类
if(register_android_media_MediaScanner(env) < 0) {
goto bail;
}
......
return JNI_VERSION_1_4;//必须返回这个值,否则会报错。
}
   c,class的结构成员变量:
成员变量和成员函数是由类定义的,它是类的属性,所以在JNI规则中,用jfieldID 和jmethodID 来表示Java类的成员变量和成员函数,它们通过JNIEnv的下面两个函数可以得到:
jfieldID GetFieldID(jclass clazz,const char*name, const char *sig);
jmethodID GetMethodID(jclass clazz, const char*name,const char *sig);
附帖子路径:http://blog.csdn.net/innost/article/details/47204557

**, JNI的参数JNIEnv实际上就是提供了一些JNI  系统函数 。通过这些函数可以做到:
·  调用Java的函数。
/* 获取java类 */
mediaScannerClientInterface  = env->FindClass("android/media/MediaScannerClient");

/* 获取java类的操作函数 */
mScanFileMethodID = env->GetMethodID(
mediaScannerClientInterface, "scanFile",
  "(Ljava/lang/String;JJ)V");
  
/*调用JNIEnv的CallVoidMethod函数,注意CallVoidMethod的参数:
*第一个是代表MediaScannerClient的jobject对象,
*第二个参数是函数scanFile的jmethodID,后面是Java中scanFile的参数。
*/
mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr,
lastModified, fileSize);

·  操作jobject对象等很多事情。
//下面我们列出一些参加的Get/Set函数。
GetObjectField()         SetObjectField()
GetBooleanField()        SetBooleanField()
GetByteField()           SetByteField()
GetCharField()           SetCharField()
GetShortField()          SetShortField()
GetIntField()            SetIntField()
GetLongField()           SetLongField()
GetFloatField()          SetFloatField()
GetDoubleField()         SetDoubleField()





**, Android的parcel通信。
Parcel data, reply;
data = super.newRequest();
reply = Parcel.obtain();//获得一个新的parcel ,相当于new一个对象
data.writeInt(LIVE_INVOKE_PLAY_SETTING);
data.writeInt(1);
data.writeInt(mPlaySettting.mVideoStopMode);
data.writeInt(mPlaySettting.mVideoX);
data.writeInt(mPlaySettting.mVideoY);
data.writeInt(mPlaySettting.mVideoWidh);
data.writeInt(mPlaySettting.mVideoHeight);
ret = super_invoke(data, reply);
if (ret == 0){
reply.setDataPosition(0);
ret = reply.readInt();//从reply中返回操作的返回值。
if (ret != 0){
Log.e(TAG, "setPlaySetting>>>Failed to invoke play set reply:"+ret);
}
}
reply.recycle();//相当于回收一个parcel对象
data.recycle();
===============================分割线============================
java上层控制av设置接口的调用栈:
LivePlayer::setPlaySetting
super_invoke
super.invoke
MediaPlayer::invoke
native_invoke-->android_media_MediaPlayer_invoke->media_player->invoke
......
StbPlayer->setDataSource->mpCurPlayer
StbLivePlayer::invoke//dvb播放最底层就在这里,基本都是将上层参数在这里转换为hdi参数,然后调用hdi函数。


解决疑问:当初认为如果java调用driver函数的话,应该都需要用jni绑定driver接口才能进行,分析发现的c/c++的api调用driver,这样的话是不需要jni的,
 java直接调用api,那样只需jni绑api就行。分层如下:
 | java App                 |
 | mediaservice(api) |
 | driver              |



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值