Goddess. PNG

Android 6.0 permissions are no longer given to you at install time. If you need permissions, you need to get them in your code. For users, the “Access Permissions” will pop up so that users can see what permissions the application has, and then decide whether to grant them or not.

For example, the following example is a spammy program to obtain the permission for SMS





PNG

I just need to add a line in the code, the “2” in the parameter is arbitrarily written, is to enter an integer, representing the request code.

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.requestPermissions(
                new String[]{Manifest.permission.SEND_SMS},
                2);
    }Copy the code

This article does not say too much, say how this popbox is good. The first entry is the Activity class, which calls requestPermissions to get the permissions. You can see that he starts another Activity. You can imagine that the popbox is inside the Activity. Let’s look at what the Intent is and find the package name and Action of the Intent. /frameworks/ base/core/java/android/app/Activity.java

    public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
        Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
        startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
    }Copy the code

Through ContextImpl. GetPackageManager () get ApplicationPackageManager, he is the parent of the PackageManager. /frameworks/base/core/java/android/app/ContextImpl.java

    @Override
    public PackageManager getPackageManager() {
        if(mPackageManager ! =null) {
            return mPackageManager;
        }

        IPackageManager pm = ActivityThread.getPackageManager();
        if(pm ! =null) {
            // Doesn't matter if we make more than one instance.
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }

        return null;
    }Copy the code

ApplicationPackageManager access to the intent of the action is android. The content. PM. Action. REQUEST_PERMISSIONS, package name to look at, Through getPermissionControllerPackageName (). /frameworks/base/core/java/android/app/ApplicationPackageManager.java

    public static final String ACTION_REQUEST_PERMISSIONS =
            "android.content.pm.action.REQUEST_PERMISSIONS";
    public static final String EXTRA_REQUEST_PERMISSIONS_NAMES =
            "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";

    public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
        if (ArrayUtils.isEmpty(permissions)) {
           throw new NullPointerException("permission cannot be null or empty");
        }
        Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
        intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
        intent.setPackage(getPermissionControllerPackageName());
        return intent;
    }Copy the code

GetPermissionControllerPackageName () will further call mPM. GetPermissionControllerPackageName (), the mPM is the service PackageManagerService remote agent system.

    @Override
    public String getPermissionControllerPackageName(a) {
        synchronized (mLock) {
            if (mPermissionsControllerPackageName == null) {
                try {
                    mPermissionsControllerPackageName = mPM.getPermissionControllerPackageName();
                } catch (RemoteException e) {
                    throw new RuntimeException("Package manager has died", e); }}returnmPermissionsControllerPackageName; }}Copy the code

The PackageManagerService getRequiredInstallerLPr is used to obtain the package name, which is used to install apk.





Installer. PNG


/frameworks/base/services/core/java/ com/android/server/ pm/PackageManagerService.java

    private String getRequiredInstallerLPr() {
        Intent installerIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
        installerIntent.addCategory(Intent.CATEGORY_DEFAULT);
        installerIntent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);

        final List<ResolveInfo> installers = queryIntentActivities(installerIntent,
                PACKAGE_MIME_TYPE, 0.0);

        String requiredInstaller = null;

        final int N = installers.size();
        for (int i = 0; i < N; i++) {
            final ResolveInfo info = installers.get(i);
            final String packageName = info.activityInfo.packageName;

            if(! info.activityInfo.applicationInfo.isSystemApp()) {continue;
            }

            if(requiredInstaller ! =null) {
                throw new RuntimeException("There must be one required installer");
            }

            requiredInstaller = packageName;
        }

        if (requiredInstaller == null) {
            throw new RuntimeException("There must be one required installer");
        }

        return requiredInstaller;
    }Copy the code

So, finally the combination of the intent of the package name is com. The android. Packageinstaller, the action is android. The content. PM. Action. REQUEST_PERMISSIONS.





PNG application installer

This Action starts the application installer’s GrantPermissionsActivity for authorization





Listing. PNG

So, this box is popped up from GrantPermissionsActivity. Analysis done!