美文网首页Android知识我爱编程Android开发探索
Android Camera的一些调试技巧总结

Android Camera的一些调试技巧总结

作者: 幽客 | 来源:发表于2018-05-26 11:55 被阅读41次

    把之前开发遇到的一些问题总结一下, 由于很多东西都是和具体平台(高通/MKT)相关的, 本来有更多的内容可以总结, 但由于不在之前公司了,一些源码和环境都没了, 只能写一下记得比较清楚的东西了.

    dumpsys

    dumpsys是Android系统中一个调试神器, 可以看内存信息, 电池信息, 相机参数等等, 基本Android中每一个大的模块, 都能通过dumpsys来查看. 调试Camera我们通常需要知道一些参数信息, 默认参数, 实际设置参数, 支持的参数, 这些信息都可以通过dumpsys media.camera来查看, 具体用法如下:

    //执行这个adb命令会打印所有默认参数和当前使用参数
    adb shell dumpsys media.camera
    //查看某一项参数,使用过滤命令grep(linux), windows下可使用findstr来过滤
    adb shell dumpsys media.camera |grep picture-size
    //输出
    picture-size: 3264x2448
    picture-size-values:
    5520x4140,5984x3366,3840x2160,3264x2448,2048x1536,1920x1080,1280x720,640x480,480x320,320x240
    

    其中参数后面带values(比如上面picture-size-values)表示这个参数可设置的值,需要注意的是, 如果当前没有打开Camera, 执行命令也会有相应输出, 此时输出的值是默认值(打开camera不设置任何参数).
    上面说的是针对HAL1的参数, 如果是HAL3参数, 输出内容就不一样了,如下:

    adb shell dumpsys media.camera 
    // HAL3部分参数输出
    android.control.aeLockAvailable (10024): byte[1]
            [TRUE ]
    android.control.awbLockAvailable (10025): byte[1]
            [TRUE ]
    android.control.availableModes (10026): byte[2]
            [1 2 ]
    android.shading.availableModes (100002): byte[2]
            [1 2 ]
    android.statistics.info.availableLensShadingMapModes (120007): byte[1]
            [0 ]
    android.sensor.info.preCorrectionActiveArraySize (f000a): int32[4]
    

    可以看到, HAL1和HAL3差别很大, HAL3参数格式和Android Camera API2是对应的,如果要看HAL3的相关参数, 直接使用grep命令存在问题, 因为grep只会输出有关键字的那一行,但HAL3参数的Key和Values一般都不在一行, 所以要把输出保存到文件中,然后搜索关键字

    adb shell dumpsys media.camera > camera.txt
    

    No Display Mode

    通常情况下,正常使用Camera的流程是:

    1. 打开Camera
    2. 设置参数
    3. 设置预览Surface
    4. 开启预览:startPreview()
    5. 拍照:takePicture()

    但有些情况下, 我们希望不设置预览Surface就能拍照(默认情况下不设置预览进行拍照会Crash), 常见的应用场景是双摄项目, 打开了两个Camera,但副摄预览不需要用户看到, 这样做也可以减少系统资源占用, 高通和MTK平台都提供了不设置预览也可以拍照的功能, 使用方法如下:

    • 高通平台
      高通平台可以在ZSL开启的情况下, 通过设置参数Parameters.set("no-display-mode", "1");来达到不用设置Surface也能拍照的效果(参数必须在startPreview()之前设置).
    • MTK平台
      MTK平台要更简单些, 保证ZSD开启的情况下, 直接不用设置Surface, 进行startPreview()和takePicture()即可.

    Camera内存占用问题

    我们都知道, Camera App和CameraService是两个进程, App内存占用大家一般用Android Studio就能看到, 但如果我们在HAL层加入了一些修改, 要看内存占用, 这个时候就需要看CameraService的内存占用了, CameraService调用HAL层接口, 所以HAL层内存占用就体现在CameraService中, 要找到CameraService的进程, 可通过如下方法:
    Android 7.1及以下版本

    adb shell ps |grep -i camera
    //高通Android 7.1.1, 输出如下:
    cameraserver 371   1     20456  2240  binder_thr a84b396c S /system/bin/cameraserver
    camera    401   1     73188  3404  poll_sched ab1a8a6c S /system/bin/mm-qcamera-daemon
    

    可以看到和Camera相关的进程有两个, 一个是我们要找的CameraService,名称为cameraserver
    另一个就高通的Camera守护进程qcamera-daemon
    找到进程后, 查看内存就简单了,也是通过dumpsys来查看(meminfo后面也可以使用pid作为参数):

    $ adb shell dumpsys meminfo cameraserver
    Applications Memory Usage (in Kilobytes):
    Uptime: 24402928 Realtime: 83208095
                       Pss  Private  Private     Swap     Heap     Heap     Heap
                     Total    Dirty    Clean    Dirty     Size    Alloc     Free
                    ------   ------   ------   ------   ------   ------   ------
      Native Heap      196      196        0       40        0        0        0
      Dalvik Heap        0        0        0        0        0        0        0
            Stack       32       32        0       64
        Other dev        5        0        4        0
         .so mmap      470      204      176      508
       Other mmap       14        8        4        8
          Unknown       88       88        0       88
            TOTAL      805      528      184      708        0        0        0
    
     App Summary
                           Pss(KB)
                            ------
               Java Heap:        0
             Native Heap:      196
                    Code:      380
                   Stack:       32
                Graphics:        0
           Private Other:      104
                  System:       93
    
                   TOTAL:      805      TOTAL SWAP (KB):      708
    
    

    Android 8.0及以上版本
    在Android 8.0上, Google推出了一项Project Treble计划,旨在规范HAL接口, 简化Android的版本升级,其中一个重要改变就是, Framework层和HAL层也是通过Binder(此Binder和我们通常使用Binder不是同一个)通信, 因此HAL层内存占用并不在CameraService中, 而是在名为android.hardware.camera.provider@xx(xx表示版本号)中,比如SDM450平台就是android.hardware.camera.provider@2.4,我们找到这个进程也是通过 adb shell ps |grep -i camera, 然后通过pid(名字可能会重复)来查看内存即可, 基本方法和上面一样, 只是进程不是CameraService.

    API和HAL版本

    Camera由于其复杂的特点, Android在发展过程中, Camera API也进行了更新, 在Android 5.0上, Google推出了Camera2 API, 同样HAL版本中API1和API2对应的版本是HAL1和HAL3. 但由于一些原因, HAL3和API2普及并不理想, 到目前为止, 中低端手机基本都是API1+HAL1, 对于开发者来说,我们可能想知道一个App用的API和HAL的版本,这个时候可以通过过滤Log方式来实现(高通和MTK都通用):

    $ adb logcat |grep CameraService
    04-07 14:07:43.174   371  4415 I CameraService: CameraService::connect call (PID -1 "com.smewise.camera2", camera ID 0) for HAL version default and Camera API version 1
    

    可以看到Log打印的信息有App API的版本和HAL版本, API版本只有API1 和API2, HAL版本一般有三个结果: 256, 768, default.
    256代表使用HAL1, 768为HAL3, default一般表示调用的是没有特别指定版本, 根据平台配置来决定,这种情况如果想知道到底使用的哪个版本, 需要看平台代码或者一些Log.

    注:如果平台只支持HAL1, App通过API2去调用Camera的话, Framework层会将API2的调用转为用API1去调用, 也就是说虽然App使用的API2, 单对于CameraService来说使用的还是API1.

    高通平台副摄可见

    做过双摄项目的一般都知道, 副摄(一般id为2)对上层App是不可见的, 但我们在开发过程用需要对副摄进行一些测试, 因此是需要能打开副摄的,高通平台隐藏副摄是在Framework层做的处理, 代码如下:
    API1 代码:
    frameworks/base/core/java/android/hardware/Camera.java

        public static int getNumberOfCameras() {
            boolean exposeAuxCamera = false;
            String packageName = ActivityThread.currentOpPackageName();
            /* Force to expose only two cameras
             * if the package name does not falls in this bucket
             */
            String packageList = SystemProperties.get("camera.aux.packagelist");
            if (packageList.length() > 0) {
                TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
                splitter.setString(packageList);
                for (String str : splitter) {
                    if (packageName.equals(str)) {
                        exposeAuxCamera = true;
                        break;
                    }
                }
            }
            int numberOfCameras = _getNumberOfCameras();
            if (exposeAuxCamera == false && (numberOfCameras > 2)) {
                numberOfCameras = 2;
            }
            return numberOfCameras;
        }
    

    API2 代码:

    private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException {
     // 部分代码省略
                try {
                    numCameras = cameraService.getNumberOfCameras(CAMERA_TYPE_ALL);
                    /* Force to expose only two cameras
                     * if the package name does not falls in this bucket
                     */
                    boolean exposeAuxCamera = false;
                    String packageName = ActivityThread.currentOpPackageName();
                    String packageList = SystemProperties.get("camera.aux.packagelist");
                    if (packageList.length() > 0) {
                        TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
                        splitter.setString(packageList);
                        for (String str : splitter) {
                            if (packageName.equals(str)) {
                                exposeAuxCamera = true;
                                break;
                            }
                        }
                    }
                    if (exposeAuxCamera == false && (numCameras > 2)) {
                        numCameras = 2;
                    }
    //部分代码省略
    

    可以看到,这段代码逻辑是如果App包名在camera.aux.packagelist这个属性中,则可以打开副摄, 否则不行.因此打开副摄有两种方法:

    1. 设置camera.aux.packagelist这个属性, 把要打开的App包名添加进去
    2. 删除这部分限制Camera个数的代码(不推荐)

    SnapdragonCamera高级设置

    高通平台调试Camera一般用的就是SnapdragonCamera这个App, 这个App默认的设置参数比较有限, 有些我们想调节的参数没有, 比如anti-banding, 其实高通埋了个彩蛋在设置中的, 只要疯狂点击设置菜单中的Reduce Red Eye(减少红眼)选项, 然后重新进入设置菜单, 就能看到额外的设置选项了, 内容非常多, 比较有用, 控制这个额外菜单选项(DeveloperMenu)的代码如下:
    packages/apps/SnapdragonCamera/src/com/android/camera/PhotoMenu.java

     public void onPreferenceClicked(ListPreference pref, int y) {
            if (!mActivity.isDeveloperMenuEnabled()) {
                if (pref.getKey().equals(CameraSettings.KEY_REDEYE_REDUCTION)) {
                    privateCounter++;
                    if (privateCounter >= DEVELOPER_MENU_TOUCH_COUNT) {
                        mActivity.enableDeveloperMenu();
                        SharedPreferences prefs = PreferenceManager
                                .getDefaultSharedPreferences(mActivity);
                        prefs.edit().putBoolean(CameraSettings.KEY_DEVELOPER_MENU, true).apply();
                        RotateTextToast.makeText(mActivity,
                                "Camera developer option is enabled now", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    privateCounter = 0;
                }
            }
       //其他代码省略
    

    CameraService启动流程

    CameraService是在开机的的时候启动的, 并且不管有没有App使用Camera, 进程会一直存在, 在开机时,CameraService会发起一次对底层Camera信息的查询, 这个操作主要是确定Camera的个数和Camera基本信息的, 也就是说如果在HAL层及以下, 修改了Camera个数, 需要重启手机才会生效.
    另外由于CameraService开机启动, 如果HAL层修改东西存在问题, 可能会导致手机无法开机, 但据我所知, 高通平台Android 7.1.1及以后的版本, CameraService无法启动应该是不会影响整个系统的启动.

    相关文章

      网友评论

        本文标题:Android Camera的一些调试技巧总结

        本文链接:https://www.haomeiwen.com/subject/krqmjftx.html