• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.location;
18 
19 import static android.os.UserManager.DISALLOW_SHARE_LOCATION;
20 
21 import static com.android.server.location.LocationManagerService.D;
22 import static com.android.server.location.LocationManagerService.TAG;
23 import static com.android.server.location.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
24 import static com.android.server.location.UserInfoHelper.UserListener.USER_STARTED;
25 import static com.android.server.location.UserInfoHelper.UserListener.USER_STOPPED;
26 
27 import android.annotation.CallSuper;
28 import android.annotation.IntDef;
29 import android.annotation.Nullable;
30 import android.annotation.UserIdInt;
31 import android.app.ActivityManagerInternal;
32 import android.content.Context;
33 import android.os.Binder;
34 import android.os.UserHandle;
35 import android.os.UserManager;
36 import android.util.Log;
37 
38 import com.android.internal.annotations.GuardedBy;
39 import com.android.internal.util.Preconditions;
40 import com.android.server.LocalServices;
41 
42 import java.io.FileDescriptor;
43 import java.io.PrintWriter;
44 import java.lang.annotation.Retention;
45 import java.lang.annotation.RetentionPolicy;
46 import java.util.Arrays;
47 import java.util.Objects;
48 import java.util.concurrent.CopyOnWriteArrayList;
49 
50 /**
51  * Provides accessors and listeners for all user info.
52  */
53 public abstract class UserInfoHelper {
54 
55     /**
56      * Listener for current user changes.
57      */
58     public interface UserListener {
59 
60         int CURRENT_USER_CHANGED = 1;
61         int USER_STARTED = 2;
62         int USER_STOPPED = 3;
63 
64         @IntDef({CURRENT_USER_CHANGED, USER_STARTED, USER_STOPPED})
65         @Retention(RetentionPolicy.SOURCE)
66         @interface UserChange {}
67 
68         /**
69          * Called when something has changed about the given user.
70          */
onUserChanged(@serIdInt int userId, @UserChange int change)71         void onUserChanged(@UserIdInt int userId, @UserChange int change);
72     }
73 
74     private final Context mContext;
75     private final CopyOnWriteArrayList<UserListener> mListeners;
76 
77     @GuardedBy("this")
78     @Nullable private ActivityManagerInternal mActivityManagerInternal;
79     @GuardedBy("this")
80     @Nullable private UserManager mUserManager;
81 
UserInfoHelper(Context context)82     public UserInfoHelper(Context context) {
83         mContext = context;
84         mListeners = new CopyOnWriteArrayList<>();
85     }
86 
87     /** Called when system is ready. */
88     @CallSuper
onSystemReady()89     public synchronized void onSystemReady() {
90         if (mActivityManagerInternal != null) {
91             return;
92         }
93 
94         mActivityManagerInternal = Objects.requireNonNull(
95                 LocalServices.getService(ActivityManagerInternal.class));
96         mUserManager = mContext.getSystemService(UserManager.class);
97     }
98 
99     /**
100      * Adds a listener for user changed events. Callbacks occur on an unspecified thread.
101      */
addListener(UserListener listener)102     public final void addListener(UserListener listener) {
103         mListeners.add(listener);
104     }
105 
106     /**
107      * Removes a listener for user changed events.
108      */
removeListener(UserListener listener)109     public final void removeListener(UserListener listener) {
110         mListeners.remove(listener);
111     }
112 
dispatchOnUserStarted(@serIdInt int userId)113     protected void dispatchOnUserStarted(@UserIdInt int userId) {
114         if (D) {
115             Log.d(TAG, "u" + userId + " started");
116         }
117 
118         for (UserListener listener : mListeners) {
119             listener.onUserChanged(userId, USER_STARTED);
120         }
121     }
122 
dispatchOnUserStopped(@serIdInt int userId)123     protected void dispatchOnUserStopped(@UserIdInt int userId) {
124         if (D) {
125             Log.d(TAG, "u" + userId + " stopped");
126         }
127 
128         for (UserListener listener : mListeners) {
129             listener.onUserChanged(userId, USER_STOPPED);
130         }
131     }
132 
dispatchOnCurrentUserChanged(@serIdInt int fromUserId, @UserIdInt int toUserId)133     protected void dispatchOnCurrentUserChanged(@UserIdInt int fromUserId,
134             @UserIdInt int toUserId) {
135         int[] fromUserIds = getProfileIds(fromUserId);
136         int[] toUserIds = getProfileIds(toUserId);
137         if (D) {
138             Log.d(TAG, "current user changed from u" + Arrays.toString(fromUserIds) + " to u"
139                     + Arrays.toString(toUserIds));
140         }
141 
142         for (UserListener listener : mListeners) {
143             for (int userId : fromUserIds) {
144                 listener.onUserChanged(userId, CURRENT_USER_CHANGED);
145             }
146         }
147 
148         for (UserListener listener : mListeners) {
149             for (int userId : toUserIds) {
150                 listener.onUserChanged(userId, CURRENT_USER_CHANGED);
151             }
152         }
153     }
154 
155     /**
156      * Returns an array of current user ids. This will always include the current user, and will
157      * also include any profiles of the current user. The caller must never mutate the returned
158      * array.
159      */
getCurrentUserIds()160     public int[] getCurrentUserIds() {
161         synchronized (this) {
162             if (mActivityManagerInternal == null) {
163                 return new int[] {};
164             }
165         }
166 
167         long identity = Binder.clearCallingIdentity();
168         try {
169             return mActivityManagerInternal.getCurrentProfileIds();
170         } finally {
171             Binder.restoreCallingIdentity(identity);
172         }
173     }
174 
175     /**
176      * Returns true if the given user id is either the current user or a profile of the current
177      * user.
178      */
isCurrentUserId(@serIdInt int userId)179     public boolean isCurrentUserId(@UserIdInt int userId) {
180         synchronized (this) {
181             if (mActivityManagerInternal == null) {
182                 return false;
183             }
184         }
185 
186         long identity = Binder.clearCallingIdentity();
187         try {
188             return mActivityManagerInternal.isCurrentProfile(userId);
189         } finally {
190             Binder.restoreCallingIdentity(identity);
191         }
192     }
193 
getProfileIds(@serIdInt int userId)194     private int[] getProfileIds(@UserIdInt int userId) {
195         synchronized (this) {
196             Preconditions.checkState(mUserManager != null);
197         }
198 
199         long identity = Binder.clearCallingIdentity();
200         try {
201             return mUserManager.getEnabledProfileIds(userId);
202         } finally {
203             Binder.restoreCallingIdentity(identity);
204         }
205     }
206 
207     /**
208      * Dump info for debugging.
209      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)210     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
211         int[] currentUserProfiles = getCurrentUserIds();
212         pw.println("current users: " + Arrays.toString(currentUserProfiles));
213         UserManager userManager = mContext.getSystemService(UserManager.class);
214         if (userManager != null) {
215             for (int userId : currentUserProfiles) {
216                 if (userManager.hasUserRestrictionForUser(DISALLOW_SHARE_LOCATION,
217                         UserHandle.of(userId))) {
218                     pw.println("  u" + userId + " restricted");
219                 }
220             }
221         }
222     }
223 }
224