V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
jeesk
V2EX  ›  Android

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

  •  1
     
  •   jeesk · 170 天前 · 5017 次点击
    这是一个创建于 170 天前的主题,其中的信息可能已经有所发展或是发生改变。

    首先我们有个需求, 就是能够在 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<intptr_t>(this));
    
    

    继续往下面看

    MediaSessionAndroid::MediaSessionAndroid(MediaSessionImpl* session)
        : media_session_(session) {
      DCHECK(media_session_);
    
      JNIEnv* env = base::android::AttachCurrentThread();
      ScopedJavaLocalRef<jobject> j_media_session =
          Java_MediaSessionImpl_create(env, reinterpret_cast<intptr_t>(this));
      j_media_session_ = JavaObjectWeakGlobalRef(env, j_media_session);
    
      WebContentsImpl* contents =
          static_cast<WebContentsImpl*>(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 文件内容了, 奇奇怪怪的折腾。

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

    9 条回复    2024-06-07 17:55:32 +08:00
    anbus
        1
    anbus  
       169 天前
    这么抽象的吗
    z836454898
        2
    z836454898  
       169 天前
    hack chromium 内核这是在给后人留坑啊,后人一更新 app 里的 chromium 程序就崩了,除非你的 app 像小程序一样有深度定制内核需求
    jeesk
        3
    jeesk  
    OP
       169 天前
    @z836454898 自己处理好兼容性就行了.
    jeesk
        4
    jeesk  
    OP
       169 天前
    @anbus 没办法, 坑太多了. 只有像苹果这种闭源, hack 的可能性就很小
    jeesk
        5
    jeesk  
    OP
       169 天前
    @z836454898 我们自己定制了内核. 不过有些场景不需要定制内核 , 主要是为了减少体积.
    HtPM
        6
    HtPM  
       169 天前
    “这个时候直接反射出了 mMediaSession , 但是发现这个字段怎么都不存在, 惊呆了我的下巴, 继续测试,发现 setMediaSession 这个方法存在的”
    这句话什么意思?你是说反射出了 MediaSession 的这个对象,但是字段 mMediaSession 不存在?这正常啊,如果做了代码混淆,mMediaSession 不就不存在了?变成其它名称了
    HtPM
        7
    HtPM  
       169 天前
    “认真分析 media_session_android.cc , 发现 setMediaSession 这个方法肯定是调用了的。 这个时候又去查询了一些资料,发现 native 方法的调用的原理是反射”
    还有这句话是什么意思?你是说 setMediaSession 这个 Java 函数是被 native 方法反射调用的?
    jeesk
        8
    jeesk  
    OP
       169 天前
    @HtPM setMediaSession 就是被 native 代码调用了, native 如何知道调用哪个方法? 不就是使用反射吗?
    jeesk
        9
    jeesk  
    OP
       169 天前
    @HtPM setMediaSession() 这个方法存在, 但是 里面的 this.mMediaSession = mediaSession; 和 private mMediaSession 代码被编译丢弃了.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2740 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 59ms · UTC 15:08 · PVG 23:08 · LAX 07:08 · JFK 10:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.