记录一次失败需求的经历, hack 终究是不归路。

查看 28|回复 0
作者:jeesk   
首先我们有个需求, 就是能够在 WebView 中适配控制 media 的播放控制, 但是查看 api 发现,webview 根本没有暴露 mediasssion 这方面的 api. 怎么办? 只能去看看源码。
通过搜索, 发现 chromium 项目中有 MediaSession 这个接口,然后找到了这个类的实现 org.chromium.content.browser.MediaSessionImpl
,发现这个类有一个静态方法。
@CalledByNative private static MediaSessionImpl create(long nativeMediaSession),  这个时候肯定是 native 调用了 java 的代码。
那么继续搜索 MediaSessionImpl_create 在 chromium 源码中, 继续搜索
➜  src git:(123.0.6312.121) ✗ grep -rn "MediaSessionImpl" --include="*.cc"  |grep create
content/browser/media/session/media_session_android.cc:38:      Java_MediaSessionImpl_create(env, reinterpret_cast[i](this));
继续往下面看
MediaSessionAndroid::MediaSessionAndroid(MediaSessionImpl* session)
    : media_session_(session) {
  DCHECK(media_session_);
  JNIEnv* env = base::android::AttachCurrentThread();
  ScopedJavaLocalRef j_media_session =
      Java_MediaSessionImpl_create(env, reinterpret_cast[i](this));
  j_media_session_ = JavaObjectWeakGlobalRef(env, j_media_session);
  WebContentsImpl* contents =
      static_cast(media_session_->web_contents());
  if (contents) {
    web_contents_android_ = contents->GetWebContentsAndroid();
    DCHECK(web_contents_android_);
    web_contents_android_->SetMediaSession(j_media_session);
  }
  session->AddObserver(observer_receiver_.BindNewPipeAndPassRemote());
}
发现了 mediaSession 被设置到 WebContents, 通过搜索发现 WebContents 是一个接口, 继续找到该类的子类 WebContentsImpl.java , 发现里面有一行代码
    @CalledByNative
    private final void setMediaSession(MediaSessionImpl mediaSession) {
        mMediaSession = mediaSession;
    }
, 哈哈惊喜过度, 对象 mediaSession 竟然还在。 那还不简单, 直接通过反射去拿这个对象?
这里直接反射的过程简单说一下, 首先我们通过 WebView 的 classloader 拿到 WebView 的 Class 对象 ,再反射拿到 WebView 类里面的 mProvider 对象, 这个 mProdiver 其实就是 WebViewChromium.java, 在通过 WebViewChromium.java 对象里面的 AwContents 拿到对象 WebContens ,找到 WebContens 对象后, 就能反射拿到 mediaSession 了, 这个里面有很多坑,反射通过字段很多拿不到,名字和类名被混淆了,所以需要写很多 hack 代码。
这个时候直接反射出了 mMediaSession , 但是发现这个字段怎么都不存在, 惊呆了我的下巴, 继续测试,发现 setMediaSession 这个方法存在的。 这是怎么回事儿了? 二进制和源代码不一致?
这个时候不得不使用一些反编译工具了, 反编译出 MediaSessionImpl.java 文件,发现 mMediaSession 字段不存在, 并且 mMediaSession = mediaSession; 代码也消失了。
这这这这这? 心里一万个草泥马。 经过多次测试,发现这段代码被编译器忽略掉了。
认真分析 media_session_android.cc , 发现 setMediaSession 这个方法肯定是调用了的。 这个时候又去查询了一些资料,发现 native 方法的调用的原理是反射, 这个时候就只能去修改 classloader 里面的 class 文件内容了, 奇奇怪怪的折腾。
未完待续, 后面会继续分析。
您需要登录后才可以回帖 登录 | 立即注册

返回顶部