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

Commit 94a52182 authored by Automerger Merge Worker's avatar Automerger Merge Worker Committed by Android (Google) Code Review
Browse files

Merge changes from topic "am-78a99633f9cc44cd9ea44ad541faff01" into rvc-qpr-dev-plus-aosp

* changes:
  Merge "DO NOT MERGE Fix work profile change race condition in LMS" into rvc-dev am: 48e0bab2 am: 40ca7392 am: 51a81f6f
  DO NOT MERGE Fix work profile change race condition in LMS am: 9b0b32bd am: 2b503451 am: 5bd268d4
parents afc55e67 70dcfa88
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.