前言
项目需要给某个应用授予安装未知应用权限 防止进入设置的授权界面,一开始和之前一样想着在framework中的DefaultPermissionGrantPolicy.java中授予所有权限,哈哈,结果是啥,你应该想的到的
具体解决
解决之前的操作,像495行代码一样设置安装未知应用权限,然并卵,其他的权限是可以的,这个一点反应都没有
恩,上面的操作不靠谱,那就只能换另外的操作了,想着PackageManagerService.java中可能可以,就在这里面尝试了一下
结果还是不行.没办法了,只能看Settings 的源码了
看看点击之后到底做了什么操作
下面是安装未知应用界面的代码
packages/apps/Settings/src/com/android/settings/applications/ExternalSourcesDetails.java
package com.android.settings.applications;
import android.app.AlertDialog;
import android.app.AppOpsManager;
import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.Settings;
import com.android.settings.applications.AppStateInstallAppsBridge.InstallAppsState;
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import static android.app.Activity.RESULT_CANCELED;
import static android.app.Activity.RESULT_OK;
public class ExternalSourcesDetails extends AppInfoWithHeader
implements OnPreferenceChangeListener {
private static final String KEY_EXTERNAL_SOURCE_SWITCH = "external_sources_settings_switch";
private AppStateInstallAppsBridge mAppBridge;
private AppOpsManager mAppOpsManager;
private UserManager mUserManager;
private RestrictedSwitchPreference mSwitchPref;
private InstallAppsState mInstallAppsState;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Context context = getActivity();
mAppBridge = new AppStateInstallAppsBridge(context, mState, null);
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mUserManager = UserManager.get(context);
addPreferencesFromResource(R.xml.external_sources_details);
mSwitchPref = (RestrictedSwitchPreference) findPreference(KEY_EXTERNAL_SOURCE_SWITCH);
mSwitchPref.setOnPreferenceChangeListener(this);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean checked = (Boolean) newValue;
if (preference == mSwitchPref) {
if (mInstallAppsState != null && checked != mInstallAppsState.canInstallApps()) {
if (Settings.ManageAppExternalSourcesActivity.class.getName().equals(
getIntent().getComponent().getClassName())) {
setResult(checked ? RESULT_OK : RESULT_CANCELED);
}
setCanInstallApps(checked);
refreshUi();
}
return true;
}
return false;
}
static CharSequence getPreferenceSummary(Context context, AppEntry entry) {
final UserManager um = UserManager.get(context);
final int userRestrictionSource = um.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserHandle.getUserHandleForUid(entry.info.uid));
switch (userRestrictionSource) {
case UserManager.RESTRICTION_SOURCE_DEVICE_OWNER:
case UserManager.RESTRICTION_SOURCE_PROFILE_OWNER:
return context.getString(R.string.disabled_by_admin);
case UserManager.RESTRICTION_SOURCE_SYSTEM:
return context.getString(R.string.disabled);
}
final InstallAppsState appsState = new AppStateInstallAppsBridge(context, null, null)
.createInstallAppsStateFor(entry.info.packageName, entry.info.uid);
return context.getString(appsState.canInstallApps()
? R.string.app_permission_summary_allowed
: R.string.app_permission_summary_not_allowed);
}
private void setCanInstallApps(boolean newState) {
mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
mPackageInfo.applicationInfo.uid, mPackageName,
newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED);
}
@Override
protected boolean refreshUi() {
if (mUserManager.hasBaseUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserHandle.of(UserHandle.myUserId()))) {
mSwitchPref.setChecked(false);
mSwitchPref.setSummary(R.string.disabled);
mSwitchPref.setEnabled(false);
return true;
}
mSwitchPref.checkRestrictionAndSetDisabled(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
if (mSwitchPref.isDisabledByAdmin()) {
return true;
}
mInstallAppsState = mAppBridge.createInstallAppsStateFor(mPackageName,
mPackageInfo.applicationInfo.uid);
if (!mInstallAppsState.isPotentialAppSource()) {
// Invalid app entry. Should not allow changing permission
mSwitchPref.setEnabled(false);
return true;
}
mSwitchPref.setChecked(mInstallAppsState.canInstallApps());
return true;
}
@Override
protected AlertDialog createDialog(int id, int errorCode) {
return null;
}
@Override
public int getMetricsCategory() {
return MetricsEvent.MANAGE_EXTERNAL_SOURCES;
}
}
可以看到具体的实现是setCanInstallApps方法
private void setCanInstallApps(boolean newState) {
mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
mPackageInfo.applicationInfo.uid, mPackageName,
newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED);
}
恩,通过AppOpsManager来设置的,所有我们只要开机时调用这个方法指定对应APK包名即可
AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, mPackageName, AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED
这四个值我们不用管,就在AppOpsManager中,只需找到mPackageInfo.applicationInfo.uid 即可,然后我们发现mPackageInfo 不在这个类中定义,应该是属于它的父类中定义的,而ExternalSourcesDetails 继承于 AppInfoWithHeader类 但是呢,在AppInfoWithHeader也没有发现这个的定义,所以我们要再往上找,然后在AppInfoWithHeader父类AppInfoBase类的第73行找到了mPackageInfo的定义
73行仅仅只是定义个变量,最终赋值是在retrieveAppEntry方法中
mPm根据80行可以知道是PackageManager
mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
mPackageInfo.applicationInfo.uid, mPackageName,
newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED);
所以上面这个方法的所有值我们都已经知道了,照猫画虎即可
整个方法的实现如下
try {
AppOpsManager mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
PackageManager mPm = context.getPackageManager();
PackageInfo mPackageInfo = mPm.getPackageInfo(packageName,
PackageManager.MATCH_DISABLED_COMPONENTS |
PackageManager.MATCH_ANY_USER |
PackageManager.GET_SIGNATURES |
PackageManager.GET_PERMISSIONS);
mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
mPackageInfo.applicationInfo.uid, packageName,AppOpsManager.MODE_ALLOWED);
}catch (NameNotFoundException e) {
Log.e(TAG, "Exception when retrieving package:" + packageName, e);
}
因此只需在开机的时候使用此方法设置对应的APK即可
感谢您看完整篇文章,希望您点个赞哦