uid和sharedUserId, andoird:process属性 沙箱

1.pid和uid

Pid是进程ID,Uid是用户ID,只是Android和计算机不一样,计算机每个用户都具有一个Uid,哪个用户start的程序,这个程序的Uid就是那个用户,而Android中每个程序都有一个Uid,默认情况下,Android会给每个程序分配一个普通级别互不相同的 Uid,如果应用之间要互相调用,只能是Uid相同才行,这就使得共享数据具有了一定安全性,每个软件之间是不能随意获得数据的。而同一个application 只有一个Uid,所以application下的Activity之间不存在访问权限的问题。

2. 跨应用共享数据

可以用这个方法:

A和B的AndroidManifest的manifest节点添加相同的sharedUserId.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cn.andoop.android.dload"
    android:sharedUserId="com.share.test">


这两个应用程序的userid相同,都为com.share.test 因此两个应用程序共享userid,如果1想访问2的数据怎么办呢?
Content content = this.createPackageContent("com.test.application2“,Content.CONTENT_IGNORE_SECURITY);
这样通过content可以获取到应用2中的资源,包括:数据库,preference,资源文件等等

假设获取一个drawable资源

        Resources res = content.getResources();  
        int menuIconId = res.getIdentifier("icon", "drawable",  
                "com.test.application2");  
        Drawable drawable = res.getDrawable(menuIconId); 

3. andoird:process

在Manifest文件中Application以及各个组件均可以设置
(0)以‘:进程名称’(比如:remote)的方式进行命名,和字符串(com.test.name)完整命名方式有什么区别呢?
第一个区别: 以 ':进程名称' 的方式命名的话代表 在当前进程名前面附加上当前的包名 最终的进程名称就是 com.test.remote ,其实这只是一种缩写的方式
第二个区别: 以':进程名称' 的命名的进程的 表示是当前应用的私有进程,其它应用的组件不可以和他跑在同一个进程中,而进程名不以':'开头的进程属于全局进程,其它应用通过ShareID【android系统会为每一个应用分配一个唯一的UID,具有相同的UID应用才可以共享数据】方式可以和他跑着同一个进程中

(1)在Application中设置:

应用程序的进程名,所有组件默认情况下均运行在这个进程中,其默认名字为PackageName。可以设置两个APP运行在同个process下,当且仅当两个APP具有想通的user ID并且被同一个私钥签名。

(2)在activity中设置

为这个Activity、Service单独创建一个进程。

所以:

(1)可以设置android:process属性使APP的组件运行在不同的进程上
(2)可以设置android:process以使不同应用的组件们可以运行于同一个进程—假如这些应用共享同一个用户ID并且有相同的数字证书

4.多进程多模块应用的场景

1.在新进程中开启服务.
2.多模块的好处. 
(1)比如我做的应用大而全,里面肯定会有很多模块,假如有地图模块、大图浏览、自定义WebView等等(这些都是吃内存大户),还会有一些诸如下载服务,监控服务等等,一个成熟的应用一定是多模块化的。
(2)多进程开发能为应用解决了OOM问题,Android对内存的限制是针对于进程的,这个阈值可以是48M、24M、16M等,视机型而定,所以,当我们需要加载大图之类的操作,可以在新的进程中去执行,避免主进程OOM。
(3)多进程还能更有效、合理的利用内存。我们可以在适当的时候生成新的进程,在不需要的时候及时杀掉,合理分配,提升用户体验。减少系统被杀掉的风险。
(4)多进程还能带来一个好处就是,单一进程崩溃并不影响整体应用的使用。例如我在图片浏览进程打开了一个过大的图片,java heap 申请内存失败,但是不影响我主进程的使用,而且,还能通过监控进程,将这个错误上报给系统,告知他在什么机型、环境下、产生了什么样的Bug,提升用户体验。
(5)再一个好处就是,当我们的应用开发越来越大,模块越来越多,团队规模也越来越大,协作开发也是个很麻烦的事情。项目解耦,模块化,是这阶段的目标。通过模块解耦,开辟新的进程,独立的JVM,来达到数据解耦目的。模块之间互不干预,团队并行开发,责任分工也明确。

5.进程的5个等级

重要性层次结构一共有 5 级。以下列表按照重要程度列出了各类进程(第一个进程最重要,将是最后一个被终止的进程):

1.前台进程:(foreground process)
用户当前操作所必需的进程。如果一个进程满足以下任一条件,即视为前台进程:
托管用户正在交互的 Activity(已调用 Activity 的 onResume() 方法)
托管某个 Service,后者绑定到用户正在交互的 Activity
托管正在“前台”运行的 Service(服务已调用 startForeground())
托管正执行一个生命周期回调的 Service(onCreate()、onStart() 或 onDestroy())
托管正执行其 onReceive() 方法的 BroadcastReceiver
通常,在任意给定时间前台进程都为数不多。只有在内存不足以支持它们同时继续运行这一万不得已的情况下,系统才会终止它们。 此时,设备往往已达到内存分页状态,因此需要终止一些前台进程来确保用户界面正常响应。

2.可见进程:
没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。 如果一个进程满足以下任一条件,即视为可见进程:
托管不在前台、但仍对用户可见的 Activity(已调用其 onPause() 方法)。例如,如果前台 Activity 启动了一个对话框,允许在其后显示上一 Activity,则有可能会发生这种情况。
托管绑定到可见(或前台)Activity 的 Service。
可见进程被视为是极其重要的进程,除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。

3.服务进程
正在运行已使用 startService() 方法启动的服务且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如,在后台播放音乐或从网络下载数据)。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。

4.后台进程:
包含目前对用户不可见的 Activity 的进程(已调用 Activity 的 onStop() 方法)。这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。 通常会有很多后台进程在运行,因此它们会保存在 LRU (最近最少使用)列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。如果某个 Activity 正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该 Activity 时,Activity 会恢复其所有可见状态。 有关保存和恢复状态的信息,请参阅 Activity文档。

5.空进程
不含任何活动应用组件的进程。保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。 为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。
根据进程中当前活动组件的重要程度,Android 会将进程评定为它可能达到的最高级别。例如,如果某进程托管着服务和可见 Activity,则会将此进程评定为可见进程,而不是服务进程。

此外,一个进程的级别可能会因其他进程对它的依赖而有所提高,即服务于另一进程的进程其级别永远不会低于其所服务的进程。 例如,如果进程 A 中的内容提供程序为进程 B 中的客户端提供服务,或者如果进程 A 中的服务绑定到进程 B 中的组件,则进程 A 始终被视为至少与进程 B 同样重要。

由于运行服务的进程其级别高于托管后台 Activity 的进程,因此启动长时间运行操作的 Activity 最好为该操作启动服务,而不是简单地创建工作线程,当操作有可能比 Activity 更加持久时尤要如此。例如,正在将图片上传到网站的 Activity 应该启动服务来执行上传,这样一来,即使用户退出 Activity,仍可在后台继续执行上传操作。使用服务可以保证,无论 Activity 发生什么情况,该操作至少具备“服务进程”优先级。 同理,广播接收器也应使用服务,而不是简单地将耗时冗长的操作放入线程中。

6.多进程可能遇到的问题

1:静态成员和单例模式的失效

首先我举个例子:
应用中有一个静态成员变量
public static int staticMember=0;
我们在MainActivity 中设置staticMember=1,然后在Main2Activity获取静态成员staticMember值会是1吗?当然不是,WHY ,这是为什么呢。。
这就是多进程的运行机制了,一个应用中的每一个进程都是运行在独立的虚拟机上的,也就是拥有独立的内存。进程之间不采取手段的话,是不可以共享内存数据的。当前是没有采取手段的,那么Main2Activiy访问的变量其实就是静态成员变量的初始副本值,也就是默认值0.或者说,不同的虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问同一个类的对象会产生多份副本

通过静态成员变量的例子,也就得以知道了单例模式的失效原因,那是因为单例模式是在当前单例实例化进程中有限的。

2:线程同步机制完全丧失

在这里我们讲下线程和进程的概念关系
(1):线程
是cpu调度的最小单元,是一种有限的资源。
(2):进程
指一个执行单元,在pc和移动设备中指一个程序或者一个应用或一个进程
二者之间的关系为进程包括线程,线程只生存在他运行所处的进程中。

线程同步机制丧失也是因为不同进程锁的不是同一个对象,或者不是同一个全局类,由进程的运行机制可以看出,独立的虚拟机,独立的内存。。。
3:SharedPreferences的可靠性下降

因为SharedPreferences 不支持两个进程同时去执行读写操作,否者会导致一定几率的数据丢失,这是因为它的底层是通过读写xml文件来实现的,并发读写有可能会出问题
4:Application的多次创建

当一个组件跑在一个新的进程中的时候,由于系统要在创建新的进程的同时分配独立的虚拟机,所以这个过程其实就是一个启动应用的过程。相当于应用重新启动了下,重新启动的话,自然就会重新创建Application

多进程的运行机制一句话总结就是,每一个进程是运行在独立的虚拟机和拥有独立的内存。多进程模式中,不同进程的组件会拥有独立的虚拟机,Application以及内存空间,当然这会给实际开发带来困扰,

android系统提供了很多的跨进程通信的方法,虽然不可以直接的共享内存,但是通过通信我们还是可以实现数据交换的。实现跨进程通信的方式有很多种,除了有四大组件的方式还有共享文件,SharedPreferences,基于Binder 的Messenger和AIDL以及Scoket等

7.沙箱

沙箱是什么?
对使用者来说可以理解为一种安全环境,对恶意访问者来说是一种限制。
Android“沙箱”的本质是为了实现不同应用程序和进程之间的互相隔离,即在默认情况 下,应用程序没有权限访问系统资源或其它应用程序的资源。

(1)每个APP和系统进程都被分配唯一并且固定的User Id,这个uid与内核层进程的uid对应。
(2)每个APP在各自独立的Dalvik虚拟机中运行,拥有独立的地址空间和资源。
(3)运行于Dalvik虚拟机中的 进程必须依托内核层Linux进程而存在,因此Android使用Dalvik虚拟机和Linux的文件访问控制来实现沙箱机制
(4)任何应用程序如果想要访 问系统资源或者其它应用程序的资源必须在自己的manifest文件中进行声明权限或者共享uid。
(5)通过sharedUserId,拥有同一个id的多个APK可以配置成运行在同一个进程中.所以默认就是可以互相访问任意数据. 也可以配置成运行成不同的进程, 同时可以访问其他APK的数据目录下的数据库和文件.就像访问本程序的数据一样.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值