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

18次阅读

共计 2034 个字符,预计需要花费 6 分钟才能阅读完成。

首先我们有个需求,就是能够在 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(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(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 文件内容了,奇奇怪怪的折腾。

未完待续,后面会继续分析。

正文完
 0