如何阅读Android framework层源代码

阅读Android Framework层的源码可能是Android 开发者深入学习的必经之路。但在我学习的过程中看到最多的是各路大神的源码分析,而很少有展示如何一步一步找到相关代码的。直到前不久看到老罗的视频《Android源代码情景分析法》,很有启发。但是老罗也只是讲到Java层的分析追踪,在我的日常工作中,经常涉及从Java 层到JNI 层,再到Native层,经常追着追着就丢了。

之后我仿照老罗的方法,尝试追踪MediaRecorder的setOutputFormat方法是怎么实现的,现在总结如下。

准备:

  • Source Insight 3

  • Android Framework层源码

分析开始

首先看MediaRecorder.java内的setOutputFormat方法:

    /**
     * Sets the format of the output file produced during recording. Call this
     * after setAudioSource()/setVideoSource() but before prepare().
     *
     * <p>It is recommended to always use 3GP format when using the H.263
     * video encoder and AMR audio encoder. Using an MPEG-4 container format
     * may confuse some desktop players.</p>
     *
     * @param output_format the output format to use. The output format
     * needs to be specified before setting recording-parameters or encoders.
     * @throws IllegalStateException if it is called after prepare() or before
     * setAudioSource()/setVideoSource().
     * @see android.media.MediaRecorder.OutputFormat
     */
    public native void setOutputFormat(int output_format)
            throws IllegalStateException;

这是一个native方法,根据JNI的规则,我们应该去android_media_MediaRecorder.cpp里看这个方法的实现:

static void
android_media_MediaRecorder_setVideoEncoder(JNIEnv *env, jobject thiz, jint ve)
{
    ALOGV("setVideoEncoder(%d)", ve);
    if (ve < VIDEO_ENCODER_DEFAULT || ve >= VIDEO_ENCODER_LIST_END) {
        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid video encoder");
        return;
    }
    sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
    process_media_recorder_call(env, mr->setVideoEncoder(ve), "java/lang/RuntimeException", "setVideoEncoder failed.");
}

关键是最后的两句,sp是Android 里的一个指针,就当没看见~ 所以最后两句的意思是调用Native层的MediaRecorder的setVideoEncoder方法。

继续去MediaRecorder.cpp里看setVideoEncoder方法:

status_t MediaRecorder::setVideoEncoder(int ve)
{
    ALOGV("setVideoEncoder(%d)", ve);
    if (mMediaRecorder == NULL) {
        ALOGE("media recorder is not initialized yet");
        return INVALID_OPERATION;
    }
    if (!mIsVideoSourceSet) {
        ALOGE("try to set the video encoder without setting the video source first");
        return INVALID_OPERATION;
    }
    if (mIsVideoEncoderSet) {
        ALOGE("video encoder has already been set");
        return INVALID_OPERATION;
    }
    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
        ALOGE("setVideoEncoder called in an invalid state(%d)", mCurrentState);
        return INVALID_OPERATION;
    }

    status_t ret = mMediaRecorder->setVideoEncoder(ve);
    if (OK != ret) {
        ALOGV("setVideoEncoder failed: %d", ret);
        mCurrentState = MEDIA_RECORDER_ERROR;
        return ret;
    }
    mIsVideoEncoderSet = true;
    return ret;
}

这里的mMediaReocorder定义在MediaRecorder.h里:

sp<IMediaRecorder>          mMediaRecorder;

可见其是一个IMediaRecorder类型的变量,这是一个接口类型,看一下其接口定义,在IMediaRecorder.h中:

class IMediaRecorder: public IInterface
{
public:
    DECLARE_META_INTERFACE(MediaRecorder);

    virtual status_t setCamera(const sp<hardware::ICamera>& camera,
                               const sp<ICameraRecordingProxy>& proxy) = 0;
    virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface) = 0;
    virtual status_t setVideoSource(int vs) = 0;
    virtual status_t setAudioSource(int as) = 0;
    virtual status_t setOutputFormat(int of) = 0;
    virtual status_t setVideoEncoder(int ve) = 0;
    virtual status_t setAudioEncoder(int ae) = 0;
    virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
    virtual status_t setVideoSize(int width, int height) = 0;
    virtual status_t setVideoFrameRate(int frames_per_second) = 0;
    virtual status_t setParameters(const String8& params) = 0;
    virtual status_t setListener(const sp<IMediaRecorderClient>& listener) = 0;
    virtual status_t setClientName(const String16& clientName) = 0;
    virtual status_t prepare() = 0;
    virtual status_t getMaxAmplitude(int* max) = 0;
    virtual status_t start() = 0;
    virtual status_t stop() = 0;
    virtual status_t reset() = 0;
    virtual status_t pause() = 0;
    virtual status_t resume() = 0;
    virtual status_t init() = 0;
    virtual status_t close() = 0;
    virtual status_t release() = 0;
    virtual status_t setInputSurface(const sp<IGraphicBufferConsumer>& surface) = 0;
    virtual sp<IGraphicBufferProducer> querySurfaceMediaSource() = 0;
};

// ----------------------------------------------------------------------------

class BnMediaRecorder: public BnInterface<IMediaRecorder>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

呐~关键的步骤来了,在以前我基本就追到这,就算完蛋了,不知道怎么继续往下追了,后来看Binder相关的内容,知道了BnInterface的作用,这是Binder中关键的一环,我们这就不展开讲了,只要记得,接下来我们要追的是BnMediaRecorder这个类。

全局搜索一下“: public BnMediaRecorder”,也就是去找它的实现类,发现在MediaRecorderClient.h当中有如下的定义:

class MediaRecorderClient : public BnMediaRecorder
{
    class ServiceDeathNotifier: public IBinder::DeathRecipient
    {
    public:
        ServiceDeathNotifier(
                const sp<IBinder>& service,
                const sp<IMediaRecorderClient>& listener,
                int which);
        virtual ~ServiceDeathNotifier();
        virtual void binderDied(const wp<IBinder>& who);

    private:
        int mWhich;
        sp<IBinder> mService;
        wp<IMediaRecorderClient> mListener;
    };

public:
    virtual     status_t   setCamera(const sp<hardware::ICamera>& camera,
                                    const sp<ICameraRecordingProxy>& proxy);
    virtual     status_t   setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
    virtual     status_t   setVideoSource(int vs);
    virtual     status_t   setAudioSource(int as);
    virtual     status_t   setOutputFormat(int of);
    virtual     status_t   setVideoEncoder(int ve);
    virtual     status_t   setAudioEncoder(int ae);
    virtual     status_t   setOutputFile(int fd, int64_t offset,
                                                  int64_t length);
    virtual     status_t   setVideoSize(int width, int height);
    virtual     status_t   setVideoFrameRate(int frames_per_second);
    virtual     status_t   setParameters(const String8& params);
    virtual     status_t   setListener(
                              const sp<IMediaRecorderClient>& listener);
    virtual     status_t   setClientName(const String16& clientName);
    virtual     status_t   prepare();
    virtual     status_t   getMaxAmplitude(int* max);
    virtual     status_t   start();
    virtual     status_t   stop();
    virtual     status_t   reset();
    virtual     status_t   pause();
    virtual     status_t   resume();
    virtual     status_t   init();
    virtual     status_t   close();
    virtual     status_t   release();
    virtual     status_t   dump(int fd, const Vector<String16>& args);
    virtual     status_t   setInputSurface(const sp<IGraphicBufferConsumer>& surface);
    virtual     sp<IGraphicBufferProducer> querySurfaceMediaSource();

private:
    friend class           MediaPlayerService;  // for accessing private constructor

                           MediaRecorderClient(
                                   const sp<MediaPlayerService>& service,
                                                               pid_t pid,
                                                               const String16& opPackageName);
    virtual                ~MediaRecorderClient();

    sp<IBinder::DeathRecipient> mCameraDeathListener;
    sp<IBinder::DeathRecipient> mCodecDeathListener;

    pid_t                  mPid;
    Mutex                  mLock;
    MediaRecorderBase      *mRecorder;
    sp<MediaPlayerService> mMediaPlayerService;
};

那么我们去MediaRecorderClient.cpp里看看:

status_t MediaRecorderClient::setVideoEncoder(int ve)
{
    ALOGV("setVideoEncoder(%d)", ve);
    Mutex::Autolock lock(mLock);
    if (mRecorder == NULL) {
        ALOGE("recorder is not initialized");
        return NO_INIT;
    }
    return mRecorder->setVideoEncoder((video_encoder)ve);
}

这里的mRecorder 定义在MediaRecorderClient.h当中:

MediaRecorderBase      *mRecorder;

来,我们继续搜索“: public MediaRecorderBase”,在StagefrightRecorder.h中找到了,那么我们去StagefrightRecorder.cpp当中看看~

status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
    ALOGV("setVideoEncoder: %d", ve);
    if (ve < VIDEO_ENCODER_DEFAULT ||
        ve >= VIDEO_ENCODER_LIST_END) {
        ALOGE("Invalid video encoder: %d", ve);
        return BAD_VALUE;
    }

    mVideoEncoder = ve;

    return OK;
}

呐,这就算完了~最后我们会发现MediaRecorder中的接口实现基本到最后都会落在这个StagefrightRecorder.cpp当中。

总结

在Android源码阅读当中,由于大多数人都没接触过大型的C++工程,所以在Native层的追踪上一开始会有较大困难,但只要静下心来,会发现其实只要记住C++的继承、实现、接口的相关概念,和一般的读代码没啥区别。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容