Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> (Android Framework 之路) N版本 Framework Camera的一些改動

(Android Framework 之路) N版本 Framework Camera的一些改動

編輯:關於Android編程

前言

Android N版本最近發布,Nougat是否好吃,不得而知,慢慢看下~
感謝AndroidXref這個網站,給開發者提供了大量的便捷~以後學習Android就靠它了。


N版本上Framework關於Camera的一些改動

CameraServer

N版本之前,CameraService是運行在MediaServer下的,這樣存在一定的問題,因為MediaServer下同時還運行這其他的多媒體內容
M版本

/frameworks/av/media/mediaserver/main_mediaserver.cpp

int main(int argc __unused, char** argv)
{
    signal(SIGPIPE, SIG_IGN);
    char value[PROPERTY_VALUE_MAX];
    bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
    pid_t childPid;
    // FIXME The advantage of making the process containing media.log service the parent process of
    // the process that contains all the other real services, is that it allows us to collect more
    // detailed information such as signal numbers, stop and continue, resource usage, etc.
    // But it is also more complex.  Consider replacing this by independent processes, and using
    // binder on death notification instead.
    if (doLog && (childPid = fork()) != 0) {
        // media.log service
        //prctl(PR_SET_NAME, (unsigned long) "media.log", 0, 0, 0);
        // unfortunately ps ignores PR_SET_NAME for the main thread, so use this ugly hack
        strcpy(argv[0], "media.log");
        sp proc(ProcessState::self());
        MediaLogService::instantiate();
        ProcessState::self()->startThreadPool();
        for (;;) {
            siginfo_t info;
            int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED);
            if (ret == EINTR) {
                continue;
            }
            if (ret < 0) {
                break;
            }
            char buffer[32];
            const char *code;
            switch (info.si_code) {
            case CLD_EXITED:
                code = "CLD_EXITED";
                break;
            case CLD_KILLED:
                code = "CLD_KILLED";
                break;
            case CLD_DUMPED:
                code = "CLD_DUMPED";
                break;
            case CLD_STOPPED:
                code = "CLD_STOPPED";
                break;
            case CLD_TRAPPED:
                code = "CLD_TRAPPED";
                break;
            case CLD_CONTINUED:
                code = "CLD_CONTINUED";
                break;
            default:
                snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
                code = buffer;
                break;
            }
            struct rusage usage;
            getrusage(RUSAGE_CHILDREN, &usage);
            ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
                    info.si_pid, info.si_status, code,
                    usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
                    usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
            sp sm = defaultServiceManager();
            sp binder = sm->getService(String16("media.log"));
            if (binder != 0) {
                Vector args;
                binder->dump(-1, args);
            }
            switch (info.si_code) {
            case CLD_EXITED:
            case CLD_KILLED:
            case CLD_DUMPED: {
                ALOG(LOG_INFO, "media.log", "exiting");
                _exit(0);
                // not reached
                }
            default:
                break;
            }
        }
    } else {
        // all other services
        if (doLog) {
            prctl(PR_SET_PDEATHSIG, SIGKILL);   // if parent media.log dies before me, kill me also
            setpgid(0, 0);                      // but if I die first, don't kill my parent
        }
        InitializeIcuOrDie();
        sp proc(ProcessState::self());
        sp sm = defaultServiceManager();
        ALOGI("ServiceManager: %p", sm.get());
        AudioFlinger::instantiate();
        MediaPlayerService::instantiate();
        ResourceManagerService::instantiate();
        CameraService::instantiate();
        AudioPolicyService::instantiate();
        SoundTriggerHwService::instantiate();
        RadioService::instantiate();
        registerExtensions();
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }
}

可以看到AudioFlinger,MediaPlayerService, ResourceManagerService,CameraService,AudioPolicyService,SoundTriggerHwService,RadioService等都是運行在這個進程下面的,這樣就存在一個問題,假如說其他任何一個服務因為某些原因掛掉了,整個MediaServer將會重啟,而這個重啟的過程中,倘若相機正在操作,就會出現相機突然掛掉的問題。

N版本
/frameworks/av/media/mediaserver/main_mediaserver.cpp

int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);

    sp proc(ProcessState::self());
    sp sm(defaultServiceManager());
    ALOGI("ServiceManager: %p", sm.get());
    InitializeIcuOrDie();
    MediaPlayerService::instantiate();
    ResourceManagerService::instantiate();
    registerExtensions();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

有沒有覺得少了很多,不僅CameraService被抽離出去了,還有一些內容好像也被抽離出去了。
在N版本的工程中多出來一個文件夾
/frameworks/av/camera/cameraserver/
這裡寫圖片描述
說明CameraServer是獨立於MediaServer的單獨的進程,執行PS操作你講看到獨立的Camera進程。

#define LOG_TAG "cameraserver"
//#define LOG_NDEBUG 0

// from LOCAL_C_INCLUDES
#include "CameraService.h"

using namespace android;

int main(int argc __unused, char** argv __unused)
{
    signal(SIGPIPE, SIG_IGN);

    sp proc(ProcessState::self());
    sp sm = defaultServiceManager();
    ALOGI("ServiceManager: %p", sm.get());
    CameraService::instantiate();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

初始化的過程並沒有變化,只是單純的將它獨立出來而已。
那麼問題來了,CameraService何時啟動?
看到cameraserver.rc文件,

service cameraserver /system/bin/cameraserver
    class main
    user cameraserver
    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
    ioprio rt 4
    writepid /dev/cpuset/foreground/tasks

也就是說只要加載了cameraserver.rc文件,服務就開始啟動了,就會往main_cameraserer.cpp的入口函數中執行,因為mk文件中定義了這個模塊為cameraserver

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    main_cameraserver.cpp//源文件

LOCAL_SHARED_LIBRARIES := \//依賴庫
    libcameraservice \
    libcutils \
    libutils \
    libbinder \
    libcamera_client

LOCAL_MODULE:= cameraserver//模塊名
LOCAL_32_BIT_ONLY := true//只支持32位

LOCAL_CFLAGS += -Wall -Wextra -Werror -Wno-unused-parameter//一些編譯條件,N版本在編譯這一塊也作出了很大的改動,有機會再研究下

LOCAL_INIT_RC := cameraserver.rc

include $(BUILD_EXECUTABLE)//執行文件

尋找,誰調用的camearserver.rc ????????????????
首先我們要看這個文件編譯出來之後放在手機的什麼位置
/build/core/base_rules.mk

# Rule to install the module's companion init.rc.
my_init_rc := $(LOCAL_INIT_RC_$(my_32_64_bit_suffix))
my_init_rc_src :=
my_init_rc_installed :=
ifndef my_init_rc
my_init_rc := $(LOCAL_INIT_RC)
# Make sure we don't define the rule twice in multilib module.
LOCAL_INIT_RC :=
endif
ifdef my_init_rc
my_init_rc_src := $(LOCAL_PATH)/$(my_init_rc)
my_init_rc_installed := $(TARGET_OUT$(partition_tag)_ETC)/init/$(notdir $(my_init_rc_src))
$(my_init_rc_installed) : $(my_init_rc_src) | $(ACP)
    @echo "Install: $@"
    $(copy-file-to-new-target)

$(my_register_name) : $(my_init_rc_installed)

大致可以看出一些端倪,應該是放在xxx/etc/init目錄下,這個xxx根據什麼看判斷,partition_tag變量

  ifdef LOCAL_IS_HOST_MODULE
    partition_tag :=
  else
  ifeq (true,$(LOCAL_PROPRIETARY_MODULE))
    partition_tag := _VENDOR
  else ifeq (true,$(LOCAL_OEM_MODULE))
    partition_tag := _OEM
  else ifeq (true,$(LOCAL_ODM_MODULE))
    partition_tag := _ODM
  else
    # The definition of should-install-to-system will be different depending
    # on which goal (e.g., sdk or just droid) is being built.
    partition_tag := $(if $(call should-install-to-system,$(my_module_tags)),,_DATA)
  endif

cameraserver應該是系統所有的,不是oem或者odm特有,存放在system/etc/init目錄下。
接下面看看這個文件
/system/core/init/readme.txt

One may specify paths in the mount_all command line to have it import
.rc files at the specified paths instead of the default ones listed above.
This is primarily for supporting factory mode and other non-standard boot
modes.  The three default paths should be used for the normal boot process.

The intention of these directories is as follows
   1) /system/etc/init/ is for core system items such as
      SurfaceFlinger, MediaService, and logcatd.
   2) /vendor/etc/init/ is for SoC vendor items such as actions or
      daemons needed for core SoC functionality.
   3) /odm/etc/init/ is for device manufacturer items such as
      actions or daemons needed for motion sensor or other peripheral
      functionality.

顯然是在執行“mount_all“的時候,CameraServer啟動 ~ ,找到啟動的位置,這一點和之前的版本是有很大差別的。


Aidl
N版本上對於Camera的一些接口采用了Aidl的文件格式
frameworks/av/camera/aidl/android/hardware/
這裡寫圖片描述

其他模塊想要訪問這些接口,需要include libcamera_client模塊才行<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160914/20160914095413502.png" title="" />

mk文件中有說明。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved