Android rom开发:第三方app开放全部权限+支持静默安装卸载

开发平台:

高通 android 7.1

需求:

app不带系统签名,仅仅以反射的方式调用PackageManager类的installPackage、deletePackage方法,实现静默安装卸载。


背景知识:
常规情况下,静默安装卸载需要以下2个系统级权限+系统签名
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />

解决思路如下:

首先,没有系统签名的情况下,安装app的时候这2个权限不会放开,因此先修改PackageManagerService.java->grantPermissionsLPw方法

+        //允许app全部权限
+        mPkgList.add("com.android.testa");
+        mPkgList.add("com.android.testb");
+        if (mPkgList.contains(pkg.packageName)) {
+            final int permsSize = pkg.requestedPermissions.size();
+            for (int i = 0; i < permsSize; i++) {
+                final String name = pkg.requestedPermissions.get(i);
+                final BasePermission bp = mSettings.mPermissions.get(name);
+                if (null != bp && permissionsState.grantInstallPermission(bp) != PermissionsState.PERMISSION_OPERATION_FAILURE) {
+                    Slog.d(TAG, "grant permission " + name + " to package " + pkg.packageName);
+                    changedInstallPermission = true;
+                }
+            }
+        }
+
         if ((changedInstallPermission || replace) && !ps.installPermissionsFixed &&
                 !isSystemApp(ps) || isUpdatedSystemApp(ps)){
             // This is the first that we have heard about this package, so the

这一步修改后,mmm frameworks/base/services,然后重新替换/system/framework/service.jar验证,静默安装ok,静默卸载不ok,但是log里面没有显示权限问题,说明权限实际上已经具备,其他地方出了问题。

继续读源码,追踪代码继承关系和调用逻辑:

1.PackageManagerService.java继承IPackageManager.Stub

2.ApplicationPackageManager.java继承PackageManager.java

3.反射调用PackageManager.java的installPackage deletePackage方法,实际上是调用ApplicationPackageManager.java里面的方法

ApplicationPackageManager.java里面的对应源码:
/** @hide */
public class ApplicationPackageManager extends PackageManager {

//install
    @Override
    public void installPackage(Uri packageURI, PackageInstallObserver observer,
            int flags, String installerPackageName) {
        installCommon(packageURI, observer, flags, installerPackageName, mContext.getUserId());
    }

    private void installCommon(Uri packageURI,
            PackageInstallObserver observer, int flags, String installerPackageName,
            int userId) {
        if (!"file".equals(packageURI.getScheme())) {
            throw new UnsupportedOperationException("Only file:// URIs are supported");
        }

        final String originPath = packageURI.getPath();
        try {
            mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
                    userId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

//delete
    @Override
    public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
        deletePackageAsUser(packageName, observer, flags, mContext.getUserId());
    }

    @Override
    public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags,
            int userId) {
        try {
            mPM.deletePackageAsUser(packageName, observer, userId, flags);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

//实际上是通过aidl调用mPM的方法,mPM是一个IPackageManager对象,在创建ApplicationPackageManager对象的时候赋值
    ApplicationPackageManager(ContextImpl context,
                              IPackageManager pm) {
        mContext = context;
        mPM = pm;
    }

4.从ApplicationPackageManager源码可以看到,安装卸载是通过aidl调用mPM的方法,mPM是一个IPackageManager对象,在创建ApplicationPackageManager对象的时候赋值。

5.PackageManagerService.java继承IPackageManager.Stub,实际上就调用了PackageManagerService.java里面的installPackageAsUser和deletePackageAsUser方法,因此本质上静默安装卸载都是在PackageManagerService.java里面实现的。

6.仔细查看PackageManagerService.java卸载的代码逻辑,注意看isCallerAllowedToSilentlyUninstall方法,从命名就可以看出,这里是判断是否允许调用者执行静默卸载,显然第三方app在默认情况下是返回的false,因此无法继续执行静默卸载的逻辑,并且从PMS源码看,不会抛出什么异常信息,实测加打印确实如此。

@Override
public void deletePackage(final String packageName,
        final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
    //如果app的清单文件里面没有申明卸载权限,那么这一句会抛出异常,提示没有权限
    mContext.enforceCallingOrSelfPermission(
            android.Manifest.permission.DELETE_PACKAGES, null);
    Preconditions.checkNotNull(packageName);
    Preconditions.checkNotNull(observer);
    final int uid = Binder.getCallingUid();
    if (!isOrphaned(packageName)
            && !isCallerAllowedToSilentlyUninstall(uid, packageName)) {
        try {
            final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
            intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
            intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
            observer.onUserActionRequired(intent);
        } catch (RemoteException re) {
        }
        return;
    }
   ...省略
       
private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
    if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID
          || callingUid == Process.SYSTEM_UID) {
        return true;
    }
    final int callingUserId = UserHandle.getUserId(callingUid);
    // If the caller installed the pkgName, then allow it to silently uninstall.
    if (callingUid == getPackageUid(getInstallerPackageName(pkgName), 0, callingUserId)) {
        return true;
    }

    // Allow package verifier to silently uninstall.
    if (mRequiredVerifierPackage != null &&
            callingUid == getPackageUid(mRequiredVerifierPackage, 0, callingUserId)) {
        return true;
    }

    // Allow package uninstaller to silently uninstall.
    if (mRequiredUninstallerPackage != null &&
            callingUid == getPackageUid(mRequiredUninstallerPackage, 0, callingUserId)) {
        return true;
    }

    // Allow storage manager to silently uninstall.
    if (mStorageManagerPackage != null &&
            callingUid == getPackageUid(mStorageManagerPackage, 0, callingUserId)) {
        return true;
    }
    return false;
}

7.在isCallerAllowedToSilentlyUninstall方法里面,增加特殊处理

     private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
+        if (mPkgList.size() > 0) {
+            try {
+                if (mPkgList.contains(AppGlobals.getPackageManager().getNameForUid(callingUid))) {
+                    return true;
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+                Slog.e(TAG, "getNameForUid error is " + e.getMessage());
+            }
+        }

加上以上修改之后实测,卸载正常。

还是得多读源码呀。。。RTFSC!!!


PS:
测试代码如下:

//AndroidManiFest.xml里面声明权限
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />

mPackageDeleteObserver = new PackageDeleteObserver();
mPackageInstallObserver = new PackageInstallObserver();

//卸载
try {
    Class<?>[] uninstalltypes = new Class[]{String.class, IPackageDeleteObserver.class, int.class};
    PackageManager pm = mContext.getPackageManager();
    Method uninstall = pm.getClass().getMethod("deletePackage", uninstalltypes);
    uninstall.invoke(pm, new Object[]{"cache.wind.nfc", mPackageDeleteObserver, 0});
    Log.d(TAG, "invoke uninstall app>>>>>>>");
} catch (Exception e) {
    Log.e(TAG, "error " + e.getMessage());
    e.printStackTrace();
}

//安装
try {
    Class<?>[] installtypes = new Class[]{Uri.class, IPackageInstallObserver.class, int.class, String.class};
    PackageManager pm = mContext.getPackageManager();
    Method install = pm.getClass().getMethod("installPackage", installtypes);
    int installFlags = 0;
    installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
    install.invoke(pm, new Object[]{Uri.fromFile(new File("/sdcard/NfcReader.apk")), mPackageInstallObserver, installFlags, null});
    Log.d(TAG, "invoke install app>>>>>>>");
} catch (Exception e) {
    Log.e(TAG, "error " + e.getMessage());
    e.printStackTrace();
}

class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
    @Override
    public void packageDeleted(String s, int i) throws RemoteException {
        Log.d(TAG, "packageDeleted s is " + s + " return code is " + i);
    }
}

class PackageInstallObserver extends IPackageInstallObserver.Stub {
    @Override
    public void packageInstalled(String s, int i) throws RemoteException {
        Log.d(TAG, "packageInstalled s is " + s + " return code is " + i);
    }
}

你可能感兴趣的:(android,rom开发,android源码)