【Android面试题】Android Framework核心面试题——Android中Pid&Uid的区别和联系

Android中Pid&Uid的区别和联系

这道题想考察什么?

考察Android 系统中Pid 以及Uid的概念和理解

考试应该如何回答

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

PID

Android中的PID全称为Process Identifier,来源于Linux中,在进程启动的时候系统会为进程分配一个独一无二的标识,进程销毁后PID会被系统回收,但是在Android中一般不会重新分配,后面的进程PID会比前面的进程的大。但是对同一个安卓应用可以具有多个PID,添加也很方便,只需要在声明类时指定进程名称即可,代码如下:

 <activity android:name=".TestActivty" android:process="com.xiaohan.test"/>

添加很方便,但是不能随意使用,因为在同一个应用(PID)中,设计到程序之间最多的是线程间的通信,一旦独立出PID则涉及到进程间通信,类似于不同的两个应用,当然也可以通过上面的私有暴露和权限暴露的方式实现数据的通信,但是系统的开销较大。

UID

Android中的UID一般认为是User Identifier,同样来源于Linux中。但是在Android中不太一样,Android最初的设计是单用户,所以UID并不是为了区别用户的,而是为了不同程序间进行数据共享。Android中每个程序都有一个Uid,默认情况下,Android会给每个程序分配一个普通级别互不相同的Uid,因此如果程序期望互相调用,只有Uid相同才行,这就使得共享数据具有了一定安全性,每个软件之间是不能随意获得数据的。而同一个application只有一个Uid,所以application下的Activity之间不存在访问权限的问题。

android中uid用于标识一个应用程序,uid在应用安装时被分配,并且在应用存在于手机上期间,都不会改变。一个应用程序只能有一个uid,多个应用可以使用sharedUserId 方式共享同一个uid,前提是这些应用的签名要相同。

UID如何分配

在应用启动的时候,或者手机启动的时候,PackageManagerService都会去解析apk,并且为app分配一个UID,具体的流程如下(基于Android11):

PackageManagerService.java 中在PMS 构造函数初始化的时候会执行到一个函数scanDirTracedLI(),在scanDirTracedLI()中会执行scanDirLI(),然后会执行scanPackageTracedLI(),然后再执行scanPackageLI(),然后再执行addForInitLI(),然后执行scanPackageNewLI(),当然这个过程中会涉及到很多代码细节,建议大家去学习本章中关于PKMS部分的内容。在这个scanPackageNewLI函数中会执行mSettings.getSharedUserLPw(),去获取共享用户,如果没有就创建新的,大家看下面的代码:

SharedUserSetting getSharedUserLPw(String name, int pkgFlags, int pkgPrivateFlags,
		boolean create) throws PackageManagerException {
    
    
	SharedUserSetting s = mSharedUsers.get(name);
	if (s == null && create) {
    
    
		s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
		s.userId = acquireAndRegisterNewAppIdLPw(s); //核心代码
		if (s.userId < 0) {
    
    
			// < 0 means we couldn't assign a userid; throw exception
			throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
					"Creating shared user " + name + " failed");
		}
		Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
		mSharedUsers.put(name, s);
	}
	return s;
}

上面的代码显示,如果没有为这个app创建SharedUserSetting 信息且需要创建一个,那么就创建一个,然后再调用acquireAndRegisterNewAppIdLPw函数为其分配UID。

private int acquireAndRegisterNewAppIdLPw(SettingBase obj) {
    
    
	// Let's be stupidly inefficient for now...
	final int size = mAppIds.size();
	//code1 从0开始,找到第一个未使用的ID,此处对应之前有应用被移除的情况,复用之前的ID
	for (int i = mFirstAvailableUid; i < size; i++) {
    
    
		if (mAppIds.get(i) == null) {
    
    
			mAppIds.set(i, obj);
			return Process.FIRST_APPLICATION_UID + i;
		}
	}

   //code2 最多只能安装 9999 个应用
	// None left?
	if (size > (Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID)) {
    
    
		return -1;
	}

	mAppIds.add(obj);
    // code3 可以解释为什么普通应用的UID 都是从 10000开始的
	return Process.FIRST_APPLICATION_UID + size;
}

从上面我们可以看到,给APP分配的UID是遵守如下几个原则:1)从code1知道,id是可以复用的,当一个app卸载了,那么它的id会被后面安装的app复用,2)从code2得知,用户id不能超过19999,也就是说可以安装的app数不能超过9999个,否则安装的app没有uid分配;3)每个UID 都是一个大于 Process.FIRST_APPLICATION_UID 的数字,也就是都大于10000;

Android中UID的价值

在Android中一个UID的对应的就是一个可执行的程序,程序在Android系统留存期间,其UID不变。 在Android中采用沙箱的概念来管理程序,不同的程序具有唯一的UID和PID,通过该UID来标识其所具有的“资源”,包括文件目录、数据库的访问、网络、传感器和日志等,和Linux一样,相互之间互不影响。

在这里插入图片描述

不同的应用程序一般是运行在不同的进程中,相互之间的“资源”不可以访问,但可以通过进程共享的方式,实现不同程序之间的数据访问主要是针对Activity、Service和ContentProvider,其实现方式按照权限暴露级别分为:完全暴露、权限提示暴露和私有暴露三种方式。

完全暴露

是指通过android:exported=”true”实现,在AndroidMaindfest.xml中申明Activity、Service或ContentProvider时,将该属性设置为true后,就表明该类允许外界的数据访问。如果在申明时添加了intentFilter属性,则默认exported就为true,此时也可强制的设置为fasle。如未做其他设置(exported/intentFilter),则默认exported为fasle,即不对外暴露。如下代码所示:

<activity android:name=".TestActivty" android:exported="true"/>

权限提示暴露

在AndroidMaindfest.xml中申明Activity、Service或ContentProvider时,添加了permission,表明如果其他应用需要访问该类时,需要在该应用添加该类声明时的权限, 声明私有的权限,如下所示。

<activity android:name=".TestActivty" android:permission="com.xiaohan.permission"/>
//添加访问的权限说明
<uses-permission android:name="com.xiaohan.permission"/>

私有暴露

不同于以上两种类的暴露方式,如果想对于不同应用之间可以互相访问任何数据,则需要通过sharedUserId+同一套签名的方式实现,只有这样才能运行在同一个进程中(同一个沙箱中)保证数据的相互访问。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.xiaohan.test"      //应用包名
    android:sharedUserId="com.xiaohan.sharedUID"  //暴露的唯一标识
    android:sharedUserLabel="@string/app_name"  //必须是引入资源文件中的字符串
    android:versionCode="1"
    android:versionName="1.1.0"
    //安装位置,默认在内部目录,还包括auto:自动、  preferExternal:外置SD卡中
    android:installLocation="internalOnly">

在这里插入图片描述

总结

不同的应用具有唯一的UID,同一个UID可具有不同的PID;

针对不同的PID之间数据的暴露可采用私有暴露和权限暴露,针对不同的UID之间可通过完全暴露的方式;

如果一个应用是系统应用,则不需要其他应用暴露,便可直接访问该应用的数据。

最后

我整理了一套Android面试题合集,除了以上面试题,还包含【Java 基础、集合、多线程、虚拟机、反射、泛型、并发编程、Android四大组件、异步任务和消息机制、UI绘制、性能调优、SDN、第三方框架、设计模式、Kotlin、计算机网络、系统启动流程、Dart、Flutter、算法和数据结构、NDK、H.264、H.265.音频编解码、FFmpeg、OpenMax、OpenCV、OpenGL ES
在这里插入图片描述

有需要的朋友可以扫描下方二维码,免费领取全部面试题+答案解析!!!

猜你喜欢

转载自blog.csdn.net/datian1234/article/details/133393214