转自Android系统预置应用宝
如果直接按照常规方案预置应用宝到system/app下的话,会报好多Selinux错误,导致应用闪退
而应用宝又申请了好多并不需要的权限例如su
本来的方案是第一次开机时用packageinstaller静默安装应用宝
但是效果不太好,会出现桌面图标加载完以后才安装显示应用宝
所以需要添加个系统服务,在systemserver里面启动安装
系统编译需要先把应用宝预置到/product/etc/app/yingyongbao.apk
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
......
t.traceBegin("StartBootPhaseDeviceSpecificServicesReady");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
t.traceEnd();
ConcurrentUtils.waitForFutureNoInterrupt(mBlobStoreServiceStart,
START_BLOB_STORE_SERVICE);
//silent install apk ---------------------加载时机不要太靠前,需要等pms systemReady后加载
if(android.os.SystemProperties.get("ro.hct_silent_install").equals("1")){
t.traceBegin("SilentInstallService");
mSystemServiceManager.startService(SilentInstallService.class);
t.traceEnd();
}
......
}
frameworks / base/services/install/java/com/android/server/install/SilentInstallService.java
package com.android.server.install;
import android.app.AppGlobals;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInfo;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
import com.android.server.SystemService;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public class SilentInstallService extends SystemService {
private Context mContext;
private String apkPath;
private IPackageManager pm;
private File[] apklist;
private String LOG_TAG = "SilentInstallService";
public SilentInstallService(Context context) {
super(context);
mContext = context ;
pm = AppGlobals.getPackageManager();
apklist = new File("/system/install/apk/").listFiles();
}
@Override
public void onStart() {
Log.i("wangss log", "persist.sys.hct_silent_install = " + SystemProperties.get("persist.sys.hct_silent_install"));
if(!SystemProperties.get("persist.sys.hct_silent_install").equals("1")) {
ThreadPoolManager.getInstance().execute(new Runnable() {
@Override
public void run() {
for(File file : apklist) {
if(file.isFile() && file.getName().endsWith(".apk.1")) {
install28(mContext, file.getAbsolutePath());
}
}
}
});
SystemProperties.set("persist.sys.hct_silent_install", "1");
}
}
public void install28(Context context, String apkFilePath) {
Log.i(LOG_TAG, "install28 apkFilePath=" + apkFilePath);
File apkFile = new File(apkFilePath);
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams sessionParams
= new PackageInstaller.SessionParams(PackageInstaller
.SessionParams.MODE_FULL_INSTALL);
sessionParams.setSize(apkFile.length());
int sessionId = createSession(packageInstaller, sessionParams);
Log.i(LOG_TAG, "install28 sessionId=" + sessionId);
if (sessionId != -1) {
boolean copySuccess = copyInstallFile(packageInstaller, sessionId, apkFilePath);
Log.d(LOG_TAG, "install28 copySuccess=" + copySuccess);
if (copySuccess) {
execInstallCommand(context, packageInstaller, sessionId);
}
}
}
public int createSession(PackageInstaller packageInstaller,
PackageInstaller.SessionParams sessionParams) {
int sessionId = -1;
try {
sessionId = packageInstaller.createSession(sessionParams);
} catch (IOException e) {
e.printStackTrace();
}
return sessionId;
}
public boolean copyInstallFile(PackageInstaller packageInstaller,
int sessionId, String apkFilePath) {
InputStream in = null;
OutputStream out = null;
PackageInstaller.Session session = null;
boolean success = false;
try {
File apkFile = new File(apkFilePath);
session = packageInstaller.openSession(sessionId);
out = session.openWrite("base.apk", 0, apkFile.length());
in = new FileInputStream(apkFile);
int total = 0, c;
byte[] buffer = new byte[65536];
while ((c = in.read(buffer)) != -1) {
total += c;
out.write(buffer, 0, c);
}
session.fsync(out);
Log.i(LOG_TAG, "streamed " + total + " bytes");
success = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
out.close();
in.close();
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return success;
}
public void execInstallCommand(Context context, PackageInstaller packageInstaller, int sessionId) {
PackageInstaller.Session session = null;
try {
session = packageInstaller.openSession(sessionId);
Intent intent = new Intent(context, InstallResultReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
session.commit(pendingIntent.getIntentSender());
Log.i(LOG_TAG, "begin session");
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
}
}
frameworks / base/services/install/java/com/android/server/install/InstallResultReceiver.java
package com.android.server.install;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
public class InstallResultReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
if (status == PackageInstaller.STATUS_SUCCESS) {
// success
} else {
//Log.e(TAG, intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE));
}
}
}
}
frameworks / base/services/install/java/com/android/server/install/ThreadPoolManager.java
package com.android.server.install;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.linkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.Executors;
public class ThreadPoolManager {
private static final String TAG = "ThreadPoolManager";
private static ThreadPoolManager mInstance = new ThreadPoolManager();
public static ThreadPoolManager getInstance() {
return mInstance;
}
private int corePoolSize;
private int maximumPoolSize;
private long keepAliveTime = 1;
private TimeUnit unit = TimeUnit.SECONDS;
private ThreadPoolExecutor executor;
private ThreadPoolManager() {
corePoolSize = Runtime.getRuntime().availableProcessors()*2+1;
maximumPoolSize = corePoolSize;
executor = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
new linkedBlockingQueue(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
}
public void execute(Runnable runnable){
if(runnable==null)return;
executor.execute(runnable);
}
public void remove(Runnable runnable){
if(runnable==null)return;
executor.remove(runnable);
}
}
方法二
diff --git a/base/packages/PackageInstaller/AndroidManifest.xml b/base/packages/PackageInstaller/AndroidManifest.xml
index fe4fdd349..de184128a 100644
--- a/base/packages/PackageInstaller/AndroidManifest.xml
+++ b/base/packages/PackageInstaller/AndroidManifest.xml
@@ -17,6 +17,7 @@
+
diff --git a/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java b/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java
index 54105bb84..98ec65bbf 100644
--- a/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java
+++ b/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java
@@ -82,6 +82,12 @@ public class InstallFailed extends alertActivity {
int statusCode = getIntent().getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
+ if(InstallUtil.installMode != 0) {
+ String errorStr = System.currentTimeMillis() + ", " + InstallUtil.pkgName + ", " + InstallUtil.oldVersion + ", " + InstallUtil.newVersion + ", " + statusCode;
+ InstallUtil.writeData(errorStr);
+ finish();
+ return;
+ }
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
int legacyStatus = getIntent().getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS,
PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
diff --git a/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallUtil.java b/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallUtil.java
+public class InstallUtil {
+
+
+ public static int installMode = 0;
+ public static String pkgName;
+ public static Context mContext;
+ public static String oldVersion;
+ public static String newVersion;
+
+
+ public static int installSilent(String filePath) {
+ //需添加获取apk版本号
+ String errorStr;
+ File file = new File(filePath);
+ if (filePath == null || filePath.length() == 0 || file == null || file.length() <= 0 || !file.exists() || !file.isFile()) {
+ return 1;
+ }
+ Log.i("seven", "InstallUtil: " + filePath);
+
+ Process process = null;
+ BufferedReader successResult = null;
+ BufferedReader errorResult = null;
+ StringBuilder successMsg = new StringBuilder();
+ StringBuilder errorMsg = new StringBuilder();
+ int result;
+ try {
+ process = Runtime.getRuntime().exec("pm install -i " + "com.android.packageinstaller --user 0 " + filePath);
+ successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+ String s;
+ while ((s = successResult.readLine()) != null) {
+ successMsg.append(s);
+ }
+ while ((s = errorResult.readLine()) != null) {
+ errorMsg.append(s);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (successResult != null) {
+ successResult.close();
+ }
+ if (errorResult != null) {
+ errorResult.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ if (process != null) {
+ process.destroy();
+ }
+ }
+
+ // TODO should add memory is not enough here
+ if (successMsg.toString().contains("Success") || successMsg.toString().contains("success")) {
+ result = 0;
+ } else {
+ result = 2;
+ }
+ if(!TextUtils.isEmpty(errorMsg.toString())){
+ errorStr = System.currentTimeMillis() + "," + pkgName + "," + oldVersion + "," + newVersion + "," + errorMsg.toString();
+ writeData(errorStr);
+ }
+ if(installMode == 1) {
+ doStartApplicationWithPackageName(pkgName);
+ }
+ Log.i("haocheng_songhui", "successMsg:" + successMsg + ", ErrorMsg:" + errorMsg);
+ return result;
+ }
+
+ public static String getPkgPath(Intent intent, Context context) {
+ mContext = context;
+ String pkgPath = null;
+ Uri pkgUri = intent.getData();
+ String[] proj = { MediaStore.Images.Media.DATA };
+ Cursor cursor = context.getContentResolver().query(pkgUri, proj, null, null, null);
+ if (cursor.moveToFirst()) {
+ int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
+ pkgPath = cursor.getString(columnIndex);
+ }
+ return pkgPath;
+ }
+
+
+
+ public static int getPkgWhite(String str) {
+ String whitePath= Environment.getExternalStorageDirectory().getAbsolutePath() + "/wxpayface/conf/package.conf";
+ String jsonWhite = readJsonFile(whitePath);
+ if(!TextUtils.isEmpty(jsonWhite)){
+ try {
+ JSONObject obj = new JSONObject(jsonWhite);
+ JSONArray allowedArray = obj.getJSONArray("allowed");
+ for (int i=0; i < allowedArray.length(); i++){
+ Log.i("haocheng_songhui", "conf allowed" + i + ": " + allowedArray.getString(i));
+ if(str.equals(allowedArray.getString(i))){
+ installMode = 1;
+ Log.i("haocheng_songhui", "静默安装模式,安装完成后打开apk, installMode = " + installMode);
+ }
+ }
+ JSONArray backgroundArray = obj.getJSONArray("background");
+ for (int i=0; i < backgroundArray.length(); i++){
+ Log.i("haocheng_songhui", "conf background" + i + ": " + backgroundArray.getString(i));
+ if(str.equals(backgroundArray.getString(i))){
+ installMode = 2;
+ Log.i("haocheng_songhui", "静默安装模式,安装完成后不做操作, installMode = " + installMode);
+ }
+ }
+ if(installMode == 0) {
+ Log.i("haocheng_songhui", "正常安装模式, installMode = " + installMode);
+ }
+ } catch (Exception e) {
+ Log.i("haocheng_songhui", "json解析失败!");
+ e.printStackTrace();
+ }
+ }
+ //installMode = 2; 用于测试白名单模式
+ return installMode;
+ }
+
+
+ public static String getSHA256(String str, String version){
+ pkgName = str;
+ //需添加获取当前版本号
+ oldVersion = getVersionName();
+ newVersion = version;
+ Log.i("haocheng_songhui", "oldVersion:" + oldVersion);
+ Log.i("haocheng_songhui", "newVersion:" + newVersion);
+
+ MessageDigest messageDigest;
+ String encodestr = "";
+ try {
+ messageDigest = MessageDigest.getInstance("SHA-256");
+ messageDigest.update(str.getBytes("UTF-8"));
+ encodestr = byte2Hex(messageDigest.digest());
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ Log.i("haocheng_songhui", "安装包的SHA256: " + encodestr);
+ return encodestr;
+ }
+
+ public static String byte2Hex(byte[] bytes){
+ StringBuffer stringBuffer = new StringBuffer();
+ String temp = null;
+ for (int i = 0; i < bytes.length; i++){
+ temp = Integer.toHexString(bytes[i] & 0xFF);
+ if (temp.length() == 1){
+ stringBuffer.append("0");
+ }
+ stringBuffer.append(temp);
+ }
+ return stringBuffer.toString();
+ }
+
+ public static String readJsonFile(String path) {
+ File file = new File(path);
+ StringBuilder stringBuilder = new StringBuilder();
+ if (file.isDirectory()) {
+ Log.d("TestFile", "The File doesn't not exist.");
+ } else {
+ try {
+ InputStream instream = new FileInputStream(file);
+ InputStreamReader inputreader = new InputStreamReader(instream);
+ BufferedReader buffreader = new BufferedReader(inputreader);
+ if (instream != null) {
+
+ String line;
+ while (( line = buffreader.readLine()) != null) {
+ stringBuilder.append(line);
+ }
+ instream.close();
+ }
+ }
+ catch (java.io.FileNotFoundException e){
+ Log.d("TestFile", "The File doesn't not exist.");
+ }
+ catch (IOException e){
+ Log.d("TestFile", e.getMessage());
+ }
+ }
+ return stringBuilder.toString();
+ }
+
+ public static void doStartApplicationWithPackageName(String packagename) {
+ PackageInfo packageinfo = null;
+ try {
+ packageinfo = mContext.getPackageManager().getPackageInfo(packagename, 0);
+ } catch (NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ if (packageinfo == null) {
+ return;
+ }
+
+ Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
+ resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ resolveIntent.setPackage(packageinfo.packageName);
+
+ List resolveinfoList = mContext.getPackageManager().queryIntentActivities(resolveIntent, 0);
+
+ ResolveInfo resolveinfo = resolveinfoList.iterator().next();
+ if (resolveinfo != null) {
+
+ String className = resolveinfo.activityInfo.name;
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+ ComponentName cn = new ComponentName(packagename, className);
+ intent.setComponent(cn);
+ mContext.startActivity(intent);
+ }
+ }
+
+ public static void writeData(String content) {
+ String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/wxpayface/install_log/";
+ String fileName = pkgName + ".log";
+ writeTxtToFile(content, filePath, fileName);
+ }
+
+
+ private static void writeTxtToFile(String strcontent, String filePath, String fileName) {
+ makeFilePath(filePath, fileName);
+ String strFilePath = filePath + fileName;
+ String strContent = strcontent + "rn";
+ try {
+ File file = new File(strFilePath);
+ if (!file.exists()) {
+ Log.i("haocheng_songhui", "Create the file:" + strFilePath);
+ file.getParentFile().mkdirs();
+ file.createNewFile();
+ }
+ RandomAccessFile raf = new RandomAccessFile(file, "rwd");
+ raf.seek(file.length());
+ raf.write(strContent.getBytes());
+ raf.close();
+ } catch (Exception e) {
+ Log.e("haocheng_songhui", "Error on write File:" + e);
+ }
+ }
+
+
+
+ private static File makeFilePath(String filePath, String fileName) {
+ File file = null;
+ makeRootDirectory(filePath);
+ try {
+ file = new File(filePath + fileName);
+ if (file.exists()) {
+ file.delete();
+ }
+ file.createNewFile();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return file;
+ }
+
+
+
+ private static void makeRootDirectory(String filePath) {
+ File file = null;
+ try {
+ file = new File(filePath);
+ if (!file.exists()) {
+ file.mkdir();
+ }
+ } catch (Exception e) {
+ Log.i("haocheng_songhui error:", e + "");
+ }
+ }
+
+
+ public static String getVersionName(){
+ // 获取packagemanager的实例
+ String version = null;
+ try {
+ PackageManager packageManager = mContext.getPackageManager();
+ PackageInfo packInfo = packageManager.getPackageInfo(pkgName, 0);
+ version = packInfo.versionName;
+ } catch (NameNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ return version;
+ }
+
+
+}
+
diff --git a/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index cee3521fb..9dc2875eb 100644
--- a/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -328,8 +328,11 @@ public class PackageInstallerActivity extends alertActivity {
} catch (NameNotFoundException e) {
mAppInfo = null;
}
-
- startInstall/confirm/i();
+ if(InstallUtil.installMode != 0) {
+ startInstall(); //songhui1
+ }else {
+ startInstall/confirm/i();
+ }
}
void setPmResult(int pmResult) {
diff --git a/base/services/Android.bp b/base/services/Android.bp
index 7e796d2a0..5f159c317 100644
--- a/base/services/Android.bp
+++ b/base/services/Android.bp
@@ -99,7 +99,7 @@ java_library {
//HCT.songhuo install apk
"services.install",
//HCT.chris locale system installer
- "services.systemupdate",
+ "services.systemupdate"
],



