您的位置:首页 > 移动开发 > Android开发

Android TV如何杀死后台正在播放的媒体应用。。。

2016-03-04 17:52 337 查看
  前段时间做了个android TV的项目,自己负责的模块是Launcher,这个Launcher上正好有个TV的小窗口,播放实时的TV信号。有一天一个测试跑到我这,感觉天要塌下来一样。

  说: "Hi, 兄弟大事不好啦,完蛋啦。。。Launcher的TV不能播了"

  我说“尼玛,竟有此事!”

  于是跟着测试跑到问题机器上一看。。。尼玛电视电视,竟然无法播放电视了,我勒个去。。。。

   于是分析了一下,经过一天的研究,终于发现,原来尼玛芯片厂商对media和tv信号的播放处理,在最底层使用都是同一个通道,存在缺陷,无法灵活切换。。这样的结果就是,如果用户使用播放某个视频文件,然后按住home键退出,回到launcher的TV播放页面,这个时候会出现tv无法播放的问题。

   而某些应用,在被home处理到后台的时候,是不会去释放media资源的。。。这该如何是好。而且针对TV的这种场景,不同于手机,进入launcher是需要将一些后台播放的如音乐播放等这些给关掉的。。。

   后来想了两个方法,一个叫笨笨一个叫聪聪:

   笨笨的方法就是,把这些media应用加入黑名单,只要进入launcher的TV页,遍历一遍这些应用列表,然后判断在Launcher的onResume中判断刚才的包是否是这些应用,如果是的话就kill掉他们。。。

   这种方法,虽然简单,但是不够灵活,如果用户装了多个多媒体软件,那么黑名单这种模式,就无法cover住了。。。

   后来开动脑子,想了个歪主意,就是要使能够知道谁占用了media资源,然后根据它的pid号杀死它就好了。。。

  那么就需要做两部:

  1 如何获取占用media资源的pid.也就是我是谁?

   2 如何把这个pid告诉给需要杀死我的人,这么贱。。。嘿嘿。。

   如果获取占用media资源的id号呢。。。。嘿嘿。。。这个就需要修改Framework中的MeidaPlayer源生SDK。。。

Binder.getCallingPid();这个方法写在某个方法中,就可以知道谁调用了我。。。我把它写在了MediaPlayer的start()方法中。
   这样就顺利的完成了我是谁的任务了。。。但是如何通知Launcher应用杀我呢。。用广播?MediaPlayer SDK木有context啊。。。重新封装接口?改动太大。。想想android其他的跨进程通讯的方式。。。貌似都行不通,linux的呢?socket?共享内存?尼玛。。。太蛋疼了。。。超级复杂哇。。。

   算了还是写文件告诉别人吧。。。可以由于android的安全机制,是不允许一个SDK写一个文件被应用来访问的。。。这个该如何是好啊。。。哎,根据本人之前的linux开发经验,想了个不是办法的办法。。。那就是利用tmpfs这个在内存中的文件系统。。。掉电消失。。。。呵呵。。。这个文件系统没有这么多权限,谁都可以访问。。。哈哈。。。太好了。。。可以遇到问题了,忙活了半天发现木有这个/tmp目录在我的电视中。。。咋办?

  只好,自己丰衣足食了。。。囧

   这个需要在自己的系统代码中的相应平台的xxxx_init.rc中添加,注意不是在init.rc中,那个木有用。。。至于为啥没用,请看android加载的init机制。。。

   mkdir /tmp 0777 system system
mount tmpfs tmpfs /tmp mode=0777,gid=1000,size=1024k这样就创建好了这个tmpfs的文件系统。。。烧完系统点亮机器,哎。。。尼玛有了。。。泪流满面啊。。

接下来就简单了。。。只需要将第一步中获取的pid写到这个tmpfs中就行了,我用pid号作为文件名,这个想法来自于早期学习linux /proc文件系统中看到的pid目录。。linux查看pid的ps命令就是检索这些目录名来获取pid的信息。。。呵呵。。。。

于是乎在MediaPlayer.start()中在tmpfs下创建以pid为名的文件。。。怎么创建一个文件,这里就不说了。。

记住,当MediaPlayer.realse()的时候一定要将tmpfs下的这个pid文件给删除掉,不要造成误删。

完成了,身份识别和通知机制,最后的杀手出场了,当进入到Launcher的TV页时候,我们通过读取tmpfs的pid文件,获取pid,然后通过pid获取package的名字,通过包名来杀死这个应用。。。注意这里杀死应用,需要用到java反射机制。

贴下核心杀人代码:

ActivityManager am = (ActivityManager)getSystemService(
Context.ACTIVITY_SERVICE);
Method forceStopPackage = am.getClass()
.getDeclaredMethod("forceStopPackage", String.class);
forceStopPackage.setAccessible(true);
forceStopPackage.invoke(am, kill_package);

如何通过pid获取package的包名:
是通过ps pid命令来获取输出,然后进行匹配。。。得到包名。。。。

注意你的Launcher如果没有system 权限,我这篇文章你看了也没用。。

自宫也无法练成辟邪剑谱,哈哈

打完收工。。。。哈哈。。。绕过android安全机制的一个方法。。。希望对大家有用。。。还好自己以前搞过linux,写过驱动,干过脏活。。。呵呵。。。

  

  


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: