PMS管理APP安装到data和禁止卸载列表

本文介绍如何将PMS管理APP安装到Android系统的data分区,并通过XML配置防止应用程序被卸载。详细流程涉及包名筛选及安装过程。

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



实现根据xml的packagename防止卸载,筛选安装

DataPreInstall文件夹放到vendor\tcl\sita\tvkit\uikit\frameworks\android\java\com\tcl\os\system\下
PackageManagerService.java按patch修改即可实现基本防止卸载和筛选安装功能

基本流程图

patch

+++ core/java/com/android/server/pm/PackageManagerService.java  (working copy)
@@ -308,6 +308,7 @@
 
 //Added by chyj@tcl for AppBlacklist 20170516
 import com.tcl.os.system.packageverify.PackageVerify;
+import com.tcl.os.system.DataPreInstallApp.DataPreInstallApp;
 //End of TCL package install strategy
 
 
@@ -346,20 +347,20 @@
  */
 public class PackageManagerService extends IPackageManager.Stub {

 
     // Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
     // and PackageDexOptimizer. All these classes have their own flag to allow switching a single
@@ -406,7 +407,7 @@
     static final int SCAN_CHECK_ONLY = 1<<15;
     static final int SCAN_DONT_KILL_APP = 1<<17;
     static final int SCAN_IGNORE_FROZEN = 1<<18;
-
+       private   boolean SCAN_DATA_APP = false;  //add by chyj
     static final int REMOVE_CHATTY = 1<<16;
 
     private static final int[] EMPTY_INT_ARRAY = new int[0];
@@ -548,6 +549,7 @@
 
        //Added by chyj @tcl for AppBlacklist 20170516
        PackageVerify mPackageVerify;
+       DataPreInstallApp mDataPreInstallApp;
        //End of TCL package install strategy
 
 
@@ -2129,6 +2131,7 @@
         mProtectedPackages = new ProtectedPackages(mContext);
                //Added by chyj@tcl for AppBlacklist 20170516
         mPackageVerify = null;//new PackageVerify();  tmp delete 
+        mDataPreInstallApp = new DataPreInstallApp();
                //End of TCL package install strategy
         synchronized (mInstallLock) {
         // writer
@@ -2415,8 +2418,9 @@
             if (!mOnlyCore) {
                 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                         SystemClock.uptimeMillis());
+                               SCAN_DATA_APP = true;
                 scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
-
+                               SCAN_DATA_APP = false;
                 scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags
                         | PackageParser.PARSE_FORWARD_LOCK,
                         scanFlags | SCAN_REQUIRE_KNOWN, 0);
@@ -6679,6 +6683,8 @@
                 // Ignore entries which are not packages
                 continue;
             }
+                       Slog.w(TAG, "chyj scanDirLI File to parse " + file );
+
             try {
                 scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                         scanFlags, currentTime, null);
@@ -6819,7 +6825,22 @@
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
-
+
+               if (DEBUG_INSTALL) Slog.d(TAG, "chyj scanPackageLI Parsing: scanFile=" + scanFile+" packagename="+pkg.packageName);
+               //add by chyj if is first start system and /data/app  will check is preinstall frome TCL 
+               if(SCAN_DATA_APP){
+                       if(mDataPreInstallApp != null)
+                               if(mDataPreInstallApp.verifyApp(pkg.packageName,false))
+                               {
+                                       Log.v(TAG, "chyj  package can't preinstall in Data ,delete file="+scanFile);
+                                       removeCodePathLI(scanFile);
+                                       return null;
+                               }
+                               else
+                                       Log.v(TAG, "chyj  package will preinstall in data/app");
+                       else
+                               Log.v(TAG, "chyj  mDataPreInstallApp is not init");
+               }
         return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
     }
 
@@ -15058,10 +15079,12 @@
                //End of TCL
 
     private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
+    
         final int installFlags = args.installFlags;
         final String installerPackageName = args.installerPackageName;
         final String volumeUuid = args.volumeUuid;
         final File tmpPackageFile = new File(args.getCodePath());
+               Slog.d(TAG,"chyj installPackageLI installerPackageName="+installerPackageName+" installFlags="+installFlags+" Path="+args.getCodePath()+" tmpPackageFile="+tmpPackageFile);
         final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
         final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
                 || (args.volumeUuid != null));
@@ -15144,7 +15167,7 @@
         if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
             pkg.cpuAbiOverride = args.abiOverride;
         }
-
+               Slog.d(TAG,"chyj installPackageLI pkgName="+pkg.packageName);
         String pkgName = res.name = pkg.packageName;
         if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
             if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
@@ -15675,7 +15698,23 @@
     @Override
     public void deletePackage(final String packageName,
             final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
-        mContext.enforceCallingOrSelfPermission(
+        Log.v(TAG, "chyj deletePackage packageName="+packageName+" userId="+userId+" flags=0x"+ Integer.toHexString(deleteFlags));
+               if(mDataPreInstallApp != null)
+                       if(!mDataPreInstallApp.verifyApp(packageName,false))
+                       {
+                               try {
+                       observer.onPackageDeleted(packageName,
+                               PackageManager.DELETE_FAILED_USER_RESTRICTED, null);
+                   } catch (RemoteException re) {
+                   }
+                               return;
+                       }
+                       else
+                               Log.v(TAG, "chyj deletePackage package is not preinstall in Data");
+               else
+                       Log.v(TAG, "chyj deletePackage mDataPreInstallApp is not init");
+
+               mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.DELETE_PACKAGES, null);
         Preconditions.checkNotNull(packageName);
         Preconditions.checkNotNull(observer);


arkfjxxdt



说得更好发挥梵蒂冈亿元 

第三个try他让你 
DataPreInstallApp.java
/*
 * Copyright (C) 2013 The TCL Android TV
 *   TCL Software  XI'AN 
 *   yangzp@tcl.com 
 */

package com.tcl.os.system.DataPreInstallApp;

import java.io.File;
import android.util.Slog;
import android.os.SystemProperties;
import android.os.FileObserver;
import android.os.ServiceManager;
import android.os.RemoteException;
import android.content.pm.PackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.ParceledListSlice;
import android.content.pm.IPackageManager;
import java.io.PrintWriter;
import java.util.List;
import java.util.ArrayList;
import java.lang.Runnable;
import java.lang.Thread;


public class DataPreInstallApp{
    private static final String TAG = "DataPreInstallApp";
    public static boolean DEBUG;
    private static final String PerIstallPath = "persist.tcl.datapreinstallapp";
    private static final String DefaultPath = "/data/user/0/com.tcl.appmarket2/shared_prefs/preinstall_app_data.xml";
    ParsePreInstallApp mParseIstallApp;
    FileObserver mFileObserver;
    File mFile;
    IPackageManager mPm;
    DataPreInstallApp mDataInstall;
    List<String> mPkgs = new ArrayList<String>();
    List<PackageInfo> mInstalledPkgs;
    private boolean mObservered = false;
    private static String mPerIstallPath = "";
    private static String mMonitorPath = "";
    
    public DataPreInstallApp(){
		if(DEBUG) Slog.d(TAG,"FileObserver startWatching .");
        DEBUG = true;//"true".equals(SystemProperties.get("persist.tcl.datapreinstallapp.debug"));
 //       mPackageSourceInfo = new PackageSourceInfo();
        mParseIstallApp = new ParsePreInstallApp();
        mPerIstallPath = SystemProperties.get(PerIstallPath);
        mPerIstallPath = (mPerIstallPath.equals("") || mPerIstallPath == null) ? DefaultPath : mPerIstallPath;
        mDataInstall = this;
    }

    public void update(){
        DEBUG = true;//"true".equals(SystemProperties.get("persist.tcl.datapreinstallapp.debug"));
		if(DEBUG) Slog.d(TAG,"update starting ...  ");
        synchronized (mParseIstallApp) {
            mParseIstallApp.updateAPPList(mPerIstallPath);
        }
        if(mFileObserver == null || !mObservered){
            mPerIstallPath = SystemProperties.get(PerIstallPath);
            mPerIstallPath = (mPerIstallPath.equals("") || mPerIstallPath == null) ? DefaultPath : mPerIstallPath;
            mMonitorPath = mPerIstallPath.substring(0,mPerIstallPath.lastIndexOf('/'));

            mFile = new File(mMonitorPath);
            if(mFile.exists() && mFile.canRead()){
                if(DEBUG) Slog.d(TAG,"FileObserver : " + mMonitorPath);
                mFileObserver = new FileObserver(mMonitorPath,FileObserver.ALL_EVENTS){
                    @Override 
                    public void onEvent(int event,String path){
                        if((event & (FileObserver.CLOSE_WRITE | FileObserver.ATTRIB)) != 0){
                            if(DEBUG && path != null) Slog.d(TAG,"FileObserver recieve event : " + ((event == 8)? "write close":"attrib (permission) changed") + "recieve path : " + path);
                            if(path.equals(mPerIstallPath.substring(mPerIstallPath.lastIndexOf('/') + 1 ,mPerIstallPath.length()))){
                                File file = new File(mPerIstallPath);
                                if(file.exists() && file.canRead()){
                                    synchronized(mParseIstallApp){
                                        mParseIstallApp.updateAPPList(mPerIstallPath);
                                        //mDataInstall.updateAppState();
                                    }
                                }
                            }
                        }
                    }//end of onEvent()
                };
                if(DEBUG) Slog.d(TAG,"FileObserver startWatching .");
                mFileObserver.startWatching();
                mObservered = true;
            }
        }
    }
    
    @SuppressWarnings("unchecked")
    private List<PackageInfo> getInstalledPackages(IPackageManager pm, int flags, int userId)
            throws RemoteException {
        ParceledListSlice<PackageInfo> slice = pm.getInstalledPackages(flags,userId);
        return slice.getList();
    }




    public boolean  verifyApp(String pkgName ,boolean booting){
		if(DEBUG) Slog.d(TAG,"verifyApp pkgName="+pkgName+" booting="+booting);
        if(!booting && (mParseIstallApp.mDataPreInstallApps == null || mParseIstallApp.mDataPreInstallApps.isEmpty())){
            update();
        }
        synchronized (mParseIstallApp) {
            if(mParseIstallApp.mDataPreInstallApps.contains(pkgName)){
				if(DEBUG) Slog.d(TAG,"pkgName="+pkgName+" is System PreInstall App can't uninstall");
                return false;
            }
        }
		if(DEBUG) Slog.d(TAG,"pkgName="+pkgName+" is not System PreInstall App will  uninstall");
        return true;
    }





    public void dump(PrintWriter pw){
        pw.println("------DataPreInstallApp dump :");
        int i = 0;
        for(String name : mParseIstallApp.mDataPreInstallApps){
            i++;
            pw.println("--" + i + "-- data pre install app : " + name + ";");
        }
        pw.println("===========================");

        if(mPerIstallPath != null)
            pw.println("-- preinstall data app  file path : " + mPerIstallPath);

        pw.println("----------DataPreInstallApp Dump end -------");
    }
}



几室几厅
开裆裤论坛
ParsePreInstallApp.java
/*
 * Copyright (C) 201706 The TCL Android TV
 *   TCL Software  XI'AN 
 *   yangzp@tcl.com 
 */

package com.tcl.os.system.DataPreInstallApp;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Slog;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ParsePreInstallApp{
    private final static String TAG = "ParsePreInstallApp";

    ArrayList<String> mDataPreInstallApps= new ArrayList<String>();
	ArrayList<String> mOldDataPreInstallApps= new ArrayList<String>();

    public ParsePreInstallApp(){
		 if(DataPreInstallApp.DEBUG) Slog.d(TAG," new ParsePreInstallApp  ");
    }

    private DefaultHandler mDefaultHandler = new DefaultHandler() {
        private boolean appList = false;
        private StringBuilder value;
        private String attr;
        private String str;
        
        @Override
        public void startDocument () throws SAXException {
            super.startDocument();
            value = new StringBuilder();
            str = "";
            attr = "";
            appList = false;
            mOldDataPreInstallApps.clear();
            mOldDataPreInstallApps.addAll(mDataPreInstallApps);
            mDataPreInstallApps.clear();
        }

        @Override
        public void endDocument () throws SAXException {
            super.endDocument();
            value = new StringBuilder();
            str = "";
            attr = "";
            appList = false;
        }

        @Override
        public void error(SAXParseException e) throws SAXException {
            super.error(e);
            Slog.e(TAG,"parse error .");
            e.printStackTrace();
        }

        @Override
        public void startElement(String uri, String localName, String qName,
                Attributes attributes) throws SAXException {
            super.startElement(uri, localName, qName, attributes);
            if(DataPreInstallApp.DEBUG) Slog.d(TAG,"uri : " + uri + ";\n localName : " + localName + 
                                               ";\n qName :" + qName + ";\n attributes.getValue(0) :" + attributes.getValue(0));
            if(localName.trim().equals("set")){
                attr = attributes.getValue(0).trim();
                if("DataPreInstallApps".equals(attr)){
                    appList = true;
                }
            }
        }

        @Override
        public void characters(char ch[], int start, int length)throws SAXException {
            super.characters(ch,start,length);
            value.append(new String(ch,start,length));
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            super.endElement(uri,localName,qName);
            str = trimStr(value.toString());
            if(str != null && !str.equals("")){
                if(appList && !mDataPreInstallApps.contains(str)){
                    if(DataPreInstallApp.DEBUG) Slog.d(TAG,"add to mDataPreInstallApps : " + str);
                    mDataPreInstallApps.add(str);
                }
            }
            value.delete(0,value.length());
            if(localName.trim().equals("set")){
                appList = false;
            }
        }
    };

    String trimStr(String str){
        if(DataPreInstallApp.DEBUG) Slog.d(TAG,"trimStr enter str = " + str);
        String res = "";
        Pattern pattern = Pattern.compile("\\s*|\t|\r|\n");
        if(str != null){
            Matcher m = pattern.matcher(str);
            res = m.replaceAll("");
        }

        if(DataPreInstallApp.DEBUG) Slog.d(TAG,"trimStr exit res = " + res);
        return res;
    }


    public void updateAPPList(String path){
        if(DataPreInstallApp.DEBUG) Slog.d(TAG,"updateAPPList .");
        onParsePreIstallAppListXml(path);
    }

    public ArrayList<String> getPreInstallApps(){
        return mDataPreInstallApps;
    }


    private void onParsePreIstallAppListXml(String xmlFileName) {
        if(DataPreInstallApp.DEBUG) Slog.d(TAG, "Parse pre install data App  list from xml's file!");
        File file = new File(xmlFileName);
        String res = "";
        if (file.exists()) {
            if(DataPreInstallApp.DEBUG) Slog.d(TAG,"onParsePreIstallAppListXml file : " + xmlFileName);

            if(!file.canRead()){
                Slog.d(TAG,"can not read file : " + xmlFileName);
            }
            try {
                InputStream in = new FileInputStream(file);
                
                int length = in.available();
                if(length <= 0){
                    in.close();
                    Slog.d(TAG,"onParsePreIstallAppListXml file :" + xmlFileName + " size <=0 or Other Exception");
                    return;
                }

                SAXParserFactory factory = SAXParserFactory.newInstance();
                SAXParser parser = factory.newSAXParser();
                parser.parse(in,mDefaultHandler);
                in.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}   

反对虎头虎脑

preinstall_app_data.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <set name="DataPreInstallApps">
        <string>com.tcl.qiyiguo</string>
		<string>com.starcor.mango</string>
    </set>
</map>





                
<think>嗯,用户想了解AndroidPMS的功能、原理以及APK的安装卸载流程。首先,我需要回忆一下PMS相关的知识。PMS全称是PackageManagerService,是Android系统中负责管理应用程序安装卸载、权限等的重要服务。用户主要问了四个部分:主要功能、核心原理、安装流程卸载流程。我得逐一解答。首先,主要功能应该包括APK管理、权限控制、组件信息存储、安装卸载处理等。核心原理可能涉及系统启动时的初始化过程,比如SystemServer启动PMS,构造函数里扫描APK文件,初始化权限这些步骤。引用中的PMS初始化DefaultContainerService的信息可能需要用到。安装流程的话,用户提到的DefaultContainerService进程,负责检查复制APK文件,通过IMediaContainerService与PMS通信。步骤可能包括复制APK到目标目录、解析包信息、验证签名、检查权限、更新数据库等。卸载流程可能涉及删除数据目录、移除安装标记、更新数据库发送广播。需要注意的是用户可能对具体的技术细节感兴趣,比如安装过程中的服务间通信,或者权限验证的具体步骤。引用中的信息需要正确对应到各个流程中,比如引用[1]提到PMS的初始化权限初始化,引用[2]提到安装时的DefaultContainerService进程。还要确保回答结构清晰,分点说明,每个部分用标题分开。可能需要使用LaTeX格式,比如方法名或类名用$符号包裹,但用户的问题中并没有涉及数学公式,所以可能只需要在提到代码或特定术语时使用。不过根据系统指令,行内数学表达式需要用$...$,但这里可能用不上,但如果有变量或代码可能需要处理。另外,用户要求生成相关问题,我需要根据回答内容提出相关的问题,比如安装流程中的签名验证作用,或者PMS的启动过程如何影响应用管理等。要确保问题与内容相关,能够帮助用户进一步深入学习。 最后,检查引用是否正确插入,比如在提到PMS初始化时添加[^1],在安装流程提到DefaultContainerService时添加[^2]。确保引用标识自然,不打断句子的流畅性。</think>### Android PMS功能与原理详解 #### 一、PMS主要功能 1. **APK管理** - 负责系统启动时扫描所有预装APK文件(如`/system/app`目录) - 管理第三方应用安装、更新、卸载操作 - 维护应用安装状态数据库(路径:`/data/system/packages.xml`) 2. **权限控制** - 初始化系统权限定义(如`AndroidManifest.xml`中的`<uses-permission>`) - 实现动态权限授予/回收机制(API 23+) 3. **组件信息存储** - 记录所有应用的四大组件信息(Activity/Service/Receiver/Provider) - 提供快速检索能力,支撑`startActivity()`等系统调用 4. **安装过程处理** - 通过`DefaultContainerService`实现APK文件复制与验证[^2] - 解析APK的`AndroidManifest.xml`并生成`Package`对象 #### 二、核心实现原理 1. **系统级服务架构** - 在`SystemServer`启动阶段初始化,通过`main()`方法创建实例[^1] ```java // SystemServer.java中初始化代码 mPackageManagerService = PackageManagerService.main(...); ``` 2. **多进程通信机制** - 使用`Binder`机制对外暴露`IPackageManager`接口 - 安装进程通过`IMediaContainerService`与PMS通信[^2] 3. **数据存储结构** - 使用`Settings`类管理安装应用信息 - 通过`FileInstallObserver`监控APK目录变化 #### 三、APK安装流程(以第三方应用为例) 1. **文件准备阶段** - 用户触发安装请求(如点击.apk文件) - 启动`PackageInstaller`界面收集用户确认 2. **安装服务激活** ```mermaid graph TD A[调用PMS.installPackageAsUser] --> B[启动DefaultContainerService] B --> C[复制APK到/data/app目录] ``` 3. **核心处理流程 - **步骤1**:验证APK签名完整性(使用`JarFile`解析) - **步骤2**:创建应用专属目录(如`/data/data/<包名>`) - **步骤3**:生成优化后的`odex`文件(`DexClassLoader`加载) - **步骤4**:更新`packages.xml``packages.list` 4. **安装后处理** - 发送`ACTION_PACKAGE_ADDED`广播 - 触发`ApplicationPackageManager`更新缓存 #### 四、APK卸载流程 1. **用户触发阶段** - 通过系统设置或`PackageInstaller`发起请求 2. **核心卸载过程 - **步骤1**:删除`/data/app/<包名>`目录 - **步骤2**:清理`/data/data/<包名>`用户数据(可选) - **步骤3**:移除`packages.xml`中的相关条目 3. **系统更新阶段** ```java // PMS处理卸载的核心方法 deletePackage(packageName, DELETE_KEEP_DATA); ``` 4. **卸载后处理** - 发送`ACTION_PACKAGE_REMOVED`广播 - 更新`Launcher`应用列表
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值