谈谈Android的进程

Sun 01 November 2015

谈谈Android的进程

原创内容转载请注明源地址: http://jksoftcn.com/

Android的底层虽然是Linux,但是它的进程管理机制和Linux还是有些差异的。

传统层面的进程

传统层面的进程规则还是和Linux一样

init是1号进程,这是Linux内核启动的第一个应用层程序,其他进程都是1号进程的子孙。 进程可以fork出自己的子进程。这意味着你使用JNI在APP中调用fork函数fork出子进程。

Android层面的进程

APP进程虽然本质上是Linux进程,但这个层面的游戏规则不一样了

所有正常启动的APP进程都是zygote创建出来的子进程。因为zygote已经创建好虚拟机了,并且预加载了framework,由zygote fork可以让其他APP进程直接使用zygote创建好的虚拟机环境,省了很多事。

一个APP可以拥有多个进程,即:不同的组件运行在不同的进程。但同一个APP的不同进程间是平级的,没有从属关系,父进程都是zygote。看了下面的内容,应该能理解这么设计的意图。

APP默认的进程名是APP的包名,可以指定组件运行在:xxx这样相对命名进程里面,实际上是packageName:xxx

不同的APP(不管签名是否一样)都可以共用一个进程名(其实进程名只是cmdline)。某ROM里面Low memory Killer的白名单用的就是进程名,这是一个漏洞。

APP进程执行的代码由两部分组成:apk里面的dex文件,加系统的framework。并且APP进程的入口main不在apk中,这和桌面的Java程序不同,相同的是都有main

网上有个关于Android面试的笑话,面试官问APP的入口是什么?回答ActivityThread中的main,面试官纠正是ActivityonCreate

呵呵,不要学那个面试官。APP的入口确实在ActivityThread中。zygotefork出我们的APP进程后就是执行这里的main,但执行后只创建了一个消息循环,没有干其他的事情。

因为ActivityService都不是APP进程主动创建的,而是被动创建执行的。被动的执行系统服务的远程调用,把系统的请求丢进消息队列里面去执行。

APP启动

从上图(该图来源于网络)可以看出APP进程在创建后收到两条指令:

  1. BIND_APPLICATION,要求进程构造出Application对象,激活Application对象(attach),调用onCreate
  2. LAUNCH_ACTIVITY,要求进程构造出指定的Activity对象,激活Activity对象(attach),调用onCreate

实际上指令顺序仅是一种场景。还有其他场景,如:有可能进程是因为要启动服务而起来,或收到广播而起来,但有一个是绝对不变的,就是每个APP的进程,都必定实例化了一个Application对象。

为什么关联进程不是由主进程fork的,那是因为关联进程只需要运行指定的组件加Application。非要这么搞弊大于利,如:内存占用,继承来的fd,系统服务缺少进程记录,请求发不过来等等。

不使用Android SDK枚举APP进程

Android 5.0前我们可以使用ActivityManager.getRunningAppProcesses()枚举进程 但5.0后系统限制了我们使用这个API

SDK中的实现在ActivityManagerService这个类中。5.0系统要求android.Manifest.permission.REAL_GET_TASKS权限加系统签名。为了兼容旧的system APP,过渡期允许android.Manifest.permission.GET_TASKS权限。

说白了,普通应用再也没法调用这个API了。怎么办了?

Android层面没权限,但在Linux层面我们却是有权限的,Linux的内核维护了procfs这样一个虚拟的文件系统。在/proc下面,每个数字命名的文件夹都代表一个进程。我们有权限枚举/proc这个目录,而且每个进程对应目录下面的cmdline, stat文件我们也有读取的权限。

枚举APP进程的方法就变得很简单:

  1. 通过/proc枚举出所有的进程,和其父进程PID
  2. 找出zygote进程的PID
  3. 所有父进程PID是zygote的PID的进程,都是APP进程

如何结束APP进程

如果是APP结束自己的进程很简单,但一般的APP没有这个需求,并且系统也不推荐你主动退出。

桌面Java程序退出进程的方法:System.exit(),在Android上一样可以使用。

另外Android也有专门的API:

android.os.Process.killProcess(android.os.Process.myPid());

如果要结束其他APP的进程,在Linux层面普通APP是没有权限的,因为不同APP(排除指定共享UID,签名一样的不同APP)运行的UID是不一样的。虽然Linux层面没戏,但是Android层面还是有办法的,系统给用户提供了一个强制停止应用的方法。

强制停止是按UID来结束进程的,相同UID不管是zygote fork出来的,还是APP自己用JNI fork出来的,是一起杀的。因此用子进程监控父进程是否被杀对于这种情况不适用。

普通APP可以利用辅助功能模拟点击去执行这个强制停止功能,就和用户自己操作一样。辅助功能当然不是能随便获得的,需要用户到设置里面勾选。

如何保证进程不退出

暂时只讨论进程不被系统干掉

系统的Low Memory Killer是按进程的oom_adj来选择进程杀死的。对于普通的APP,没界面的比有界面的先被杀。

大部分APP都想让某个Service能一种跑着,肯定是没有界面的。怎么办?目前有两个黑暗技术能达到目的:

  1. 在跑Service的进程里面,跑一个你看不到的悬浮窗
  2. Service设为前台服务, 就是一直有个常驻通知栏的

现在很多ROM给悬浮窗搞了权限控制,悬浮窗都不是能随便显示的了,因此方法1现在不可靠。方法2看上去有一个常驻的通知栏,但却是有方法让它不显示出来。

总结

上面描述的都是一个普通APP。系统APP和以root用户跑的APP情况不一样。有空了再补充 跨进程共享组件

Category: Android Tagged: Android Linux Process

comments


Android源码镜像站的操作

Mon 12 October 2015

Android源码镜像站的操作

制作镜像站

本文假设你已经阅读过Android官方的Downloading the Source。 假设机器是www.jksoftcn.com,一台Ubuntu的Linux, 下面的操作在root用户下面操作

先准备好代理服务器:

如果你用的是shadowsocks,可用这样启动一个本地的代理:

sslocal -s 服务器 -p 端口 -b 127.0.0.1 -l 1080 -k 密码 -t 600 -m 加密算法 &

让git也可用使用这个socks5代理:

cat << EOF > ./proxy.sh
#!/bin/bash

export HTTP_PROXY=socks5://127.0.0.1:1080
export HTTPS_PROXY=socks5 …

Category: Android Tagged: Android 源码 Linux

comments

Read More

Android和Linux的关系

Thu 01 October 2015

Android和Linux的关系

引导

GRUB vs Bootloader

Linux主流引导程序是grub,以grub2为例,如果GRUB是安装在MBR上,BIOS加载MBR执行GRUB,GRUB寻找/boot分区, 按grub.cfg的内容显示系统列表。 grub2引入了模块的概念,原因是:识别设备,文件系统靠all in one的程序已经搞不定了。grub2加载Linux内核和initrd系统,操作系统真正开始执行。

Android没有硬盘,没有GRUB,CPU加电后执行flash上的Bootloader,Bootloader加载Linux内核。过程和GRUB类似,不同的是Bootloader位于flash的起始位置,kernel是接在kernel后面的一个固定位置。每个SoC厂商的bootloader一般是不一样的,而GRUB是通用的。

文件系统

ext4目前都很受欢迎

system分区, data分区都在flash(NAND)上:

shell@android:/ $ ls -al /dev/block/platform/omap/omap_hsmmc.0/by-name
lrwxrwxrwx root     root …

Category: Android Tagged: Android Linux

comments

Read More

KVM安装黑群晖

Thu 01 October 2015

KVM安装黑群晖

用VMWare ESX和MS Hyper-V虚拟黑群晖的教程论坛里面已经有一大把。但使用KVM虚拟黑群晖的帖子基本没有。

系统环境

用Ubuntu 14.04 LTS做虚拟机的Host。为什么是Ubuntu不是CentOS不解释,每个人喜好不一样。个人觉得Ubuntu的网桥配置会简单一点,LVM的支持也更稳定些。

为什么是Ubuntu而不是CentOS,

STEP1. 安装Ubuntu的Host

网速快的朋友建议网络安装:

http://mirrors.aliyun.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/mini.iso

网速不快的朋友,可以下载完整的ISO:

http://mirrors.aliyun.com/ubuntu-releases/14.04.3/ubuntu-14.04.3-server-amd64.iso

安装的过程就不细说,网上大把的教程,我只选择安装了OpenSSH Server …

Category: Linux Tagged: Linux KVM NAS

comments

Read More

虚拟化技术的选择

Mon 04 August 2014

虚拟化技术的选择

目前大家接触到的主流虚拟化方案有:VMWare的esx(不管它之前叫什么,现在又叫什么),基于Linux的XEN,KVM,基于Windows的Hyper-V。琳琅满目,怎么选择呢?

首先在不缺钱的情况下,优先选择商业的解决方案,在商业解决方案里面,优先选择VMWare。因为VMWare的实力摆在哪里,而且提供的API接口和Sample足以支持你进行符合你需求的管理开发。Esx方案是对硬件有一定的要求,主要是驱动,不过网络上已经有订制工具可以给安装iso增加网卡驱动,raid的驱动能不能加就不太清楚。

XEN是KVM之前基于Linux的主流虚拟化方案,它和KVM相似的地方都是基于Linux,都可以使用libvirt进行管理,都使用qemu的部分技术。现在的阿里云应该就是就要XEN实现的。如果现在你在XEN和KVM直接选择的话,我不推荐你使用XEN。因为Linux现在主推KVM,除非你使用XENServer类的商业XEN方案。在体验XEN的时候还遇到诡异的问题,virsh获取的VM的状态飘忽不定,我果断中止了对XEN的探索,把有限的技术拿去学习更靠谱的技术。

KVM是目前Linux内核支持的虚拟化方案,你不想要专门去定制一个内核。和XEN相比,XEN的host算一个VM,而KVM的host就是host。libvirt对两者都有支持,都可以使用virsh来管理。都使用了qemu技术,但区别很明显XEN是半虚拟化方案,而KVM既支持半虚拟化也支持全虚拟化。KVM的优势很明显,在使用全虚拟化的时候,可以在I/O部分使用半虚拟化驱动来提供I/O性能。

就目前而言KVM的资料应该比XEN更容易找到,如果要学习 …

Category: Linux Tagged: Linux KVM XEN esx

comments

Read More
Page 1 of 1