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

Commit 97e433aa 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 am: ffc90397

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

Change-Id: Iac9f2094b01aeb7f516a9ac7c0636801d75d570b
parents a9b41a8e ffc90397
Loading
Loading
Loading
Loading
+53 −22
Original line number Original line 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_COARSE;
import static com.android.server.location.CallerIdentity.PERMISSION_FINE;
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;
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.CallerIdentity.PermissionLevel;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
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.location.gnss.GnssManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.permission.PermissionManagerServiceInternal;


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


        private final UserInfoHelper mUserInfoHelper;
        private final LocationManagerService mService;
        private final LocationManagerService mService;


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


        @Override
        @Override
@@ -161,6 +166,29 @@ public class LocationManagerService extends ILocationManager.Stub {
                mService.onSystemThirdPartyAppsCanStart();
                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";
    public static final String TAG = "LocationManagerService";
@@ -232,7 +260,7 @@ public class LocationManagerService extends ILocationManager.Stub {
    @PowerManager.LocationPowerSaveMode
    @PowerManager.LocationPowerSaveMode
    private int mBatterySaverMode;
    private int mBatterySaverMode;


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


        mAppOpsHelper = new AppOpsHelper(mContext);
        mAppOpsHelper = new AppOpsHelper(mContext);
        mUserInfoHelper = new UserInfoHelper(mContext);
        mUserInfoHelper = userInfoHelper;
        mSettingsHelper = new SettingsHelper(mContext, mHandler);
        mSettingsHelper = new SettingsHelper(mContext, mHandler);
        mAppForegroundHelper = new AppForegroundHelper(mContext);
        mAppForegroundHelper = new AppForegroundHelper(mContext);
        mLocationUsageLogger = new LocationUsageLogger();
        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
            // 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.
            // users eventually anyways, but this takes care of it as early as possible.
            for (int userId: mUserInfoHelper.getCurrentUserIds()) {
            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) {
        switch (change) {
            case UserListener.USER_SWITCHED:
            case CURRENT_USER_CHANGED:
                if (D) {
                    Log.d(TAG, "user " + userId + " current status changed");
                }
                synchronized (mLock) {
                synchronized (mLock) {
                    for (LocationProviderManager manager : mProviderManagers) {
                    for (LocationProviderManager manager : mProviderManagers) {
                        manager.onEnabledChangedLocked(userId);
                        manager.onEnabledChangedLocked(userId);
                    }
                    }
                }
                }
                break;
                break;
            case UserListener.USER_STARTED:
            case USER_STARTED:
                if (D) {
                    Log.d(TAG, "user " + userId + " started");
                }
                synchronized (mLock) {
                synchronized (mLock) {
                    for (LocationProviderManager manager : mProviderManagers) {
                    for (LocationProviderManager manager : mProviderManagers) {
                        manager.onUserStarted(userId);
                        manager.onUserStarted(userId);
                    }
                    }
                }
                }
                break;
                break;
            case UserListener.USER_STOPPED:
            case USER_STOPPED:
                if (D) {
                    Log.d(TAG, "user " + userId + " stopped");
                }
                synchronized (mLock) {
                synchronized (mLock) {
                    for (LocationProviderManager manager : mProviderManagers) {
                    for (LocationProviderManager manager : mProviderManagers) {
                        manager.onUserStopped(userId);
                        manager.onUserStopped(userId);
@@ -957,10 +976,22 @@ public class LocationManagerService extends ILocationManager.Stub {
                pw.increaseIndent();
                pw.increaseIndent();


                // for now we only dump for the parent user
                // 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 location=" + mLastLocation.get(userId));
                        pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
                        pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
                        pw.println("enabled=" + isEnabled(userId));
                        pw.println("enabled=" + isEnabled(userId));
                        pw.decreaseIndent();
                    }
                }
            }
            }


            mProvider.dump(fd, pw, args);
            mProvider.dump(fd, pw, args);
+82 −131
Original line number Original line 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.D;
import static com.android.server.location.LocationManagerService.TAG;
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.IntDef;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.Binder;
import android.os.Build;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager;
import android.util.Log;
import android.util.Log;


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


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


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


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


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


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


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


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

    @UserIdInt private volatile int mCurrentUserId;

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


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

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


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


        mActivityManagerInternal = Objects.requireNonNull(
                LocalServices.getService(ActivityManagerInternal.class));
        mUserManager = mContext.getSystemService(UserManager.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.
     * 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);
        mListeners.add(listener);
    }
    }


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


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

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


        int oldUserId = mCurrentUserId;
        for (UserListener listener : mListeners) {
        mCurrentUserId = newUserId;
            listener.onUserChanged(userId, USER_STARTED);

        }
        onUserChanged(oldUserId, UserListener.USER_SWITCHED);
        onUserChanged(newUserId, UserListener.USER_SWITCHED);
    }
    }


    private void onUserStarted(@UserIdInt int userId) {
    protected void dispatchOnUserStopped(@UserIdInt int userId) {
        if (D) {
        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) {
        for (UserListener listener : mListeners) {
            listener.onUserChanged(userId, change);
            for (int userId : fromUserIds) {
                listener.onUserChanged(userId, CURRENT_USER_CHANGED);
            }
            }
        }
        }


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


    /**
    /**
     * Returns an array of current user ids. This will always include the current user, and will
     * 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() {
    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.
     * user.
     */
     */
    public boolean isCurrentUserId(@UserIdInt int userId) {
    public boolean isCurrentUserId(@UserIdInt int userId) {
        int currentUserId = mCurrentUserId;
        synchronized (this) {
        return userId == currentUserId || ArrayUtils.contains(
            if (mActivityManagerInternal == null) {
                getProfileUserIdsForParentUser(currentUserId), userId);
                return false;
            }
        }
        }


    @GuardedBy("this")
    private synchronized int[] getProfileUserIdsForParentUser(@UserIdInt int parentUserId) {
        if (parentUserId != mCachedParentUserId) {
        long identity = Binder.clearCallingIdentity();
        long identity = Binder.clearCallingIdentity();
        try {
        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
    private int[] getProfileIds(@UserIdInt int userId) {
                if (Build.IS_DEBUGGABLE) {
        synchronized (this) {
                    Preconditions.checkArgument(
            Preconditions.checkState(mUserManager != null);
                            mUserManager.getProfileParent(parentUserId) == null);
        }
        }


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


        return mCachedProfileUserIds;
    }

    /**
    /**
     * Dump info for debugging.
     * Dump info for debugging.
     */
     */
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        boolean systemRunning;
        int[] currentUserProfiles = getCurrentUserIds();
        synchronized (this) {
        pw.println("current users: " + Arrays.toString(currentUserProfiles));
            systemRunning = mUserManager != null;
        UserManager userManager = mContext.getSystemService(UserManager.class);
        }
        if (userManager != null) {

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

File changed.

Preview size limit exceeded, changes collapsed.