This commit is contained in:
committed by
Android (Google) Code Review
commit
3ff8e1a800
@@ -127,6 +127,8 @@ public class Am {
|
||||
runSetDebugApp();
|
||||
} else if (op.equals("clear-debug-app")) {
|
||||
runClearDebugApp();
|
||||
} else if (op.equals("bug-report")) {
|
||||
runBugReport();
|
||||
} else if (op.equals("monitor")) {
|
||||
runMonitor();
|
||||
} else if (op.equals("screen-compat")) {
|
||||
@@ -844,6 +846,11 @@ public class Am {
|
||||
mAm.setDebugApp(null, false, true);
|
||||
}
|
||||
|
||||
private void runBugReport() throws Exception {
|
||||
mAm.requestBugReport();
|
||||
System.out.println("Your lovely bug report is being created; please be patient.");
|
||||
}
|
||||
|
||||
private void runSwitchUser() throws Exception {
|
||||
String user = nextArgRequired();
|
||||
mAm.switchUser(Integer.parseInt(user));
|
||||
@@ -1508,6 +1515,9 @@ public class Am {
|
||||
"\n" +
|
||||
"am clear-debug-app: clear the previously set-debug-app.\n" +
|
||||
"\n" +
|
||||
"am bug-report: request bug report generation; will launch UI\n" +
|
||||
" when done to select where it should be delivered." +
|
||||
"\n" +
|
||||
"am monitor: start monitoring for crashes or ANRs.\n" +
|
||||
" --gdb: start gdbserv on the given port at crash/ANR\n" +
|
||||
"\n" +
|
||||
|
||||
@@ -1783,6 +1783,12 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
|
||||
return true;
|
||||
}
|
||||
|
||||
case REQUEST_BUG_REPORT_TRANSACTION: {
|
||||
data.enforceInterface(IActivityManager.descriptor);
|
||||
requestBugReport();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return super.onTransact(code, data, reply, flags);
|
||||
@@ -4066,5 +4072,15 @@ class ActivityManagerProxy implements IActivityManager
|
||||
reply.recycle();
|
||||
}
|
||||
|
||||
public void requestBugReport() throws RemoteException {
|
||||
Parcel data = Parcel.obtain();
|
||||
Parcel reply = Parcel.obtain();
|
||||
data.writeInterfaceToken(IActivityManager.descriptor);
|
||||
mRemote.transact(REQUEST_BUG_REPORT_TRANSACTION, data, reply, 0);
|
||||
reply.readException();
|
||||
data.recycle();
|
||||
reply.recycle();
|
||||
}
|
||||
|
||||
private IBinder mRemote;
|
||||
}
|
||||
|
||||
@@ -361,6 +361,8 @@ public interface IActivityManager extends IInterface {
|
||||
public void registerUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException;
|
||||
public void unregisterUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException;
|
||||
|
||||
public void requestBugReport() throws RemoteException;
|
||||
|
||||
/*
|
||||
* Private non-Binder interfaces
|
||||
*/
|
||||
@@ -613,4 +615,5 @@ public interface IActivityManager extends IInterface {
|
||||
int REGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+154;
|
||||
int UNREGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+155;
|
||||
int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156;
|
||||
int REQUEST_BUG_REPORT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+157;
|
||||
}
|
||||
|
||||
@@ -171,11 +171,17 @@ public class ActivityInfo extends ComponentInfo
|
||||
* {@see android.app.Notification#FLAG_HIGH_PRIORITY}
|
||||
*/
|
||||
public static final int FLAG_IMMERSIVE = 0x0400;
|
||||
/**
|
||||
* @hide Bit in {@link #flags}: If set, this component will only be seen
|
||||
* by the primary user. Only works with broadcast receivers. Set from the
|
||||
* {@link android.R.attr#primaryUserOnly} attribute.
|
||||
*/
|
||||
public static final int FLAG_PRIMARY_USER_ONLY = 0x20000000;
|
||||
/**
|
||||
* Bit in {@link #flags}: If set, a single instance of the receiver will
|
||||
* run for all users on the device. Set from the
|
||||
* {@link android.R.attr#singleUser} attribute. Note that this flag is
|
||||
* only relevent for ActivityInfo structures that are describiner receiver
|
||||
* only relevant for ActivityInfo structures that are describing receiver
|
||||
* components; it is not applied to activities.
|
||||
*/
|
||||
public static final int FLAG_SINGLE_USER = 0x40000000;
|
||||
|
||||
@@ -2193,7 +2193,7 @@ public class PackageParser {
|
||||
if (sa.getBoolean(
|
||||
com.android.internal.R.styleable.AndroidManifestActivity_singleUser,
|
||||
false)) {
|
||||
a.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
|
||||
a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
|
||||
if (a.info.exported) {
|
||||
Slog.w(TAG, "Activity exported request ignored due to singleUser: "
|
||||
+ a.className + " at " + mArchiveSourcePath + " "
|
||||
@@ -2202,6 +2202,11 @@ public class PackageParser {
|
||||
}
|
||||
setExported = true;
|
||||
}
|
||||
if (sa.getBoolean(
|
||||
com.android.internal.R.styleable.AndroidManifestActivity_primaryUserOnly,
|
||||
false)) {
|
||||
a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY;
|
||||
}
|
||||
}
|
||||
|
||||
sa.recycle();
|
||||
|
||||
@@ -34,6 +34,14 @@ public class PackageUserState {
|
||||
public HashSet<String> enabledComponents;
|
||||
|
||||
public PackageUserState() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public PackageUserState(boolean isSystem) {
|
||||
if (!isSystem) {
|
||||
stopped = notLaunched = true;
|
||||
}
|
||||
installed = true;
|
||||
enabled = COMPONENT_ENABLED_STATE_DEFAULT;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,9 @@ public class UserInfo implements Parcelable {
|
||||
public long creationTime;
|
||||
public long lastLoggedInTime;
|
||||
|
||||
/** User is only partially created. */
|
||||
public boolean partial;
|
||||
|
||||
public UserInfo(int id, String name, int flags) {
|
||||
this(id, name, null, flags);
|
||||
}
|
||||
@@ -105,6 +108,7 @@ public class UserInfo implements Parcelable {
|
||||
serialNumber = orig.serialNumber;
|
||||
creationTime = orig.creationTime;
|
||||
lastLoggedInTime = orig.lastLoggedInTime;
|
||||
partial = orig.partial;
|
||||
}
|
||||
|
||||
public UserHandle getUserHandle() {
|
||||
@@ -128,6 +132,7 @@ public class UserInfo implements Parcelable {
|
||||
dest.writeInt(serialNumber);
|
||||
dest.writeLong(creationTime);
|
||||
dest.writeLong(lastLoggedInTime);
|
||||
dest.writeInt(partial ? 1 : 0);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<UserInfo> CREATOR
|
||||
@@ -148,5 +153,6 @@ public class UserInfo implements Parcelable {
|
||||
serialNumber = source.readInt();
|
||||
creationTime = source.readLong();
|
||||
lastLoggedInTime = source.readLong();
|
||||
partial = source.readInt() != 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2140,7 +2140,8 @@
|
||||
android:process=":ui">
|
||||
</activity>
|
||||
|
||||
<receiver android:name="com.android.server.BootReceiver" >
|
||||
<receiver android:name="com.android.server.BootReceiver"
|
||||
android:primaryUserOnly="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
|
||||
@@ -1391,6 +1391,9 @@
|
||||
<attr name="uiOptions" />
|
||||
<attr name="parentActivityName" />
|
||||
<attr name="singleUser" />
|
||||
<!-- @hide This broacast receiver will only receive broadcasts for the
|
||||
primary user. Can only be used with receivers. -->
|
||||
<attr name="primaryUserOnly" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- The <code>activity-alias</code> tag declares a new
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
package="com.android.systemui"
|
||||
coreApp="true">
|
||||
|
||||
@@ -91,7 +92,7 @@
|
||||
android:permission="android.permission.BIND_WALLPAPER"
|
||||
android:exported="true" />
|
||||
|
||||
<receiver android:name=".BootReceiver" >
|
||||
<receiver android:name=".BootReceiver" androidprv:primaryUserOnly="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
|
||||
@@ -708,7 +708,18 @@ class QuickSettings {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||
SystemProperties.set("ctl.start", "bugreport");
|
||||
// Add a little delay before executing, to give the
|
||||
// dialog a chance to go away before it takes a
|
||||
// screenshot.
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override public void run() {
|
||||
try {
|
||||
ActivityManagerNative.getDefault()
|
||||
.requestBugReport();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -241,7 +241,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
|
||||
if (Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.BUGREPORT_IN_POWER_MENU, 0) != 0) {
|
||||
mItems.add(
|
||||
new SinglePressAction(0, R.string.global_action_bug_report) {
|
||||
new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb,
|
||||
R.string.global_action_bug_report) {
|
||||
|
||||
public void onPress() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
|
||||
@@ -257,7 +258,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
|
||||
// screenshot.
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override public void run() {
|
||||
SystemProperties.set("ctl.start", "bugreport");
|
||||
try {
|
||||
ActivityManagerNative.getDefault()
|
||||
.requestBugReport();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
@@ -912,21 +912,38 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
switch (msg.what) {
|
||||
case SHOW_ERROR_MSG: {
|
||||
HashMap data = (HashMap) msg.obj;
|
||||
boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
|
||||
synchronized (ActivityManagerService.this) {
|
||||
ProcessRecord proc = (ProcessRecord)data.get("app");
|
||||
AppErrorResult res = (AppErrorResult) data.get("result");
|
||||
if (proc != null && proc.crashDialog != null) {
|
||||
Slog.e(TAG, "App already has crash dialog: " + proc);
|
||||
if (res != null) {
|
||||
res.set(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!showBackground && UserHandle.getAppId(proc.uid)
|
||||
>= Process.FIRST_APPLICATION_UID && proc.userId != mCurrentUserId
|
||||
&& proc.pid != MY_PID) {
|
||||
Slog.w(TAG, "Skipping crash dialog of " + proc + ": background");
|
||||
if (res != null) {
|
||||
res.set(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
AppErrorResult res = (AppErrorResult) data.get("result");
|
||||
if (mShowDialogs && !mSleeping && !mShuttingDown) {
|
||||
Dialog d = new AppErrorDialog(mContext, res, proc);
|
||||
Dialog d = new AppErrorDialog(mContext,
|
||||
ActivityManagerService.this, res, proc);
|
||||
d.show();
|
||||
proc.crashDialog = d;
|
||||
} else {
|
||||
// The device is asleep, so just pretend that the user
|
||||
// saw a crash dialog and hit "force quit".
|
||||
res.set(0);
|
||||
if (res != null) {
|
||||
res.set(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -977,7 +994,8 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
AppErrorResult res = (AppErrorResult) data.get("result");
|
||||
if (mShowDialogs && !mSleeping && !mShuttingDown) {
|
||||
Dialog d = new StrictModeViolationDialog(mContext, res, proc);
|
||||
Dialog d = new StrictModeViolationDialog(mContext,
|
||||
ActivityManagerService.this, res, proc);
|
||||
d.show();
|
||||
proc.crashDialog = d;
|
||||
} else {
|
||||
@@ -3683,7 +3701,8 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
|
||||
void closeSystemDialogsLocked(String reason) {
|
||||
Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
|
||||
| Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
if (reason != null) {
|
||||
intent.putExtra("reason", reason);
|
||||
}
|
||||
@@ -3755,7 +3774,8 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
|
||||
Uri.fromParts("package", packageName, null));
|
||||
if (!mProcessesReady) {
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
|
||||
| Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
}
|
||||
intent.putExtra(Intent.EXTRA_UID, uid);
|
||||
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
|
||||
@@ -3768,7 +3788,8 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
private void forceStopUserLocked(int userId) {
|
||||
forceStopPackageLocked(null, -1, false, false, true, false, userId);
|
||||
Intent intent = new Intent(Intent.ACTION_USER_STOPPED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
|
||||
| Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
|
||||
broadcastIntentLocked(null, null, intent,
|
||||
null, null, 0, null, null, null,
|
||||
@@ -7363,7 +7384,14 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
return mController != null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void requestBugReport() {
|
||||
// No permission check because this can't do anything harmful --
|
||||
// it will just eventually cause the user to be presented with
|
||||
// a UI to select where the bug report goes.
|
||||
SystemProperties.set("ctl.start", "bugreport");
|
||||
}
|
||||
|
||||
public void registerProcessObserver(IProcessObserver observer) {
|
||||
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
|
||||
"registerProcessObserver()");
|
||||
@@ -7698,9 +7726,9 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
}
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
|
||||
|
||||
|
||||
ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
|
||||
|
||||
|
||||
final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
|
||||
for (int i=0; i<ris.size(); i++) {
|
||||
ActivityInfo ai = ris.get(i).activityInfo;
|
||||
@@ -7874,7 +7902,8 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
|
||||
| Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
|
||||
broadcastIntentLocked(null, null, intent,
|
||||
null, null, 0, null, null, null,
|
||||
@@ -8081,8 +8110,15 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
|
||||
void startAppProblemLocked(ProcessRecord app) {
|
||||
app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
|
||||
mContext, app.info.packageName, app.info.flags);
|
||||
if (app.userId == mCurrentUserId) {
|
||||
app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
|
||||
mContext, app.info.packageName, app.info.flags);
|
||||
} else {
|
||||
// If this app is not running under the current user, then we
|
||||
// can't give it a report button because that would require
|
||||
// launching the report UI under a different user.
|
||||
app.errorReportReceiver = null;
|
||||
}
|
||||
skipCurrentReceiverLocked(app);
|
||||
}
|
||||
|
||||
@@ -8590,7 +8626,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
|
||||
if (appErrorIntent != null) {
|
||||
try {
|
||||
mContext.startActivity(appErrorIntent);
|
||||
mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Slog.w(TAG, "bug report receiver dissappeared", e);
|
||||
}
|
||||
@@ -11427,6 +11463,17 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
for (int user : users) {
|
||||
List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
|
||||
.queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
|
||||
if (user != 0 && newReceivers != null) {
|
||||
// If this is not the primary user, we need to check for
|
||||
// any receivers that should be filtered out.
|
||||
for (int i=0; i<newReceivers.size(); i++) {
|
||||
ResolveInfo ri = newReceivers.get(i);
|
||||
if ((ri.activityInfo.flags&ActivityInfo.FLAG_PRIMARY_USER_ONLY) != 0) {
|
||||
newReceivers.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newReceivers != null && newReceivers.size() == 0) {
|
||||
newReceivers = null;
|
||||
}
|
||||
@@ -12271,12 +12318,14 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
|
||||
| Intent.FLAG_RECEIVER_REPLACE_PENDING);
|
||||
| Intent.FLAG_RECEIVER_REPLACE_PENDING
|
||||
| Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
|
||||
null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
|
||||
if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
|
||||
broadcastIntentLocked(null, null,
|
||||
new Intent(Intent.ACTION_LOCALE_CHANGED),
|
||||
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
broadcastIntentLocked(null, null, intent,
|
||||
null, null, 0, null, null,
|
||||
null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
|
||||
}
|
||||
@@ -14085,7 +14134,8 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
|
||||
oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
|
||||
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
|
||||
| Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
|
||||
broadcastIntentLocked(null, null, intent,
|
||||
null, null, 0, null, null, null,
|
||||
@@ -14094,17 +14144,17 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
|
||||
if (userId != 0) {
|
||||
intent = new Intent(Intent.ACTION_USER_INITIALIZE);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
broadcastIntentLocked(null, null, intent, null,
|
||||
new IIntentReceiver.Stub() {
|
||||
public void performReceive(Intent intent, int resultCode,
|
||||
String data, Bundle extras, boolean ordered,
|
||||
boolean sticky, int sendingUser) {
|
||||
synchronized (ActivityManagerService.this) {
|
||||
getUserManagerLocked().makeInitialized(userInfo.id);
|
||||
}
|
||||
userInitialized(uss);
|
||||
}
|
||||
}, 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID,
|
||||
userId);
|
||||
uss.initializing = true;
|
||||
} else {
|
||||
getUserManagerLocked().makeInitialized(userInfo.id);
|
||||
}
|
||||
@@ -14131,7 +14181,8 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
Intent intent;
|
||||
if (oldUserId >= 0) {
|
||||
intent = new Intent(Intent.ACTION_USER_BACKGROUND);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
|
||||
| Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
intent.putExtra(Intent.EXTRA_USER_HANDLE, oldUserId);
|
||||
broadcastIntentLocked(null, null, intent,
|
||||
null, null, 0, null, null, null,
|
||||
@@ -14139,13 +14190,15 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
if (newUserId >= 0) {
|
||||
intent = new Intent(Intent.ACTION_USER_FOREGROUND);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
|
||||
| Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
|
||||
broadcastIntentLocked(null, null, intent,
|
||||
null, null, 0, null, null, null,
|
||||
false, false, MY_PID, Process.SYSTEM_UID, newUserId);
|
||||
intent = new Intent(Intent.ACTION_USER_SWITCHED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
|
||||
| Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
|
||||
broadcastIntentLocked(null, null, intent,
|
||||
null, null, 0, null, null,
|
||||
@@ -14176,6 +14229,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
};
|
||||
synchronized (this) {
|
||||
uss.switching = true;
|
||||
mCurUserSwitchCallback = callback;
|
||||
}
|
||||
for (int i=0; i<N; i++) {
|
||||
@@ -14207,6 +14261,14 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
oldUserId, newUserId, uss));
|
||||
}
|
||||
|
||||
void userInitialized(UserStartedState uss) {
|
||||
synchronized (ActivityManagerService.this) {
|
||||
getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
|
||||
uss.initializing = false;
|
||||
completeSwitchAndInitalizeLocked(uss);
|
||||
}
|
||||
}
|
||||
|
||||
void continueUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {
|
||||
final int N = mUserSwitchObservers.beginBroadcast();
|
||||
for (int i=0; i<N; i++) {
|
||||
@@ -14217,6 +14279,13 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
mUserSwitchObservers.finishBroadcast();
|
||||
synchronized (this) {
|
||||
uss.switching = false;
|
||||
completeSwitchAndInitalizeLocked(uss);
|
||||
}
|
||||
}
|
||||
|
||||
void completeSwitchAndInitalizeLocked(UserStartedState uss) {
|
||||
if (!uss.switching && !uss.initializing) {
|
||||
mWindowManager.stopFreezingScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.view.WindowManager;
|
||||
class AppErrorDialog extends BaseErrorDialog {
|
||||
private final static String TAG = "AppErrorDialog";
|
||||
|
||||
private final ActivityManagerService mService;
|
||||
private final AppErrorResult mResult;
|
||||
private final ProcessRecord mProc;
|
||||
|
||||
@@ -39,11 +40,13 @@ class AppErrorDialog extends BaseErrorDialog {
|
||||
// 5-minute timeout, then we automatically dismiss the crash dialog
|
||||
static final long DISMISS_TIMEOUT = 1000 * 60 * 5;
|
||||
|
||||
public AppErrorDialog(Context context, AppErrorResult result, ProcessRecord app) {
|
||||
public AppErrorDialog(Context context, ActivityManagerService service,
|
||||
AppErrorResult result, ProcessRecord app) {
|
||||
super(context);
|
||||
|
||||
Resources res = context.getResources();
|
||||
|
||||
mService = service;
|
||||
mProc = app;
|
||||
mResult = result;
|
||||
CharSequence name;
|
||||
@@ -86,7 +89,7 @@ class AppErrorDialog extends BaseErrorDialog {
|
||||
|
||||
private final Handler mHandler = new Handler() {
|
||||
public void handleMessage(Message msg) {
|
||||
synchronized (mProc) {
|
||||
synchronized (mService) {
|
||||
if (mProc != null && mProc.crashDialog == AppErrorDialog.this) {
|
||||
mProc.crashDialog = null;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.util.Slog;
|
||||
class StrictModeViolationDialog extends BaseErrorDialog {
|
||||
private final static String TAG = "StrictModeViolationDialog";
|
||||
|
||||
private final ActivityManagerService mService;
|
||||
private final AppErrorResult mResult;
|
||||
private final ProcessRecord mProc;
|
||||
|
||||
@@ -39,11 +40,13 @@ class StrictModeViolationDialog extends BaseErrorDialog {
|
||||
// dialog
|
||||
static final long DISMISS_TIMEOUT = 1000 * 60 * 1;
|
||||
|
||||
public StrictModeViolationDialog(Context context, AppErrorResult result, ProcessRecord app) {
|
||||
public StrictModeViolationDialog(Context context, ActivityManagerService service,
|
||||
AppErrorResult result, ProcessRecord app) {
|
||||
super(context);
|
||||
|
||||
Resources res = context.getResources();
|
||||
|
||||
mService = service;
|
||||
mProc = app;
|
||||
mResult = result;
|
||||
CharSequence name;
|
||||
@@ -83,7 +86,7 @@ class StrictModeViolationDialog extends BaseErrorDialog {
|
||||
|
||||
private final Handler mHandler = new Handler() {
|
||||
public void handleMessage(Message msg) {
|
||||
synchronized (mProc) {
|
||||
synchronized (mService) {
|
||||
if (mProc != null && mProc.crashDialog == StrictModeViolationDialog.this) {
|
||||
mProc.crashDialog = null;
|
||||
}
|
||||
|
||||
@@ -32,12 +32,17 @@ public class UserStartedState {
|
||||
= new ArrayList<IStopUserCallback>();
|
||||
|
||||
public int mState = STATE_BOOTING;
|
||||
public boolean switching;
|
||||
public boolean initializing;
|
||||
|
||||
public UserStartedState(UserHandle handle, boolean initial) {
|
||||
mHandle = handle;
|
||||
}
|
||||
|
||||
void dump(String prefix, PrintWriter pw) {
|
||||
pw.print(prefix); pw.print("mState="); pw.println(mState);
|
||||
pw.print(prefix); pw.print("mState="); pw.print(mState);
|
||||
if (switching) pw.print(" SWITCHING");
|
||||
if (initializing) pw.print(" INITIALIZING");
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
|
||||
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
|
||||
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageUserState;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.util.SparseArray;
|
||||
@@ -64,7 +65,8 @@ class PackageSettingBase extends GrantedPermissions {
|
||||
boolean permissionsFixed;
|
||||
boolean haveGids;
|
||||
|
||||
private static final PackageUserState DEFAULT_USER_STATE = new PackageUserState();
|
||||
private static final PackageUserState DEFAULT_USER_STATE = new PackageUserState(false);
|
||||
private static final PackageUserState DEFAULT_SYSTEM_USER_STATE = new PackageUserState(true);
|
||||
|
||||
// Whether this package is currently stopped, thus can not be
|
||||
// started until explicitly launched by the user.
|
||||
@@ -174,7 +176,7 @@ class PackageSettingBase extends GrantedPermissions {
|
||||
private PackageUserState modifyUserState(int userId) {
|
||||
PackageUserState state = userState.get(userId);
|
||||
if (state == null) {
|
||||
state = new PackageUserState();
|
||||
state = new PackageUserState((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0);
|
||||
userState.put(userId, state);
|
||||
}
|
||||
return state;
|
||||
@@ -182,7 +184,11 @@ class PackageSettingBase extends GrantedPermissions {
|
||||
|
||||
public PackageUserState readUserState(int userId) {
|
||||
PackageUserState state = userState.get(userId);
|
||||
return state != null ? state : DEFAULT_USER_STATE;
|
||||
if (state != null) {
|
||||
return state;
|
||||
}
|
||||
return ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0)
|
||||
? DEFAULT_SYSTEM_USER_STATE : DEFAULT_USER_STATE;
|
||||
}
|
||||
|
||||
void setEnabled(int state, int userId) {
|
||||
|
||||
@@ -2609,10 +2609,11 @@ final class Settings {
|
||||
pw.print(" installerPackageName="); pw.println(ps.installerPackageName);
|
||||
}
|
||||
pw.print(" signatures="); pw.println(ps.signatures);
|
||||
pw.print(" permissionsFixed="); pw.println(ps.permissionsFixed);
|
||||
pw.print(" haveGids="); pw.println(ps.haveGids);
|
||||
pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
|
||||
pw.print(" haveGids="); pw.print(ps.haveGids);
|
||||
pw.print(" installStatus="); pw.println(ps.installStatus);
|
||||
pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
|
||||
pw.print(" installStatus="); pw.println(ps.installStatus);
|
||||
pw.println();
|
||||
for (UserInfo user : users) {
|
||||
pw.print(" User "); pw.print(user.id); pw.print(": ");
|
||||
pw.print(" installed=");
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package com.android.server.pm;
|
||||
|
||||
import static android.os.ParcelFileDescriptor.MODE_CREATE;
|
||||
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
|
||||
@@ -35,7 +32,6 @@ import android.os.Binder;
|
||||
import android.os.Environment;
|
||||
import android.os.FileUtils;
|
||||
import android.os.IUserManager;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
@@ -74,6 +70,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
private static final String ATTR_LAST_LOGGED_IN_TIME = "lastLoggedIn";
|
||||
private static final String ATTR_SERIAL_NO = "serialNumber";
|
||||
private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
|
||||
private static final String ATTR_PARTIAL = "partial";
|
||||
private static final String TAG_USERS = "users";
|
||||
private static final String TAG_USER = "user";
|
||||
|
||||
@@ -132,24 +129,40 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
private UserManagerService(Context context, PackageManagerService pm,
|
||||
Object installLock, Object packagesLock,
|
||||
File dataDir, File baseUserPath) {
|
||||
synchronized (UserManagerService.class) {
|
||||
mContext = context;
|
||||
mPm = pm;
|
||||
mInstallLock = installLock;
|
||||
mPackagesLock = packagesLock;
|
||||
mUsersDir = new File(dataDir, USER_INFO_DIR);
|
||||
mUsersDir.mkdirs();
|
||||
// Make zeroth user directory, for services to migrate their files to that location
|
||||
File userZeroDir = new File(mUsersDir, "0");
|
||||
userZeroDir.mkdirs();
|
||||
mBaseUserPath = baseUserPath;
|
||||
FileUtils.setPermissions(mUsersDir.toString(),
|
||||
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|
||||
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
|
||||
-1, -1);
|
||||
mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
|
||||
readUserList();
|
||||
sInstance = this;
|
||||
mContext = context;
|
||||
mPm = pm;
|
||||
mInstallLock = installLock;
|
||||
mPackagesLock = packagesLock;
|
||||
synchronized (mInstallLock) {
|
||||
synchronized (mPackagesLock) {
|
||||
mUsersDir = new File(dataDir, USER_INFO_DIR);
|
||||
mUsersDir.mkdirs();
|
||||
// Make zeroth user directory, for services to migrate their files to that location
|
||||
File userZeroDir = new File(mUsersDir, "0");
|
||||
userZeroDir.mkdirs();
|
||||
mBaseUserPath = baseUserPath;
|
||||
FileUtils.setPermissions(mUsersDir.toString(),
|
||||
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|
||||
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
|
||||
-1, -1);
|
||||
mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
|
||||
readUserListLocked();
|
||||
// Prune out any partially created users.
|
||||
ArrayList<UserInfo> partials = new ArrayList<UserInfo>();
|
||||
for (int i = 0; i < mUsers.size(); i++) {
|
||||
UserInfo ui = mUsers.valueAt(i);
|
||||
if (ui.partial && i != 0) {
|
||||
partials.add(ui);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < partials.size(); i++) {
|
||||
UserInfo ui = partials.get(i);
|
||||
Slog.w(LOG_TAG, "Removing partially created user #" + i
|
||||
+ " (name=" + ui.name + ")");
|
||||
removeUserStateLocked(ui.id);
|
||||
}
|
||||
sInstance = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,8 +172,12 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
synchronized (mPackagesLock) {
|
||||
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
|
||||
for (int i = 0; i < mUsers.size(); i++) {
|
||||
if (!excludeDying || !mRemovingUserIds.contains(mUsers.keyAt(i))) {
|
||||
users.add(mUsers.valueAt(i));
|
||||
UserInfo ui = mUsers.valueAt(i);
|
||||
if (ui.partial) {
|
||||
continue;
|
||||
}
|
||||
if (!excludeDying || !mRemovingUserIds.contains(ui.id)) {
|
||||
users.add(ui);
|
||||
}
|
||||
}
|
||||
return users;
|
||||
@@ -179,7 +196,12 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
* Should be locked on mUsers before calling this.
|
||||
*/
|
||||
private UserInfo getUserInfoLocked(int userId) {
|
||||
return mUsers.get(userId);
|
||||
UserInfo ui = mUsers.get(userId);
|
||||
if (ui != null && ui.partial) {
|
||||
Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
|
||||
return null;
|
||||
}
|
||||
return ui;
|
||||
}
|
||||
|
||||
public boolean exists(int userId) {
|
||||
@@ -191,14 +213,22 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
@Override
|
||||
public void setUserName(int userId, String name) {
|
||||
checkManageUsersPermission("rename users");
|
||||
boolean changed = false;
|
||||
synchronized (mPackagesLock) {
|
||||
UserInfo info = mUsers.get(userId);
|
||||
if (info == null || info.partial) {
|
||||
Slog.w(LOG_TAG, "setUserName: unknown user #" + userId);
|
||||
return;
|
||||
}
|
||||
if (name != null && !name.equals(info.name)) {
|
||||
info.name = name;
|
||||
writeUserLocked(info);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
sendUserInfoChangedBroadcast(userId);
|
||||
if (changed) {
|
||||
sendUserInfoChangedBroadcast(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -206,7 +236,10 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
checkManageUsersPermission("update users");
|
||||
synchronized (mPackagesLock) {
|
||||
UserInfo info = mUsers.get(userId);
|
||||
if (info == null) return;
|
||||
if (info == null || info.partial) {
|
||||
Slog.w(LOG_TAG, "setUserIcon: unknown user #" + userId);
|
||||
return;
|
||||
}
|
||||
writeBitmapLocked(info, bitmap);
|
||||
writeUserLocked(info);
|
||||
}
|
||||
@@ -225,7 +258,13 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
checkManageUsersPermission("read users");
|
||||
synchronized (mPackagesLock) {
|
||||
UserInfo info = mUsers.get(userId);
|
||||
if (info == null || info.iconPath == null) return null;
|
||||
if (info == null || info.partial) {
|
||||
Slog.w(LOG_TAG, "getUserIcon: unknown user #" + userId);
|
||||
return null;
|
||||
}
|
||||
if (info.iconPath == null) {
|
||||
return null;
|
||||
}
|
||||
return BitmapFactory.decodeFile(info.iconPath);
|
||||
}
|
||||
}
|
||||
@@ -239,7 +278,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
// Erase any guest user that currently exists
|
||||
for (int i = 0; i < mUsers.size(); i++) {
|
||||
UserInfo user = mUsers.valueAt(i);
|
||||
if (user.isGuest()) {
|
||||
if (!user.partial && user.isGuest()) {
|
||||
if (!enable) {
|
||||
removeUser(user.id);
|
||||
}
|
||||
@@ -271,7 +310,10 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
checkManageUsersPermission("makeInitialized");
|
||||
synchronized (mPackagesLock) {
|
||||
UserInfo info = mUsers.get(userId);
|
||||
if (info != null && (info.flags&UserInfo.FLAG_INITIALIZED) == 0) {
|
||||
if (info == null || info.partial) {
|
||||
Slog.w(LOG_TAG, "makeInitialized: unknown user #" + userId);
|
||||
}
|
||||
if ((info.flags&UserInfo.FLAG_INITIALIZED) == 0) {
|
||||
info.flags |= UserInfo.FLAG_INITIALIZED;
|
||||
writeUserLocked(info);
|
||||
}
|
||||
@@ -453,6 +495,9 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
if (userInfo.iconPath != null) {
|
||||
serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath);
|
||||
}
|
||||
if (userInfo.partial) {
|
||||
serializer.attribute(null, ATTR_PARTIAL, "true");
|
||||
}
|
||||
|
||||
serializer.startTag(null, TAG_NAME);
|
||||
serializer.text(userInfo.name);
|
||||
@@ -516,6 +561,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
String iconPath = null;
|
||||
long creationTime = 0L;
|
||||
long lastLoggedInTime = 0L;
|
||||
boolean partial = false;
|
||||
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
@@ -546,6 +592,10 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
|
||||
creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0);
|
||||
lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
|
||||
String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
|
||||
if ("true".equals(valueString)) {
|
||||
partial = true;
|
||||
}
|
||||
|
||||
while ((type = parser.next()) != XmlPullParser.START_TAG
|
||||
&& type != XmlPullParser.END_DOCUMENT) {
|
||||
@@ -562,6 +612,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
userInfo.serialNumber = serialNumber;
|
||||
userInfo.creationTime = creationTime;
|
||||
userInfo.lastLoggedInTime = lastLoggedInTime;
|
||||
userInfo.partial = partial;
|
||||
return userInfo;
|
||||
|
||||
} catch (IOException ioe) {
|
||||
@@ -613,11 +664,14 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
userInfo.serialNumber = mNextSerialNumber++;
|
||||
long now = System.currentTimeMillis();
|
||||
userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
|
||||
userInfo.partial = true;
|
||||
mUsers.put(userId, userInfo);
|
||||
writeUserListLocked();
|
||||
writeUserLocked(userInfo);
|
||||
updateUserIdsLocked();
|
||||
mPm.createNewUserLILPw(userId, userPath);
|
||||
userInfo.partial = false;
|
||||
writeUserLocked(userInfo);
|
||||
updateUserIdsLocked();
|
||||
}
|
||||
}
|
||||
if (userInfo != null) {
|
||||
@@ -670,19 +724,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
void finishRemoveUser(int userHandle) {
|
||||
synchronized (mInstallLock) {
|
||||
synchronized (mPackagesLock) {
|
||||
// Cleanup package manager settings
|
||||
mPm.cleanUpUserLILPw(userHandle);
|
||||
|
||||
// Remove this user from the list
|
||||
mUsers.remove(userHandle);
|
||||
mRemovingUserIds.remove(userHandle);
|
||||
// Remove user file
|
||||
AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
|
||||
userFile.delete();
|
||||
// Update the user list
|
||||
writeUserListLocked();
|
||||
updateUserIdsLocked();
|
||||
removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));
|
||||
removeUserStateLocked(userHandle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -698,6 +740,22 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void removeUserStateLocked(int userHandle) {
|
||||
// Cleanup package manager settings
|
||||
mPm.cleanUpUserLILPw(userHandle);
|
||||
|
||||
// Remove this user from the list
|
||||
mUsers.remove(userHandle);
|
||||
mRemovingUserIds.remove(userHandle);
|
||||
// Remove user file
|
||||
AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
|
||||
userFile.delete();
|
||||
// Update the user list
|
||||
writeUserListLocked();
|
||||
updateUserIdsLocked();
|
||||
removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));
|
||||
}
|
||||
|
||||
private void removeDirectoryRecursive(File parent) {
|
||||
if (parent.isDirectory()) {
|
||||
String[] files = parent.list();
|
||||
@@ -732,9 +790,17 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
* Caches the list of user ids in an array, adjusting the array size when necessary.
|
||||
*/
|
||||
private void updateUserIdsLocked() {
|
||||
int[] newUsers = new int[mUsers.size()];
|
||||
int num = 0;
|
||||
for (int i = 0; i < mUsers.size(); i++) {
|
||||
newUsers[i] = mUsers.keyAt(i);
|
||||
if (!mUsers.valueAt(i).partial) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
int[] newUsers = new int[num];
|
||||
for (int i = 0; i < mUsers.size(); i++) {
|
||||
if (!mUsers.valueAt(i).partial) {
|
||||
newUsers[i] = mUsers.keyAt(i);
|
||||
}
|
||||
}
|
||||
mUserIds = newUsers;
|
||||
}
|
||||
@@ -747,7 +813,11 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
synchronized (mPackagesLock) {
|
||||
UserInfo user = mUsers.get(userId);
|
||||
long now = System.currentTimeMillis();
|
||||
if (user != null && now > EPOCH_PLUS_30_YEARS) {
|
||||
if (user == null || user.partial) {
|
||||
Slog.w(LOG_TAG, "userForeground: unknown user #" + userId);
|
||||
return;
|
||||
}
|
||||
if (now > EPOCH_PLUS_30_YEARS) {
|
||||
user.lastLoggedInTime = now;
|
||||
writeUserLocked(user);
|
||||
}
|
||||
@@ -793,7 +863,9 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
UserInfo user = mUsers.valueAt(i);
|
||||
if (user == null) continue;
|
||||
pw.print(" "); pw.print(user);
|
||||
pw.println(mRemovingUserIds.contains(mUsers.keyAt(i)) ? " <removing> " : "");
|
||||
if (mRemovingUserIds.contains(mUsers.keyAt(i))) pw.print(" <removing> ");
|
||||
if (user.partial) pw.print(" <partial>");
|
||||
pw.println();
|
||||
pw.print(" Created: ");
|
||||
if (user.creationTime == 0) {
|
||||
pw.println("<unknown>");
|
||||
|
||||
Reference in New Issue
Block a user