1. 说BpXXX(如BpMediaPlayer)可爱,是因为它总是默默无闻地工作做,且基本上不露面(有点害羞的样子),但却总是做着重要的工作,没有它你如何调用mediaserver中为你准备好的各种功能呢?有了它,我们告诉它要听流行的“伤不起”,它就帮你放。你说它是不是一个听话的孩子呢?老板是不是很喜欢这样的员工呢

2. 既然它如此重要,但又基本上不露面,这可太为难我们这些天天if else的兄弟了。因为要找它难,没找到它之前,对这些if else的理解就更难了。所以做人也不能太害羞了,否则害了自己也害了大家,当然像MediaPlayer这样过于高调也不好,啥事不做,只当一个传话筒,还哪么高调,天天到处叫,来调我吧,来用我吧

3. 在上一篇文章《Android媒体播放器框架--图》中讲过,MediaPlayer在setDataSource中调用BpMediaPlayerService::create时创建了BpMediaPlayer,并把它保存在MediaPlayer的mPlayer中,以供后面的调用。

4. 本文重点分析这个BpMediaPlayer是如何创建出来的。下面不得不看代码了。

status_t MediaPlayer::setDataSource(const char *url, const KeyedVector<String8, String8> *headers)
{LOGV("setDataSource(%s)", url);status_t err = BAD_VALUE;if (url != NULL) {const sp<IMediaPlayerService>& service(getMediaPlayerService());if (service != 0) {//调用BpMediaPlayerService::createsp<IMediaPlayer> player(service->create(getpid(), this, url, headers));//把新创建的BpMediaPlayer保存在MediaPlayer的成员变量mPlayer中err = setDataSource(player);}}return err;
}

自从这个MediaPlayer有了这个mPlayer之后,什么事就叫mPlayer来做,自已就成了领导了。

5.这明明是返回的是IMediaPlayer,为什么偏说是BpMediaPlayer呢?其原因有二。

1)得益于C++中,只要这个指针指向派生类的对象,可把它转换为基类的指针来保存,调用方法时,会执行对应派生类中的方法。

2)先看看MediaPlayer的家族图谱:

现在有两个问题需要解答:

1)为什么说上面代码中创建的player为指向BpMediaPlayer的指针?

2)为什么说BpMediaPlayer中的mRemote为指向BpBinder的指针?

6. 为什么说上面代码中创建的player为指向BpMediaPlayer的指针

这个还是让代码自己来讲吧:

class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
{
public:...virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client,const char* url, const KeyedVector<String8, String8> *headers) {Parcel data, reply;data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());data.writeInt32(pid);data.writeStrongBinder(client->asBinder());data.writeCString(url);if (headers == NULL) {data.writeInt32(0);} else {// serialize the headersdata.writeInt32(headers->size());for (size_t i = 0; i < headers->size(); ++i) {data.writeString8(headers->keyAt(i));data.writeString8(headers->valueAt(i));}}//通过Binder发送请求给MediaPlayerServiceremote()->transact(CREATE_URL, data, &reply);//这就是重点??? reply.readStrongBinder()); 的返回值为一个new的BpBinderreturn interface_cast<IMediaPlayer>(reply.readStrongBinder()); //返回值为一个new的BpMediaPlayer}...
}

interface_cast<IMediaPlayer>(reply.readStrongBinder());结果是什么呢? 是IMediaPlayer还是BpMediaPlayer?期待其中的答案...(让我轻轻地告诉你,它是一个BpMeidaPlayer)

看似简单的一行代码,其内容可不简单,因为它涉及一个又一个模板。好玩吧!

6.1 先看看其参数是什么东东...(先偷偷地告诉你,一个新new的BpBinder)

reply.readStrongBinder()代码如下:

sp<IBinder> Parcel::readStrongBinder() const
{sp<IBinder> val;unflatten_binder(ProcessState::self(), *this, &val);return val;
}

没什么,再向下看,不是什么东东都可以向下看的,否则别人会骂的。

status_t unflatten_binder(const sp<ProcessState>& proc,const Parcel& in, sp<IBinder>* out)
{const flat_binder_object* flat = in.readObject(false);if (flat) {switch (flat->type) {case BINDER_TYPE_BINDER:*out = static_cast<IBinder*>(flat->cookie);return finish_unflatten_binder(NULL, *flat, in);case BINDER_TYPE_HANDLE: //因为我们是Client,当然会调用这个*out = proc->getStrongProxyForHandle(flat->handle);return finish_unflatten_binder(static_cast<BpBinder*>(out->get()), *flat, in);}        }return BAD_TYPE;
}

6.1.1 还是哪么简单,只有两行代码,可内容还是不简单,再深入一步,看看第一行代码out返回的是什么东东?

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{sp<IBinder> result;AutoMutex _l(mLock);handle_entry* e = lookupHandleLocked(handle);if (e != NULL) {// We need to create a new BpBinder if there isn't currently one, OR we// are unable to acquire a weak reference on this current one.  See comment// in getWeakProxyForHandle() for more info about this.IBinder* b = e->binder;if (b == NULL || !e->refs->attemptIncWeak(this)) {//第一次调用肯定走这儿b = new BpBinder(handle); e->binder = b;if (b) e->refs = b->getWeakRefs();result = b;} else {// This little bit of nastyness is to allow us to add a primary// reference to the remote proxy when this team doesn't have one// but another team is sending the handle to us.result.force_set(b);e->refs->decWeak(this);}}return result;
}

呵呵,终于看到了,这个返回的就是一个BpBinder,其handle为传入的handle.现在已经看到reply.readStrongBinder()的返回值为一个BpBinder,即interface_cast<IMediaPlayer>(reply.readStrongBinder());的参数为一个BpBinder.

6.1.2 返回值已经产生,第二行代码finish_unflatten_binder( static_cast<BpBinder*>(out->get()), *flat, in);做什么呢?

inline static status_t finish_unflatten_binder(BpBinder* proxy, const flat_binder_object& flat, const Parcel& in)
{return NO_ERROR;
}

啥事没干,而且游戏嘎然而止。至此,参数已经分析完成,其结果就是一个指向BpBinder的一个指针。

7. 看看interface_cast<IMediaPlayer>(reply.readStrongBinder())即interface_cast<IMediaPlayer>(BpBinder)做了些什么,且返回值是什么? 老规距,让代码自己说话。以下就要与模板打交道了。

7.1 寻找asInterface的真身

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{return INTERFACE::asInterface(obj);
}

又是一很简单。还原后代码为:

inline sp<IMediaPlayer> interface_cast(const sp<IBinder>& obj)
{return IMediaPlayer::asInterface(obj);
}      

原来以刚new的BpBinder对象为参数,调用IMediaPlayer::asInterface,还不快进去看其中的代码...,你以为你想进就进啊,你以为你是谁,告诉你没地方可进,代码中没看到这个函数,怎么办呢。只能看看IMedialayer的定义了。其定义中发现这么一行代码:

class IMediaPlayer: public IInterface
{
public:DECLARE_META_INTERFACE(MediaPlayer);...
}

很显然这是一个宏,这个可以看看吧!

#define DECLARE_META_INTERFACE(INTERFACE)                               \static const String16 descriptor;                                   \static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj);        \virtual const String16& getInterfaceDescriptor() const;             \I##INTERFACE();                                                     \virtual ~I##INTERFACE();  

我终于明白了你,原来在这儿定义了这个一直找寻的IMedaiPlayer::asInterface,老办法,还原啊!

    static const String16 descriptor;                                   static sp<IMediaPlayer> asInterface(const sp<IBinder>& obj);        virtual const String16& getInterfaceDescriptor() const;             IMediaPlayer();                                                     virtual ~IMediaPlayer();  

asInterface的定义是有了,实现呢? asInterface啊asInterface,你怎么这么喜欢折腾人呢? 原来还认为你的BpXXX很可爱,现在觉得有点狡猾了。没办法,谁叫我们是搞if esle的呢! 继续找啊,相信有定义就有实现。找啊找,找到一个有意思的东东IMPLEMENT_META_INTERFACE(INTERFACE, NAME),Search下,在IMediaPlayer发现了IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");此宏定义如下:

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \const String16 I##INTERFACE::descriptor(NAME);                      \const String16& I##INTERFACE::getInterfaceDescriptor() const {      \return I##INTERFACE::descriptor;                                \}                                                                   \sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj)  \{                                                                   \sp<I##INTERFACE> intr;                                          \if (obj != NULL) {                                              \intr = static_cast<I##INTERFACE*>(                          \obj->queryLocalInterface(                               \I##INTERFACE::descriptor).get());               \if (intr == NULL) {                                         \intr = new Bp##INTERFACE(obj);                          \}                                                           \}                                                               \return intr;                                                    \}                                                                   \I##INTERFACE::I##INTERFACE() { }                                    \I##INTERFACE::~I##INTERFACE() { }     

还原之后为:

  const String16 IMediaPlayer::descriptor("android.media.IMediaPlayer");                      const String16& IMediaPlayer::getInterfaceDescriptor() const {      return IMediaPlayer::descriptor;                                }                                                                   sp<IMediaPlayer> IMediaPlayer::asInterface(const sp<IBinder>& obj)  {                                                                   sp<IMediaPlayer> intr;                                          if (obj != NULL) {                                              intr = static_cast<IMediaPlayer*>(                          obj->queryLocalInterface(                               IMediaPlayer::descriptor).get());               if (intr == NULL) {                                         intr = new BpMediaPlayer(obj);                          }                                                           }                                                               return intr;                                                    }                                                                   IMediaPlayer::IMediaPlayer() { }                                    IMediaPlayer::~IMediaPlayer() { }     

终于有asInterface的实现了,急切的心情看看他都做了些什么,单独拿出来品品吧!

    sp<IMediaPlayer> IMediaPlayer::asInterface(const sp<IBinder>& obj)  {                                                                   sp<IMediaPlayer> intr;                                          if (obj != NULL) {                                              intr = static_cast<IMediaPlayer*>(                          obj->queryLocalInterface(                               IMediaPlayer::descriptor).get());               if (intr == NULL) {                                         intr = new BpMediaPlayer(obj); //第一次肯定执行这儿                         }                                                           }                                                               return intr;                                                    } 

看到intr = new BpMediaPlayer(obj),obj为刚创建的BpBinder, 看到没有,BpMediaPlayer(常说的BpXXX)以如此低调的方式登场,难怪我们一时找不到它。
 
至此,已经很明确了,interface_cast<IMediaPlayer>(reply.readStrongBinder());的结果是上面创建的BpMediaPlayer.

7.2 看看new BpMediaPlayer都做了些什么?
还是让代码自己讲吧!

    BpMediaPlayer(const sp<IBinder>& impl): BpInterface<IMediaPlayer>(impl){}

impl为刚创建的BpBinder, 再看看BpInterface<IMediaPlayer>(impl)做了什么。

template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote): BpRefBase(remote)
{
}

我的乖乖,又是一个模板,继续还原:

inline BpInterface<IMediaPlayer>::BpInterface(const sp<IBinder>& remote): BpRefBase(remote)
{
}

深入看看BpRefBase(remote)做了些什么?

BpRefBase::BpRefBase(const sp<IBinder>& o): mRemote(o.get()), mRefs(NULL), mState(0)
{extendObjectLifetime(OBJECT_LIFETIME_WEAK);if (mRemote) {mRemote->incStrong(this);           // Removed on first IncStrong().mRefs = mRemote->createWeak(this);  // Held for our entire lifetime.}
}

Oh,my God, 把刚创建的BpBinder赋值给了BpRefBase中的mRemote,所以上面的图上说mRemote本质上是一个BpBinder.现在得到证实了。







												

可爱的BpXXX-图相关推荐

  1. 1分钟做出一个可爱鬼畜动图!

    如何快速做一个可爱鬼畜动图,用一个简单的AE表达式,之前一直觉得代码相关对于一个设计师来说真的很难,也完全不敢想象!不过学习完,感觉好像也能看的懂嘛!!哈哈哈哈~~ 先来看下我几分钟学会的成果!!如下 ...

  2. android开发动态图ae,AE教程:1分钟做出一个可爱鬼畜动图!

    AE教程:1分钟做出一个可爱鬼畜动图! 4月 15, 2019 发表于: 视觉设计. 评论 Sponsor 在忙碌工作的同时,时不时也需要学习下新技能,今日刚学会一个小技巧,让我们可以快速做出一个鬼畜 ...

  3. 可爱二次元人物图的转换实现(利用opencv滑动条)

    滑动条是opencv动态调节参数特别好用的一种工具,它依附于窗口而存在. 我们这里便是应用滑动条实现了小鸟游六花两张美图的转化(doge 创建滑动条:createTrackbar()函数 int cr ...

  4. 美眉都是可爱的…… (美图)

    1.休闲MM         安静的午后 悄悄的想你 好想写什么点给你 纪念我们仿佛认识了 好久好久 2.公主MM     起风了 想起你低沉而温柔的话语 我的嘴角 情不自禁的上扬 风儿轻轻的拥住我 ...

  5. vue中既可以选择又可以手动输入的文本框类型_在PPT中制作一个胖乎乎的可爱圆环图...

    您好,欢迎来到[爆炒Office],这里有原创的实用办公软件技巧. 概述 有的数据图是以精确的数据为基础制作而成,而有的数据图又是使用图形制作成的示意图.本文介绍使用弧形制作示意关系的圆环图,同时,通 ...

  6. 叠加卡片列表_使用PowerBI制作卡片图

    如果要汇报重要的指标,比如超额完成的销售额.同比增长率等,不要把它埋没在图表里,用一个大大的数字自豪的展示它吧. 卡片图,也被称为大数字磁贴,严格来说不能算是一种图表,只是仪表板的一个组件而已.在仪表 ...

  7. 手把手教你制作智能桌宠(小可爱哦!)

    大家曾经记忆里的回忆,是不是腾讯企鹅的.它又萌又可爱,如图: 但是我们多么想制作一款自己的智能宠物啊,今天我们就将带你手把手制作桌宠.最主要的是文末我将给出源代码哦!大家可以DIY设计自己专属的桌面宠 ...

  8. python小应用之moviepy的视频剪辑制作gif图

    对视频动画的编辑可以使用python的moviepy库,官方文档: http://zulko.github.io/moviepy/ 1.进入cmd,pip install moviepy 2.使用代码 ...

  9. Python浪漫七夕:可爱的卡通图案合集分享

    一个浪漫的日子--七夕. 每个学科都有属于自己的浪漫.理工科的程序员们被大众普遍认为是直男直女,但其实我们才是最浪漫的,还不抓住机会展现一把,用专属于程序员的烂漫锁住爱! 下面是我搜集到的一些Pyth ...

  10. win7下,为何右击桌面计算机图标,单击管理,打不开,电脑图标点不了怎么办啊

    1.电脑桌面上的图标点不开了是怎么回事 刚打开电脑点击桌面图标发现无法打开,桌面图标无法打开怎么办呢?400pc小编教你如何解决桌面图标无法打开. 方法1 双击打开桌面上"我的电脑" ...

最新文章

  1. genesis cam 最新版_触屏精灵下载_触屏精灵最新版下载[其他行业]
  2. python中random模块中包含了随机数相关的功能函数_Python中random模块生成随机数详解...
  3. python运行mcmc为何老出错_python – 使用pyMCMC / pyMC对数据/观察结果设置非线性函数...
  4. Nuxt爬坑系列之vuex
  5. IOS开发基础之绘图的样式
  6. python 多分类情感_python 文本情感分类
  7. java 抛异常 jvm_邪恶的Java技巧使JVM忘记检查异常
  8. 条码管理系统mysql_银行通用固定资产条码管理系统
  9. Advanced Custom Fields Pro 自定义文章字段 wordpress插件
  10. python MultipartEncoder
  11. WPF中的附加行为简介
  12. ios如何看idfv_ios获取手机状态 idfa   idfv   网络类型   分辨率   获取运营商
  13. mysql实现知识图谱_基于电影知识图谱的智能问答系统学习记录
  14. Kepserver如何连接InTouch
  15. ubuntu 拷贝文件夹下所有文件到其他文件夹操作
  16. hau 3037 Saving Beans【Lucas定理】
  17. android 7.1 自动启动wifi,设置自动连接wifi-ssid
  18. 【新知实验室】腾讯云TRTC验证测试
  19. 通过.git/info/exclude文件配置忽略文件
  20. 正则表达式\\s+ - 匹配任意空白字符

热门文章

  1. 4、windows与jetson tx2文件互传工具
  2. 另类解决部分黑苹果Monterey下蓝牙睡眠后启动异常缓慢的问题
  3. MAC地址是怎么保证全球唯一的
  4. ue4 unreal NDisplay插件 简易使用 三折幕 详细...
  5. 电脑数据,电脑数据恢复软件,失易得数据恢复
  6. windows安装mysql-community-8.0.13.0
  7. PHP 通过单号查询快递( 申通、EMS、顺丰、圆通、中通、韵达、天天、汇通、全峰、德邦、宅急送)
  8. 红黑树 之 原理和算法详细介绍
  9. linux系统命令cd怎么使用,linux命令怎么用_Linux cd命令该怎么使用
  10. 成本管理-输入、输出、工具和技术