AndroidP应用uid的设置过程

本文探讨了在AndroidP中如何为特定第三方应用设置system uid,详细解析了应用uid的设置流程,包括Zygote启动应用、Package uid设定、addSharedUser逻辑、包扫描过程以及解决方法。通过分析,提出了三种方案,最终实现了在不引起系统崩溃的情况下赋予特定应用system权限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        目前有个项目,希望部分应用能运行在system uid下,但是这部分应用是第三方的,我们无法去修改这些应用的属性,因此考虑在framework层对这些特定的应用进行处理。

应用uid的设置

        我们先从底层去找起,看看应用的uid是如何设置下来的。

        Android的Java应用基本都是通过ZygoteProcess来启动一个新的process:

// frameworks/base/core/java/android/os/ZygoteProcess.java
public final Process.ProcessStartResult start(final String processClass,
                                              final String niceName,
                                              int uid, int gid, int[] gids,
                                              int runtimeFlags, int mountExternal,
                                              int targetSdkVersion,
                                              String seInfo,
                                              String abi,
                                              String instructionSet,
                                              String appDataDir,
                                              String invokeWith,
                                              String[] zygoteArgs) {
    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
        Log.e(LOG_TAG,
                "Starting VM process through Zygote failed");
        throw new RuntimeException(
                "Starting VM process through Zygote failed", ex);
    }
}

        Zygote创建应用进程时是收到了AMS的uid参数的,从此处逆推回去,溯源找到这个参数传递的地方:

// frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
ProcessRecord(ActivityManagerService _service, BatteryStatsImpl _batteryStats,
        ApplicationInfo _info, String _processName, int _uid) {
    mService = _service;
    mBatteryStats = _batteryStats;
    info = _info;
    isolated = _info.uid != _uid;
    uid = _uid;
    userId = UserHandle.getUserId(_uid);
    processName = _processName;
    pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
    maxAdj = ProcessList.UNKNOWN_ADJ;
    curRawAdj = setRawAdj = ProcessList.INVALID_ADJ;
    curAdj = setAdj = verifiedAdj = ProcessList.INVALID_ADJ;
    persistent = false;
    removed = false;
    lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
}

        uid是从ApplicationInfo.uid中获取到的。AMS启动应用进程时设置的uid我们暂且先不研究,我们主要从这条线索往上走,看看什么样的应用uid是为system的。

Package uid的设定

        应用package的uid实际上是由两个部分决定的,一个是普通的应用,一个是sharedUserId。我们知道,如果应用在AndroidManifest.xml中配置:

android:sharedUserId="android.uid.system"

        那么应用的uid就为system,我们先来看一下这部分代码的逻辑。

addSharedUser

        在PackageManagerService初始化时,就已经将系统的一部分自带的sharedUser添加到系统中:

public PackageManagerService(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    synchronized (mInstallLock) {
    synchronized (mPackages) {
        // Expose private service for system components to use.
        LocalServices.addService(
                PackageManagerInternal.class, new PackageManagerInternalImpl());
        sUserManager = new UserManagerService(context, this,
                new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
        mPermissionManager = PermissionManagerService.create(context,
                new DefaultPermissionGrantedCallback() {
                    @Override
                    public void onDefaultRuntimePermissionsGranted(int userId) {
                        synchronized(mPackages) {
                            mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
                        }
                    }
                }, mPackages /*externalLock*/);
        mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
        mSettings = new Settings(mPermissionManager.getPermissionSettings(), mPackages);
    }
    }
    mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.se", SE_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
}

包扫描

        那么使用的地方在哪呢,在PackageParser解析package的时候就使用到了:

private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
        XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
        IOException {
    mParseInstrumentationArgs = null;

    int type;
    boolean foundApp = false;

    TypedArray sa = res.obtainAttributes(parser,
            com.android.internal.R.styleable.AndroidManifest);

    String str = sa.getNonConfigurationString(
            com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
    if (str != null && str.length() > 0) {
        String nameError = validateName(str, true, false);
        if (nameError != null && !"android".equals(pkg.packageName)) {
            outError[0] = "<manifest> specifies bad sharedUserId name \""
                + str + "\": " + nameError;
            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
            return null;
        }
        pkg.mSharedUserId = str.intern();
        pkg.mSharedUserLabel = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
    }
……

        Package.n=mSharedUserId是String类型,在解析完AndroidManifest后,此值在后面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值