修改记录
1.安装器
//Installer.java
package com.kte.interfacesettings.service;
import java.io.IOException;
import java.io.InputStream;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.content.pm.IPackageInstallerCallback;
import java.io.File;
import android.os.RemoteException;
import java.io.FileInputStream;
import java.io.OutputStream;
import android.app.PendingIntent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageParser;
import android.content.pm.IPackageInstaller;
import android.os.ServiceManager;
import com.android.internal.content.PackageHelper;
import android.os.UserHandle;
import android.app.ActivityManager;
import android.os.Binder;
import android.content.pm.IPackageManager;
public class Installer {
private static String TAG = "install";
private Installer() {
}
public static void silentInstallApk(Context context, String apkFilePath, int userId, boolean openWhenInstalled) {
Log.d(TAG, "[Installer] silentInstallApk...path=" + apkFilePath);
File apkFile = new File(apkFilePath);
IPackageManager mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
try {
final IPackageInstaller packageInstaller = mPm.getPackageInstaller();
packageInstaller.registerCallback(new IPackageInstallerCallback.Stub() {
String pkgname = null;
@Override
public void onSessionProgressChanged(int sessionId, float progress) throws RemoteException {
Log.d(TAG, "[Installer] silentInstallApk...onProgressChanged-> " + sessionId);
}
@Override
public void onSessionFinished(int sessionId, boolean success) throws RemoteException {
Log.d(TAG, "[Installer] silentInstallApk...Silent Install session " + sessionId + " Success=" + success + ",,pkgName=" + pkgname);
if (success && openWhenInstalled) {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(pkgname);
context.startActivity(intent);
}
}
@Override
public void onSessionCreated(int sessionId) throws RemoteException {
SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
pkgname = sessionInfo.getAppPackageName();
Log.d(TAG, "[Installer] silentInstallApk...Install Start sessionId-> " + sessionId + ",,pkgname=" + pkgname);
}
@Override
public void onSessionBadgingChanged(int sessionId) throws RemoteException {
Log.d(TAG, "[Installer] silentInstallApk...onBadgingChanged-> " + sessionId);
}
@Override
public void onSessionActiveChanged(int sessionId, boolean active) throws RemoteException {
Log.d(TAG, "[Installer] silentInstallApk...onActiveChanged-> " + sessionId);
}
}, userId);
PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
try {
PackageParser.PackageLite pkg = PackageParser.parsePackageLite(apkFile, 0);
sessionParams.setAppPackageName(pkg.packageName);
sessionParams.setInstallLocation(pkg.installLocation);
sessionParams.setSize(PackageHelper.calculateInstalledSize(pkg, sessionParams.abiOverride));
} catch (PackageParser.PackageParserException e) {
Log.e(TAG, "[Installer] silentInstallApk...Cannot parse package " + apkFile, e);
sessionParams.setSize(apkFile.length());
} catch (IOException e) {
Log.e(TAG, "[Installer] silentInstallApk...Cannot calculate installed size " + apkFile, e);
sessionParams.setSize(apkFile.length());
}
int sessionId = -1;
final int translatedUserId = translateUserId(userId, UserHandle.USER_SYSTEM, "doCreateSession");
sessionId = packageInstaller.createSession(sessionParams, context.getApplicationContext().getPackageName(),
translatedUserId);
Log.d(TAG, "[Installer] silentInstallApk...silentInstallApk sessionId=" + sessionId);
if (sessionId != -1) {
boolean copySuccess = copyInstallFile(packageInstaller, sessionId, apkFilePath);
Log.d(TAG, "[Installer] silentInstallApk...silentInstallApk copySuccess=" + copySuccess);
if (copySuccess) {
Log.d(TAG, "[Installer] silentInstallApk...silentInstallApk copySuccess...111...");
execInstallCommand(context, packageInstaller, sessionId);
}
}
} catch (RemoteException e1) {
Log.e(TAG, "[Installer] silentInstallApk...silentInstallApk e1=" + e1);
e1.printStackTrace();
}
}
private static boolean copyInstallFile(IPackageInstaller 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 = new PackageInstaller.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(TAG, "[Installer] copyInstallFile...streamed " + total + " bytes");
success = true;
} catch (IOException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} finally {
try {
out.close();
in.close();
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return success;
}
private static int translateUserId(int userId, int allUserId, String logContext) {
final boolean allowAll = (allUserId != UserHandle.USER_NULL);
final int translatedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, allowAll, true, logContext, "pm command");
return translatedUserId == UserHandle.USER_ALL ? allUserId : translatedUserId;
}
private static void execInstallCommand(Context context, IPackageInstaller packageInstaller, int sessionId) {
PackageInstaller.Session session = null;
try {
Log.d(TAG, "[Installer] execInstallCommand......");
session = new PackageInstaller.Session(packageInstaller.openSession(sessionId));
Intent intent = new Intent("com.android.my_install_apk_broadcat");
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FROM_SHELL | 0x01000000);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
session.commit(pendingIntent.getIntentSender());
Log.i(TAG, "[Installer] execInstallCommand...begin session");
} catch (RemoteException e) {
e.printStackTrace();
} finally {
session.close();
}
}
}
2.解决正常发广播的问题
//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
if ((intent.getFlags() & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
// Don't yell about broadcasts sent via shell
return;
}
final String action = intent.getAction();
if (isProtectedBroadcast
|| "com.android.my_install_apk_broadcat".equals(action) //添加这个判断
|| Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
|| Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(action)
|| Intent.ACTION_MEDIA_BUTTON.equals(action)
|| Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
|| Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
|| Intent.ACTION_MASTER_CLEAR.equals(action)
|| Intent.ACTION_FACTORY_RESET.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
|| LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
|| TelephonyManager.ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE.equals(action)
|| SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(action)
|| AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION.equals(action)
|| AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION.equals(action)) {
// Broadcast is either protected, or it's a public action that
// we've relaxed, so it's fine for system internals to send.
return;
}
......
}
3.调用安装器
//FuncTools.java
@SuppressWarnings("deprecation")
public void directInstall(String path, boolean install, final boolean openWhenInstalled) {
try {
if (!TextUtils.isEmpty(path)) {
IPackageManager mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
if (install) { //静默安装
Installer.silentInstallApk(mContext,path,UserHandle.myUserId(),openWhenInstalled);
} else { //静默卸载
IPackageDeleteObserver observer = new IPackageDeleteObserver.Stub() {
@Override
public void packageDeleted(String packageName, int returnCode) throws RemoteException {
android.util.Log.d(TAG, "directInstall...packageDeleted...");
}
};
mPm.deletePackageAsUser(path, PackageManager.VERSION_CODE_HIGHEST, observer, UserHandle.myUserId(),
PackageManager.DELETE_ALL_USERS);
}
}
} catch (Exception e) {
e.printStackTrace();
android.util.Log.e(TAG, "directInstall error:path=" + path + ",,install=" + install + ",,open=" + openWhenInstalled+",e="+e);
}
}
4.广播接收安装信息
//MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册动态广播
IntentFilter filter = new IntentFilter();
filter.addAction("com.android.my_install_apk_broadcat");
registerReceiver(myInstallReceiver, filter);
}
//广播监听
BroadcastReceiver myInstallReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG,"[MainActivity] onReceive...action="+intent.getAction());
if ("com.android.my_install_apk_broadcat".equals(intent.getAction())) {
String pkgName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME);
String statusMsg = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0);
Log.i(TAG, "install_apk_broadcat,,,pkgName=" + pkgName + ",,statusMsg=" + statusMsg + ",,status="
+ status);
}
}
};