[MT8766][Android12] Add application installation whitelist or blacklist

Article directory

    • Basic information of development platform
    • Problem Description
    • Solution

Basic information on development platform

Chip: MT8766
Version: Android 12
kernel: msm-4.19

Problem description

During project development, some customers often require the system to perform signature verification when installing applications; that is, the system does not allow any application installation by default. When the application is installed, the public key stored in the system directory will be read and then obtained. Use the public key to parse the applications that need to be installed. Only applications that match the signature can be installed normally.

Solution

  • There are various algorithms for application signature verification, and they are relatively private, so they will not be shown here. Here we only provide methods to intercept application installations. You can read the set whitelist at the installation place, and only applications in the whitelist are included. Installation is only allowed; or the set blacklist is read. Except for the applications in the blacklist that are prohibited from being installed, other applications are installed normally. How to use it depends on the specific needs.
--- a/frameworks/base/core/api/system-current.txt
 + + + b/frameworks/base/core/api/system-current.txt
@@ -8892,6 + 8892,7 @@ package android.permission {<!-- -->
     method public int checkDeviceIdentifierAccess(@Nullable String, @Nullable String, @Nullable String, int, int);
     method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionGrantedPackages();
     method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionRequestedPackages();
 + method public android.content.Context getPermissionContext();
     method @IntRange(from=0) @RequiresPermission(anyOf={<!-- -->android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
     method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();

--- a/frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
 + + + b/frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -132,6 + 132,17 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.StringTokenizer;
 
 + import android.os.SystemProperties;
 + import android.provider.Settings;
 + import android.content.Context;
 + import android.util.Log;
 +
@@ -275,7 + 288,7 @@ public class ParsingPackageUtils {<!-- -->
                         return new ParsingPackageImpl(packageName, baseApkPath, path,
                                 manifestArray);
                     }
- });
 + },mContext);
         try {<!-- -->
             result = parser.parsePackage(input, file, parseFlags);
             if (result.isError()) {<!-- -->
@@ -309,16 + 322,19 @@ public class ParsingPackageUtils {<!-- -->
     @NonNull
     private List<PermissionManager.SplitPermissionInfo> mSplitPermissionInfos;
     private Callback mCallback;
 + private static Context mContext;
 
     public ParsingPackageUtils(boolean onlyCoreApps, String[] separateProcesses,
             DisplayMetrics displayMetrics,
             @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
- @NonNull Callback callback) {<!-- -->
 + @NonNull Callback callback,
 + @NonNull Context context) {<!-- -->
         mOnlyCoreApps = onlyCoreApps;
         mSeparateProcesses = separateProcesses;
         mDisplayMetrics = displayMetrics;
         mSplitPermissionInfos = splitPermissions;
         mCallback = callback;
 + mContext = context;
     }
 
@@ -3043,6 + 3059,11 @@ public class ParsingPackageUtils {<!-- -->
             @NonNull SigningDetails existingSigningDetails, int targetSdk) {<!-- -->
         int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
                 targetSdk);
 
 + boolean isAllow = false;
 +
         if (isStaticSharedLibrary) {<!-- -->
             // must use v2 signing scheme
             minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
@@ -3056,7 + 3077,71 @@ public class ParsingPackageUtils {<!-- -->
                 verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
                         baseCodePath, SigningDetails.SignatureSchemeVersion.JAR);
             } else {<!-- -->
- verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
 + String whiteListValue = null;
 + String[] whiteListArray = null;
 + if(mContext != null){<!-- -->
 + if(mContext.getContentResolver()!=null){<!-- -->
 + whiteListValue = Settings.System.getString(mContext.getContentResolver(), Settings.System.KEY_CERT_WHITE_LIST_ACTION);
 + }
 +
 + if (whiteListValue != null){<!-- -->
 + int count = 0;
 + String packageName = null;
 + PackageManager pm = mContext.getPackageManager();
 + PackageInfo info = pm.getPackageArchiveInfo(baseCodePath, PackageManager.GET_ACTIVITIES);
 + if(info!=null){<!-- -->
 + ApplicationInfo appInfo = info.applicationInfo;
 + packageName = appInfo.packageName; //Get the installation package name
 + Log.d(TAG, "packageName : " + packageName);
 +
 + whiteListArray = whiteListValue.split(";");
 + for(count=0; count < whiteListArray.length; count + + ){<!-- -->
 + if(packageName.equals(whiteListArray[count])){<!-- -->
 + isAllow = true;
 + break;
 + }else{<!-- -->
 + isAllow = false;
 + }
 + }
 + }
 + }else{<!-- -->
 + Log.d(TAG, "whiteList is null");
 + }
 + }
 + if (isAllow){<!-- -->
 + verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
 + }else {<!-- -->
 + throw new PackageParserException(
 + INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
 + baseCodePath + " has mismatched certificates");
 + }
             }
         } catch (PackageParserException e) {<!-- -->
             return input.error(PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES,

--- a/frameworks/base/core/java/android/permission/PermissionManager.java
 + + + b/frameworks/base/core/java/android/permission/PermissionManager.java
@@ -161,6 + 161,10 @@ public final class PermissionManager {<!-- -->
         mLegacyPermissionManager = context.getSystemService(LegacyPermissionManager.class);
     }
 
 + public Context getPermissionContext(){<!-- -->
 + return mContext;
 + }
 +
--- a/frameworks/base/services/core/java/com/android/server/pm/parsing/PackageParser2.java
 + + + b/frameworks/base/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -129,7 + 129,7 @@ public class PackageParser2 implements AutoCloseable {<!-- -->
         mCacher = cacheDir == null ? null : new PackageCacher(cacheDir);
 
         parsingUtils = new ParsingPackageUtils(onlyCoreApps, separateProcesses, displayMetrics,
- splitPermissions, callback);
 + splitPermissions, callback,permissionManager.getPermissionContext());
 
         ParseInput.Callback enforcementCallback = (changeId, packageName, targetSdkVersion) -> {<!-- -->
             ApplicationInfo appInfo = mSharedAppInfo.get();

The main reason is that the context cannot be obtained in the class installed by the application. Therefore, the only way is to get the context from the upper layer when constructing the class and then pass it in. After getting the context, you can get the Setting database, read out the black and white list, and then compare it with the currently installed package name to determine whether the current application is installed.