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

Commit ffc90397 authored by Soonil Nagarkar's avatar Soonil Nagarkar Committed by Automerger Merge Worker
Browse files

DO NOT MERGE Fix work profile change race condition in LMS am: 9b0b32bd

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11707507

Change-Id: Ibb242c0300df6ed26313e90e10e2cdac0999d4e1
parents e12aa6fa 9b0b32bd
Loading
Loading
Loading
Loading
+53 −22
Original line number Diff line number Diff line
@@ -28,6 +28,9 @@ import static android.os.PowerManager.locationPowerSaveModeToString;

import static com.android.server.location.CallerIdentity.PERMISSION_COARSE;
import static com.android.server.location.CallerIdentity.PERMISSION_FINE;
import static com.android.server.location.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
import static com.android.server.location.UserInfoHelper.UserListener.USER_STARTED;
import static com.android.server.location.UserInfoHelper.UserListener.USER_STOPPED;

import static java.util.concurrent.TimeUnit.NANOSECONDS;

@@ -101,7 +104,7 @@ import com.android.server.location.AbstractLocationProvider.State;
import com.android.server.location.CallerIdentity.PermissionLevel;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
import com.android.server.location.UserInfoHelper.UserListener;
import com.android.server.location.UserInfoHelper.UserListener.UserChange;
import com.android.server.location.gnss.GnssManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;

@@ -132,11 +135,13 @@ public class LocationManagerService extends ILocationManager.Stub {
     */
    public static class Lifecycle extends SystemService {

        private final UserInfoHelper mUserInfoHelper;
        private final LocationManagerService mService;

        public Lifecycle(Context context) {
            super(context);
            mService = new LocationManagerService(context);
            mUserInfoHelper = new SystemUserInfoHelper(context);
            mService = new LocationManagerService(context, mUserInfoHelper);
        }

        @Override
@@ -161,6 +166,29 @@ public class LocationManagerService extends ILocationManager.Stub {
                mService.onSystemThirdPartyAppsCanStart();
            }
        }

        @Override
        public void onUserStarting(TargetUser user) {
            mUserInfoHelper.dispatchOnUserStarted(user.getUserIdentifier());
        }

        @Override
        public void onUserSwitching(TargetUser from, TargetUser to) {
            mUserInfoHelper.dispatchOnCurrentUserChanged(from.getUserIdentifier(),
                    to.getUserIdentifier());
        }

        @Override
        public void onUserStopped(TargetUser user) {
            mUserInfoHelper.dispatchOnUserStopped(user.getUserIdentifier());
        }

        private static class SystemUserInfoHelper extends UserInfoHelper {

            SystemUserInfoHelper(Context context) {
                super(context);
            }
        }
    }

    public static final String TAG = "LocationManagerService";
@@ -232,7 +260,7 @@ public class LocationManagerService extends ILocationManager.Stub {
    @PowerManager.LocationPowerSaveMode
    private int mBatterySaverMode;

    private LocationManagerService(Context context) {
    private LocationManagerService(Context context, UserInfoHelper userInfoHelper) {
        mContext = context.createAttributionContext(ATTRIBUTION_TAG);
        mHandler = FgThread.getHandler();
        mLocalService = new LocalService();
@@ -240,7 +268,7 @@ public class LocationManagerService extends ILocationManager.Stub {
        LocalServices.addService(LocationManagerInternal.class, mLocalService);

        mAppOpsHelper = new AppOpsHelper(mContext);
        mUserInfoHelper = new UserInfoHelper(mContext);
        mUserInfoHelper = userInfoHelper;
        mSettingsHelper = new SettingsHelper(mContext, mHandler);
        mAppForegroundHelper = new AppForegroundHelper(mContext);
        mLocationUsageLogger = new LocationUsageLogger();
@@ -342,7 +370,7 @@ public class LocationManagerService extends ILocationManager.Stub {
            // initialize the current users. we would get the user started notifications for these
            // users eventually anyways, but this takes care of it as early as possible.
            for (int userId: mUserInfoHelper.getCurrentUserIds()) {
                onUserChanged(userId, UserListener.USER_STARTED);
                onUserChanged(userId, USER_STARTED);
            }
        }
    }
@@ -596,32 +624,23 @@ public class LocationManagerService extends ILocationManager.Stub {
        }
    }

    private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
    private void onUserChanged(@UserIdInt int userId, @UserChange int change) {
        switch (change) {
            case UserListener.USER_SWITCHED:
                if (D) {
                    Log.d(TAG, "user " + userId + " current status changed");
                }
            case CURRENT_USER_CHANGED:
                synchronized (mLock) {
                    for (LocationProviderManager manager : mProviderManagers) {
                        manager.onEnabledChangedLocked(userId);
                    }
                }
                break;
            case UserListener.USER_STARTED:
                if (D) {
                    Log.d(TAG, "user " + userId + " started");
                }
            case USER_STARTED:
                synchronized (mLock) {
                    for (LocationProviderManager manager : mProviderManagers) {
                        manager.onUserStarted(userId);
                    }
                }
                break;
            case UserListener.USER_STOPPED:
                if (D) {
                    Log.d(TAG, "user " + userId + " stopped");
                }
            case USER_STOPPED:
                synchronized (mLock) {
                    for (LocationProviderManager manager : mProviderManagers) {
                        manager.onUserStopped(userId);
@@ -957,10 +976,22 @@ public class LocationManagerService extends ILocationManager.Stub {
                pw.increaseIndent();

                // for now we only dump for the parent user
                int userId = mUserInfoHelper.getCurrentUserIds()[0];
                int[] userIds = mUserInfoHelper.getCurrentUserIds();
                if (userIds.length == 1) {
                    int userId = userIds[0];
                    pw.println("last location=" + mLastLocation.get(userId));
                    pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
                    pw.println("enabled=" + isEnabled(userId));
                } else {
                    for (int userId : userIds) {
                        pw.println("user " + userId + ":");
                        pw.increaseIndent();
                        pw.println("last location=" + mLastLocation.get(userId));
                        pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
                        pw.println("enabled=" + isEnabled(userId));
                        pw.decreaseIndent();
                    }
                }
            }

            mProvider.dump(fd, pw, args);
+82 −131
Original line number Diff line number Diff line
@@ -20,48 +20,48 @@ import static android.os.UserManager.DISALLOW_SHARE_LOCATION;

import static com.android.server.location.LocationManagerService.D;
import static com.android.server.location.LocationManagerService.TAG;
import static com.android.server.location.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
import static com.android.server.location.UserInfoHelper.UserListener.USER_STARTED;
import static com.android.server.location.UserInfoHelper.UserListener.USER_STOPPED;

import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.app.ActivityManagerInternal;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
import com.android.server.LocalServices;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Provides accessors and listeners for all user info.
 */
public class UserInfoHelper {
public abstract class UserInfoHelper {

    /**
     * Listener for current user changes.
     */
    public interface UserListener {

        int USER_SWITCHED = 1;
        int CURRENT_USER_CHANGED = 1;
        int USER_STARTED = 2;
        int USER_STOPPED = 3;

        @IntDef({USER_SWITCHED, USER_STARTED, USER_STOPPED})
        @IntDef({CURRENT_USER_CHANGED, USER_STARTED, USER_STOPPED})
        @Retention(RetentionPolicy.SOURCE)
        @interface UserChange {}

@@ -75,143 +75,101 @@ public class UserInfoHelper {
    private final CopyOnWriteArrayList<UserListener> mListeners;

    @GuardedBy("this")
    @Nullable private UserManager mUserManager;

    @UserIdInt private volatile int mCurrentUserId;

    @GuardedBy("this")
    @UserIdInt private int mCachedParentUserId;
    @Nullable private ActivityManagerInternal mActivityManagerInternal;
    @GuardedBy("this")
    private int[] mCachedProfileUserIds;
    @Nullable private UserManager mUserManager;

    public UserInfoHelper(Context context) {
        mContext = context;
        mListeners = new CopyOnWriteArrayList<>();

        mCurrentUserId = UserHandle.USER_NULL;
        mCachedParentUserId = UserHandle.USER_NULL;
        mCachedProfileUserIds = new int[]{UserHandle.USER_NULL};
    }

    /** Called when system is ready. */
    @CallSuper
    public synchronized void onSystemReady() {
        if (mUserManager != null) {
        if (mActivityManagerInternal != null) {
            return;
        }

        mActivityManagerInternal = Objects.requireNonNull(
                LocalServices.getService(ActivityManagerInternal.class));
        mUserManager = mContext.getSystemService(UserManager.class);

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
        intentFilter.addAction(Intent.ACTION_USER_STARTED);
        intentFilter.addAction(Intent.ACTION_USER_STOPPED);
        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);

        mContext.registerReceiverAsUser(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (action == null) {
                    return;
                }
                int userId;
                switch (action) {
                    case Intent.ACTION_USER_SWITCHED:
                        userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                        if (userId != UserHandle.USER_NULL) {
                            onCurrentUserChanged(userId);
                        }
                        break;
                    case Intent.ACTION_USER_STARTED:
                        userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                        if (userId != UserHandle.USER_NULL) {
                            onUserStarted(userId);
                        }
                        break;
                    case Intent.ACTION_USER_STOPPED:
                        userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                        if (userId != UserHandle.USER_NULL) {
                            onUserStopped(userId);
                        }
                        break;
                    case Intent.ACTION_MANAGED_PROFILE_ADDED:
                    case Intent.ACTION_MANAGED_PROFILE_REMOVED:
                        onUserProfilesChanged();
                        break;
                }
            }
        }, UserHandle.ALL, intentFilter, null, FgThread.getHandler());

        mCurrentUserId = ActivityManager.getCurrentUser();
    }

    /**
     * Adds a listener for user changed events. Callbacks occur on an unspecified thread.
     */
    public void addListener(UserListener listener) {
    public final void addListener(UserListener listener) {
        mListeners.add(listener);
    }

    /**
     * Removes a listener for user changed events.
     */
    public void removeListener(UserListener listener) {
    public final void removeListener(UserListener listener) {
        mListeners.remove(listener);
    }

    private void onCurrentUserChanged(@UserIdInt int newUserId) {
        if (newUserId == mCurrentUserId) {
            return;
        }

    protected void dispatchOnUserStarted(@UserIdInt int userId) {
        if (D) {
            Log.d(TAG, "current user switched from u" + mCurrentUserId + " to u" + newUserId);
            Log.d(TAG, "u" + userId + " started");
        }

        int oldUserId = mCurrentUserId;
        mCurrentUserId = newUserId;

        onUserChanged(oldUserId, UserListener.USER_SWITCHED);
        onUserChanged(newUserId, UserListener.USER_SWITCHED);
        for (UserListener listener : mListeners) {
            listener.onUserChanged(userId, USER_STARTED);
        }
    }

    private void onUserStarted(@UserIdInt int userId) {
    protected void dispatchOnUserStopped(@UserIdInt int userId) {
        if (D) {
            Log.d(TAG, "u" + userId + " started");
            Log.d(TAG, "u" + userId + " stopped");
        }

        onUserChanged(userId, UserListener.USER_STARTED);
        for (UserListener listener : mListeners) {
            listener.onUserChanged(userId, USER_STOPPED);
        }

    private void onUserStopped(@UserIdInt int userId) {
        if (D) {
            Log.d(TAG, "u" + userId + " stopped");
    }

        onUserChanged(userId, UserListener.USER_STOPPED);
    protected void dispatchOnCurrentUserChanged(@UserIdInt int fromUserId,
            @UserIdInt int toUserId) {
        int[] fromUserIds = getProfileIds(fromUserId);
        int[] toUserIds = getProfileIds(toUserId);
        if (D) {
            Log.d(TAG, "current user changed from u" + Arrays.toString(fromUserIds) + " to u"
                    + Arrays.toString(toUserIds));
        }

    private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
        for (UserListener listener : mListeners) {
            listener.onUserChanged(userId, change);
            for (int userId : fromUserIds) {
                listener.onUserChanged(userId, CURRENT_USER_CHANGED);
            }
        }

    private synchronized void onUserProfilesChanged() {
        // this intent is only sent to the current user
        if (mCachedParentUserId == mCurrentUserId) {
            mCachedParentUserId = UserHandle.USER_NULL;
            mCachedProfileUserIds = new int[]{UserHandle.USER_NULL};
        for (UserListener listener : mListeners) {
            for (int userId : toUserIds) {
                listener.onUserChanged(userId, CURRENT_USER_CHANGED);
            }
        }
    }

    /**
     * Returns an array of current user ids. This will always include the current user, and will
     * also include any profiles of the current user.
     * also include any profiles of the current user. The caller must never mutate the returned
     * array.
     */
    public int[] getCurrentUserIds() {
        return getProfileUserIdsForParentUser(mCurrentUserId);
        synchronized (this) {
            if (mActivityManagerInternal == null) {
                return new int[] {};
            }
        }

        long identity = Binder.clearCallingIdentity();
        try {
            return mActivityManagerInternal.getCurrentProfileIds();
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    /**
@@ -219,54 +177,47 @@ public class UserInfoHelper {
     * user.
     */
    public boolean isCurrentUserId(@UserIdInt int userId) {
        int currentUserId = mCurrentUserId;
        return userId == currentUserId || ArrayUtils.contains(
                getProfileUserIdsForParentUser(currentUserId), userId);
        synchronized (this) {
            if (mActivityManagerInternal == null) {
                return false;
            }
        }

    @GuardedBy("this")
    private synchronized int[] getProfileUserIdsForParentUser(@UserIdInt int parentUserId) {
        if (parentUserId != mCachedParentUserId) {
        long identity = Binder.clearCallingIdentity();
        try {
                Preconditions.checkState(mUserManager != null);
            return mActivityManagerInternal.isCurrentProfile(userId);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

                // more expensive check - check that argument really is a parent user id
                if (Build.IS_DEBUGGABLE) {
                    Preconditions.checkArgument(
                            mUserManager.getProfileParent(parentUserId) == null);
    private int[] getProfileIds(@UserIdInt int userId) {
        synchronized (this) {
            Preconditions.checkState(mUserManager != null);
        }

                mCachedParentUserId = parentUserId;
                mCachedProfileUserIds = mUserManager.getProfileIdsWithDisabled(parentUserId);
        long identity = Binder.clearCallingIdentity();
        try {
            return mUserManager.getEnabledProfileIds(userId);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

        return mCachedProfileUserIds;
    }

    /**
     * Dump info for debugging.
     */
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        boolean systemRunning;
        synchronized (this) {
            systemRunning = mUserManager != null;
        }

        if (systemRunning) {
            int[] currentUserIds = getProfileUserIdsForParentUser(mCurrentUserId);
            pw.println("current users: " + Arrays.toString(currentUserIds));
            for (int userId : currentUserIds) {
                if (mUserManager.hasUserRestrictionForUser(DISALLOW_SHARE_LOCATION,
        int[] currentUserProfiles = getCurrentUserIds();
        pw.println("current users: " + Arrays.toString(currentUserProfiles));
        UserManager userManager = mContext.getSystemService(UserManager.class);
        if (userManager != null) {
            for (int userId : currentUserProfiles) {
                if (userManager.hasUserRestrictionForUser(DISALLOW_SHARE_LOCATION,
                        UserHandle.of(userId))) {
                    pw.println("  u" + userId + " restricted");
                }
            }
        } else {
            pw.println("current user: " + mCurrentUserId);
        }
    }
}
+52 −93

File changed.

Preview size limit exceeded, changes collapsed.