Android系统预安装第三方应用

Android设备在第一次开机时需预装一些第三方应用,安装后用户可卸载。同时恢复出厂设置并清除系统数据后能够重新预装应用。

需求描述

PackageManagerService作为是Android系统中核心服务之一,管理着所有跟package相关的工作,常见的比如安装、卸载应用。我们可以在此实现该需求。

  • 开启后需要自动安装应用,PMS服务扫描时需触发一次该流程。
  • 预安装应用能够卸载,说明该应用的安装路径需要在可擦写的data目录下。
  • 为了避免重复安装,由一个系统属性开关来控制应用安装逻辑。
  • 安装过程需解决preinstall目录下的apk文件的权限问题。

源码实现

以Android 12系统为例,源码位置:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

预安装后的应用路径:/data/app

private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");

/** Directory where installed applications are stored */
private static final File sAppInstallDir =  new File(Environment.getDataDirectory(), "app");

源文件apk路径:/system/preinstall

private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");

File preinstallAppDir = new File(Environment.getRootDirectory(), "preinstall");

在PackageManagerService构造方法中,在scanDirTracedLI()扫描应用安装目录后再进行应用预安装工作。

//通过该系统属性:persist.sys.preinstalled控制预安装流程只执行一次
if (!SystemProperties.getBoolean("persist.sys.preinstalled", false)) {
    
    
	//将/system/preinstall目录下的apk文件复制到/data/app下
	copyPackagesToAppInstallDir(preinstallAppDir);
	SystemProperties.set("persist.sys.preinstalled", "1");
} else {
    
    
	handleOtaPreinstall(preinstallAppDir.getPath().toString(),sAppInstallDir.getPath().toString());
}

private void copyPackagesToAppInstallDir(File srcDir) {
    
    
	Log.i(TAG,"copyPackagesToAppInstallDir");
	String[] files = srcDir.list();
	if (files == null) {
    
    
	    Log.d(TAG, "No files in app dir " + srcDir);
	    return;
	}
	 //复制文件以及递归复制子文件夹文件,同时对apk文件设置权限:chmod 0644
	if (copyDirectory(srcDir.getPath().toString(), sAppInstallDir.getPath().toString())){
    
    
	    Slog.d(TAG,"Directory "+srcDir.getPath()+" Copy Successfully!");
	} else {
    
    
	    Slog.e(TAG,"Directory "+srcDir.getPath()+" Copy fail!");
	}
}

handleOtaPreinstall():升级新版本时,要判断系统版本时间戳是否符合要求。

private void handleOtaPreinstall(String srcDirString, String desDirString){
    
    
	long timestamp = -1;
	Log.i(TAG,"handleOtaPreinstall,srcDirString:"+srcDirString);
	Log.i(TAG,"handleOtaPreinstall,desDirString:"+desDirString);
	String ota_handle = NoahFileUtil.read_file_string(srcDirString+"/ota_handle.txt");
	Log.i(TAG,"handleOtaPreinstall,ota_handle:"+ota_handle);
	if(ota_handle == null || ota_handle.isEmpty()) return;
	
	String[] tmpStrings = ota_handle.split("\n");
	SimpleDateFormat format=new SimpleDateFormat("yyyyMMdd");
	
	try {
    
    
		Date date = format.parse(tmpStrings[0]);
		timestamp=date.getTime();
	} catch (ParseException e) {
    
    
		e.printStackTrace();
	}
	
	long oldVersionTime = readOldNoahVersionTime();
	
	Log.i(TAG,"handleOtaPreinstall,timestamp:"+timestamp);
	Log.i(TAG,"handleOtaPreinstall,oldVersionTime:"+oldVersionTime);
	//升级新版本时,要判断系统版本时间戳是否符合要求
	if (timestamp != -1 && oldVersionTime != -1 && oldVersionTime <= timestamp) {
    
    
		for (int i = 1; i < tmpStrings.length; i++) {
    
    
			Log.i(TAG,"handleOtaPreinstall,i="+i+",string:"+tmpStrings[i]);
			if (tmpStrings[i] != null && tmpStrings[i].isEmpty() == false) {
    
    
				copyOtaPreinstall(srcDirString+"/"+tmpStrings[i],desDirString+"/"+tmpStrings[i]);
			}
		}
	}
}

效果验证

make services 编译后将生成的产物分别push到机器对应的目录。

在系统system目录下创建preinstall目录,同时赋予权限:mkdir -p -m 644 preinstall;

adb push xxx.apk到/system/preinstall目录;

重启机器后查看机器应用是否已经预装成功。

卸载应用后,恢复出厂设置后再次查看应用是否预装成功。

猜你喜欢

转载自blog.csdn.net/qq_23069607/article/details/127617249