Android Process 详解

日积月累第二周第五天。学不完的东西,坚持就是胜利!




Android基础之Process
进程
默认情况下,同一个应用程序中的所有组件运行在同一个进程中,而且绝大多数的应用程序也都是这样的。但是,如果我们想要控制让某个特定的组件属于某个进程,我们可以在manifest文件中进行配置。
在每种组件元素(activity、service、receiver、provider)的manifest条目中,都支持一个“android:process”的属性,通过这个属性,我们可以指定某个组件运行的进程。我们可以通过设置这个属性,让每个组件运行在它自己的进程中,也可以只让某些组件共享一个进程。我们要可以通过设置“android:process”属性,让不同应用程序中的组件运行在相同的进程中,这些应用程序共享相同的Linux用户ID,拥有相同的证书。
元素也有一个“android:process”属性,可以设置一个应用于全部组件的默认值。
    当可用内存数量低,而一些与用户即时交互的进程又需要内存时,Android随时可能会终止某个进程。运行在被终止的进程中的组件会因此被销毁,但是,当再次需要这些组件工作时,就会再启动一个进程。
    在决定要终止哪个进程时,Android系统会权衡它们对于用户的重要性。例如,相较于运行可见activities的进程,终止一个运行不可见activities的进程会更加合理。是否终止一个进程,依赖于运行在这个进程中的组件的状态。
 
进程生命周期
Android系统会尽可能让一个应用程序进程运行更长的时间,但是它也需要移除旧的进程,为那些新创建的进程或者相比起来更加重要的进程释放内存空间。要决定哪个进程保留,哪个进程终止,系统会将每个进程放置到“importance hierarchy”中,“importance hierarchy”是基于运行在进程中的组件以及这些组件的状态的。拥有最低重要性的进程会首先被干掉,然后就是那些次低重要性的进程,依次类推。
在“importance hierarchy”中,共有五个等级。下面的列表中,按照重要性列出了五种不同类型的进程:
1、 前台进程(Foreground process)
2、 可见进程(Visible process)
3、 服务进程(Service process)
4、 后台进程(Background process)
5、 空进程(Empty process)
 
Android process与Thread 的问题
 
Android process与Thread 的问题
public class Activity2 extends Activity
{
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);




new Thread()
{
public void run()
{
dosomething();


}
}
.start();


}
在启动新线程时,出现如下错误:
W/ActivityManager( 81): Launch timeout has expired, giving up wake lock!
W/ActivityManager( 81): Activity idle timeout for HistoryRecord
解决办法:为相应的Activity1及Activity2增加Android:process属性,强制使两个Activity处于不同的应用程序私有进程之中。
问题出现的具体原因待进一步研究。
/guide/topics/manifest/activity-element.html
元素 Android:process属性定义了运行Activity所在进程的名称。通常,一个应用程序的所有组件运行在应用程序创建的默认的进程。它具有与应用程序包相同的名称。元素的 android:process属性可以为所有组件设置不同的默认进程名称。但是,每个组件都可以覆盖默认设置,让应用程序跨多个进程。
如果分配给此属性的名称以一个冒号(':')开头,发将创建一个新的属于应用程序的私有的进程,在这一进程中运行。
如果进程的名称由小写字母开始,活动将在该名称的全局进程中运行,只要它有这样做的权限。这样做将使在不同的应用程序中的组件共享一个进程,减少资源的使用。






android:process可以针对一个组件(activity,broadcast等)。







应用程序的所有组件运行在该进程中。每个组件可以通过设置它自己的process属性来覆盖该设置。
默认情况下,Android为每个应用程序创建一个单独的进程,所有组件运行在该进程中,这个默认进程的名字通常与该应用程序的包名相同。
比如         package="com.lt.mytest" >
那么该程序默认的进程名为com.lt.mytest
设置该属性可以使得本应用程序与其它应用程序共享相同的进程,仅仅当这两个应用程序也共享一个拥有相同签名的UserId。
    android:sharedUserId="android.uid.phone" >
与其它应用程序共享的一个Linux User Id的名字。
默认情况下,Android为每个应用程序分配一个唯一的User Id。然而,如果有多个应用程序都将该属性设置为一个相同的值,那么它们将共享相同的Id。如果这些应用程序再被设置成运行在一个相同的进程,它们便可以彼此访问对方的数据。






AndroidManifest.xml的Service元素 android:process设置




AndroidManifest.xml的Service元素
< service  android:name =".RemoteService"  android:process =":remote" >  
         < intent-filter >  
                 < action  android:name ="com.demo.IMyService"  />  
           

    这里的android:process=":remote",一开始我没有添加的,在同一个程序里使用IPC,即同一个程序作为客户端/服务器端,结果运行mRemoteService = IMyService.Stub.asInterface(service);时提示空指针异常。观察了人家的在不同程序里进行IPC的代码,也是没有这个android:process=":remote"的。后来在官方文档 http://androidappdocs.appspot.com/guide/topics/manifest/service-element.html里了解到(留意第二段文字):
android:process
The name of the proces s where the service is to run. Normally, all components of an application run in the default process created for the application. It has the same name as the application package. The element's process attribute can set a different default for all components. But component can override the default with its own process attribute, allowing you to spread your application across multiple processes.
 
If the name assigned to this attribute begins with a colon (':'), a new process, private to the application, is created when it's needed and the service runs in that process.  If the process name begins with a lowercase character, the service will run in a global process of that name, provided that it has permission to do so. This allows components in different applications to share a process, reducing resource usage.
 也就是说android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。




看过很多关于Android Service开发的文章, 而其中大部分在讲解远程服务时, 都只是照搬了代码格式, 即便是使用了AIDL (Android Interface Definition Language), 也用了IBinder接口, 但是App在实际运行中还是以本地服务的方式启动的.
 
除此之外, 在调试时, 我们还可以看到 ServiceConnection::onServiceConnected(ComponentName name, IBinder binder) 中binder的实际类型, 通过该类型, 即可知App到底调用的是本地对象还是远程对象.
 
P.S. IBinder是Android RPC (Remote Procedure Call) 的核心接口, 其中Camera, MediaPlayer等都是通过RPC技术实现的, 而为之服务的就是一个独立的进程, 这个可以通过adb shell ps 可以看到.
 
具体请参考 Android 源码 http://source.android.com/ .
 
 
进入正题
 
本地/远程服务最大的区别在于对 AndroidManifest.xml中service属性 android:process 的设置, 而该属性是可以随意设置的, 比如 android:process=":remote_1".
 
该属性一旦设置, 那么App启动之后, Service肯定会以远程服务方式启动, ---- 可通过adb shell ps 就可以看到有一个独立的进程启动了. 
 
假设项目 Package为 net.oschina.demo , 并设置 android:process=":remote_1", 那么App运行时, 通过 adb shell ps | grep net.oschina.demo , 可以看到有两个进程:
 
    * net.oschina.demo
    * net.oschina.demo:remote_1
 
 
官方文档
http://developer.android.com/guide/components/services.html
http://developer.android.com/reference/android/app/Service.html

你可能感兴趣的:(Android)