高通 android 7.1
app不带系统签名,仅仅以反射的方式调用PackageManager类的installPackage、deletePackage方法,实现静默安装卸载。
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
首先,没有系统签名的情况下,安装app的时候这2个权限不会放开,因此先修改PackageManagerService.java->grantPermissionsLPw方法
+ //允许app全部权限
+ mPkgList.add("com.android.testa");
+ mPkgList.add("com.android.testb");
+ if (mPkgList.contains(pkg.packageName)) {
+ final int permsSize = pkg.requestedPermissions.size();
+ for (int i = 0; i < permsSize; i++) {
+ final String name = pkg.requestedPermissions.get(i);
+ final BasePermission bp = mSettings.mPermissions.get(name);
+ if (null != bp && permissionsState.grantInstallPermission(bp) != PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ Slog.d(TAG, "grant permission " + name + " to package " + pkg.packageName);
+ changedInstallPermission = true;
+ }
+ }
+ }
+
if ((changedInstallPermission || replace) && !ps.installPermissionsFixed &&
!isSystemApp(ps) || isUpdatedSystemApp(ps)){
// This is the first that we have heard about this package, so the
这一步修改后,mmm frameworks/base/services,然后重新替换/system/framework/service.jar验证,静默安装ok,静默卸载不ok,但是log里面没有显示权限问题,说明权限实际上已经具备,其他地方出了问题。
1.PackageManagerService.java继承IPackageManager.Stub
2.ApplicationPackageManager.java继承PackageManager.java
3.反射调用PackageManager.java的installPackage deletePackage方法,实际上是调用ApplicationPackageManager.java里面的方法
ApplicationPackageManager.java里面的对应源码:
/** @hide */
public class ApplicationPackageManager extends PackageManager {
//install
@Override
public void installPackage(Uri packageURI, PackageInstallObserver observer,
int flags, String installerPackageName) {
installCommon(packageURI, observer, flags, installerPackageName, mContext.getUserId());
}
private void installCommon(Uri packageURI,
PackageInstallObserver observer, int flags, String installerPackageName,
int userId) {
if (!"file".equals(packageURI.getScheme())) {
throw new UnsupportedOperationException("Only file:// URIs are supported");
}
final String originPath = packageURI.getPath();
try {
mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
//delete
@Override
public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
deletePackageAsUser(packageName, observer, flags, mContext.getUserId());
}
@Override
public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags,
int userId) {
try {
mPM.deletePackageAsUser(packageName, observer, userId, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
//实际上是通过aidl调用mPM的方法,mPM是一个IPackageManager对象,在创建ApplicationPackageManager对象的时候赋值
ApplicationPackageManager(ContextImpl context,
IPackageManager pm) {
mContext = context;
mPM = pm;
}
4.从ApplicationPackageManager源码可以看到,安装卸载是通过aidl调用mPM的方法,mPM是一个IPackageManager对象,在创建ApplicationPackageManager对象的时候赋值。
5.PackageManagerService.java继承IPackageManager.Stub,实际上就调用了PackageManagerService.java里面的installPackageAsUser和deletePackageAsUser方法,因此本质上静默安装卸载都是在PackageManagerService.java里面实现的。
6.仔细查看PackageManagerService.java卸载的代码逻辑,注意看isCallerAllowedToSilentlyUninstall方法,从命名就可以看出,这里是判断是否允许调用者执行静默卸载,显然第三方app在默认情况下是返回的false,因此无法继续执行静默卸载的逻辑,并且从PMS源码看,不会抛出什么异常信息,实测加打印确实如此。
@Override
public void deletePackage(final String packageName,
final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
//如果app的清单文件里面没有申明卸载权限,那么这一句会抛出异常,提示没有权限
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_PACKAGES, null);
Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(observer);
final int uid = Binder.getCallingUid();
if (!isOrphaned(packageName)
&& !isCallerAllowedToSilentlyUninstall(uid, packageName)) {
try {
final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
observer.onUserActionRequired(intent);
} catch (RemoteException re) {
}
return;
}
...省略
private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID
|| callingUid == Process.SYSTEM_UID) {
return true;
}
final int callingUserId = UserHandle.getUserId(callingUid);
// If the caller installed the pkgName, then allow it to silently uninstall.
if (callingUid == getPackageUid(getInstallerPackageName(pkgName), 0, callingUserId)) {
return true;
}
// Allow package verifier to silently uninstall.
if (mRequiredVerifierPackage != null &&
callingUid == getPackageUid(mRequiredVerifierPackage, 0, callingUserId)) {
return true;
}
// Allow package uninstaller to silently uninstall.
if (mRequiredUninstallerPackage != null &&
callingUid == getPackageUid(mRequiredUninstallerPackage, 0, callingUserId)) {
return true;
}
// Allow storage manager to silently uninstall.
if (mStorageManagerPackage != null &&
callingUid == getPackageUid(mStorageManagerPackage, 0, callingUserId)) {
return true;
}
return false;
}
7.在isCallerAllowedToSilentlyUninstall方法里面,增加特殊处理
private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
+ if (mPkgList.size() > 0) {
+ try {
+ if (mPkgList.contains(AppGlobals.getPackageManager().getNameForUid(callingUid))) {
+ return true;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Slog.e(TAG, "getNameForUid error is " + e.getMessage());
+ }
+ }
加上以上修改之后实测,卸载正常。
PS:
测试代码如下:
//AndroidManiFest.xml里面声明权限
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
mPackageDeleteObserver = new PackageDeleteObserver();
mPackageInstallObserver = new PackageInstallObserver();
//卸载
try {
Class<?>[] uninstalltypes = new Class[]{String.class, IPackageDeleteObserver.class, int.class};
PackageManager pm = mContext.getPackageManager();
Method uninstall = pm.getClass().getMethod("deletePackage", uninstalltypes);
uninstall.invoke(pm, new Object[]{"cache.wind.nfc", mPackageDeleteObserver, 0});
Log.d(TAG, "invoke uninstall app>>>>>>>");
} catch (Exception e) {
Log.e(TAG, "error " + e.getMessage());
e.printStackTrace();
}
//安装
try {
Class<?>[] installtypes = new Class[]{Uri.class, IPackageInstallObserver.class, int.class, String.class};
PackageManager pm = mContext.getPackageManager();
Method install = pm.getClass().getMethod("installPackage", installtypes);
int installFlags = 0;
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
install.invoke(pm, new Object[]{Uri.fromFile(new File("/sdcard/NfcReader.apk")), mPackageInstallObserver, installFlags, null});
Log.d(TAG, "invoke install app>>>>>>>");
} catch (Exception e) {
Log.e(TAG, "error " + e.getMessage());
e.printStackTrace();
}
class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
@Override
public void packageDeleted(String s, int i) throws RemoteException {
Log.d(TAG, "packageDeleted s is " + s + " return code is " + i);
}
}
class PackageInstallObserver extends IPackageInstallObserver.Stub {
@Override
public void packageInstalled(String s, int i) throws RemoteException {
Log.d(TAG, "packageInstalled s is " + s + " return code is " + i);
}
}