SDL中文论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 5670|回复: 7
打印 上一主题 下一主题

[Discuss] Android源码汇总

[复制链接]

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
跳转到指定楼层
楼主
发表于 2018-4-29 09:48:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、kernel log和android log
回复

使用道具 举报

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
沙发
 楼主| 发表于 2018-4-29 09:49:26 | 只看该作者

kernel log和android log

本帖最后由 ancientcc 于 2018-5-2 10:17 编辑

android中的日志分为kernel log和android log。
  • kernel log。该日志输出目的地是控制台,对开发板来说,就是在串口终端就能直接看到它们。输出它们的api分为两类,一是bsp中的printk,二则android中的klog。libcutils实现了klog,使用它的一个重要进程就是init。
  • android log。输出目的地是Android特有的Logger日志系统。开发板的串口终端要能看到它们需执行logcat。输出它们是调用Logger日志系统提供的api,像ALOGV/D/I/W/E,SLOGV/D/I/W/E,__android_log_print,等等。

一、为了调试,如何让开发板输出全部的调试信息
把klog的可输出最低优先级设到KLOG_DEBUG_LEVEL。为设置这个优先级要两步骤。第一步是修改init,让在klog_init()后调用klog_set_level。
  1. klog_init();
  2. klog_set_level(KLOG_DEBUG_LEVEL);   //设置klog的级别为最低优先级DEBUG
复制代码
第二步是检查init.rc,确保最低优先级依旧是KLOG_DEBUG_LEVEL。init.rc提供了loglevel命令可修改klog的优先级。为保持不变,或是不让出现loglevel,或使用下面的loglevel。
  1. loglevel 7
复制代码

二、增加自个的kernel log输出

三、让kernel log和android log同时输出向串口终端
正如开始写的android log是输向logcat,这意味着如果写了下面代码。
  1. KLOG_NOTICE(tag, "11");
  2. ALOGV(tag, "aa");
复制代码

串口中看到的只是"11",要看到"aa"需单独执行logcat。为知道输出先后次序,自然希望让kernel log和android log同时输出向串口终端,为达到目的试过这样方法。1)接管android log底层的“写入"函数,改为调用klog,像ALOGV,底下会调用__android_log_print,改为调用KLOG_NOTICE。用它需要个条件,即liblog需要链接libcutils,但到现在我没能解决让liblog成功链接libcutils。

减少ALOGV、SLOGV
android很多系统模块在不断输出ALOGV、SLOGV,它们会影响查看。但要是全关掉ALOGV、SLOGV,你希望看到的模块也会被关掉,这时最好修改ALOGV、SLOGV的宏定义。
  1. #define ALOGV(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0)
  2. 改为
  3. #define ALOGV(...) do { if (LOG_NDEBUG >= 2) { __ALOGV(__VA_ARGS__); } } while (0)
  4. 同样修改SLOGV。
复制代码
经过这样修改后,这时你模块打开ALOGV、SLOGV的cpp开始处把LOG_NDEBUG定义为2,避免LOG_NDEBUG取默认值1。
回复 支持 反对

使用道具 举报

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
板凳
 楼主| 发表于 2018-5-3 20:53:56 | 只看该作者

Android 5.1 Camera架构

本帖最后由 ancientcc 于 2018-5-23 15:52 编辑

Android 5.1 Camera 架构学习之Camera初始化。注:对一些开发板的HAL实现,当中CameraClient可能要换成Camera2Client。

app调用camera框架的入口java文件是<android>/frameworks/base/core/java/android/hardware/Camera.java,app在调用时先执行静态方法open。
  1. final android.hardware.Camera camera = android.hardware.Camera.open(cameraId);
复制代码
接下就可用camera调用它的方法了。在android.hardware.Camera,它调用C/C++原生实现是在android_hardware_Camera.cpp,在该cpp内,调用get_native_camera得到的sp<Camera>就是av/camera/Camera.cpp实现的Camera,以下是Camera结构。
  1. class Camera :
  2.     public CameraBase<Camera>,
  3.     public BnCameraClient
  4. {
  5.         ......
  6. };
复制代码
它的父类CameraBase,该类中有个重要的成员变量:mCamera。
  1. template <typename TCam, typename TCamTraits = CameraTraits<TCam> >
  2. class CameraBase : public IBinder::DeathRecipient
  3. {
  4.         typedef typename TCamTraits::TCamUser           TCamUser;
  5. .....
  6.         sp<TCamUser>                     mCamera;
  7.         typedef CameraBase<TCam>         CameraBaseT;
  8. };
复制代码
注:结合Camera、CameraBase的关系定义可看到,CameraBase须要的模板参数TCam的值就是Camera,因而sp<TCam>等于sp<Camera>,这有助于理解CameraBase<TCam, TCamTraits>::connect。——回到mCamera,让转去TCamTraits。
  1. template <>
  2. struct CameraTraits<Camera>
  3. {
  4. ......
  5.     typedef ICamera               TCamUser;
  6. };
复制代码
综合它们可得出个结论:Camera中mCamera的类型是sp<ICamera>。ICamera是app和相机服务之间的接口,通过分析会知道它实际指向的对象正是CameraClient,后者在相机服务(CameraService)的connect时创建。于是可以想象成这么个结构:CameraClient位在相机服务(CameraService)内,向外暴露着ICamera接口,app则调用ICamera中方法向CameraService请求服务。

省去中间分发,在C/C++代码可以认为app拿到的camera是CameraClient。C/C++另有一个类是Camera2Device,它是Camera2Client中的成员,mDevice是对应的成员变量,它在Camera2ClientBase(Camera2Client的父类)的构造函数中用CameraDeviceFactory::createDevice(cameraId)创建。

以下几个函数是从app到Camera2Client.cpp的变换流程
app(java/android.hardware.Camera)Camera.javaandroid_hardware_Camera.cpp(c++)Camera2Client.cpp
setPreviewTexturesetPreviewTextureandroid_hardware_Camera_setPreviewTexturesetPreviewTarget
startPreviewstartPreviewandroid_hardware_Camera_startPreviewstartPreview


HAL模块
相机在硬件抽像层模块的ID:CAMERA_HARDWARE_MODULE_ID

app和硬件访问服务器之间有AIDL定义的接口,那硬件访问服务和HAL模块之间接口的是什么?——Android内部定义的一个C++接口,像相机对应的是camera_module_t(<android>/hardware/libhardware/include/hardware/camera_common.h)。因为要支持标准的HAL访问操作,像加操作hw_get_module,它的第一个字段应该是hw_module_t。
  1. typedef struct camera_module {
  2.         hw_module_t common;
  3.         int (*get_number_of_cameras)(void);
  4.         int (*get_camera_info)(int camera_id, struct camera_info *info);
  5.         .....
  6. } camera_module_t;
复制代码
相应的,<android>/hardware/libhardware/include\hardware\camera2.h定义了相机设备camera2_device_t,类似camera_module_t,camera2_device_t的和一个字段应该是hw_device_t。
  1. typedef struct camera2_device {
  2.         hw_device_t common;
  3.         camera2_device_ops_t *ops;
  4.         void *priv;
  5. } camera2_device_t;
复制代码


如何采集帧,并传给app
  1. 第N次查询
  2. 01-01 16:18:44.050 119-5043/? V/Camera2-Device: consumer_dequeue: E
  3. 01-01 16:18:44.050 119-5043/? I/Camera2-Device: dequeue: Streaming 1 frames to queue
  4. 01-01 16:18:44.050 119-5043/? I/Camera2-Device: MetadataQueue: deque (1 buffers)
  5. 01-01 16:18:44.051 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setExposure
  6. 01-01 16:18:44.051 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setAwbMode
  7. 01-01 16:18:44.051 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setAfMode
  8. 01-01 16:18:44.051 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setSceneMode
  9. 01-01 16:18:44.051 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setEffectMode
  10. 01-01 16:18:44.051 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setAntibandingMode
  11. 01-01 16:18:44.051 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): doListenersCallback
  12. 01-01 16:18:44.051 119-5043/? D/NXCommandThread: void android::NXCommandThread::doListenersCallback(camera_metadata_entry_t&, camera_metadata_t*): streams.count: 1
  13. 01-01 16:18:44.051 119-5043/? V/NXCommandThread: void android::NXCommandThread::doListenersCallback(camera_metadata_entry_t&, camera_metadata_t*): streamId(1)
  14. 01-01 16:18:44.051 119-5043/? V/Camera2-Device: consumer_free: E
  15. 第N+1次查询
  16. 01-01 16:18:44.051 119-5043/? V/Camera2-Device: consumer_dequeue: E
  17. 01-01 16:18:44.052 119-5043/? I/Camera2-Device: dequeue: E
  18. 01-01 16:18:44.052 119-5043/? I/Camera2-Device: dequeue: Streaming 1 frames to queue
  19. 01-01 16:18:44.052 119-5043/? I/Camera2-Device: MetadataQueue: deque (1 buffers)
  20. 01-01 16:18:44.052 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setExposure
  21. 01-01 16:18:44.052 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setAwbMode
  22. 01-01 16:18:44.052 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setAfMode
  23. 01-01 16:18:44.052 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setSceneMode
  24. 01-01 16:18:44.052 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setEffectMode
  25. 01-01 16:18:44.052 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): setAntibandingMode
  26. 01-01 16:18:44.052 119-5043/? D/NXCommandThread: bool android::NXCommandThread::processCommand(): doListenersCallback
  27. 01-01 16:18:44.052 119-5043/? D/NXCommandThread: void android::NXCommandThread::doListenersCallback(camera_metadata_entry_t&, camera_metadata_t*): streams.count: 1
  28. 01-01 16:18:44.052 119-5043/? V/NXCommandThread: void android::NXCommandThread::doListenersCallback(camera_metadata_entry_t&, camera_metadata_t*): streamId(1)
  29. 01-01 16:18:44.052 119-5043/? V/Camera2-Device: consumer_free: E
复制代码
到现在也不清楚android是如何采集帧,并传给app。以上日志的入口函数是NXCommandThread::processCommand(<android>/hardware/samsung_slsi/slsiap/camera/NXCommandThread.cpp),它是个线程函数,执行着一个while循环。以下是一次循环的逻辑。
  • 调用Camera2Device::consumer_dequeue从请求队列弹出一个元素。
  • 一系统标志检查,根据该请求类型执行相应操作。doListenersCallback则是放在末尾且一定会执行的操作。
  • 调用Camera2Device::consumer_free,释放单元分配的内存。
    1. <android>/system/media/camera/src/camera_metadata.c
    2. void free_camera_metadata(camera_metadata_t *metadata) {
    3.         free(metadata);
    4. }
    复制代码
猜测:重点是在doListenersCallback。该函数把request分发给所有注册的CommandListener,让listener的onCommand的处理这request。而CommandListener是什么?——是从NXStreamThread派生的线程(见NXCommandThread::registerListener),像PreviewThread。但不清楚onCommand是怎么个执行流程,是如何采集帧,并上传到app的?
回复 支持 反对

使用道具 举报

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
地板
 楼主| 发表于 2018-5-6 21:23:30 | 只看该作者

platform驱动:nxp-v4l2

本帖最后由 ancientcc 于 2018-5-8 11:43 编辑

nxp-v4l2是个platform驱动,用于封装v4l2相关的多个设备,像相机有关的sensor,显示有关的hdmi。

系统一启动就会调用nxp_board_devices_register把“nxp-v4l2”这个设备注册向内核。运行到加载“nxp-v4l2”驱动后,platformat总线匹配到对应设备,于是调用“nxp-v4l2”驱动的prob方法,即nxp_v4l2_probe。正是它完成了nxp-v4l2内部各设备的就绪功能。

nxp-v4l2是个和media密切相关的驱动。以下entity就是media中的entity。
  1. nxp_v4l2_probe
  2.   v4l2_device_register。 --v4l2_device设备名称是“nxp-v4l2.0”
  3.   media_device_register。 --media_dev设备名称是“nxp-v4l2.0”
  4.   register_nxp_capture
  5.     nxp_vin_clipper_register。 ——添加的entity: 1)NXP VIN CLIPPER0,2)VIDEO CLIPPER0。
  6.     nxp_decimator_register。 ——添加的entity: 1)NXP DECIMATOR0,2)VIDEO DECIMATOR0。
  7.     _register_sensor。 ——添加的entity: 1)ov5640 0-003c。
  8.   register_nxp_scaler。 ——添加的entity: 1)NXP SCALER,2)VIDEO SCALER。
  9.   register_nxp_out。 ——添加的entity:1)NXP MLC0,2)VIDEO MLC RGB0。3)VIDEO MLC VID0。4)NXP MLC1。5)VIDEO MLC RGB1。6)VIDEO MLC VID1。7)NXP RESC0。8)NXP HDMI。
  10.   v4l2_device_register_subdev_nodes。 --v4l2_device设备名称是nxp-v4l2.0
  11.   platform_set_drvdata
复制代码
运行nxp_v4l2_probe后,media将有16个entity,各entity的id依次从1到16。接下具体分析“ov5640 0-003c”这个entity。
“ov5640 0-003c”对应相机设备,它在_register_sensor被注册,并创建相应的entity。
  1. _register_sensor
  2.   i2c_get_adapter。——返回名称是“nxp-i2c”的i2c_adapter。
  3.   v4l2_i2c_new_subdev_board
  4.     request_module。——请求的module叫“ov5640”。
  5.     i2c_new_device。——注册设备,由于之前已加载叫“ov5640”驱动,将调用ov5640_probe。
  6.     try_module_get
  7.     v4l2_device_register_subdev。——添加一个叫“ov5640 0-003c”的entity。
  8.     module_put。
  9.   media_entity_create_link
  10.   _set_sensor_entity_name
复制代码
经过_register_sensor,相机驱动就绪了,同时添加了一个叫“ov5640 0-003c”的entity。

Nanopc-t2相机用的是ov5640,很自然会问一个问题,ov5640驱动是如何被Android的camera这个HAL调用的。
  1. android_nxp_v4l2_init
  2.   V4l2UsageScheme* scheme;
  3.   v4l2_init(scheme);
  4.      _priv = new V4l2NexellPrivate();
  5.      int ret = _priv->init(scheme);
  6.        MediaFD = open("/dev/media0", O_RDWR);
  7.        enumEntities();——填充pDevice中的id、pads、links字段。当前16个。
  8.        enumDevices();——填充pDevice中的Devnode字段。
  9.        createDevices();——创建pDevice中的Device字段。
  10.        linkDefault();
  11.        activateDevices();
复制代码
首先要清楚两个id,EntityID和DeviceID。
  • EntityID指的是Entity结构中的id。用MEDIA_IOC_ENUM_ENTITIES去枚举时,返回的该Entity在media驱动的Entity数组中的索引。在值上,可认为就是该Entity所在驱动挂载到内核的次序+1。该值会随着加载次序变化而变化,因而不宜作为预设值。
  • DeviceID。也叫InternalID、nxp_v4l2_id。V4l2NexellPrivate有个数组变量:DeviceInfo Devices[INTERNAL_ID_MAX]。DeviceID值是这个数组的索引。getDevice(int id)中的id就是DeviceID。bsp和android之间的固定值用的也是DeviceID。

到现在也不理解ov5640驱动是如何被Android的camera这个HAL调用的,先放几个结论。
  • ov5640对应的Entity名称是“ov5640 0-003c”,DeviceID应该是0(InternalID是Sensor0)。再用getDevice(char *name)比较前会调用getCameraInfo,从/sys/devices/platform/camera sensor/sensor.0读出名称填充CameraInfo[0].SensorEntityName字段。
  • 猜测PreviewThread要从ov5640驱动读视频帧,然后看该线程的线程片断函数threadLoop。
    1. PreviewThread::threadLoop()
    2.   v4l2_dqbuf(Id, PlaneNum, &dqIdx, NULL);——Id是DeviceID,值是nxp_v4l2_decimator0(11),不是0!
    3.     V4l2NexellPrivate::dqBuf(Id, plane_num, index0, index1);
    4.       info->Device->dqBuf(planeNum, index0);——Device的类型是V4l2Device,它是DeviceInfo内的字段,而info是根据Id这个索引在DeviceInfo Devices[INTERNAL_ID_MAX]这个数组对应的单元。
    5.         ioctl(FD, VIDIOC_DQBUF, &v4l2_buf);——FD是打开设备驱动返回的句柄,DeviceInfo中的Devnode字段就是open的第一个参数。
    6.   NXStream *stream = getActiveStream();
    7.   stream->enqueueBuffer(timestamp);
    8.   stream->dequeueBuffer(&buf);
    9.   v4l2_qbuf(Id, PlaneNum, dqIdx, ZoomController->getBuffer(dqIdx), -1, NULL);
    复制代码

    PreviewThread是如何得到用于v4l2的Id?——get_board_preview_v4l2_id(),它返回nxp_v4l2_decimator0,后者是一个Composite设备(V4l2Composite),让看它的dqBuf。
    1. virtual int V4l2Composite::dqBuf(int planeNum, int *index0, int *index1 = NULL) {
    2.         return VideoDev->dqBuf(planeNum, index0, index1);
    3. }
    4. virtual int V4l2Video::dqBuf(int planeNum, int *index0, int *index1)
    5. {
    6.         ...
    7.         ret = ioctl(FD, VIDIOC_DQBUF, &v4l2_buf);
    8.         ...
    9. }
    复制代码
    V4l2Composite是通过调用V4l2Video的dqBuf。而nxp_v4l2_decimator0中的VideoDev正是nxp_v4l2_sensor0指向的“ov5640 0-003c”,于是发向nxp_v4l2_decimator0的dqBuf实际导向了“ov5640 0-003c”的dqBuf。

接下要如何理解?得深入v4l2如何处理VIDIOC_QBUF、VIDIOC_DQBUF,对nxp-v4l各个驱动,处理这两个ioctl对应的是nxp_video_dqbuf、nxp_video_qbuf。
  1. struct v4l2_subdev {
  2.         struct media_entity entity;
  3.         ......
  4. };

  5. struct nxp_csi {
  6.         ......
  7.         struct v4l2_subdev subdev;
  8.         ......
  9. };
复制代码


回复 支持 反对

使用道具 举报

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
5#
 楼主| 发表于 2018-5-6 21:52:38 | 只看该作者

make系统是如何生成boot.img

本帖最后由 ancientcc 于 2018-5-6 21:54 编辑

  • 編译出uImage复制到<android>/device/friendly-arm/nanopi2/boot。
  • 命令行执行以下命令。
    1. make bootimage
    复制代码

以下描述Makefile相关细节。
>>进入<android>/build/core/main.mk
  1. .PHONY: bootimage
  2. bootimage: $(INSTALLED_BOOTIMAGE_TARGET)
复制代码

注:变量INSTALLED_BOOTIMAGE_TARGET的值:<android>/out/target/product/nanopi2/boot.img

哪里定义了$(INSTALLED_BOOTIMAGE_TARGET)这个target?
>>进入<android>/vendor/friendly-arm/build/common/boot.mk
  1. $(INSTALLED_BOOTIMAGE_TARGET): $(INSTALLED_RAMDISK_TARGET) \
  2.                 $(INSTALLED_KERNEL_IMAGE) \
  3.                 $(INSTALLED_RECOVERY_RAMDISK_TARGET)
  4.         $(hide) ln -sf uImage $(TARGET_OUT_BOOT)/uImage.hdmi
  5.         $(hide) cp -f $(INSTALLED_RAMDISK_TARGET) $(TARGET_OUT_BOOT)/root.img.gz
  6.         $(hide) cp -f $(INSTALLED_RECOVERY_RAMDISK_TARGET) $(TARGET_OUT_BOOT)/
  7.         $(build-bootext4image-target)
复制代码

  • INSTALLED_RAMDISK_TARGET: <android>/out/target/product/nanopi2/ramdisk.img
  • INSTALLED_KERNEL_IMAGE: <android>/out/target/product/nanopi2/boot/uImage
  • INSTALLED_RECOVERY_RAMDISK_TARGET: <android>/out/target/product/nanopi2/ramdisk-recovery.img
  • TARGET_OUT_BOOT: <android>/out/target/product/nanopi2/boot
在这三个文件中,和内核相关的只有uImage,于是我们就看uImage是如何生成的。

>>进入<android>/device/friendly-arm/nanopi2/device.mk
  1. PRODUCT_COPY_FILES += $(LOCAL_PATH)/boot/uImage:boot/uImage
复制代码

uImage是事先放在了<android>/device/friendly-arm/nanopi2/boot目录下,然后会把它复制到out的boot目录下。而android不会把内核編译出的自动放在device下的boot目录。



回复 支持 反对

使用道具 举报

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
6#
 楼主| 发表于 2018-8-13 21:07:12 | 只看该作者
让app能修改以太网(ethernet)的ip地址
android分配IP地址的过程参考“Android5.1系统启动过程中启动有线网卡并为其分配静态IP地址”。

修改android源码
1、注释checkUseStaticIp()
<firefly-rk3288>/frameworks/base/services/core/java/com/android/server/net/EthernetServiceImpl.java
注释checkUseStaticIp()。
目的:让使用/data/misc/ethernet/ipconfig.txt中的以太网设置。一旦调用checkUseStaticIp,它会替换为用环境变量。

2、让app用户对/data/misc/ethernet有读写权根
在init.rc,mkdir /data/misc/ethernet 0770 system system中的0770改为0777。

3、增加服务chmod
  1. service system_chmod /system/bin/system_chmod.sh
  2.         disabled
  3.         oneshot
复制代码
system_chmod.sh内容。
  1. #!/system/bin/sh
  2. su
  3. chmod 0777 $1
复制代码


app代码
获取IP地址
  1. Android_JNI_SetProperty("ctl.start", "system_chmod:/data/misc/ethernet/ipconfig.txt");
  2. read_ipconfiguration(ipconfig_txt, &ipconfig);
  3. ipconfig返回当前正使用的ip地址。
复制代码


设置IP地址
  1. 把想设置的ip填充到ipconfig。
  2. write_ipconfiguration(ipconfig_txt, &ipconfig);
  3. Android_JNI_SetProperty("ctl.start", "system_chmod:/data/misc/ethernet/ipconfig.txt");
复制代码
回复 支持 反对

使用道具 举报

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
7#
 楼主| 发表于 2018-8-20 13:55:12 | 只看该作者

linux串口驱动(读串口)

本帖最后由 ancientcc 于 2018-9-1 20:23 编辑
  1. <AIO-3288J>/linux-3.x/drivers/tty/n_tty.c
  2. ssize_t n_tty_read(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr)
复制代码

n_tty_read调用copy_from_read_buf将tty->read_buf中的数据送到用户传下来的buf中。 主要是以下两条语句。
  1. uncopied = copy_from_read_buf(tty, &b, &nr);
  2. uncopied += copy_from_read_buf(tty, &b, &nr);
复制代码
第一条copy_from_read_buf复制tty->read_buf中从tail到结尾的部分。第二条复制tty->read_buf中从0到read_cnt部分。注:tty.read_head记录已读数据的末尾位置(下一次读到数据将从它开始放置),tty.read_tail记录已读数据的起始位置,tty.read_cnt记录已读数据的字节数。

read_buf中的数据是从那里来的? 首先:数据当然是从硬件里read出来的。 那么当我们的串口有数据的话,当然就调用我们以前注册的rx中断函数了。参考n_tty_receive_buf。

如何区分是调试串口?tty_struct中的name字段。如何确定调试串口的name值(ttyS2)?

其中tty.read_head记录已读数据的末尾位置(下一次读到数据将从它开始放置),tty.read_tail记录已读数据的起始位置,tty.read_cnt记录已读数据的数量。
回复 支持 反对

使用道具 举报

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
8#
 楼主| 发表于 2018-12-16 11:27:39 | 只看该作者

dlopen

本帖最后由 ancientcc 于 2018-12-16 11:33 编辑

1、dlopen时,不管flags是什么值,都须要dlopen所有A的依赖库,才能dlopen A。否则用dlerror时会报以下错误:“dlopen failed: library "libc++_shared.so" not found”。
2、bionic有一套so自已的搜索路径规则,该规则主要基于一个叫android_namespace_t的对象。
  1. struct android_namespace_t {
  2.         ......
  3.         const char* name_;
  4.         bool is_isolated_;
  5.         std::vector<std::string> ld_library_paths_;
  6.         std::vector<std::string> default_library_paths_;
  7.         std::vector<std::string> permitted_paths_;
  8.         soinfo::soinfo_list_t soinfo_list_;
  9. };
复制代码

  • name_:*.so的文件名。像libmain.so。
  • ld_library_paths_:不清楚。目前认为置空。
  • default_library_paths_:属于该命名空间的*.so优先搜索路径。
      [0]: /data/app/aismart/armeabi-v7a
  • permitted_paths_:不清楚。目前认为置空。
  • soinfo_list_:属于该命名空间的*.so。
启动一个app,调用dlopen前,须要创建两个android_namespace_t。
  1. bool android_init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path)
  2. android_init_namespaces(nullptr, "/system/lib:/vendor/lib");
复制代码
创建一个name_是“(anonymous)”的命名空间。public_ns_sonames是依赖的系统so,多个时用“:”隔开,anon_ns_library_path是搜索路径,多个时用“:”隔开。

  1. android_create_namespaceconst char* name, const char* ld_library_path, const char* default_library_path, uint64_t type, const char* permitted_when_isolated_path, android_namespace_t* parent_namespace)
  2. android_create_namespace("classloader-namespace", nullptr, "/data/app/aismart/armeabi-v7a", ANDROID_NAMESPACE_TYPE_ISOLATED, "/data:/mnt/expand:/data/user/0/com.leagor.aismart");
复制代码
创建一个name_是“classloader-namespace”的命名空间。叫“classloader-namespace”原因是libnativeloader.so叫这个名称。default_library_path是搜索路径,多个时用“:”隔开。

未解决问题。1)“(anonymous)”、“classloader-namespace”、g_default_namespace,这三个命名空间是什么关系。2)如何释放命名空间、soinfo的内存。

soinfo
每个曾用过的so会创建一个soinfo对象,这些soinfo被组织成一个单向链表。两个全局变量和链表相关,solist和sonext。solist指向链表头的soinfo,一旦赋值后就不会再变,sonext指向链表尾的soinfo。
  1. struct soinfo {
  2.         ElfW(Addr) base;
  3.         size_t size;

  4.         android_namespace_t* primary_namespace_;
  5. };
复制代码
base是该so加载到内存的基地址,size是该so在内存中长度。soinfo* find_containing_library(const void* p),该函数根据p这地址,找到对应的so。

soinfo中的两个字段soname_(const char*),realpath_(realpath_),这两个字段意义。
        soname: libvpx.so
        realpath: /data/app/com.leagor.iaccess-1/lib/arm/libvpx.so
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|丽谷软件|libsdl.cn

GMT+8, 2025-5-2 04:01 , Processed in 0.052605 second(s), 19 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表