Android 8.1预置应用高级权限之安装未知应用权限

前言

项目需要给某个应用授予安装未知应用权限 防止进入设置的授权界面,一开始和之前一样想着在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即可

 

感谢您看完整篇文章,希望您点个赞哦

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值