Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 267c50e7 authored by xiaobing.sun's avatar xiaobing.sun
Browse files

Synchronize mPermissions to void NullPointerException.

When we run mokey test on App permissions activity of a APK for example Contacts(Settings -> Apps & notifications ->See all ** apps -> Contacts ->Permissions),if we grant and revoke some permission frequently,NullPointerException may happen.

As granting runtime perimssion leads to writting new state of runtime permissions on disk via BackgroundThread. To write new state of runtime permissions, system will get the permissionData stored in mPermissions(assume that this permissionData is stored at the last location ).If we revoke this permison,permissionData will be removed from mPermissions on another thread. So in function getPermissionStatesInternal,mPermissions.valueAt(i) may return null by chance so that crash will happen. So we should synchronize mPermissions to void NullPointerException.

Bug:115697209

Test: Make services.jar,push it into phone and reboot.Run monkey test on App permissions activity and no NullPointerException happens.

Change-Id: I61151fa7df7a2c3830cff2eac9cc8284bd28c448
parent 0af8c5c7
Loading
Loading
Loading
Loading
+162 −111
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import com.android.internal.annotations.GuardedBy;

/**
 * This class encapsulates the permissions for a package or a shared user.
@@ -62,6 +63,9 @@ public final class PermissionsState {

    private static final int[] NO_GIDS = {};

    private final Object mLock = new Object();

    @GuardedBy("mLock")
    private ArrayMap<String, PermissionData> mPermissions;

    private int[] mGlobalGids = NO_GIDS;
@@ -96,6 +100,8 @@ public final class PermissionsState {
        if (other == this) {
            return;
        }

        synchronized (mLock) {
            if (mPermissions != null) {
                if (other.mPermissions == null) {
                    mPermissions = null;
@@ -114,6 +120,7 @@ public final class PermissionsState {
                    mPermissions.put(name, new PermissionData(permissionData));
                }
            }
        }

        mGlobalGids = NO_GIDS;
        if (other.mGlobalGids != NO_GIDS) {
@@ -153,6 +160,7 @@ public final class PermissionsState {
        }
        final PermissionsState other = (PermissionsState) obj;

        synchronized (mLock) {
            if (mPermissions == null) {
                if (other.mPermissions != null) {
                    return false;
@@ -160,6 +168,8 @@ public final class PermissionsState {
            } else if (!mPermissions.equals(other.mPermissions)) {
                return false;
            }
        }

        if (mPermissionReviewRequired == null) {
            if (other.mPermissionReviewRequired != null) {
                return false;
@@ -266,19 +276,23 @@ public final class PermissionsState {
    public boolean hasPermission(String name, int userId) {
        enforceValidUserId(userId);

        synchronized (mLock) {
            if (mPermissions == null) {
                return false;
            }

            PermissionData permissionData = mPermissions.get(name);

            return permissionData != null && permissionData.isGranted(userId);
        }

    }

    /**
     * Returns whether the state has any known request for the given permission name,
     * whether or not it has been granted.
     */
    public boolean hasRequestedPermission(ArraySet<String> names) {
        synchronized (mLock) {
            if (mPermissions == null) {
                return false;
            }
@@ -287,6 +301,8 @@ public final class PermissionsState {
                    return true;
                }
            }
        }

        return false;
    }

@@ -300,6 +316,7 @@ public final class PermissionsState {
    public Set<String> getPermissions(int userId) {
        enforceValidUserId(userId);

        synchronized (mLock) {
            if (mPermissions == null) {
                return Collections.emptySet();
            }
@@ -324,6 +341,7 @@ public final class PermissionsState {

            return permissions;
        }
    }

    /**
     * Gets the state for an install permission or null if no such.
@@ -399,14 +417,20 @@ public final class PermissionsState {

        final boolean mayChangeFlags = flagValues != 0 || flagMask != 0;

        synchronized (mLock) {
            if (mPermissions == null) {
                if (!mayChangeFlags) {
                    return false;
                }
                ensurePermissionData(permission);
            }
        }

        PermissionData permissionData = null;
        synchronized (mLock) {
            permissionData = mPermissions.get(permission.getName());
        }

        PermissionData permissionData = mPermissions.get(permission.getName());
        if (permissionData == null) {
            if (!mayChangeFlags) {
                return false;
@@ -439,6 +463,7 @@ public final class PermissionsState {
    }

    private boolean hasPermissionRequiringReview(int userId) {
        synchronized (mLock) {
            final int permissionCount = mPermissions.size();
            for (int i = 0; i < permissionCount; i++) {
                final PermissionData permission = mPermissions.valueAt(i);
@@ -447,6 +472,8 @@ public final class PermissionsState {
                    return true;
                }
            }
        }

        return false;
    }

@@ -454,6 +481,7 @@ public final class PermissionsState {
            int userId, int flagMask, int flagValues) {
        enforceValidUserId(userId);

        synchronized (mLock) {
            if (mPermissions == null) {
                return false;
            }
@@ -463,8 +491,10 @@ public final class PermissionsState {
                PermissionData permissionData = mPermissions.valueAt(i);
                changed |= permissionData.updateFlags(userId, flagMask, flagValues);
            }

            return changed;
        }
    }

    /**
     * Compute the Linux gids for a given device user from the permissions
@@ -479,6 +509,7 @@ public final class PermissionsState {

        int[] gids = mGlobalGids;

        synchronized (mLock) {
            if (mPermissions != null) {
                final int permissionCount = mPermissions.size();
                for (int i = 0; i < permissionCount; i++) {
@@ -493,6 +524,7 @@ public final class PermissionsState {
                    }
                }
            }
        }

        return gids;
    }
@@ -519,11 +551,16 @@ public final class PermissionsState {
     */
    public void reset() {
        mGlobalGids = NO_GIDS;

        synchronized (mLock) {
            mPermissions = null;
        }

        mPermissionReviewRequired = null;
    }

    private PermissionState getPermissionState(String name, int userId) {
        synchronized (mLock) {
            if (mPermissions == null) {
                return null;
            }
@@ -531,12 +568,15 @@ public final class PermissionsState {
            if (permissionData == null) {
                return null;
            }

            return permissionData.getPermissionState(userId);
        }
    }

    private List<PermissionState> getPermissionStatesInternal(int userId) {
        enforceValidUserId(userId);

        synchronized (mLock) {
            if (mPermissions == null) {
                return Collections.emptyList();
            }
@@ -555,6 +595,7 @@ public final class PermissionsState {

            return permissionStates;
        }
    }

    private int grantPermission(BasePermission permission, int userId) {
        if (hasPermission(permission.getName(), userId)) {
@@ -589,7 +630,10 @@ public final class PermissionsState {
        final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
        final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;

        PermissionData permissionData = mPermissions.get(permName);
        PermissionData permissionData = null;
        synchronized (mLock) {
            permissionData = mPermissions.get(permName);
        }

        if (!permissionData.revoke(userId)) {
            return PERMISSION_OPERATION_FAILURE;
@@ -627,6 +671,8 @@ public final class PermissionsState {

    private PermissionData ensurePermissionData(BasePermission permission) {
        final String permName = permission.getName();

        synchronized (mLock) {
            if (mPermissions == null) {
                mPermissions = new ArrayMap<>();
            }
@@ -638,7 +684,10 @@ public final class PermissionsState {
            return permissionData;
        }

    }

    private void ensureNoPermissionData(String name) {
        synchronized (mLock) {
            if (mPermissions == null) {
                return;
            }
@@ -648,6 +697,8 @@ public final class PermissionsState {
            }
        }

    }

    private static final class PermissionData {
        private final BasePermission mPerm;
        private SparseArray<PermissionState> mUserStates = new SparseArray<>();