Skip to content

Commit 12631ec

Browse files
Dianne HackbornAndroid (Google) Code Review
authored andcommitted
Merge "Start implementing concept of "running" users." into jb-mr1-dev
2 parents ffc45b7 + 80a4af2 commit 12631ec

File tree

16 files changed

+536
-104
lines changed

16 files changed

+536
-104
lines changed

Android.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ LOCAL_SRC_FILES += \
7474
core/java/android/app/ISearchManager.aidl \
7575
core/java/android/app/ISearchManagerCallback.aidl \
7676
core/java/android/app/IServiceConnection.aidl \
77+
core/java/android/app/IStopUserCallback.aidl \
7778
core/java/android/app/IThumbnailReceiver.aidl \
7879
core/java/android/app/IThumbnailRetriever.aidl \
7980
core/java/android/app/ITransientNotification.aidl \

cmds/am/src/com/android/commands/am/Am.java

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import android.content.pm.IPackageManager;
3232
import android.content.pm.ResolveInfo;
3333
import android.net.Uri;
34-
import android.os.Binder;
3534
import android.os.Bundle;
3635
import android.os.ParcelFileDescriptor;
3736
import android.os.RemoteException;
@@ -141,6 +140,8 @@ private void run(String[] args) throws Exception {
141140
runToUri(true);
142141
} else if (op.equals("switch-user")) {
143142
runSwitchUser();
143+
} else if (op.equals("stop-user")) {
144+
runStopUser();
144145
} else {
145146
throw new IllegalArgumentException("Unknown command: " + op);
146147
}
@@ -323,7 +324,6 @@ private Intent makeIntent() throws URISyntaxException {
323324
mUserId = Integer.parseInt(nextArgRequired());
324325
} else {
325326
System.err.println("Error: Unknown option: " + opt);
326-
showUsage();
327327
return null;
328328
}
329329
}
@@ -594,7 +594,6 @@ private void runInstrument() throws Exception {
594594
no_window_animation = true;
595595
} else {
596596
System.err.println("Error: Unknown option: " + opt);
597-
showUsage();
598597
return;
599598
}
600599
}
@@ -738,7 +737,6 @@ private void runSetDebugApp() throws Exception {
738737
persistent = true;
739738
} else {
740739
System.err.println("Error: Unknown option: " + opt);
741-
showUsage();
742740
return;
743741
}
744742
}
@@ -752,13 +750,27 @@ private void runClearDebugApp() throws Exception {
752750
}
753751

754752
private void runSwitchUser() throws Exception {
755-
if (android.os.Process.myUid() != 0) {
756-
throw new RuntimeException("switchuser can only be run as root");
757-
}
758753
String user = nextArgRequired();
759754
mAm.switchUser(Integer.parseInt(user));
760755
}
761756

757+
private void runStopUser() throws Exception {
758+
String user = nextArgRequired();
759+
int res = mAm.stopUser(Integer.parseInt(user), null);
760+
if (res != ActivityManager.USER_OP_SUCCESS) {
761+
String txt = "";
762+
switch (res) {
763+
case ActivityManager.USER_OP_IS_CURRENT:
764+
txt = " (Can't stop current user)";
765+
break;
766+
case ActivityManager.USER_OP_UNKNOWN_USER:
767+
txt = " (Unknown user " + user + ")";
768+
break;
769+
}
770+
System.err.println("Switch failed: " + res + txt);
771+
}
772+
}
773+
762774
class MyActivityController extends IActivityController.Stub {
763775
final String mGdbPort;
764776

@@ -1047,7 +1059,6 @@ private void runMonitor() throws Exception {
10471059
gdbPort = nextArgRequired();
10481060
} else {
10491061
System.err.println("Error: Unknown option: " + opt);
1050-
showUsage();
10511062
return;
10521063
}
10531064
}
@@ -1065,7 +1076,6 @@ private void runScreenCompat() throws Exception {
10651076
enabled = false;
10661077
} else {
10671078
System.err.println("Error: enabled mode must be 'on' or 'off' at " + mode);
1068-
showUsage();
10691079
return;
10701080
}
10711081

@@ -1090,7 +1100,6 @@ private void runDisplaySize() throws Exception {
10901100
int div = size.indexOf('x');
10911101
if (div <= 0 || div >= (size.length()-1)) {
10921102
System.err.println("Error: bad size " + size);
1093-
showUsage();
10941103
return;
10951104
}
10961105
String mstr = size.substring(0, div);
@@ -1100,7 +1109,6 @@ private void runDisplaySize() throws Exception {
11001109
n = Integer.parseInt(nstr);
11011110
} catch (NumberFormatException e) {
11021111
System.err.println("Error: bad number " + e);
1103-
showUsage();
11041112
return;
11051113
}
11061114
}
@@ -1139,12 +1147,10 @@ private void runDisplayDensity() throws Exception {
11391147
density = Integer.parseInt(densityStr);
11401148
} catch (NumberFormatException e) {
11411149
System.err.println("Error: bad number " + e);
1142-
showUsage();
11431150
return;
11441151
}
11451152
if (density < 72) {
11461153
System.err.println("Error: density must be >= 72");
1147-
showUsage();
11481154
return;
11491155
}
11501156
}
@@ -1345,6 +1351,7 @@ private static void showUsage() {
13451351
" am to-uri [INTENT]\n" +
13461352
" am to-intent-uri [INTENT]\n" +
13471353
" am switch-user <USER_ID>\n" +
1354+
" am stop-user <USER_ID>\n" +
13481355
"\n" +
13491356
"am start: start an Activity. Options are:\n" +
13501357
" -D: enable debugging\n" +
@@ -1403,6 +1410,12 @@ private static void showUsage() {
14031410
"\n" +
14041411
"am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
14051412
"\n" +
1413+
"am switch-user: switch to put USER_ID in the foreground, starting" +
1414+
" execution of that user if it is currently stopped.\n" +
1415+
"\n" +
1416+
"am stop-user: stop execution of USER_ID, not allowing it to run any" +
1417+
" code until a later explicit switch to it.\n" +
1418+
"\n" +
14061419
"<INTENT> specifications include these flags and arguments:\n" +
14071420
" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
14081421
" [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +

core/java/android/app/ActivityManager.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,15 @@ public class ActivityManager {
211211
*/
212212
public static final int INTENT_SENDER_SERVICE = 4;
213213

214+
/** @hide User operation call: success! */
215+
public static final int USER_OP_SUCCESS = 0;
216+
217+
/** @hide User operation call: given user id is not known. */
218+
public static final int USER_OP_UNKNOWN_USER = -1;
219+
220+
/** @hide User operation call: given user id is the current user, can't be stopped. */
221+
public static final int USER_OP_IS_CURRENT = -2;
222+
214223
/*package*/ ActivityManager(Context context, Handler handler) {
215224
mContext = context;
216225
mHandler = handler;

core/java/android/app/ActivityManagerNative.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,17 @@ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
15701570
return true;
15711571
}
15721572

1573+
case STOP_USER_TRANSACTION: {
1574+
data.enforceInterface(IActivityManager.descriptor);
1575+
int userid = data.readInt();
1576+
IStopUserCallback callback = IStopUserCallback.Stub.asInterface(
1577+
data.readStrongBinder());
1578+
int result = stopUser(userid, callback);
1579+
reply.writeNoException();
1580+
reply.writeInt(result);
1581+
return true;
1582+
}
1583+
15731584
case GET_CURRENT_USER_TRANSACTION: {
15741585
data.enforceInterface(IActivityManager.descriptor);
15751586
UserInfo userInfo = getCurrentUser();
@@ -3756,11 +3767,25 @@ public boolean switchUser(int userid) throws RemoteException {
37563767
return result;
37573768
}
37583769

3770+
public int stopUser(int userid, IStopUserCallback callback) throws RemoteException {
3771+
Parcel data = Parcel.obtain();
3772+
Parcel reply = Parcel.obtain();
3773+
data.writeInterfaceToken(IActivityManager.descriptor);
3774+
data.writeInt(userid);
3775+
data.writeStrongInterface(callback);
3776+
mRemote.transact(STOP_USER_TRANSACTION, data, reply, 0);
3777+
reply.readException();
3778+
int result = reply.readInt();
3779+
reply.recycle();
3780+
data.recycle();
3781+
return result;
3782+
}
3783+
37593784
public UserInfo getCurrentUser() throws RemoteException {
37603785
Parcel data = Parcel.obtain();
37613786
Parcel reply = Parcel.obtain();
37623787
data.writeInterfaceToken(IActivityManager.descriptor);
3763-
mRemote.transact(SWITCH_USER_TRANSACTION, data, reply, 0);
3788+
mRemote.transact(GET_CURRENT_USER_TRANSACTION, data, reply, 0);
37643789
reply.readException();
37653790
UserInfo userInfo = UserInfo.CREATOR.createFromParcel(reply);
37663791
reply.recycle();

core/java/android/app/IActivityManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ public void setPackageAskScreenCompat(String packageName, boolean ask)
331331

332332
// Multi-user APIs
333333
public boolean switchUser(int userid) throws RemoteException;
334+
public int stopUser(int userid, IStopUserCallback callback) throws RemoteException;
334335
public UserInfo getCurrentUser() throws RemoteException;
335336

336337
public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException;
@@ -611,4 +612,5 @@ private WaitResult(Parcel source) {
611612
int UNSTABLE_PROVIDER_DIED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+150;
612613
int IS_INTENT_SENDER_AN_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+151;
613614
int START_ACTIVITY_AS_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+152;
615+
int STOP_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+153;
614616
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
** Copyright 2012, 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 android.app;
18+
19+
/**
20+
* Callback to find out when we have finished stopping a user.
21+
* {@hide}
22+
*/
23+
interface IStopUserCallback
24+
{
25+
void userStopped(int userId);
26+
void userStopAborted(int userId);
27+
}

core/java/android/content/Intent.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import android.content.res.Resources;
2828
import android.content.res.TypedArray;
2929
import android.graphics.Rect;
30-
import android.media.RemoteControlClient;
3130
import android.net.Uri;
3231
import android.os.Bundle;
3332
import android.os.IBinder;
@@ -2286,6 +2285,15 @@ public static Intent createChooser(Intent target, CharSequence title) {
22862285
public static final String ACTION_USER_ADDED =
22872286
"android.intent.action.USER_ADDED";
22882287

2288+
/**
2289+
* Broadcast sent to the system when a user is stopped. Carries an extra EXTRA_USER_HANDLE that has
2290+
* the userHandle of the user. This is similar to {@link #ACTION_PACKAGE_RESTARTED},
2291+
* but for an entire user instead of a specific package.
2292+
* @hide
2293+
*/
2294+
public static final String ACTION_USER_STOPPED =
2295+
"android.intent.action.USER_STOPPED";
2296+
22892297
/**
22902298
* Broadcast sent to the system when a user is removed. Carries an extra EXTRA_USER_HANDLE that has
22912299
* the userHandle of the user.

core/java/com/android/internal/content/PackageMonitor.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
4949
sPackageFilt.addAction(Intent.ACTION_UID_REMOVED);
5050
sPackageFilt.addDataScheme("package");
5151
sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
52+
sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
5253
sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
5354
sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
5455
}
@@ -136,6 +137,9 @@ public void onPackageChanged(String packageName, int uid, String[] components) {
136137
public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
137138
return false;
138139
}
140+
141+
public void onHandleUserStop(Intent intent, int userHandle) {
142+
}
139143

140144
public void onUidRemoved(int uid) {
141145
}
@@ -307,6 +311,10 @@ public void onReceive(Context context, Intent intent) {
307311
intent.getIntExtra(Intent.EXTRA_UID, 0), true);
308312
} else if (Intent.ACTION_UID_REMOVED.equals(action)) {
309313
onUidRemoved(intent.getIntExtra(Intent.EXTRA_UID, 0));
314+
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
315+
if (intent.hasExtra(Intent.EXTRA_USER_HANDLE)) {
316+
onHandleUserStop(intent, intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
317+
}
310318
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
311319
String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
312320
mAppearingPackages = pkgList;

core/res/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<protected-broadcast android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" />
6363
<protected-broadcast android:name="android.intent.action.USER_ADDED" />
6464
<protected-broadcast android:name="android.intent.action.USER_REMOVED" />
65+
<protected-broadcast android:name="android.intent.action.USER_STOPPED" />
6566
<protected-broadcast android:name="android.intent.action.USER_SWITCHED" />
6667

6768
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />

services/java/com/android/server/AlarmManagerService.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import android.os.PowerManager;
3535
import android.os.SystemClock;
3636
import android.os.SystemProperties;
37+
import android.os.UserHandle;
3738
import android.os.WorkSource;
3839
import android.text.TextUtils;
3940
import android.text.format.Time;
@@ -303,7 +304,7 @@ private void removeLocked(ArrayList<Alarm> alarmList,
303304
}
304305
}
305306
}
306-
307+
307308
public void removeLocked(String packageName) {
308309
removeLocked(mRtcWakeupAlarms, packageName);
309310
removeLocked(mRtcAlarms, packageName);
@@ -327,6 +328,29 @@ private void removeLocked(ArrayList<Alarm> alarmList,
327328
}
328329
}
329330
}
331+
332+
public void removeUserLocked(int userHandle) {
333+
removeUserLocked(mRtcWakeupAlarms, userHandle);
334+
removeUserLocked(mRtcAlarms, userHandle);
335+
removeUserLocked(mElapsedRealtimeWakeupAlarms, userHandle);
336+
removeUserLocked(mElapsedRealtimeAlarms, userHandle);
337+
}
338+
339+
private void removeUserLocked(ArrayList<Alarm> alarmList, int userHandle) {
340+
if (alarmList.size() <= 0) {
341+
return;
342+
}
343+
344+
// iterator over the list removing any it where the intent match
345+
Iterator<Alarm> it = alarmList.iterator();
346+
347+
while (it.hasNext()) {
348+
Alarm alarm = it.next();
349+
if (UserHandle.getUserId(alarm.operation.getTargetUid()) == userHandle) {
350+
it.remove();
351+
}
352+
}
353+
}
330354

331355
public boolean lookForPackageLocked(String packageName) {
332356
return lookForPackageLocked(mRtcWakeupAlarms, packageName)
@@ -822,6 +846,7 @@ public UninstallReceiver() {
822846
// Register for events related to sdcard installation.
823847
IntentFilter sdFilter = new IntentFilter();
824848
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
849+
sdFilter.addAction(Intent.ACTION_USER_STOPPED);
825850
mContext.registerReceiver(this, sdFilter);
826851
}
827852

@@ -841,6 +866,11 @@ public void onReceive(Context context, Intent intent) {
841866
return;
842867
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
843868
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
869+
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
870+
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
871+
if (userHandle >= 0) {
872+
removeUserLocked(userHandle);
873+
}
844874
} else {
845875
if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
846876
&& intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {

0 commit comments

Comments
 (0)