Android 系统配置第三方应用不可以卸载

场景描述

android系统system分区大小是固定,如果system分区大小超过云机system分区固定大小,system分区升级时会占用下个分区内存,导致基线分区地址错乱、系统升级失败、系统启动崩溃。

内置应用配置过多,会导致system.img镜像过大。但客户需求安装多个应用,且安装应用标记为系统应用,不可卸载处理。

方案设计

在系统/data/local/config/路径下配置不可卸载应用NoDeleteApp列表项,根据配置列表,应用安装解析应用包和云机重启扫描解析应用包过程中,标记改应用为系统应用,应用在卸载时,设置不可卸载。

可行性场景分析

android系统adb命令、pm命令、静默安装、packageInstaller等应用安装方式,最终Binder IPC方式调用PackageManagerService服务的verifyPendingInstall-->installPackageLI方法,同时PackageParser.java-->parseBaseApkCommon会对apk进行解析,填充Package信息,返回一个Package对象。parseBaseApkCommon解析过程中,获取NoDeleteApp配置项,设置Package的applicationinfo.flags参数为系统应用。

android系统adb命令、pm命令、packageInstaller等应用卸载方式,最终Binder IPC方式调用PackageManagerService服务的deletePackageX方法,改方法内根据NoDeleteApplist配置项,返回是否可卸载应用。

android系统重启,PackageManagerService具有scanPackageLI 过程,在扫描/data/app目录时,会判断非系统应用的Package中是否存在改目录中,如果不存在,会删除对应/data/app目录下数据。因此,removePackageLI内获取NoDeleteApplist配置项,设置不可删除/data/app目录下对应应用数据。

具体代码实现

diff --git a/frameworks/base/core/java/android/content/pm/PackageParser.java b/frameworks/base/core/java/android/content/pm/PackageParser.java
index 2da2cb4c9..842b92ae3 100755
--- a/frameworks/base/core/java/android/content/pm/PackageParser.java
+++ b/frameworks/base/core/java/android/content/pm/PackageParser.java
@@ -126,6 +126,8 @@ import java.util.List;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.io.BufferedReader;
+import java.io.FileReader;
 
 /**
  * Parser for package files (APKs) on disk. This supports apps packaged either
@@ -199,6 +201,17 @@ public class PackageParser {
 
     private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
 
+    /**
+     * Profile file path
+     */
+    private static final String PROFILE_FILE_PATH = "/data/local/config/";
+
+    /**
+     * Profile file name
+     */
+    private static final String PROFILE_FILE_PATH_NAME = "NoDeleteApp";
+
+
     /**
      * Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
      * @hide
@@ -2489,9 +2502,51 @@ public class PackageParser {
         if (pkg.applicationInfo.usesCompatibilityMode()) {
             adjustPackageToBeUnresizeableAndUnpipable(pkg);
         }
+
+        if (isProfileNoDeleteApp(pkg.packageName)) {
+            Slog.w(TAG, "parser not removing packages " );
+            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        }
         return pkg;
     }
 
+    /**
+     * profile no delete app file
+     * @param pkgName
+     * @return
+     */
+    private boolean isProfileNoDeleteApp(String pkgName) {
+        final File systemDir;
+        final File blackListFile;
+        final ArrayList<String> blackListApps = new ArrayList<String>();
+        systemDir = new File(PROFILE_FILE_PATH);
+        blackListFile = new File(systemDir, PROFILE_FILE_PATH_NAME);
+        if (!blackListFile.exists()) {
+            return false;
+        }
+        try {
+            blackListApps.clear();
+            BufferedReader br = new BufferedReader(new FileReader(blackListFile));
+            String line = br.readLine();
+            while (line != null) {
+                blackListApps.add(line);
+                line = br.readLine();
+            }
+            br.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+            return false;
+        }
+        Iterator<String> it = blackListApps.iterator();
+        while (it.hasNext()) {
+            String blacklistItem = it.next();
+            if (pkgName.equals(blacklistItem)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private boolean checkOverlayRequiredSystemProperty(String propName, String propValue) {
 
         if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) {
diff --git a/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java b/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
index 65e188f6e..491dd72e7 100755
--- a/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -372,6 +372,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Predicate;
 
+import java.io.BufferedReader;
+import java.io.FileReader;
+
 /**
  * Keep track of all those APKs everywhere.
  * <p>
@@ -735,6 +738,16 @@ public class PackageManagerService extends IPackageManager.Stub
      */
     boolean mPromoteSystemApps;
 
+    /**
+     * Profile file path
+     */
+    private static final String PROFILE_FILE_PATH = "/data/local/config/";
+
+    /**
+     * Profile file name
+     */
+    private static final String PROFILE_FILE_PATH_NAME = "NoDeleteApplist";
+
     @GuardedBy("mPackages")
     final Settings mSettings;
 
@@ -2821,7 +2834,11 @@ public class PackageManagerService extends IPackageManager.Stub
                      * If this is not a system app, it can't be a
                      * disable system app.
                      */
-                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+                        continue;
+                    }
+
+                    if (isProfileNoDeleteApp(ps.name)) {
                         continue;
                     }
 
@@ -8489,6 +8506,10 @@ public class PackageManagerService extends IPackageManager.Stub
                     // Ignore entries which are not packages
                     continue;
                 }
+
+                if (!isPackage && !isProfileNoDeleteApp(file.getAbsolutePath())) {
+                    continue;
+                }
                 parallelPackageParser.submit(file, parseFlags);
                 fileCount++;
             }
@@ -9633,6 +9654,10 @@ public class PackageManagerService extends IPackageManager.Stub
     }
 
     void removeCodePathLI(File codePath) {
+        if (isProfileNoDeleteApp(codePath.getAbsolutePath())) {
+            Slog.w(TAG, "profile app file removeCodePathLI error");
+            return;
+        }
         if (codePath.isDirectory()) {
             try {
                 mInstaller.rmPackageDir(codePath.getAbsolutePath());
@@ -12271,6 +12296,9 @@ public class PackageManagerService extends IPackageManager.Stub
     }
 
     private void removePackageLI(PackageParser.Package pkg, boolean chatty) {
+        if (isProfileNoDeleteApp(pkg.packageName)) {
+            return;
+        }
         // Remove the parent package setting
         PackageSetting ps = (PackageSetting) pkg.mExtras;
         if (ps != null) {
@@ -18294,6 +18322,43 @@ public class PackageManagerService extends IPackageManager.Stub
         return mKeepUninstalledPackages != null && mKeepUninstalledPackages.contains(packageName);
     }
 
+    /**
+     * profile no delete app file
+     * @param pkgName
+     * @return
+     */
+    private boolean isProfileNoDeleteApp(String pkgName) {
+        final File systemDir;
+        final File blackListFile;
+        final ArrayList<String> blackListApps = new ArrayList<String>();
+        systemDir = new File(PROFILE_FILE_PATH);
+        blackListFile = new File(systemDir, PROFILE_FILE_PATH_NAME);
+        if (!blackListFile.exists()) {
+            return false;
+        }
+        try {
+            blackListApps.clear();
+            BufferedReader br = new BufferedReader(new FileReader(blackListFile));
+            String line = br.readLine();
+            while (line != null) {
+                blackListApps.add(line);
+                line = br.readLine();
+            }
+            br.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+            return false;
+        }
+        Iterator<String> it = blackListApps.iterator();
+        while (it.hasNext()) {
+            String blacklistItem = it.next();
+            if (pkgName.contains(blacklistItem)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      *  This method is an internal method that could be get invoked either
      *  to delete an installed package or to clean up a failed installation.
@@ -18320,6 +18385,11 @@ public class PackageManagerService extends IPackageManager.Stub
             return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
         }
 
+        if (isProfileNoDeleteApp(packageName)) {
+            Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
+            return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
+        }
+
         PackageSetting uninstalledPs = null;
         PackageParser.Package pkg = null;
 
@@ -18564,6 +18634,9 @@ public class PackageManagerService extends IPackageManager.Stub
     private void removePackageDataLIF(PackageSetting ps, int[] allUserHandles,
             PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
         String packageName = ps.name;
+        if (isProfileNoDeleteApp(packageName)) {
+            return;
+        }
         if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps);
         // Retrieve object to delete permissions for shared user later on
         final PackageParser.Package deletedPkg;
@@ -18735,6 +18808,11 @@ public class PackageManagerService extends IPackageManager.Stub
             return false;
         }
 
+        if (isProfileNoDeleteApp(deletedPkg.packageName)) {
+            Slog.w(TAG, "deleteSystemPackageLIF packageName =  " + deletedPkg.packageName);
+            return false;
+        }
+
         final boolean applyUserRestrictions
                 = (allUserHandles != null) && outInfo != null && (outInfo.origUsers != null);
         final PackageSetting disabledPs;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 如果Android Studio无法运行,可能是出现了一些错误。请检查以下几点: 1. 确保安装了Java Development Kit (JDK) 2. 确保安装了最新版本的Android Studio 3. 检查系统配置是否符合Android Studio的要求 4. 检查是否有其他程序占用了与Android Studio相同的端口 5. 清理缓存,重新启动 6. 检查是否有更新可用的SDK 7. 检查是否存在虚拟设备或真机可连接. 如果仍然无法解决问题,请尝试在官网或社区上寻求帮助。 ### 回答2: Android Studio是一款用于开发Android应用的集成开发环境(IDE),如果无法运行可能有以下几个可能的原因: 1. 问题可能出现在Android Studio的安装上。首先,确保已经正确下并安装了最新版本的Android Studio。然后,检查系统的要求是否满足,包括操作系统版本、内存和处理器要求等。如果系统不满足要求,可能无法正常运行。 2. 另一个常见的问题是配置错误。在首次运行之前,应该正确配置Android Studio。这包括设置Android SDK路径和Java开发工具包(JDK)路径等。确保这些配置正确无误,以便Android Studio能够正确地定位所需的工具和资源。 3. 如果Android Studio已经成功安装并且配置正确,但仍然无法运行,则可能是由于项目或代码本身的问题。检查项目中的错误和警告,并根据需要进行修复。如果无法确定问题所在,可以尝试创建一个新项目,或者尝试使用示例项目来验证Android Studio是否可以正常运行。 4. 另外,某些可能干扰Android Studio运行的第三方软件也可能是原因之一。例如,杀毒软件、防火墙或其他安全工具可能会阻止Android Studio的正常运行。尝试将这些软件关闭或暂时禁用,然后再次尝试运行Android Studio。 5. 最后,如果以上方法都没有解决问题,可以尝试重新安装Android Studio。首先,完全当前的版本,然后重新下和安装最新版本。这样可以确保安装过程中没有出现任何问题,并且可以修复任何可能的损坏或丢失的文件。 总之,Android Studio无法运行通常是由于安装、配置、项目或代码等方面的问题引起的。通过检查和修复这些可能的问题,应该可以解决Android Studio无法运行的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值