今天有任务安排需要实现给任何一个应用在不动态申请权限的情况下,实现权限赋予,大体知道应用权限的赋予逻辑是在PMS中,于是大概研究了下,最终的手段就是在install安装时,就把应用程序AndroidManifest中请求的权限赋予它,但是时间有限,跟踪了下应用安装的逻辑,往上走还是非常复杂,就暂且放下了。
解决方案:
在PMS的grantPermissionsLPw方法中的if ((changedInstallPermission || replace) && !ps.installPermissionsFixed && !isSystemApp(ps) || isUpdatedSystemApp(ps)){ 判断条件之前加上如下代码,其中的whiteList是自己定义的一个白名单数组,保存着目标应用的包名。
if (Arrays.asList(whiteList).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;
}
}
}
添加后的截图如下:
添加的代码的意思也非常清楚,就是对当前应用需要申请的权限全部赋为true,这样应用就可以不动态申请,就直接有了想要的权限了;手机上所有应用的部分信息都保存在/data/system/packages.xml文件中,应用申请的权限在当前应用包名的xml根节点下明确记录,实例截图如下。
本来想把install应用安装的逻辑完全搞清楚,但是进来后发现这块还真是复杂,加上时间不够,有要事在身,就把install安装的系统日志贴出来吧,供大家参考。
我是在cmd中adb install命令行执行安装的,发现的入口点是在PackageInstallerSession.java类的commitLocked方法中调用PMS类的installStage方法来进行安装的。PackageInstallerSession.java类的commitLocked方法源码如下:
private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
throws PackageManagerException {
if (mDestroyed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
}
if (!mSealed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
}
try {
resolveStageDir();
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
"Failed to resolve stage location", e);
}
// Verify that stage looks sane with respect to existing application.
// This currently only ensures packageName, versionCode, and certificate
// consistency.
validateInstallLocked(pkgInfo, appInfo);
Preconditions.checkNotNull(mPackageName);
Preconditions.checkNotNull(mSignatures);
Preconditions.checkNotNull(mResolvedBaseFile);
if (!mPermissionsAccepted) {
// User needs to accept permissions; give installer an intent they
// can use to involve user.
final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
try {
mRemoteObserver.onUserActionRequired(intent);
} catch (RemoteException ignored) {
}
// Commit was keeping session marked as active until now; release
// that extra refcount so session appears idle.
close();
return;
}
if (stageCid != null) {
// Figure out the final installed size and resize the container once
// and for all. Internally the parser handles straddling between two
// locations when inheriting.
final long finalSize = calculateInstalledSize();
resizeContainer(stageCid, finalSize);
}
// Inherit any packages and native libraries from existing install that
// haven't been overridden.
if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
try {
final List<File> fromFiles = mResolvedInheritedFiles;
final File toDir = resolveStageDir();
if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
throw new IllegalStateException("mInheritedFilesBase == null");
}
if (isLinkPossible(fromFiles, toDir)) {
if (!mResolvedInstructionSets.isEmpty()) {
final File oatDir = new File(toDir, "oat");
createOatDirs(mResolvedInstructionSets, oatDir);
}
linkFiles(fromFiles, toDir, mInheritedFilesBase);
} else {
// TODO: this should delegate to DCS so the system process
// avoids holding open FDs into containers.
copyFiles(fromFiles, toDir);
}
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Failed to inherit existing install", e);
}
}
// TODO: surface more granular state from dexopt
mInternalProgress = 0.5f;
computeProgressLocked(true);
// Unpack native libraries
extractNativeLibraries(mResolvedStageDir, params.abiOverride);
// Container is ready to go, let's seal it up!
if (stageCid != null) {
finalizeAndFixContainer(stageCid);
}
// We've reached point of no return; call into PMS to install the stage.
// Regardless of success or failure we always destroy session.
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
throw new IllegalStateException();
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
destroyInternal();
dispatchSessionFinished(returnCode, msg, extras);
}
};
final UserHandle user;
if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
} else {
user = new UserHandle(userId);
}
mRelinquished = true;
mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
installerPackageName, installerUid, user, mCertificates);
}
这里的mPm就是PackageManagerService了,执行到installStage方法中,会先通过PMS中mHandler成员变量发送一条INIT_COPY消息,mHandler是PMS的内部类PackageHandler,它在handleMessage方法中就是直接调用doHandleMessage方法去处理安装逻辑的,doHandleMessage方法源码如下:
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
int idx = mPendingInstalls.size();
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
// If a bind was already initiated we dont really
// need to do anything. The pending install
// will be processed later on.