summaryrefslogtreecommitdiffstats
path: root/services/java/com/android
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android')
-rw-r--r--services/java/com/android/server/AlarmManagerService.java2
-rw-r--r--services/java/com/android/server/DevicePolicyManagerService.java970
-rw-r--r--services/java/com/android/server/DreamController.java217
-rw-r--r--services/java/com/android/server/DreamManagerService.java387
-rw-r--r--services/java/com/android/server/MountService.java32
-rw-r--r--services/java/com/android/server/SystemServer.java3
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java170
-rw-r--r--services/java/com/android/server/am/ActivityRecord.java18
-rwxr-xr-xservices/java/com/android/server/am/ActivityStack.java80
-rw-r--r--services/java/com/android/server/am/BroadcastQueue.java10
-rw-r--r--services/java/com/android/server/am/TaskAccessInfo.java3
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java69
-rw-r--r--services/java/com/android/server/display/PersistentDataStore.java292
-rw-r--r--services/java/com/android/server/display/WifiDisplayAdapter.java90
-rw-r--r--services/java/com/android/server/display/WifiDisplayController.java292
-rw-r--r--services/java/com/android/server/net/LockdownVpnTracker.java8
-rw-r--r--services/java/com/android/server/net/NetworkStatsCollection.java5
-rw-r--r--services/java/com/android/server/net/NetworkStatsRecorder.java27
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java71
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java4
-rw-r--r--services/java/com/android/server/pm/UserManagerService.java48
-rw-r--r--services/java/com/android/server/power/PowerManagerService.java35
-rw-r--r--services/java/com/android/server/updates/CertPinInstallReceiver.java (renamed from services/java/com/android/server/updatable/CertPinInstallReceiver.java)0
-rw-r--r--services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java (renamed from services/java/com/android/server/updatable/ConfigUpdateInstallReceiver.java)3
-rw-r--r--services/java/com/android/server/usb/UsbDeviceManager.java29
-rw-r--r--services/java/com/android/server/wm/KeyguardDisableHandler.java14
-rwxr-xr-xservices/java/com/android/server/wm/WindowManagerService.java46
-rw-r--r--services/java/com/android/server/wm/WindowState.java4
-rw-r--r--services/java/com/android/server/wm/WindowStateAnimator.java4
29 files changed, 2206 insertions, 727 deletions
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index f4ad756..f960833 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -353,7 +353,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
while (it.hasNext()) {
Alarm alarm = it.next();
- if (UserHandle.getUserId(alarm.operation.getTargetUid()) == userHandle) {
+ if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
it.remove();
}
}
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 28a4310..aec5d6e 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -16,7 +16,6 @@
package com.android.server;
-import com.android.internal.content.PackageMonitor;
import com.android.internal.os.storage.ExternalStorageFormatter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
@@ -28,7 +27,9 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.app.Activity;
+import android.app.ActivityManagerNative;
import android.app.AlarmManager;
+import android.app.AppGlobals;
import android.app.PendingIntent;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminReceiver;
@@ -40,6 +41,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
@@ -49,6 +51,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.IPowerManager;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RecoverySystem;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -56,10 +59,12 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.Xml;
import android.view.IWindowManager;
import android.view.WindowManagerPolicy;
@@ -82,56 +87,86 @@ import java.util.Set;
* Implementation of the device policy APIs.
*/
public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ private static final String DEVICE_POLICIES_XML = "device_policies.xml";
+
private static final String TAG = "DevicePolicyManagerService";
private static final int REQUEST_EXPIRE_PASSWORD = 5571;
- private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms
+ private static final long MS_PER_DAY = 86400 * 1000;
+
+ private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
= "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
- private static final long MS_PER_DAY = 86400 * 1000;
+ private static final boolean DBG = false;
final Context mContext;
- final MyPackageMonitor mMonitor;
final PowerManager.WakeLock mWakeLock;
IPowerManager mIPowerManager;
IWindowManager mIWindowManager;
- int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
- int mActivePasswordLength = 0;
- int mActivePasswordUpperCase = 0;
- int mActivePasswordLowerCase = 0;
- int mActivePasswordLetters = 0;
- int mActivePasswordNumeric = 0;
- int mActivePasswordSymbols = 0;
- int mActivePasswordNonLetter = 0;
- int mFailedPasswordAttempts = 0;
-
- int mPasswordOwner = -1;
- Handler mHandler = new Handler();
+ public static class DevicePolicyData {
+ int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ int mActivePasswordLength = 0;
+ int mActivePasswordUpperCase = 0;
+ int mActivePasswordLowerCase = 0;
+ int mActivePasswordLetters = 0;
+ int mActivePasswordNumeric = 0;
+ int mActivePasswordSymbols = 0;
+ int mActivePasswordNonLetter = 0;
+ int mFailedPasswordAttempts = 0;
+
+ int mUserHandle;;
+ int mPasswordOwner = -1;
+ long mLastMaximumTimeToLock = -1;
+
+ final HashMap<ComponentName, ActiveAdmin> mAdminMap
+ = new HashMap<ComponentName, ActiveAdmin>();
+ final ArrayList<ActiveAdmin> mAdminList
+ = new ArrayList<ActiveAdmin>();
+
+ public DevicePolicyData(int userHandle) {
+ mUserHandle = userHandle;
+ }
+ }
- long mLastMaximumTimeToLock = -1;
+ final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
- final HashMap<ComponentName, ActiveAdmin> mAdminMap
- = new HashMap<ComponentName, ActiveAdmin>();
- final ArrayList<ActiveAdmin> mAdminList
- = new ArrayList<ActiveAdmin>();
+ Handler mHandler = new Handler();
BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
+ final String action = intent.getAction();
+ final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ getSendingUserId());
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
- Slog.v(TAG, "Sending password expiration notifications for action " + action);
+ Slog.v(TAG, "Sending password expiration notifications for action " + action
+ + " for user " + userHandle);
mHandler.post(new Runnable() {
public void run() {
- handlePasswordExpirationNotification();
+ handlePasswordExpirationNotification(getUserData(userHandle));
}
});
+ } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+ removeUserData(userHandle);
+ } else if (Intent.ACTION_USER_STARTED.equals(action)
+ || Intent.ACTION_PACKAGE_CHANGED.equals(action)
+ || Intent.ACTION_PACKAGE_REMOVED.equals(action)
+ || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+
+ if (Intent.ACTION_USER_STARTED.equals(action)) {
+ // Reset the policy data
+ synchronized (DevicePolicyManagerService.this) {
+ mUserData.remove(userHandle);
+ }
+ }
+
+ handlePackagesChanged(userHandle);
}
}
};
@@ -194,6 +229,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int getUid() { return info.getActivityInfo().applicationInfo.uid; }
+ public UserHandle getUserHandle() {
+ return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
+ }
+
void writeToXml(XmlSerializer out)
throws IllegalArgumentException, IllegalStateException, IOException {
out.startTag(null, "policies");
@@ -421,39 +460,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- class MyPackageMonitor extends PackageMonitor {
- @Override
- public void onSomePackagesChanged() {
- synchronized (DevicePolicyManagerService.this) {
- boolean removed = false;
- for (int i=mAdminList.size()-1; i>=0; i--) {
- ActiveAdmin aa = mAdminList.get(i);
- int change = isPackageDisappearing(aa.info.getPackageName());
- if (change == PACKAGE_PERMANENT_CHANGE
- || change == PACKAGE_TEMPORARY_CHANGE) {
- Slog.w(TAG, "Admin unexpectedly uninstalled: "
- + aa.info.getComponent());
- removed = true;
- mAdminList.remove(i);
- } else if (isPackageModified(aa.info.getPackageName())) {
- try {
- mContext.getPackageManager().getReceiverInfo(
- aa.info.getComponent(), 0);
- } catch (NameNotFoundException e) {
- Slog.w(TAG, "Admin package change removed component: "
- + aa.info.getComponent());
- removed = true;
- mAdminList.remove(i);
- }
- }
- }
- if (removed) {
- validatePasswordOwnerLocked();
- syncDeviceCapabilitiesLocked();
- saveSettingsLocked();
+ private void handlePackagesChanged(int userHandle) {
+ boolean removed = false;
+ Slog.d(TAG, "Handling package changes for user " + userHandle);
+ DevicePolicyData policy = getUserData(userHandle);
+ IPackageManager pm = AppGlobals.getPackageManager();
+ for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
+ ActiveAdmin aa = policy.mAdminList.get(i);
+ try {
+ if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
+ || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
+ removed = true;
+ policy.mAdminList.remove(i);
}
+ } catch (RemoteException re) {
+ // Shouldn't happen
}
}
+ if (removed) {
+ validatePasswordOwnerLocked(policy);
+ syncDeviceCapabilitiesLocked(policy);
+ saveSettingsLocked(policy.mUserHandle);
+ }
}
/**
@@ -461,22 +489,62 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
*/
public DevicePolicyManagerService(Context context) {
mContext = context;
- mMonitor = new MyPackageMonitor();
- mMonitor.register(context, null, true);
mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
- context.registerReceiver(mReceiver, filter);
+ filter.addAction(Intent.ACTION_USER_REMOVED);
+ filter.addAction(Intent.ACTION_USER_STARTED);
+ context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
+ filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ filter.addDataScheme("package");
+ context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
+ }
+
+ /**
+ * Creates and loads the policy data from xml.
+ * @param userHandle the user for whom to load the policy data
+ * @return
+ */
+ DevicePolicyData getUserData(int userHandle) {
+ synchronized (this) {
+ DevicePolicyData policy = mUserData.get(userHandle);
+ if (policy == null) {
+ policy = new DevicePolicyData(userHandle);
+ mUserData.append(userHandle, policy);
+ loadSettingsLocked(policy, userHandle);
+ }
+ return policy;
+ }
+ }
+
+ void removeUserData(int userHandle) {
+ synchronized (this) {
+ if (userHandle == UserHandle.USER_OWNER) {
+ Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
+ return;
+ }
+ DevicePolicyData policy = mUserData.get(userHandle);
+ if (policy != null) {
+ mUserData.remove(userHandle);
+ }
+ File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
+ DEVICE_POLICIES_XML);
+ policyFile.delete();
+ Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
+ }
}
/**
* Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
* reminders. Clears alarm if no expirations are configured.
*/
- protected void setExpirationAlarmCheckLocked(Context context) {
- final long expiration = getPasswordExpirationLocked(null);
+ protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
+ final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
final long now = System.currentTimeMillis();
final long timeToExpire = expiration - now;
final long alarmTime;
@@ -499,9 +567,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long token = Binder.clearCallingIdentity();
try {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
+ PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
- PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
+ new UserHandle(policy.mUserHandle));
am.cancel(pi);
if (alarmTime != 0) {
am.set(AlarmManager.RTC, alarmTime, pi);
@@ -527,8 +596,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return mIWindowManager;
}
- ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
- ActiveAdmin admin = mAdminMap.get(who);
+ ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
+ ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
if (admin != null
&& who.getPackageName().equals(admin.info.getActivityInfo().packageName)
&& who.getClassName().equals(admin.info.getActivityInfo().name)) {
@@ -540,8 +609,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
throws SecurityException {
final int callingUid = Binder.getCallingUid();
+ final int userHandle = UserHandle.getUserId(callingUid);
+ final DevicePolicyData policy = getUserData(userHandle);
if (who != null) {
- ActiveAdmin admin = mAdminMap.get(who);
+ ActiveAdmin admin = policy.mAdminMap.get(who);
if (admin == null) {
throw new SecurityException("No active admin " + who);
}
@@ -556,9 +627,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
return admin;
} else {
- final int N = mAdminList.size();
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
return admin;
}
@@ -579,18 +650,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
intent.putExtra("expiration", admin.passwordExpirationDate);
}
if (result != null) {
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
+ mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
null, result, mHandler, Activity.RESULT_OK, null, null);
} else {
mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
}
}
- void sendAdminCommandLocked(String action, int reqPolicy) {
- final int N = mAdminList.size();
- if (N > 0) {
- for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
+ final DevicePolicyData policy = getUserData(userHandle);
+ final int count = policy.mAdminList.size();
+ if (count > 0) {
+ for (int i = 0; i < count; i++) {
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (admin.info.usesPolicy(reqPolicy)) {
sendAdminCommandLocked(admin, action);
}
@@ -598,8 +670,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- void removeActiveAdminLocked(final ComponentName adminReceiver) {
- final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
+ void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
+ final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (admin != null) {
sendAdminCommandLocked(admin,
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
@@ -607,28 +679,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (DevicePolicyManagerService.this) {
+ int userHandle = admin.getUserHandle().getIdentifier();
+ DevicePolicyData policy = getUserData(userHandle);
boolean doProxyCleanup = admin.info.usesPolicy(
DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
- mAdminList.remove(admin);
- mAdminMap.remove(adminReceiver);
- validatePasswordOwnerLocked();
- syncDeviceCapabilitiesLocked();
+ policy.mAdminList.remove(admin);
+ policy.mAdminMap.remove(adminReceiver);
+ validatePasswordOwnerLocked(policy);
+ syncDeviceCapabilitiesLocked(policy);
if (doProxyCleanup) {
- resetGlobalProxyLocked();
+ resetGlobalProxyLocked(getUserData(userHandle));
}
- saveSettingsLocked();
- updateMaximumTimeToLockLocked();
+ saveSettingsLocked(userHandle);
+ updateMaximumTimeToLockLocked(policy);
}
}
});
}
}
- public DeviceAdminInfo findAdmin(ComponentName adminName) {
+ public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
+ enforceCrossUserPermission(userHandle);
Intent resolveIntent = new Intent();
resolveIntent.setComponent(adminName);
List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
- resolveIntent, PackageManager.GET_META_DATA);
+ resolveIntent, PackageManager.GET_META_DATA, userHandle);
if (infos == null || infos.size() <= 0) {
throw new IllegalArgumentException("Unknown admin: " + adminName);
}
@@ -636,21 +711,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
try {
return new DeviceAdminInfo(mContext, infos.get(0));
} catch (XmlPullParserException e) {
- Slog.w(TAG, "Bad device admin requested: " + adminName, e);
+ Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
return null;
} catch (IOException e) {
- Slog.w(TAG, "Bad device admin requested: " + adminName, e);
+ Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
return null;
}
}
- private static JournaledFile makeJournaledFile() {
- final String base = "/data/system/device_policies.xml";
+ private static JournaledFile makeJournaledFile(int userHandle) {
+ final String base = userHandle == 0
+ ? "/data/system/" + DEVICE_POLICIES_XML
+ : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
+ .getAbsolutePath();
return new JournaledFile(new File(base), new File(base + ".tmp"));
}
- private void saveSettingsLocked() {
- JournaledFile journal = makeJournaledFile();
+ private void saveSettingsLocked(int userHandle) {
+ DevicePolicyData policy = getUserData(userHandle);
+ JournaledFile journal = makeJournaledFile(userHandle);
FileOutputStream stream = null;
try {
stream = new FileOutputStream(journal.chooseForWrite(), false);
@@ -660,9 +739,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
out.startTag(null, "policies");
- final int N = mAdminList.size();
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- ActiveAdmin ap = mAdminList.get(i);
+ ActiveAdmin ap = policy.mAdminList.get(i);
if (ap != null) {
out.startTag(null, "admin");
out.attribute(null, "name", ap.info.getComponent().flattenToString());
@@ -671,32 +750,32 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- if (mPasswordOwner >= 0) {
+ if (policy.mPasswordOwner >= 0) {
out.startTag(null, "password-owner");
- out.attribute(null, "value", Integer.toString(mPasswordOwner));
+ out.attribute(null, "value", Integer.toString(policy.mPasswordOwner));
out.endTag(null, "password-owner");
}
- if (mFailedPasswordAttempts != 0) {
+ if (policy.mFailedPasswordAttempts != 0) {
out.startTag(null, "failed-password-attempts");
- out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
+ out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts));
out.endTag(null, "failed-password-attempts");
}
- if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
- || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
- || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
- || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
+ if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0
+ || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0
+ || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0
+ || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) {
out.startTag(null, "active-password");
- out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
- out.attribute(null, "length", Integer.toString(mActivePasswordLength));
- out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
- out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
- out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
+ out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality));
+ out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength));
+ out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase));
+ out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase));
+ out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters));
out.attribute(null, "numeric", Integer
- .toString(mActivePasswordNumeric));
- out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
- out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
+ .toString(policy.mActivePasswordNumeric));
+ out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols));
+ out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter));
out.endTag(null, "active-password");
}
@@ -705,7 +784,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
out.endDocument();
stream.close();
journal.commit();
- sendChangedNotification();
+ sendChangedNotification(userHandle);
} catch (IOException e) {
try {
if (stream != null) {
@@ -718,20 +797,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- private void sendChangedNotification() {
+ private void sendChangedNotification(int userHandle) {
Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
long ident = Binder.clearCallingIdentity();
try {
- // TODO: This shouldn't be sent to all users, if DPM is per user.
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- private void loadSettingsLocked() {
- JournaledFile journal = makeJournaledFile();
+ private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
+ JournaledFile journal = makeJournaledFile(userHandle);
FileInputStream stream = null;
File file = journal.chooseForRead();
try {
@@ -760,40 +838,46 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
String name = parser.getAttributeValue(null, "name");
try {
DeviceAdminInfo dai = findAdmin(
- ComponentName.unflattenFromString(name));
+ ComponentName.unflattenFromString(name), userHandle);
+ if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
+ != userHandle)) {
+ Slog.w(TAG, "findAdmin returned an incorrect uid "
+ + dai.getActivityInfo().applicationInfo.uid + " for user "
+ + userHandle);
+ }
if (dai != null) {
ActiveAdmin ap = new ActiveAdmin(dai);
ap.readFromXml(parser);
- mAdminMap.put(ap.info.getComponent(), ap);
- mAdminList.add(ap);
+ policy.mAdminMap.put(ap.info.getComponent(), ap);
+ policy.mAdminList.add(ap);
}
} catch (RuntimeException e) {
Slog.w(TAG, "Failed loading admin " + name, e);
}
} else if ("failed-password-attempts".equals(tag)) {
- mFailedPasswordAttempts = Integer.parseInt(
+ policy.mFailedPasswordAttempts = Integer.parseInt(
parser.getAttributeValue(null, "value"));
XmlUtils.skipCurrentTag(parser);
} else if ("password-owner".equals(tag)) {
- mPasswordOwner = Integer.parseInt(
+ policy.mPasswordOwner = Integer.parseInt(
parser.getAttributeValue(null, "value"));
XmlUtils.skipCurrentTag(parser);
} else if ("active-password".equals(tag)) {
- mActivePasswordQuality = Integer.parseInt(
+ policy.mActivePasswordQuality = Integer.parseInt(
parser.getAttributeValue(null, "quality"));
- mActivePasswordLength = Integer.parseInt(
+ policy.mActivePasswordLength = Integer.parseInt(
parser.getAttributeValue(null, "length"));
- mActivePasswordUpperCase = Integer.parseInt(
+ policy.mActivePasswordUpperCase = Integer.parseInt(
parser.getAttributeValue(null, "uppercase"));
- mActivePasswordLowerCase = Integer.parseInt(
+ policy.mActivePasswordLowerCase = Integer.parseInt(
parser.getAttributeValue(null, "lowercase"));
- mActivePasswordLetters = Integer.parseInt(
+ policy.mActivePasswordLetters = Integer.parseInt(
parser.getAttributeValue(null, "letters"));
- mActivePasswordNumeric = Integer.parseInt(
+ policy.mActivePasswordNumeric = Integer.parseInt(
parser.getAttributeValue(null, "numeric"));
- mActivePasswordSymbols = Integer.parseInt(
+ policy.mActivePasswordSymbols = Integer.parseInt(
parser.getAttributeValue(null, "symbols"));
- mActivePasswordNonLetter = Integer.parseInt(
+ policy.mActivePasswordNonLetter = Integer.parseInt(
parser.getAttributeValue(null, "nonletter"));
XmlUtils.skipCurrentTag(parser);
} else {
@@ -827,24 +911,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// a sanity check in case the two get out of sync; this should
// never normally happen.
LockPatternUtils utils = new LockPatternUtils(mContext);
- if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
+ if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
Slog.w(TAG, "Active password quality 0x"
- + Integer.toHexString(mActivePasswordQuality)
+ + Integer.toHexString(policy.mActivePasswordQuality)
+ " does not match actual quality 0x"
+ Integer.toHexString(utils.getActivePasswordQuality()));
- mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
- mActivePasswordLength = 0;
- mActivePasswordUpperCase = 0;
- mActivePasswordLowerCase = 0;
- mActivePasswordLetters = 0;
- mActivePasswordNumeric = 0;
- mActivePasswordSymbols = 0;
- mActivePasswordNonLetter = 0;
+ policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ policy.mActivePasswordLength = 0;
+ policy.mActivePasswordUpperCase = 0;
+ policy.mActivePasswordLowerCase = 0;
+ policy.mActivePasswordLetters = 0;
+ policy.mActivePasswordNumeric = 0;
+ policy.mActivePasswordSymbols = 0;
+ policy.mActivePasswordNonLetter = 0;
}
- validatePasswordOwnerLocked();
- syncDeviceCapabilitiesLocked();
- updateMaximumTimeToLockLocked();
+ validatePasswordOwnerLocked(policy);
+ syncDeviceCapabilitiesLocked(policy);
+ updateMaximumTimeToLockLocked(policy);
}
static void validateQualityConstant(int quality) {
@@ -862,19 +946,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ Integer.toHexString(quality));
}
- void validatePasswordOwnerLocked() {
- if (mPasswordOwner >= 0) {
+ void validatePasswordOwnerLocked(DevicePolicyData policy) {
+ if (policy.mPasswordOwner >= 0) {
boolean haveOwner = false;
- for (int i=mAdminList.size()-1; i>=0; i--) {
- if (mAdminList.get(i).getUid() == mPasswordOwner) {
+ for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
+ if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) {
haveOwner = true;
break;
}
}
if (!haveOwner) {
- Slog.w(TAG, "Previous password owner " + mPasswordOwner
+ Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
+ " no longer active; disabling");
- mPasswordOwner = -1;
+ policy.mPasswordOwner = -1;
}
}
}
@@ -883,11 +967,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* Pushes down policy information to the system for any policies related to general device
* capabilities that need to be enforced by lower level services (e.g. Camera services).
*/
- void syncDeviceCapabilitiesLocked() {
+ void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
// Ensure the status of the camera is synced down to the system. Interested native services
// should monitor this value and act accordingly.
boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
- boolean cameraDisabled = getCameraDisabled(null);
+ boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
if (cameraDisabled != systemState) {
long token = Binder.clearCallingIdentity();
try {
@@ -903,19 +987,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
public void systemReady() {
synchronized (this) {
- loadSettingsLocked();
+ loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
}
}
- private void handlePasswordExpirationNotification() {
+ private void handlePasswordExpirationNotification(DevicePolicyData policy) {
synchronized (this) {
final long now = System.currentTimeMillis();
- final int N = mAdminList.size();
+ final int N = policy.mAdminList.size();
if (N <= 0) {
return;
}
for (int i=0; i < N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
&& admin.passwordExpirationTimeout > 0L
&& admin.passwordExpirationDate > 0L
@@ -923,7 +1007,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
}
}
- setExpirationAlarmCheckLocked(mContext);
+ setExpirationAlarmCheckLocked(mContext, policy);
}
}
@@ -931,27 +1015,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* @param adminReceiver The admin to add
* @param refreshing true = update an active admin, no error
*/
- public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
+ public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ enforceCrossUserPermission(userHandle);
- DeviceAdminInfo info = findAdmin(adminReceiver);
+ DevicePolicyData policy = getUserData(userHandle);
+ DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
if (info == null) {
throw new IllegalArgumentException("Bad admin: " + adminReceiver);
}
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
- if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
+ if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
throw new IllegalArgumentException("Admin is already added");
}
ActiveAdmin newAdmin = new ActiveAdmin(info);
- mAdminMap.put(adminReceiver, newAdmin);
+ policy.mAdminMap.put(adminReceiver, newAdmin);
int replaceIndex = -1;
if (refreshing) {
- final int N = mAdminList.size();
+ final int N = policy.mAdminList.size();
for (int i=0; i < N; i++) {
- ActiveAdmin oldAdmin = mAdminList.get(i);
+ ActiveAdmin oldAdmin = policy.mAdminList.get(i);
if (oldAdmin.info.getComponent().equals(adminReceiver)) {
replaceIndex = i;
break;
@@ -959,11 +1045,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
if (replaceIndex == -1) {
- mAdminList.add(newAdmin);
+ policy.mAdminList.add(newAdmin);
} else {
- mAdminList.set(replaceIndex, newAdmin);
+ policy.mAdminList.set(replaceIndex, newAdmin);
}
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -971,15 +1057,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public boolean isAdminActive(ComponentName adminReceiver) {
+ public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
- return getActiveAdminUncheckedLocked(adminReceiver) != null;
+ return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
}
}
- public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
+ public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
- ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
+ ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (administrator == null) {
throw new SecurityException("No active admin " + adminReceiver);
}
@@ -987,25 +1075,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public List<ComponentName> getActiveAdmins() {
+ public List<ComponentName> getActiveAdmins(int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
if (N <= 0) {
return null;
}
ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
for (int i=0; i<N; i++) {
- res.add(mAdminList.get(i).info.getComponent());
+ res.add(policy.mAdminList.get(i).info.getComponent());
}
return res;
}
}
- public boolean packageHasActiveAdmins(String packageName) {
+ public boolean packageHasActiveAdmins(String packageName, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
+ if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
return true;
}
}
@@ -1013,9 +1105,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public void removeActiveAdmin(ComponentName adminReceiver) {
+ public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (admin == null) {
return;
}
@@ -1025,15 +1118,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
long ident = Binder.clearCallingIdentity();
try {
- removeActiveAdminLocked(adminReceiver);
+ removeActiveAdminLocked(adminReceiver, userHandle);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
- public void setPasswordQuality(ComponentName who, int quality) {
+ public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
validateQualityConstant(quality);
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1043,23 +1137,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.passwordQuality != quality) {
ap.passwordQuality = quality;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
}
}
- public int getPasswordQuality(ComponentName who) {
+ public int getPasswordQuality(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ DevicePolicyData policy = getUserData(userHandle);
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.passwordQuality : mode;
}
- final int N = mAdminList.size();
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (mode < admin.passwordQuality) {
mode = admin.passwordQuality;
}
@@ -1068,7 +1164,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public void setPasswordMinimumLength(ComponentName who, int length) {
+ public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -1077,23 +1174,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordLength != length) {
ap.minimumPasswordLength = length;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
}
}
- public int getPasswordMinimumLength(ComponentName who) {
+ public int getPasswordMinimumLength(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
+ DevicePolicyData policy = getUserData(userHandle);
int length = 0;
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordLength : length;
}
- final int N = mAdminList.size();
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordLength) {
length = admin.minimumPasswordLength;
}
@@ -1102,7 +1201,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public void setPasswordHistoryLength(ComponentName who, int length) {
+ public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -1111,23 +1211,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.passwordHistoryLength != length) {
ap.passwordHistoryLength = length;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
}
}
- public int getPasswordHistoryLength(ComponentName who) {
+ public int getPasswordHistoryLength(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
+ DevicePolicyData policy = getUserData(userHandle);
int length = 0;
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.passwordHistoryLength : length;
}
- final int N = mAdminList.size();
+ final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.passwordHistoryLength) {
length = admin.passwordHistoryLength;
}
@@ -1136,7 +1238,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
+ public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -1155,8 +1258,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
.format(new Date(expiration)));
}
- saveSettingsLocked();
- setExpirationAlarmCheckLocked(mContext); // in case this is the first one
+ saveSettingsLocked(userHandle);
+ // in case this is the first one
+ setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
}
}
@@ -1164,17 +1268,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* Return a single admin's expiration cycle time, or the min of all cycle times.
* Returns 0 if not configured.
*/
- public long getPasswordExpirationTimeout(ComponentName who) {
+ public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.passwordExpirationTimeout : 0L;
}
long timeout = 0L;
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
&& timeout > admin.passwordExpirationTimeout)) {
timeout = admin.passwordExpirationTimeout;
@@ -1188,16 +1294,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* Return a single admin's expiration date/time, or the min (soonest) for all admins.
* Returns 0 if not configured.
*/
- private long getPasswordExpirationLocked(ComponentName who) {
+ private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.passwordExpirationDate : 0L;
}
long timeout = 0L;
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (timeout == 0L || (admin.passwordExpirationDate != 0
&& timeout > admin.passwordExpirationDate)) {
timeout = admin.passwordExpirationDate;
@@ -1206,13 +1313,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return timeout;
}
- public long getPasswordExpiration(ComponentName who) {
+ public long getPasswordExpiration(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
- return getPasswordExpirationLocked(who);
+ return getPasswordExpirationLocked(who, userHandle);
}
}
- public void setPasswordMinimumUpperCase(ComponentName who, int length) {
+ public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -1221,23 +1330,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordUpperCase != length) {
ap.minimumPasswordUpperCase = length;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
}
}
- public int getPasswordMinimumUpperCase(ComponentName who) {
+ public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordUpperCase : length;
}
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordUpperCase) {
length = admin.minimumPasswordUpperCase;
}
@@ -1246,7 +1357,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public void setPasswordMinimumLowerCase(ComponentName who, int length) {
+ public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -1255,23 +1367,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordLowerCase != length) {
ap.minimumPasswordLowerCase = length;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
}
}
- public int getPasswordMinimumLowerCase(ComponentName who) {
+ public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordLowerCase : length;
}
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordLowerCase) {
length = admin.minimumPasswordLowerCase;
}
@@ -1280,7 +1394,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public void setPasswordMinimumLetters(ComponentName who, int length) {
+ public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -1289,23 +1404,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordLetters != length) {
ap.minimumPasswordLetters = length;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
}
}
- public int getPasswordMinimumLetters(ComponentName who) {
+ public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordLetters : length;
}
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordLetters) {
length = admin.minimumPasswordLetters;
}
@@ -1314,7 +1431,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public void setPasswordMinimumNumeric(ComponentName who, int length) {
+ public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -1323,23 +1441,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordNumeric != length) {
ap.minimumPasswordNumeric = length;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
}
}
- public int getPasswordMinimumNumeric(ComponentName who) {
+ public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordNumeric : length;
}
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordNumeric) {
length = admin.minimumPasswordNumeric;
}
@@ -1348,7 +1468,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public void setPasswordMinimumSymbols(ComponentName who, int length) {
+ public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -1357,23 +1478,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordSymbols != length) {
ap.minimumPasswordSymbols = length;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
}
}
- public int getPasswordMinimumSymbols(ComponentName who) {
+ public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordSymbols : length;
}
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordSymbols) {
length = admin.minimumPasswordSymbols;
}
@@ -1382,7 +1505,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public void setPasswordMinimumNonLetter(ComponentName who, int length) {
+ public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -1391,23 +1515,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordNonLetter != length) {
ap.minimumPasswordNonLetter = length;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
}
}
- public int getPasswordMinimumNonLetter(ComponentName who) {
+ public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordNonLetter : length;
}
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordNonLetter) {
length = admin.minimumPasswordNonLetter;
}
@@ -1416,39 +1542,43 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public boolean isActivePasswordSufficient() {
+ public boolean isActivePasswordSufficient(int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
+ DevicePolicyData policy = getUserData(userHandle);
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
- if (mActivePasswordQuality < getPasswordQuality(null)
- || mActivePasswordLength < getPasswordMinimumLength(null)) {
+ if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
+ || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
return false;
}
- if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
+ if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
return true;
}
- return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
- && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
- && mActivePasswordLetters >= getPasswordMinimumLetters(null)
- && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
- && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
- && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
+ return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
+ && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
+ && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
+ && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
+ && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
+ && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
}
}
- public int getCurrentFailedPasswordAttempts() {
+ public int getCurrentFailedPasswordAttempts(int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
- return mFailedPasswordAttempts;
+ return getUserData(userHandle).mFailedPasswordAttempts;
}
}
- public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
+ public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
@@ -1458,23 +1588,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
if (ap.maximumFailedPasswordsForWipe != num) {
ap.maximumFailedPasswordsForWipe = num;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
}
}
- public int getMaximumFailedPasswordsForWipe(ComponentName who) {
+ public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
+ DevicePolicyData policy = getUserData(userHandle);
int count = 0;
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.maximumFailedPasswordsForWipe : count;
}
- final int N = mAdminList.size();
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (count == 0) {
count = admin.maximumFailedPasswordsForWipe;
} else if (admin.maximumFailedPasswordsForWipe != 0
@@ -1486,14 +1618,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public boolean resetPassword(String password, int flags) {
+ public boolean resetPassword(String password, int flags, int userHandle) {
+ enforceCrossUserPermission(userHandle);
int quality;
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
- quality = getPasswordQuality(null);
+ quality = getPasswordQuality(null, userHandle);
if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
int realQuality = LockPatternUtils.computePasswordQuality(password);
if (realQuality < quality
@@ -1506,7 +1639,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
quality = Math.max(realQuality, quality);
}
- int length = getPasswordMinimumLength(null);
+ int length = getPasswordMinimumLength(null, userHandle);
if (password.length() < length) {
Slog.w(TAG, "resetPassword: password length " + password.length()
+ " does not meet required length " + length);
@@ -1535,13 +1668,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
nonletter++;
}
}
- int neededLetters = getPasswordMinimumLetters(null);
+ int neededLetters = getPasswordMinimumLetters(null, userHandle);
if(letters < neededLetters) {
Slog.w(TAG, "resetPassword: number of letters " + letters
+ " does not meet required number of letters " + neededLetters);
return false;
}
- int neededNumbers = getPasswordMinimumNumeric(null);
+ int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
if (numbers < neededNumbers) {
Slog
.w(TAG, "resetPassword: number of numerical digits " + numbers
@@ -1549,27 +1682,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ neededNumbers);
return false;
}
- int neededLowerCase = getPasswordMinimumLowerCase(null);
+ int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
if (lowercase < neededLowerCase) {
Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
+ " does not meet required number of lowercase letters "
+ neededLowerCase);
return false;
}
- int neededUpperCase = getPasswordMinimumUpperCase(null);
+ int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
if (uppercase < neededUpperCase) {
Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
+ " does not meet required number of uppercase letters "
+ neededUpperCase);
return false;
}
- int neededSymbols = getPasswordMinimumSymbols(null);
+ int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
if (symbols < neededSymbols) {
Slog.w(TAG, "resetPassword: number of special symbols " + symbols
+ " does not meet required number of special symbols " + neededSymbols);
return false;
}
- int neededNonLetter = getPasswordMinimumNonLetter(null);
+ int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
if (nonletter < neededNonLetter) {
Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
+ " does not meet required number of non-letter characters "
@@ -1580,7 +1713,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
int callingUid = Binder.getCallingUid();
- if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
+ DevicePolicyData policy = getUserData(userHandle);
+ if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
return false;
}
@@ -1590,13 +1724,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long ident = Binder.clearCallingIdentity();
try {
LockPatternUtils utils = new LockPatternUtils(mContext);
- utils.saveLockPassword(password, quality);
+ utils.saveLockPassword(password, quality, false, userHandle);
synchronized (this) {
int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
!= 0 ? callingUid : -1;
- if (mPasswordOwner != newOwner) {
- mPasswordOwner = newOwner;
- saveSettingsLocked();
+ if (policy.mPasswordOwner != newOwner) {
+ policy.mPasswordOwner = newOwner;
+ saveSettingsLocked(userHandle);
}
}
} finally {
@@ -1606,7 +1740,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return true;
}
- public void setMaximumTimeToLock(ComponentName who, long timeMs) {
+ public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -1615,15 +1750,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
if (ap.maximumTimeToUnlock != timeMs) {
ap.maximumTimeToUnlock = timeMs;
- saveSettingsLocked();
- updateMaximumTimeToLockLocked();
+ saveSettingsLocked(userHandle);
+ updateMaximumTimeToLockLocked(getUserData(userHandle));
}
}
}
- void updateMaximumTimeToLockLocked() {
- long timeMs = getMaximumTimeToLock(null);
- if (mLastMaximumTimeToLock == timeMs) {
+ void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
+ long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
+ if (policy.mLastMaximumTimeToLock == timeMs) {
return;
}
@@ -1638,7 +1773,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
}
- mLastMaximumTimeToLock = timeMs;
+ policy.mLastMaximumTimeToLock = timeMs;
try {
getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
@@ -1650,18 +1785,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public long getMaximumTimeToLock(ComponentName who) {
+ public long getMaximumTimeToLock(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
long time = 0;
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.maximumTimeToUnlock : time;
}
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (time == 0) {
time = admin.maximumTimeToUnlock;
} else if (admin.maximumTimeToUnlock != 0
@@ -1679,17 +1816,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// so try to retrieve it to check that the caller is one.
getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
- long ident = Binder.clearCallingIdentity();
- try {
- // Power off the display
- getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
- PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
- // Ensure the device is locked
- getWindowManager().lockNow();
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ lockNowUnchecked();
+ }
+ }
+
+ private void lockNowUnchecked() {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ // Power off the display
+ getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
+ // Ensure the device is locked
+ getWindowManager().lockNow();
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -1719,7 +1860,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- public void wipeData(int flags) {
+ public void wipeData(int flags, final int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
@@ -1727,19 +1869,35 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_WIPE_DATA);
long ident = Binder.clearCallingIdentity();
try {
- wipeDataLocked(flags);
+ if (userHandle == UserHandle.USER_OWNER) {
+ wipeDataLocked(flags);
+ } else {
+ lockNowUnchecked();
+ mHandler.post(new Runnable() {
+ public void run() {
+ try {
+ ActivityManagerNative.getDefault().switchUser(0);
+ ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
+ .removeUser(userHandle);
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ }
+ }
+ });
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
- public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
+ public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
+ enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
synchronized (this) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
if (admin == null) {
try {
result.sendResult(null);
@@ -1749,7 +1907,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
intent.setComponent(admin.info.getComponent());
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
+ mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle),
null, new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -1763,34 +1921,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
public void setActivePasswordState(int quality, int length, int letters, int uppercase,
- int lowercase, int numbers, int symbols, int nonletter) {
+ int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
+ enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ DevicePolicyData p = getUserData(userHandle);
validateQualityConstant(quality);
synchronized (this) {
- if (mActivePasswordQuality != quality || mActivePasswordLength != length
- || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
- || mActivePasswordUpperCase != uppercase
- || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
- || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
+ if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
+ || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
+ || p.mActivePasswordUpperCase != uppercase
+ || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
+ || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
long ident = Binder.clearCallingIdentity();
try {
- mActivePasswordQuality = quality;
- mActivePasswordLength = length;
- mActivePasswordLetters = letters;
- mActivePasswordLowerCase = lowercase;
- mActivePasswordUpperCase = uppercase;
- mActivePasswordNumeric = numbers;
- mActivePasswordSymbols = symbols;
- mActivePasswordNonLetter = nonletter;
- mFailedPasswordAttempts = 0;
- saveSettingsLocked();
- updatePasswordExpirationsLocked();
- setExpirationAlarmCheckLocked(mContext);
+ p.mActivePasswordQuality = quality;
+ p.mActivePasswordLength = length;
+ p.mActivePasswordLetters = letters;
+ p.mActivePasswordLowerCase = lowercase;
+ p.mActivePasswordUpperCase = uppercase;
+ p.mActivePasswordNumeric = numbers;
+ p.mActivePasswordSymbols = symbols;
+ p.mActivePasswordNonLetter = nonletter;
+ p.mFailedPasswordAttempts = 0;
+ saveSettingsLocked(userHandle);
+ updatePasswordExpirationsLocked(userHandle);
+ setExpirationAlarmCheckLocked(mContext, p);
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
- DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -1801,55 +1961,60 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
/**
* Called any time the device password is updated. Resets all password expiration clocks.
*/
- private void updatePasswordExpirationsLocked() {
- final int N = mAdminList.size();
+ private void updatePasswordExpirationsLocked(int userHandle) {
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
if (N > 0) {
for (int i=0; i<N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
long timeout = admin.passwordExpirationTimeout;
long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
admin.passwordExpirationDate = expiration;
}
}
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
}
- public void reportFailedPasswordAttempt() {
+ public void reportFailedPasswordAttempt(int userHandle) {
+ enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
synchronized (this) {
+ DevicePolicyData policy = getUserData(userHandle);
long ident = Binder.clearCallingIdentity();
try {
- mFailedPasswordAttempts++;
- saveSettingsLocked();
- int max = getMaximumFailedPasswordsForWipe(null);
- if (max > 0 && mFailedPasswordAttempts >= max) {
+ policy.mFailedPasswordAttempts++;
+ saveSettingsLocked(userHandle);
+ int max = getMaximumFailedPasswordsForWipe(null, userHandle);
+ if (max > 0 && policy.mFailedPasswordAttempts >= max) {
wipeDataLocked(0);
}
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
- DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
- public void reportSuccessfulPasswordAttempt() {
+ public void reportSuccessfulPasswordAttempt(int userHandle) {
+ enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
synchronized (this) {
- if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
+ DevicePolicyData policy = getUserData(userHandle);
+ if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
long ident = Binder.clearCallingIdentity();
try {
- mFailedPasswordAttempts = 0;
- mPasswordOwner = -1;
- saveSettingsLocked();
+ policy.mFailedPasswordAttempts = 0;
+ policy.mPasswordOwner = -1;
+ saveSettingsLocked(userHandle);
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
- DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -1858,26 +2023,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
- String exclusionList) {
+ String exclusionList, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized(this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
+ // Only check if owner has set global proxy. We don't allow other users to set it.
+ DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
// Scan through active admins and find if anyone has already
// set the global proxy.
- Set<ComponentName> compSet = mAdminMap.keySet();
+ Set<ComponentName> compSet = policy.mAdminMap.keySet();
for (ComponentName component : compSet) {
- ActiveAdmin ap = mAdminMap.get(component);
+ ActiveAdmin ap = policy.mAdminMap.get(component);
if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
// Another admin already sets the global proxy
// Return it to the caller.
return component;
}
}
+
+ // If the user is not the owner, don't set the global proxy. Fail silently.
+ if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+ Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
+ + userHandle + " is not permitted.");
+ return null;
+ }
if (proxySpec == null) {
admin.specifiesGlobalProxy = false;
admin.globalProxySpec = null;
@@ -1892,19 +2067,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Reset the global proxy accordingly
// Do this using system permissions, as apps cannot write to secure settings
long origId = Binder.clearCallingIdentity();
- resetGlobalProxyLocked();
+ resetGlobalProxyLocked(policy);
Binder.restoreCallingIdentity(origId);
return null;
}
}
- public ComponentName getGlobalProxyAdmin() {
+ public ComponentName getGlobalProxyAdmin(int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized(this) {
+ DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
// Scan through active admins and find if anyone has already
// set the global proxy.
- final int N = mAdminList.size();
+ final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
- ActiveAdmin ap = mAdminList.get(i);
+ ActiveAdmin ap = policy.mAdminList.get(i);
if (ap.specifiesGlobalProxy) {
// Device admin sets the global proxy
// Return it to the caller.
@@ -1916,10 +2093,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return null;
}
- private void resetGlobalProxyLocked() {
- final int N = mAdminList.size();
+ private void resetGlobalProxyLocked(DevicePolicyData policy) {
+ final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
- ActiveAdmin ap = mAdminList.get(i);
+ ActiveAdmin ap = policy.mAdminList.get(i);
if (ap.specifiesGlobalProxy) {
saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
return;
@@ -1957,12 +2134,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* Set the storage encryption request for a single admin. Returns the new total request
* status (for all admins).
*/
- public int setStorageEncryption(ComponentName who, boolean encrypt) {
+ public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
// Check for permissions
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
+ // Only owner can set storage encryption
+ if (userHandle != UserHandle.USER_OWNER
+ || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+ Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
+ + UserHandle.getCallingUserId() + " is not permitted.");
+ return 0;
+ }
+
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
@@ -1974,14 +2160,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// (1) Record the value for the admin so it's sticky
if (ap.encryptionRequested != encrypt) {
ap.encryptionRequested = encrypt;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
+ DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
// (2) Compute "max" for all admins
boolean newRequested = false;
- final int N = mAdminList.size();
+ final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
- newRequested |= mAdminList.get(i).encryptionRequested;
+ newRequested |= policy.mAdminList.get(i).encryptionRequested;
}
// Notify OS of new request
@@ -1998,20 +2185,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* Get the current storage encryption request status for a given admin, or aggregate of all
* active admins.
*/
- public boolean getStorageEncryption(ComponentName who) {
+ public boolean getStorageEncryption(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
// Check for permissions if a particular caller is specified
if (who != null) {
// When checking for a single caller, status is based on caller's request
- ActiveAdmin ap = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
return ap != null ? ap.encryptionRequested : false;
}
// If no particular caller is specified, return the aggregate set of requests.
// This is short circuited by returning true on the first hit.
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
- if (mAdminList.get(i).encryptionRequested) {
+ if (policy.mAdminList.get(i).encryptionRequested) {
return true;
}
}
@@ -2022,7 +2211,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
/**
* Get the current encryption status of the device.
*/
- public int getStorageEncryptionStatus() {
+ public int getStorageEncryptionStatus(int userHandle) {
+ enforceCrossUserPermission(userHandle);
return getEncryptionStatus();
}
@@ -2069,7 +2259,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
/**
* Disables all device cameras according to the specified admin.
*/
- public void setCameraDisabled(ComponentName who, boolean disabled) {
+ public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -2078,9 +2269,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
if (ap.disableCamera != disabled) {
ap.disableCamera = disabled;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
- syncDeviceCapabilitiesLocked();
+ syncDeviceCapabilitiesLocked(getUserData(userHandle));
}
}
@@ -2088,17 +2279,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* Gets whether or not all device cameras are disabled for a given admin, or disabled for any
* active admins.
*/
- public boolean getCameraDisabled(ComponentName who) {
+ public boolean getCameraDisabled(ComponentName who, int userHandle) {
synchronized (this) {
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return (admin != null) ? admin.disableCamera : false;
}
+ DevicePolicyData policy = getUserData(userHandle);
// Determine whether or not the device camera is disabled for any active admins.
- final int N = mAdminList.size();
+ final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
if (admin.disableCamera) {
return true;
}
@@ -2110,7 +2302,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
/**
* Selectively disable keyguard widgets.
*/
- public void setKeyguardWidgetsDisabled(ComponentName who, int which) {
+ public void setKeyguardWidgetsDisabled(ComponentName who, int which, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
@@ -2119,9 +2312,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_WIDGETS);
if ((ap.disableKeyguardWidgets & which) != which) {
ap.disableKeyguardWidgets |= which;
- saveSettingsLocked();
+ saveSettingsLocked(userHandle);
}
- syncDeviceCapabilitiesLocked();
+ syncDeviceCapabilitiesLocked(getUserData(userHandle));
}
}
@@ -2129,24 +2322,39 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* Gets the disabled state for widgets in keyguard for the given admin,
* or the aggregate of all active admins if who is null.
*/
- public int getKeyguardWidgetsDisabled(ComponentName who) {
+ public int getKeyguardWidgetsDisabled(ComponentName who, int userHandle) {
+ enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return (admin != null) ? admin.disableKeyguardWidgets : 0;
}
// Determine whether or not keyguard widgets are disabled for any active admins.
- final int N = mAdminList.size();
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
int which = 0;
for (int i = 0; i < N; i++) {
- ActiveAdmin admin = mAdminList.get(i);
+ ActiveAdmin admin = policy.mAdminList.get(i);
which |= admin.disableKeyguardWidgets;
}
return which;
}
}
+ private void enforceCrossUserPermission(int userHandle) {
+ if (userHandle < 0) {
+ throw new IllegalArgumentException("Invalid userId " + userHandle);
+ }
+ final int callingUid = Binder.getCallingUid();
+ if (userHandle == UserHandle.getUserId(callingUid)) return;
+ if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
+ + " INTERACT_ACROSS_USERS_FULL permission");
+ }
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -2163,19 +2371,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
p.println("Current Device Policy Manager state:");
- p.println(" Enabled Device Admins:");
- final int N = mAdminList.size();
- for (int i=0; i<N; i++) {
- ActiveAdmin ap = mAdminList.get(i);
- if (ap != null) {
- pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
- pw.println(":");
- ap.dump(" ", pw);
+ int userCount = mUserData.size();
+ for (int u = 0; u < userCount; u++) {
+ DevicePolicyData policy = getUserData(mUserData.keyAt(u));
+ p.println(" Enabled Device Admins (User " + policy.mUserHandle + "):");
+ final int N = policy.mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin ap = policy.mAdminList.get(i);
+ if (ap != null) {
+ pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
+ pw.println(":");
+ ap.dump(" ", pw);
+ }
}
- }
- pw.println(" ");
- pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
+ pw.println(" ");
+ pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner);
+ }
}
}
}
diff --git a/services/java/com/android/server/DreamController.java b/services/java/com/android/server/DreamController.java
new file mode 100644
index 0000000..498e581
--- /dev/null
+++ b/services/java/com/android/server/DreamController.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.IBinder.DeathRecipient;
+import android.service.dreams.IDreamService;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import com.android.internal.util.DumpUtils;
+
+import java.io.PrintWriter;
+import java.util.NoSuchElementException;
+
+/**
+ * Internal controller for starting and stopping the current dream and managing related state.
+ *
+ * Assumes all operations (except {@link #dump}) are called from a single thread.
+ */
+final class DreamController {
+ private static final boolean DEBUG = true;
+ private static final String TAG = DreamController.class.getSimpleName();
+
+ public interface Listener {
+ void onDreamStopped(boolean wasTest);
+ }
+
+ private final Context mContext;
+ private final IWindowManager mIWindowManager;
+ private final DeathRecipient mDeathRecipient;
+ private final ServiceConnection mServiceConnection;
+ private final Listener mListener;
+
+ private Handler mHandler;
+
+ private ComponentName mCurrentDreamComponent;
+ private IDreamService mCurrentDream;
+ private Binder mCurrentDreamToken;
+ private boolean mCurrentDreamIsTest;
+
+ public DreamController(Context context, DeathRecipient deathRecipient,
+ ServiceConnection serviceConnection, Listener listener) {
+ mContext = context;
+ mDeathRecipient = deathRecipient;
+ mServiceConnection = serviceConnection;
+ mListener = listener;
+ mIWindowManager = WindowManagerGlobal.getWindowManagerService();
+ }
+
+ public void setHandler(Handler handler) {
+ mHandler = handler;
+ }
+
+ public void dump(PrintWriter pw) {
+ if (mHandler== null || pw == null) {
+ return;
+ }
+ DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
+ @Override
+ public void dump(PrintWriter pw) {
+ pw.print(" component="); pw.println(mCurrentDreamComponent);
+ pw.print(" token="); pw.println(mCurrentDreamToken);
+ pw.print(" dream="); pw.println(mCurrentDream);
+ }
+ }, pw, 200);
+ }
+
+ public void start(ComponentName dream, boolean isTest) {
+ if (DEBUG) Slog.v(TAG, String.format("start(%s,%s)", dream, isTest));
+
+ if (mCurrentDreamComponent != null ) {
+ if (dream.equals(mCurrentDreamComponent) && isTest == mCurrentDreamIsTest) {
+ if (DEBUG) Slog.v(TAG, "Dream is already started: " + dream);
+ return;
+ }
+ // stop the current dream before starting a new one
+ stop();
+ }
+
+ mCurrentDreamComponent = dream;
+ mCurrentDreamIsTest = isTest;
+ mCurrentDreamToken = new Binder();
+
+ try {
+ if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurrentDreamToken
+ + " for window type: " + WindowManager.LayoutParams.TYPE_DREAM);
+ mIWindowManager.addWindowToken(mCurrentDreamToken,
+ WindowManager.LayoutParams.TYPE_DREAM);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to add window token.");
+ stop();
+ return;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_MAIN)
+ .setComponent(mCurrentDreamComponent)
+ .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ .putExtra("android.dreams.TEST", mCurrentDreamIsTest);
+
+ if (!mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)) {
+ Slog.w(TAG, "Unable to bind service");
+ stop();
+ return;
+ }
+ if (DEBUG) Slog.v(TAG, "Bound service");
+ }
+
+ public void attach(ComponentName name, IBinder dream) {
+ if (DEBUG) Slog.v(TAG, String.format("attach(%s,%s)", name, dream));
+ mCurrentDream = IDreamService.Stub.asInterface(dream);
+
+ boolean linked = linkDeathRecipient(dream);
+ if (!linked) {
+ stop();
+ return;
+ }
+
+ try {
+ if (DEBUG) Slog.v(TAG, "Attaching with token:" + mCurrentDreamToken);
+ mCurrentDream.attach(mCurrentDreamToken);
+ } catch (Throwable ex) {
+ Slog.w(TAG, "Unable to send window token to dream:" + ex);
+ stop();
+ }
+ }
+
+ public void stop() {
+ if (DEBUG) Slog.v(TAG, "stop()");
+
+ if (mCurrentDream != null) {
+ unlinkDeathRecipient(mCurrentDream.asBinder());
+
+ if (DEBUG) Slog.v(TAG, "Unbinding: " + mCurrentDreamComponent + " service: " + mCurrentDream);
+ mContext.unbindService(mServiceConnection);
+ }
+ if (mCurrentDreamToken != null) {
+ removeWindowToken(mCurrentDreamToken);
+ }
+
+ final boolean wasTest = mCurrentDreamIsTest;
+ mCurrentDream = null;
+ mCurrentDreamToken = null;
+ mCurrentDreamComponent = null;
+ mCurrentDreamIsTest = false;
+
+ if (mListener != null && mHandler != null) {
+ mHandler.post(new Runnable(){
+ @Override
+ public void run() {
+ mListener.onDreamStopped(wasTest);
+ }});
+ }
+ }
+
+ public void stopSelf(IBinder token) {
+ if (DEBUG) Slog.v(TAG, String.format("stopSelf(%s)", token));
+ if (token == null || token != mCurrentDreamToken) {
+ Slog.w(TAG, "Stop requested for non-current dream token: " + token);
+ } else {
+ stop();
+ }
+ }
+
+ private void removeWindowToken(IBinder token) {
+ if (DEBUG) Slog.v(TAG, "Removing window token: " + token);
+ try {
+ mIWindowManager.removeWindowToken(token);
+ } catch (Throwable e) {
+ Slog.w(TAG, "Error removing window token", e);
+ }
+ }
+
+ private boolean linkDeathRecipient(IBinder dream) {
+ if (DEBUG) Slog.v(TAG, "Linking death recipient");
+ try {
+ dream.linkToDeath(mDeathRecipient, 0);
+ return true;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to link death recipient", e);
+ return false;
+ }
+ }
+
+ private void unlinkDeathRecipient(IBinder dream) {
+ if (DEBUG) Slog.v(TAG, "Unlinking death recipient");
+ try {
+ dream.unlinkToDeath(mDeathRecipient, 0);
+ } catch (NoSuchElementException e) {
+ // we tried
+ }
+ }
+
+} \ No newline at end of file
diff --git a/services/java/com/android/server/DreamManagerService.java b/services/java/com/android/server/DreamManagerService.java
new file mode 100644
index 0000000..b02ea7f
--- /dev/null
+++ b/services/java/com/android/server/DreamManagerService.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static android.provider.Settings.Secure.SCREENSAVER_COMPONENTS;
+import static android.provider.Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT;
+
+import android.app.ActivityManagerNative;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.dreams.Dream;
+import android.service.dreams.IDreamManager;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Service api for managing dreams.
+ *
+ * @hide
+ */
+public final class DreamManagerService
+ extends IDreamManager.Stub
+ implements ServiceConnection {
+ private static final boolean DEBUG = true;
+ private static final String TAG = DreamManagerService.class.getSimpleName();
+
+ private static final Intent mDreamingStartedIntent = new Intent(Dream.ACTION_DREAMING_STARTED)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ private static final Intent mDreamingStoppedIntent = new Intent(Dream.ACTION_DREAMING_STOPPED)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+
+ private final Object mLock = new Object();
+ private final DreamController mController;
+ private final DreamControllerHandler mHandler;
+ private final Context mContext;
+
+ private final CurrentUserManager mCurrentUserManager = new CurrentUserManager();
+
+ private final DeathRecipient mAwakenOnBinderDeath = new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ if (DEBUG) Slog.v(TAG, "binderDied()");
+ awaken();
+ }
+ };
+
+ private final DreamController.Listener mControllerListener = new DreamController.Listener() {
+ @Override
+ public void onDreamStopped(boolean wasTest) {
+ synchronized(mLock) {
+ setDreamingLocked(false, wasTest);
+ }
+ }};
+
+ private boolean mIsDreaming;
+
+ public DreamManagerService(Context context) {
+ if (DEBUG) Slog.v(TAG, "DreamManagerService startup");
+ mContext = context;
+ mController = new DreamController(context, mAwakenOnBinderDeath, this, mControllerListener);
+ mHandler = new DreamControllerHandler(mController);
+ mController.setHandler(mHandler);
+ }
+
+ public void systemReady() {
+ mCurrentUserManager.init(mContext);
+
+ if (DEBUG) Slog.v(TAG, "Ready to dream!");
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+ pw.println("Dreamland:");
+ mController.dump(pw);
+ mCurrentUserManager.dump(pw);
+ }
+
+ // begin IDreamManager api
+ @Override
+ public ComponentName[] getDreamComponents() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+ int userId = UserHandle.getCallingUserId();
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getDreamComponentsForUser(userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void setDreamComponents(ComponentName[] componentNames) {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+ int userId = UserHandle.getCallingUserId();
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ SCREENSAVER_COMPONENTS,
+ componentsToString(componentNames),
+ userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public ComponentName getDefaultDreamComponent() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+ int userId = UserHandle.getCallingUserId();
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ SCREENSAVER_DEFAULT_COMPONENT,
+ userId);
+ return name == null ? null : ComponentName.unflattenFromString(name);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ }
+
+ @Override
+ public boolean isDreaming() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+ return mIsDreaming;
+ }
+
+ @Override
+ public void dream() {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) Slog.v(TAG, "Dream now");
+ ComponentName[] dreams = getDreamComponentsForUser(mCurrentUserManager.getCurrentUserId());
+ ComponentName firstDream = dreams != null && dreams.length > 0 ? dreams[0] : null;
+ if (firstDream != null) {
+ mHandler.requestStart(firstDream, false /*isTest*/);
+ synchronized (mLock) {
+ setDreamingLocked(true, false /*isTest*/);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void testDream(ComponentName dream) {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) Slog.v(TAG, "Test dream name=" + dream);
+ if (dream != null) {
+ mHandler.requestStart(dream, true /*isTest*/);
+ synchronized (mLock) {
+ setDreamingLocked(true, true /*isTest*/);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ }
+
+ @Override
+ public void awaken() {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) Slog.v(TAG, "Wake up");
+ mHandler.requestStop();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void awakenSelf(IBinder token) {
+ // requires no permission, called by Dream from an arbitrary process
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) Slog.v(TAG, "Wake up from dream: " + token);
+ if (token != null) {
+ mHandler.requestStopSelf(token);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ // end IDreamManager api
+
+ // begin ServiceConnection
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder dream) {
+ if (DEBUG) Slog.v(TAG, "Service connected: " + name + " binder=" +
+ dream + " thread=" + Thread.currentThread().getId());
+ mHandler.requestAttach(name, dream);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Slog.v(TAG, "Service disconnected: " + name);
+ // Only happens in exceptional circumstances, awaken just to be safe
+ awaken();
+ }
+ // end ServiceConnection
+
+ private void checkPermission(String permission) {
+ if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) {
+ throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
+ + ", must have permission " + permission);
+ }
+ }
+
+ private void setDreamingLocked(boolean isDreaming, boolean isTest) {
+ boolean wasDreaming = mIsDreaming;
+ if (!isTest) {
+ if (!wasDreaming && isDreaming) {
+ if (DEBUG) Slog.v(TAG, "Firing ACTION_DREAMING_STARTED");
+ mContext.sendBroadcast(mDreamingStartedIntent);
+ } else if (wasDreaming && !isDreaming) {
+ if (DEBUG) Slog.v(TAG, "Firing ACTION_DREAMING_STOPPED");
+ mContext.sendBroadcast(mDreamingStoppedIntent);
+ }
+ }
+ mIsDreaming = isDreaming;
+ }
+
+ private ComponentName[] getDreamComponentsForUser(int userId) {
+ String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ SCREENSAVER_COMPONENTS,
+ userId);
+ return names == null ? null : componentsFromString(names);
+ }
+
+ private static String componentsToString(ComponentName[] componentNames) {
+ StringBuilder names = new StringBuilder();
+ if (componentNames != null) {
+ for (ComponentName componentName : componentNames) {
+ if (names.length() > 0) {
+ names.append(',');
+ }
+ names.append(componentName.flattenToString());
+ }
+ }
+ return names.toString();
+ }
+
+ private static ComponentName[] componentsFromString(String names) {
+ String[] namesArray = names.split(",");
+ ComponentName[] componentNames = new ComponentName[namesArray.length];
+ for (int i = 0; i < namesArray.length; i++) {
+ componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
+ }
+ return componentNames;
+ }
+
+ /**
+ * Keeps track of the current user, since dream() uses the current user's configuration.
+ */
+ private static class CurrentUserManager {
+ private final Object mLock = new Object();
+ private int mCurrentUserId;
+
+ public void init(Context context) {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ context.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ synchronized(mLock) {
+ mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+ if (DEBUG) Slog.v(TAG, "userId " + mCurrentUserId + " is in the house");
+ }
+ }
+ }}, filter);
+ try {
+ synchronized (mLock) {
+ mCurrentUserId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
+ }
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.print(" user="); pw.println(getCurrentUserId());
+ }
+
+ public int getCurrentUserId() {
+ synchronized(mLock) {
+ return mCurrentUserId;
+ }
+ }
+ }
+
+ /**
+ * Handler for asynchronous operations performed by the dream manager.
+ *
+ * Ensures operations to {@link DreamController} are single-threaded.
+ */
+ private static final class DreamControllerHandler extends Handler {
+ private final DreamController mController;
+ private final Runnable mStopRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mController.stop();
+ }};
+
+ public DreamControllerHandler(DreamController controller) {
+ super(true /*async*/);
+ mController = controller;
+ }
+
+ public void requestStart(final ComponentName name, final boolean isTest) {
+ post(new Runnable(){
+ @Override
+ public void run() {
+ mController.start(name, isTest);
+ }});
+ }
+
+ public void requestAttach(final ComponentName name, final IBinder dream) {
+ post(new Runnable(){
+ @Override
+ public void run() {
+ mController.attach(name, dream);
+ }});
+ }
+
+ public void requestStopSelf(final IBinder token) {
+ post(new Runnable(){
+ @Override
+ public void run() {
+ mController.stopSelf(token);
+ }});
+ }
+
+ public void requestStop() {
+ post(mStopRunnable);
+ }
+
+ }
+
+}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 32ab154..ba758e5 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -549,34 +549,6 @@ class MountService extends IMountService.Stub
}
}
- private final BroadcastReceiver mBootReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId == -1) return;
- final UserHandle user = new UserHandle(userId);
-
- Slog.d(TAG, "BOOT_COMPLETED for " + user);
-
- // Broadcast mounted volumes to newly booted user. This kicks off
- // media scanner when a user becomes active.
- synchronized (mVolumesLock) {
- for (StorageVolume volume : mVolumes) {
- final UserHandle owner = volume.getOwner();
- final boolean ownerMatch = owner == null
- || owner.getIdentifier() == user.getIdentifier();
-
- final String state = mVolumeStates.get(volume.getPath());
-
- if (ownerMatch && (Environment.MEDIA_MOUNTED.equals(state)
- || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))) {
- sendStorageIntent(Intent.ACTION_MEDIA_MOUNTED, volume, user);
- }
- }
- }
- }
- };
-
private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -1309,10 +1281,6 @@ class MountService extends IMountService.Stub
mHandlerThread.start();
mHandler = new MountServiceHandler(mHandlerThread.getLooper());
- // Watch for user boot completion
- mContext.registerReceiverAsUser(mBootReceiver, UserHandle.ALL,
- new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, mHandler);
-
// Watch for user changes
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_ADDED);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 90783b7..2792704 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -38,7 +38,6 @@ import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.server.search.SearchManagerService;
-import android.service.dreams.DreamManagerService;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -189,7 +188,7 @@ class ServerThread extends Thread {
// For debug builds, log event loop stalls to dropbox for analysis.
if (StrictMode.conditionallyEnableDebugLogging()) {
- Slog.i(TAG, "Enabled StrictMode logging for UI Looper");
+ Slog.i(TAG, "Enabled StrictMode logging for WM Looper");
}
}
});
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 989477f..1f5fa4d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -168,6 +168,7 @@ public final class ActivityManagerService extends ActivityManagerNative
static final boolean localLOGV = DEBUG;
static final boolean DEBUG_SWITCH = localLOGV || false;
static final boolean DEBUG_TASKS = localLOGV || false;
+ static final boolean DEBUG_THUMBNAILS = localLOGV || false;
static final boolean DEBUG_PAUSE = localLOGV || false;
static final boolean DEBUG_OOM_ADJ = localLOGV || false;
static final boolean DEBUG_TRANSITION = localLOGV || false;
@@ -253,6 +254,9 @@ public final class ActivityManagerService extends ActivityManagerNative
// giving up on them and unfreezing the screen.
static final int USER_SWITCH_TIMEOUT = 2*1000;
+ // Maximum number of users we allow to be running at a time.
+ static final int MAX_RUNNING_USERS = 3;
+
static final int MY_PID = Process.myPid();
static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -1794,7 +1798,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private final void updateLruProcessInternalLocked(ProcessRecord app,
- boolean oomAdj, boolean updateActivityTime, int bestPos) {
+ boolean updateActivityTime, int bestPos) {
// put it on the LRU to keep track of when it should be exited.
int lrui = mLruProcesses.indexOf(app);
if (lrui >= 0) mLruProcesses.remove(lrui);
@@ -1851,7 +1855,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (cr.binding != null && cr.binding.service != null
&& cr.binding.service.app != null
&& cr.binding.service.app.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cr.binding.service.app, false,
+ updateLruProcessInternalLocked(cr.binding.service.app,
updateActivityTime, i+1);
}
}
@@ -1859,21 +1863,21 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int j=app.conProviders.size()-1; j>=0; j--) {
ContentProviderRecord cpr = app.conProviders.get(j).provider;
if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cpr.proc, false,
+ updateLruProcessInternalLocked(cpr.proc,
updateActivityTime, i+1);
}
}
-
- //Slog.i(TAG, "Putting proc to front: " + app.processName);
- if (oomAdj) {
- updateOomAdjLocked();
- }
}
final void updateLruProcessLocked(ProcessRecord app,
boolean oomAdj, boolean updateActivityTime) {
mLruSeq++;
- updateLruProcessInternalLocked(app, oomAdj, updateActivityTime, 0);
+ updateLruProcessInternalLocked(app, updateActivityTime, 0);
+
+ //Slog.i(TAG, "Putting proc to front: " + app.processName);
+ if (oomAdj) {
+ updateOomAdjLocked();
+ }
}
final ProcessRecord getProcessRecordLocked(
@@ -4455,7 +4459,13 @@ public final class ActivityManagerService extends ActivityManagerNative
enableScreenAfterBoot();
}
}
-
+
+ public final void activityResumed(IBinder token) {
+ final long origId = Binder.clearCallingIdentity();
+ mMainStack.activityResumed(token);
+ Binder.restoreCallingIdentity(origId);
+ }
+
public final void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
mMainStack.activityPaused(token, false);
@@ -5840,6 +5850,18 @@ public final class ActivityManagerService extends ActivityManagerNative
return null;
}
+ public Bitmap getTaskTopThumbnail(int id) {
+ synchronized (this) {
+ enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
+ "getTaskTopThumbnail()");
+ TaskRecord tr = taskForIdLocked(id);
+ if (tr != null) {
+ return mMainStack.getTaskTopThumbnailLocked(tr);
+ }
+ }
+ return null;
+ }
+
public boolean removeSubTask(int taskId, int subTaskIndex) {
synchronized (this) {
enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
@@ -11432,7 +11454,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Add the new results to the existing results, tracking
// and de-dupping single user receivers.
for (int i=0; i<newReceivers.size(); i++) {
- ResolveInfo ri = receivers.get(i);
+ ResolveInfo ri = newReceivers.get(i);
if ((ri.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
ComponentName cn = new ComponentName(
ri.activityInfo.packageName, ri.activityInfo.name);
@@ -13960,6 +13982,8 @@ public final class ActivityManagerService extends ActivityManagerNative
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
+ mWindowManager.setCurrentUser(userId);
+
final UserStartedState uss = mStartedUsers.get(userId);
mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
@@ -13998,7 +14022,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (!haveActivities) {
startHomeActivityLocked(userId);
}
-
+
sendUserSwitchBroadcastsLocked(oldUserId, userId);
}
} finally {
@@ -14117,6 +14141,33 @@ public final class ActivityManagerService extends ActivityManagerNative
android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
false, false, MY_PID, Process.SYSTEM_UID, userId);
}
+ int num = mUserLru.size();
+ int i = 0;
+ while (num > MAX_RUNNING_USERS && i < mUserLru.size()) {
+ Integer oldUserId = mUserLru.get(i);
+ UserStartedState oldUss = mStartedUsers.get(oldUserId);
+ if (oldUss == null) {
+ // Shouldn't happen, but be sane if it does.
+ mUserLru.remove(i);
+ num--;
+ continue;
+ }
+ if (oldUss.mState == UserStartedState.STATE_STOPPING) {
+ // This user is already stopping, doesn't count.
+ num--;
+ i++;
+ continue;
+ }
+ if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId) {
+ // Owner and current can't be stopped, but count as running.
+ i++;
+ continue;
+ }
+ // This is a user to be stopped.
+ stopUserLocked(oldUserId, null);
+ num--;
+ i++;
+ }
}
}
@@ -14135,52 +14186,56 @@ public final class ActivityManagerService extends ActivityManagerNative
throw new IllegalArgumentException("Can't stop primary user " + userId);
}
synchronized (this) {
- if (mCurrentUserId == userId) {
- return ActivityManager.USER_OP_IS_CURRENT;
- }
-
- final UserStartedState uss = mStartedUsers.get(userId);
- if (uss == null) {
- // User is not started, nothing to do... but we do need to
- // callback if requested.
- if (callback != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- callback.userStopped(userId);
- } catch (RemoteException e) {
- }
- }
- });
- }
- return ActivityManager.USER_OP_SUCCESS;
- }
+ return stopUserLocked(userId, callback);
+ }
+ }
+ private int stopUserLocked(final int userId, final IStopUserCallback callback) {
+ if (mCurrentUserId == userId) {
+ return ActivityManager.USER_OP_IS_CURRENT;
+ }
+
+ final UserStartedState uss = mStartedUsers.get(userId);
+ if (uss == null) {
+ // User is not started, nothing to do... but we do need to
+ // callback if requested.
if (callback != null) {
- uss.mStopCallbacks.add(callback);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ callback.userStopped(userId);
+ } catch (RemoteException e) {
+ }
+ }
+ });
}
+ return ActivityManager.USER_OP_SUCCESS;
+ }
- if (uss.mState != UserStartedState.STATE_STOPPING) {
- uss.mState = UserStartedState.STATE_STOPPING;
+ if (callback != null) {
+ uss.mStopCallbacks.add(callback);
+ }
- long ident = Binder.clearCallingIdentity();
- try {
- // Inform of user switch
- Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
- final IIntentReceiver resultReceiver = new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
- finishUserStop(uss);
- }
- };
- broadcastIntentLocked(null, null, intent,
- null, resultReceiver, 0, null, null, null,
- true, false, MY_PID, Process.SYSTEM_UID, userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ if (uss.mState != UserStartedState.STATE_STOPPING) {
+ uss.mState = UserStartedState.STATE_STOPPING;
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ // Inform of user switch
+ Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
+ final IIntentReceiver resultReceiver = new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
+ finishUserStop(uss);
+ }
+ };
+ broadcastIntentLocked(null, null, intent,
+ null, resultReceiver, 0, null, null, null,
+ true, false, MY_PID, Process.SYSTEM_UID, userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -14200,6 +14255,7 @@ public final class ActivityManagerService extends ActivityManagerNative
stopped = true;
// User can no longer run.
mStartedUsers.remove(userId);
+ mUserLru.remove(Integer.valueOf(userId));
// Clean up all state and processes associated with the user.
// Kill all the processes for the user.
@@ -14218,12 +14274,14 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public UserInfo getCurrentUser() {
- if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
- != PackageManager.PERMISSION_GRANTED) {
+ if ((checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
+ != PackageManager.PERMISSION_GRANTED) && (
+ checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ != PackageManager.PERMISSION_GRANTED)) {
String msg = "Permission Denial: getCurrentUser() from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
- + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+ + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 009fb5d..7ff5748 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -219,7 +219,13 @@ final class ActivityRecord {
pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
pw.print(" forceNewConfig="); pw.println(forceNewConfig);
- pw.print(prefix); pw.print("thumbHolder="); pw.println(thumbHolder);
+ pw.print(prefix); pw.print("thumbHolder: ");
+ pw.print(Integer.toHexString(System.identityHashCode(thumbHolder)));
+ if (thumbHolder != null) {
+ pw.print(" bm="); pw.print(thumbHolder.lastThumbnail);
+ pw.print(" desc="); pw.print(thumbHolder.lastDescription);
+ }
+ pw.println();
if (launchTime != 0 || startTime != 0) {
pw.print(prefix); pw.print("launchTime=");
if (launchTime == 0) pw.print("0");
@@ -674,19 +680,15 @@ final class ActivityRecord {
}
if (thumbHolder != null) {
if (newThumbnail != null) {
+ if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
+ "Setting thumbnail of " + this + " holder " + thumbHolder
+ + " to " + newThumbnail);
thumbHolder.lastThumbnail = newThumbnail;
}
thumbHolder.lastDescription = description;
}
}
- void clearThumbnail() {
- if (thumbHolder != null) {
- thumbHolder.lastThumbnail = null;
- thumbHolder.lastDescription = null;
- }
- }
-
void startLaunchTickingLocked() {
if (ActivityManagerService.IS_USER_BUILD) {
return;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index f72d318..df50d89 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -52,7 +52,6 @@ import android.os.IBinder;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
-import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -755,8 +754,6 @@ final class ActivityStack {
completeResumeLocked(r);
checkReadyForSleepLocked();
if (DEBUG_SAVED_STATE) Slog.i(TAG, "Launch completed; removing icicle of " + r.icicle);
- r.icicle = null;
- r.haveState = false;
} else {
// This activity is not starting in the resumed state... which
// should look like we asked it to pause+stop (but remain visible),
@@ -1010,7 +1007,21 @@ final class ActivityStack {
resumeTopActivityLocked(null);
}
}
-
+
+ final void activityResumed(IBinder token) {
+ ActivityRecord r = null;
+
+ synchronized (mService) {
+ int index = indexOfTokenLocked(token);
+ if (index >= 0) {
+ r = mHistory.get(index);
+ if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
+ r.icicle = null;
+ r.haveState = false;
+ }
+ }
+ }
+
final void activityPaused(IBinder token, boolean timeout) {
if (DEBUG_PAUSE) Slog.v(
TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
@@ -1192,8 +1203,7 @@ final class ActivityStack {
if (mMainStack) {
mService.reportResumedActivityLocked(next);
}
-
- next.clearThumbnail();
+
if (mMainStack) {
mService.setFocusedActivityLocked(next);
}
@@ -1488,6 +1498,15 @@ final class ActivityStack {
// can be resumed...
if (mResumedActivity != null) {
if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
+ // At this point we want to put the upcoming activity's process
+ // at the top of the LRU list, since we know we will be needing it
+ // very soon and it would be a waste to let it get killed if it
+ // happens to be sitting towards the end.
+ if (next.app != null && next.app.thread != null) {
+ // No reason to do full oom adj update here; we'll let that
+ // happen whenever it needs to later.
+ mService.updateLruProcessLocked(next.app, false, true);
+ }
startPausingLocked(userLeaving, false);
return true;
}
@@ -1728,11 +1747,6 @@ final class ActivityStack {
"resume-exception", true);
return true;
}
-
- // Didn't need to use the icicle, and it is now out of date.
- if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; didn't need icicle of: " + next);
- next.icicle = null;
- next.haveState = false;
next.stopped = false;
} else {
@@ -2578,7 +2592,6 @@ final class ActivityStack {
mDismissKeyguardOnNextActivity = false;
mService.mWindowManager.dismissKeyguard();
}
- Slog.i(TAG, "DONE STARTING!");
return err;
}
@@ -4314,18 +4327,33 @@ final class ActivityStack {
finishTaskMoveLocked(task);
return true;
}
-
+
public ActivityManager.TaskThumbnails getTaskThumbnailsLocked(TaskRecord tr) {
TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
ActivityRecord resumed = mResumedActivity;
if (resumed != null && resumed.thumbHolder == tr) {
info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
- } else {
- info.mainThumbnail = tr.lastThumbnail;
}
return info;
}
+ public Bitmap getTaskTopThumbnailLocked(TaskRecord tr) {
+ ActivityRecord resumed = mResumedActivity;
+ if (resumed != null && resumed.task == tr) {
+ // This task is the current resumed task, we just need to take
+ // a screenshot of it and return that.
+ return resumed.stack.screenshotActivities(resumed);
+ }
+ // Return the information about the task, to figure out the top
+ // thumbnail to return.
+ TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
+ if (info.numSubThumbbails <= 0) {
+ return info.mainThumbnail;
+ } else {
+ return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
+ }
+ }
+
public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex,
boolean taskRequired) {
TaskAccessInfo info = getTaskAccessInfoLocked(taskId, false);
@@ -4356,7 +4384,6 @@ final class ActivityStack {
}
public TaskAccessInfo getTaskAccessInfoLocked(int taskId, boolean inclThumbs) {
- ActivityRecord resumed = mResumedActivity;
final TaskAccessInfo thumbs = new TaskAccessInfo();
// How many different sub-thumbnails?
final int NA = mHistory.size();
@@ -4366,6 +4393,10 @@ final class ActivityStack {
ActivityRecord ar = mHistory.get(j);
if (!ar.finishing && ar.task.taskId == taskId) {
holder = ar.thumbHolder;
+ if (holder != null) {
+ thumbs.mainThumbnail = holder.lastThumbnail;
+ }
+ j++;
break;
}
j++;
@@ -4380,7 +4411,6 @@ final class ActivityStack {
ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>();
thumbs.subtasks = subtasks;
- ActivityRecord lastActivity = null;
while (j < NA) {
ActivityRecord ar = mHistory.get(j);
j++;
@@ -4390,30 +4420,28 @@ final class ActivityStack {
if (ar.task.taskId != taskId) {
break;
}
- lastActivity = ar;
if (ar.thumbHolder != holder && holder != null) {
thumbs.numSubThumbbails++;
holder = ar.thumbHolder;
TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask();
- sub.thumbnail = holder.lastThumbnail;
+ sub.holder = holder;
sub.activity = ar;
sub.index = j-1;
subtasks.add(sub);
}
}
- if (lastActivity != null && subtasks.size() > 0) {
- if (resumed == lastActivity) {
- TaskAccessInfo.SubTask sub = subtasks.get(subtasks.size()-1);
- sub.thumbnail = lastActivity.stack.screenshotActivities(lastActivity);
- }
- }
if (thumbs.numSubThumbbails > 0) {
thumbs.retriever = new IThumbnailRetriever.Stub() {
public Bitmap getThumbnail(int index) {
if (index < 0 || index >= thumbs.subtasks.size()) {
return null;
}
- return thumbs.subtasks.get(index).thumbnail;
+ TaskAccessInfo.SubTask sub = thumbs.subtasks.get(index);
+ ActivityRecord resumed = mResumedActivity;
+ if (resumed != null && resumed.thumbHolder == sub.holder) {
+ return resumed.stack.screenshotActivities(resumed);
+ }
+ return sub.holder.lastThumbnail;
}
};
}
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 1b6ff7a..b0af081 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -965,12 +965,12 @@ public class BroadcastQueue {
if (!printed) {
if (needSep) {
pw.println();
- needSep = false;
}
+ needSep = true;
printed = true;
pw.println(" Active broadcasts [" + mQueueName + "]:");
}
- pw.println(" Broadcast #" + i + ":");
+ pw.println(" Active Broadcast " + mQueueName + " #" + i + ":");
br.dump(pw, " ");
}
printed = false;
@@ -985,9 +985,10 @@ public class BroadcastQueue {
pw.println();
}
needSep = true;
+ printed = true;
pw.println(" Active ordered broadcasts [" + mQueueName + "]:");
}
- pw.println(" Ordered Broadcast #" + i + ":");
+ pw.println(" Active Ordered Broadcast " + mQueueName + " #" + i + ":");
mOrderedBroadcasts.get(i).dump(pw, " ");
}
if (dumpPackage == null || (mPendingBroadcast != null
@@ -1023,7 +1024,8 @@ public class BroadcastQueue {
printed = true;
}
if (dumpAll) {
- pw.print(" Historical Broadcast #"); pw.print(i); pw.println(":");
+ pw.print(" Historical Broadcast " + mQueueName + " #");
+ pw.print(i); pw.println(":");
r.dump(pw, " ");
} else {
if (i >= 50) {
diff --git a/services/java/com/android/server/am/TaskAccessInfo.java b/services/java/com/android/server/am/TaskAccessInfo.java
index 5618c1a..50aeec1 100644
--- a/services/java/com/android/server/am/TaskAccessInfo.java
+++ b/services/java/com/android/server/am/TaskAccessInfo.java
@@ -19,11 +19,10 @@ package com.android.server.am;
import java.util.ArrayList;
import android.app.ActivityManager.TaskThumbnails;
-import android.graphics.Bitmap;
final class TaskAccessInfo extends TaskThumbnails {
final static class SubTask {
- Bitmap thumbnail;
+ ThumbnailHolder holder;
ActivityRecord activity;
int index;
}
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 39f2418..02fc6b1 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -148,6 +148,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
private final DisplayViewport mDefaultViewport = new DisplayViewport();
private final DisplayViewport mExternalTouchViewport = new DisplayViewport();
+ // Persistent data store for all internal settings maintained by the display manager service.
+ private final PersistentDataStore mPersistentDataStore = new PersistentDataStore();
+
// Temporary callback list, used when sending display events to applications.
// May be used outside of the lock but only on the handler thread.
private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
@@ -403,6 +406,50 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
@Override // Binder call
+ public void renameWifiDisplay(String address, String alias) {
+ if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+ }
+ if (address == null) {
+ throw new IllegalArgumentException("address must not be null");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ if (mWifiDisplayAdapter != null) {
+ mWifiDisplayAdapter.requestRenameLocked(address, alias);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
+ public void forgetWifiDisplay(String address) {
+ if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+ }
+ if (address == null) {
+ throw new IllegalArgumentException("address must not be null");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ if (mWifiDisplayAdapter != null) {
+ mWifiDisplayAdapter.requestForgetLocked(address);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
public WifiDisplayStatus getWifiDisplayStatus() {
if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
!= PackageManager.PERMISSION_GRANTED) {
@@ -439,15 +486,27 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
private void registerAdditionalDisplayAdapters() {
synchronized (mSyncRoot) {
if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
- registerDisplayAdapterLocked(new OverlayDisplayAdapter(
- mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
- mWifiDisplayAdapter = new WifiDisplayAdapter(
- mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
- registerDisplayAdapterLocked(mWifiDisplayAdapter);
+ registerOverlayDisplayAdapterLocked();
+ registerWifiDisplayAdapterLocked();
}
}
}
+ private void registerOverlayDisplayAdapterLocked() {
+ registerDisplayAdapterLocked(new OverlayDisplayAdapter(
+ mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
+ }
+
+ private void registerWifiDisplayAdapterLocked() {
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableWifiDisplay)) {
+ mWifiDisplayAdapter = new WifiDisplayAdapter(
+ mSyncRoot, mContext, mHandler, mDisplayAdapterListener,
+ mPersistentDataStore);
+ registerDisplayAdapterLocked(mWifiDisplayAdapter);
+ }
+ }
+
private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() {
// In safe mode, we disable non-essential display adapters to give the user
// an opportunity to fix broken settings or other problems that might affect
diff --git a/services/java/com/android/server/display/PersistentDataStore.java b/services/java/com/android/server/display/PersistentDataStore.java
new file mode 100644
index 0000000..3a6e1a6
--- /dev/null
+++ b/services/java/com/android/server/display/PersistentDataStore.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.hardware.display.WifiDisplay;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+
+import libcore.io.IoUtils;
+import libcore.util.Objects;
+
+/**
+ * Manages persistent state recorded by the display manager service as an XML file.
+ * Caller must acquire lock on the data store before accessing it.
+ *
+ * File format:
+ * <code>
+ * &lt;display-manager-state>
+ * &lt;remembered-wifi-displays>
+ * &lt;wifi-display deviceAddress="00:00:00:00:00:00" deviceName="XXXX" deviceAlias="YYYY" />
+ * &gt;remembered-wifi-displays>
+ * &gt;/display-manager-state>
+ * </code>
+ *
+ * TODO: refactor this to extract common code shared with the input manager's data store
+ */
+final class PersistentDataStore {
+ static final String TAG = "DisplayManager";
+
+ // Remembered Wifi display devices.
+ private ArrayList<WifiDisplay> mRememberedWifiDisplays = new ArrayList<WifiDisplay>();
+
+ // The atomic file used to safely read or write the file.
+ private final AtomicFile mAtomicFile;
+
+ // True if the data has been loaded.
+ private boolean mLoaded;
+
+ // True if there are changes to be saved.
+ private boolean mDirty;
+
+ public PersistentDataStore() {
+ mAtomicFile = new AtomicFile(new File("/data/system/display-manager-state.xml"));
+ }
+
+ public void saveIfNeeded() {
+ if (mDirty) {
+ save();
+ mDirty = false;
+ }
+ }
+
+ public WifiDisplay[] getRememberedWifiDisplays() {
+ loadIfNeeded();
+ return mRememberedWifiDisplays.toArray(new WifiDisplay[mRememberedWifiDisplays.size()]);
+ }
+
+ public WifiDisplay applyWifiDisplayAlias(WifiDisplay display) {
+ if (display != null) {
+ loadIfNeeded();
+
+ String alias = null;
+ int index = findRememberedWifiDisplay(display.getDeviceAddress());
+ if (index >= 0) {
+ alias = mRememberedWifiDisplays.get(index).getDeviceAlias();
+ }
+ if (!Objects.equal(display.getDeviceAlias(), alias)) {
+ return new WifiDisplay(display.getDeviceAddress(), display.getDeviceName(), alias);
+ }
+ }
+ return display;
+ }
+
+ public WifiDisplay[] applyWifiDisplayAliases(WifiDisplay[] displays) {
+ WifiDisplay[] results = displays;
+ if (results != null) {
+ int count = displays.length;
+ for (int i = 0; i < count; i++) {
+ WifiDisplay result = applyWifiDisplayAlias(displays[i]);
+ if (result != displays[i]) {
+ if (results == displays) {
+ results = new WifiDisplay[count];
+ System.arraycopy(displays, 0, results, 0, count);
+ }
+ results[i] = result;
+ }
+ }
+ }
+ return results;
+ }
+
+ public boolean rememberWifiDisplay(WifiDisplay display) {
+ loadIfNeeded();
+
+ int index = findRememberedWifiDisplay(display.getDeviceAddress());
+ if (index >= 0) {
+ WifiDisplay other = mRememberedWifiDisplays.get(index);
+ if (other.equals(display)) {
+ return false; // already remembered without change
+ }
+ mRememberedWifiDisplays.set(index, display);
+ } else {
+ mRememberedWifiDisplays.add(display);
+ }
+ setDirty();
+ return true;
+ }
+
+ public boolean renameWifiDisplay(String deviceAddress, String alias) {
+ int index = findRememberedWifiDisplay(deviceAddress);
+ if (index >= 0) {
+ WifiDisplay display = mRememberedWifiDisplays.get(index);
+ if (Objects.equal(display.getDeviceAlias(), alias)) {
+ return false; // already has this alias
+ }
+ WifiDisplay renamedDisplay = new WifiDisplay(deviceAddress,
+ display.getDeviceName(), alias);
+ mRememberedWifiDisplays.set(index, renamedDisplay);
+ setDirty();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean forgetWifiDisplay(String deviceAddress) {
+ int index = findRememberedWifiDisplay(deviceAddress);
+ if (index >= 0) {
+ mRememberedWifiDisplays.remove(index);
+ setDirty();
+ return true;
+ }
+ return false;
+ }
+
+ private int findRememberedWifiDisplay(String deviceAddress) {
+ int count = mRememberedWifiDisplays.size();
+ for (int i = 0; i < count; i++) {
+ if (mRememberedWifiDisplays.get(i).getDeviceAddress().equals(deviceAddress)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private void loadIfNeeded() {
+ if (!mLoaded) {
+ load();
+ mLoaded = true;
+ }
+ }
+
+ private void setDirty() {
+ mDirty = true;
+ }
+
+ private void clearState() {
+ mRememberedWifiDisplays.clear();
+ }
+
+ private void load() {
+ clearState();
+
+ final InputStream is;
+ try {
+ is = mAtomicFile.openRead();
+ } catch (FileNotFoundException ex) {
+ return;
+ }
+
+ XmlPullParser parser;
+ try {
+ parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(is), null);
+ loadFromXml(parser);
+ } catch (IOException ex) {
+ Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
+ clearState();
+ } catch (XmlPullParserException ex) {
+ Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
+ clearState();
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
+ }
+
+ private void save() {
+ final FileOutputStream os;
+ try {
+ os = mAtomicFile.startWrite();
+ boolean success = false;
+ try {
+ XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(new BufferedOutputStream(os), "utf-8");
+ saveToXml(serializer);
+ serializer.flush();
+ success = true;
+ } finally {
+ if (success) {
+ mAtomicFile.finishWrite(os);
+ } else {
+ mAtomicFile.failWrite(os);
+ }
+ }
+ } catch (IOException ex) {
+ Slog.w(TAG, "Failed to save display manager persistent store data.", ex);
+ }
+ }
+
+ private void loadFromXml(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ XmlUtils.beginDocument(parser, "display-manager-state");
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (parser.getName().equals("remembered-wifi-displays")) {
+ loadRememberedWifiDisplaysFromXml(parser);
+ }
+ }
+ }
+
+ private void loadRememberedWifiDisplaysFromXml(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (parser.getName().equals("wifi-display")) {
+ String deviceAddress = parser.getAttributeValue(null, "deviceAddress");
+ String deviceName = parser.getAttributeValue(null, "deviceName");
+ String deviceAlias = parser.getAttributeValue(null, "deviceAlias");
+ if (deviceAddress == null || deviceName == null) {
+ throw new XmlPullParserException(
+ "Missing deviceAddress or deviceName attribute on wifi-display.");
+ }
+ if (findRememberedWifiDisplay(deviceAddress) >= 0) {
+ throw new XmlPullParserException(
+ "Found duplicate wifi display device address.");
+ }
+
+ mRememberedWifiDisplays.add(
+ new WifiDisplay(deviceAddress, deviceName, deviceAlias));
+ }
+ }
+ }
+
+ private void saveToXml(XmlSerializer serializer) throws IOException {
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startTag(null, "display-manager-state");
+ serializer.startTag(null, "remembered-wifi-displays");
+ for (WifiDisplay display : mRememberedWifiDisplays) {
+ serializer.startTag(null, "wifi-display");
+ serializer.attribute(null, "deviceAddress", display.getDeviceAddress());
+ serializer.attribute(null, "deviceName", display.getDeviceName());
+ if (display.getDeviceAlias() != null) {
+ serializer.attribute(null, "deviceAlias", display.getDeviceAlias());
+ }
+ serializer.endTag(null, "wifi-display");
+ }
+ serializer.endTag(null, "remembered-wifi-displays");
+ serializer.endTag(null, "display-manager-state");
+ serializer.endDocument();
+ }
+} \ No newline at end of file
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index b57d3dc..1d50ded 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -49,21 +49,26 @@ import java.util.Arrays;
final class WifiDisplayAdapter extends DisplayAdapter {
private static final String TAG = "WifiDisplayAdapter";
+ private PersistentDataStore mPersistentDataStore;
+
private WifiDisplayController mDisplayController;
private WifiDisplayDevice mDisplayDevice;
private WifiDisplayStatus mCurrentStatus;
- private boolean mEnabled;
+ private int mFeatureState;
private int mScanState;
private int mActiveDisplayState;
private WifiDisplay mActiveDisplay;
- private WifiDisplay[] mKnownDisplays = WifiDisplay.EMPTY_ARRAY;
+ private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
+ private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
private boolean mPendingStatusChangeBroadcast;
public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
- Context context, Handler handler, Listener listener) {
+ Context context, Handler handler, Listener listener,
+ PersistentDataStore persistentDataStore) {
super(syncRoot, context, handler, listener, TAG);
+ mPersistentDataStore = persistentDataStore;
}
@Override
@@ -71,11 +76,12 @@ final class WifiDisplayAdapter extends DisplayAdapter {
super.dumpLocked(pw);
pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
- pw.println("mEnabled=" + mEnabled);
+ pw.println("mFeatureState=" + mFeatureState);
pw.println("mScanState=" + mScanState);
pw.println("mActiveDisplayState=" + mActiveDisplayState);
pw.println("mActiveDisplay=" + mActiveDisplay);
- pw.println("mKnownDisplays=" + Arrays.toString(mKnownDisplays));
+ pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
+ pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
// Try to dump the controller state.
@@ -93,6 +99,8 @@ final class WifiDisplayAdapter extends DisplayAdapter {
public void registerLocked() {
super.registerLocked();
+ updateRememberedDisplaysLocked();
+
getHandler().post(new Runnable() {
@Override
public void run() {
@@ -135,18 +143,58 @@ final class WifiDisplayAdapter extends DisplayAdapter {
});
}
+ public void requestRenameLocked(String address, String alias) {
+ if (alias != null) {
+ alias = alias.trim();
+ if (alias.isEmpty()) {
+ alias = null;
+ }
+ }
+
+ if (mPersistentDataStore.renameWifiDisplay(address, alias)) {
+ mPersistentDataStore.saveIfNeeded();
+ updateRememberedDisplaysLocked();
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+
+ public void requestForgetLocked(String address) {
+ if (mPersistentDataStore.forgetWifiDisplay(address)) {
+ mPersistentDataStore.saveIfNeeded();
+ updateRememberedDisplaysLocked();
+ scheduleStatusChangedBroadcastLocked();
+ }
+
+ if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
+ requestDisconnectLocked();
+ }
+ }
+
public WifiDisplayStatus getWifiDisplayStatusLocked() {
if (mCurrentStatus == null) {
- mCurrentStatus = new WifiDisplayStatus(mEnabled, mScanState, mActiveDisplayState,
- mActiveDisplay, mKnownDisplays);
+ mCurrentStatus = new WifiDisplayStatus(
+ mFeatureState, mScanState, mActiveDisplayState,
+ mActiveDisplay, mAvailableDisplays, mRememberedDisplays);
}
return mCurrentStatus;
}
+ private void updateRememberedDisplaysLocked() {
+ mRememberedDisplays = mPersistentDataStore.getRememberedWifiDisplays();
+ mActiveDisplay = mPersistentDataStore.applyWifiDisplayAlias(mActiveDisplay);
+ mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
+ }
+
private void handleConnectLocked(WifiDisplay display,
Surface surface, int width, int height, int flags) {
handleDisconnectLocked();
+ if (mPersistentDataStore.rememberWifiDisplay(display)) {
+ mPersistentDataStore.saveIfNeeded();
+ updateRememberedDisplaysLocked();
+ scheduleStatusChangedBroadcastLocked();
+ }
+
int deviceFlags = 0;
if ((flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0) {
deviceFlags |= DisplayDeviceInfo.FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT;
@@ -154,7 +202,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
float refreshRate = 60.0f; // TODO: get this for real
- String name = display.getDeviceName();
+ String name = display.getFriendlyDisplayName();
IBinder displayToken = Surface.createDisplay(name);
mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
refreshRate, deviceFlags, surface);
@@ -170,6 +218,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
private void scheduleStatusChangedBroadcastLocked() {
+ mCurrentStatus = null;
if (!mPendingStatusChangeBroadcast) {
mPendingStatusChangeBroadcast = true;
getHandler().post(mStatusChangeBroadcast);
@@ -202,11 +251,10 @@ final class WifiDisplayAdapter extends DisplayAdapter {
private final WifiDisplayController.Listener mWifiDisplayListener =
new WifiDisplayController.Listener() {
@Override
- public void onEnablementChanged(boolean enabled) {
+ public void onFeatureStateChanged(int featureState) {
synchronized (getSyncRoot()) {
- if (mEnabled != enabled) {
- mCurrentStatus = null;
- mEnabled = enabled;
+ if (mFeatureState != featureState) {
+ mFeatureState = featureState;
scheduleStatusChangedBroadcastLocked();
}
}
@@ -216,20 +264,21 @@ final class WifiDisplayAdapter extends DisplayAdapter {
public void onScanStarted() {
synchronized (getSyncRoot()) {
if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
- mCurrentStatus = null;
mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
scheduleStatusChangedBroadcastLocked();
}
}
}
- public void onScanFinished(WifiDisplay[] knownDisplays) {
+ public void onScanFinished(WifiDisplay[] availableDisplays) {
synchronized (getSyncRoot()) {
+ availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
+ availableDisplays);
+
if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING
- || !Arrays.equals(mKnownDisplays, knownDisplays)) {
- mCurrentStatus = null;
+ || !Arrays.equals(mAvailableDisplays, availableDisplays)) {
mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
- mKnownDisplays = knownDisplays;
+ mAvailableDisplays = availableDisplays;
scheduleStatusChangedBroadcastLocked();
}
}
@@ -238,10 +287,11 @@ final class WifiDisplayAdapter extends DisplayAdapter {
@Override
public void onDisplayConnecting(WifiDisplay display) {
synchronized (getSyncRoot()) {
+ display = mPersistentDataStore.applyWifiDisplayAlias(display);
+
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
|| mActiveDisplay == null
|| !mActiveDisplay.equals(display)) {
- mCurrentStatus = null;
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
mActiveDisplay = display;
scheduleStatusChangedBroadcastLocked();
@@ -254,7 +304,6 @@ final class WifiDisplayAdapter extends DisplayAdapter {
synchronized (getSyncRoot()) {
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
|| mActiveDisplay != null) {
- mCurrentStatus = null;
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
mActiveDisplay = null;
scheduleStatusChangedBroadcastLocked();
@@ -266,12 +315,12 @@ final class WifiDisplayAdapter extends DisplayAdapter {
public void onDisplayConnected(WifiDisplay display, Surface surface,
int width, int height, int flags) {
synchronized (getSyncRoot()) {
+ display = mPersistentDataStore.applyWifiDisplayAlias(display);
handleConnectLocked(display, surface, width, height, flags);
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
|| mActiveDisplay == null
|| !mActiveDisplay.equals(display)) {
- mCurrentStatus = null;
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
mActiveDisplay = display;
scheduleStatusChangedBroadcastLocked();
@@ -287,7 +336,6 @@ final class WifiDisplayAdapter extends DisplayAdapter {
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
|| mActiveDisplay != null) {
- mCurrentStatus = null;
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
mActiveDisplay = null;
scheduleStatusChangedBroadcastLocked();
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 87e11e6..84f4e83 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -19,13 +19,17 @@ package com.android.server.display;
import com.android.internal.util.DumpUtils;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplayStatus;
import android.media.AudioManager;
import android.media.RemoteDisplay;
import android.net.NetworkInfo;
+import android.net.Uri;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
@@ -37,6 +41,7 @@ import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.GroupInfoListener;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.os.Handler;
+import android.provider.Settings;
import android.util.Slog;
import android.view.Surface;
@@ -48,6 +53,8 @@ import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
+import libcore.util.Objects;
+
/**
* Manages all of the various asynchronous interactions with the {@link WifiP2pManager}
* on behalf of {@link WifiDisplayAdapter}.
@@ -94,9 +101,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
private boolean mWfdEnabling;
private NetworkInfo mNetworkInfo;
- private final ArrayList<WifiP2pDevice> mKnownWifiDisplayPeers =
+ private final ArrayList<WifiP2pDevice> mAvailableWifiDisplayPeers =
new ArrayList<WifiP2pDevice>();
+ // True if Wifi display is enabled by the user.
+ private boolean mWifiDisplayOnSetting;
+
// True if there is a call to discoverPeers in progress.
private boolean mDiscoverPeersInProgress;
@@ -132,6 +142,13 @@ final class WifiDisplayController implements DumpUtils.Dump {
// True if the remote submix is enabled.
private boolean mRemoteSubmixOn;
+ // The information we have most recently told WifiDisplayAdapter about.
+ private WifiDisplay mAdvertisedDisplay;
+ private Surface mAdvertisedDisplaySurface;
+ private int mAdvertisedDisplayWidth;
+ private int mAdvertisedDisplayHeight;
+ private int mAdvertisedDisplayFlags;
+
public WifiDisplayController(Context context, Handler handler, Listener listener) {
mContext = context;
mHandler = handler;
@@ -146,10 +163,31 @@ final class WifiDisplayController implements DumpUtils.Dump {
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
- context.registerReceiver(mWifiP2pReceiver, intentFilter);
+ context.registerReceiver(mWifiP2pReceiver, intentFilter, null, mHandler);
+
+ ContentObserver settingsObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateSettings();
+ }
+ };
+
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.WIFI_DISPLAY_ON), false, settingsObserver);
+ updateSettings();
+ }
+
+ private void updateSettings() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ mWifiDisplayOnSetting = Settings.Global.getInt(resolver,
+ Settings.Global.WIFI_DISPLAY_ON, 0) != 0;
+
+ updateWfdEnableState();
}
public void dump(PrintWriter pw) {
+ pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
pw.println("mWfdEnabled=" + mWfdEnabled);
pw.println("mWfdEnabling=" + mWfdEnabling);
@@ -164,9 +202,14 @@ final class WifiDisplayController implements DumpUtils.Dump {
pw.println("mRemoteDisplayInterface=" + mRemoteDisplayInterface);
pw.println("mRemoteDisplayConnected=" + mRemoteDisplayConnected);
pw.println("mRemoteSubmixOn=" + mRemoteSubmixOn);
-
- pw.println("mKnownWifiDisplayPeers: size=" + mKnownWifiDisplayPeers.size());
- for (WifiP2pDevice device : mKnownWifiDisplayPeers) {
+ pw.println("mAdvertisedDisplay=" + mAdvertisedDisplay);
+ pw.println("mAdvertisedDisplaySurface=" + mAdvertisedDisplaySurface);
+ pw.println("mAdvertisedDisplayWidth=" + mAdvertisedDisplayWidth);
+ pw.println("mAdvertisedDisplayHeight=" + mAdvertisedDisplayHeight);
+ pw.println("mAdvertisedDisplayFlags=" + mAdvertisedDisplayFlags);
+
+ pw.println("mAvailableWifiDisplayPeers: size=" + mAvailableWifiDisplayPeers.size());
+ for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
pw.println(" " + describeWifiP2pDevice(device));
}
}
@@ -176,7 +219,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
public void requestConnect(String address) {
- for (WifiP2pDevice device : mKnownWifiDisplayPeers) {
+ for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
if (device.deviceAddress.equals(address)) {
connect(device);
}
@@ -187,49 +230,65 @@ final class WifiDisplayController implements DumpUtils.Dump {
disconnect();
}
- private void enableWfd() {
- if (!mWfdEnabled && !mWfdEnabling) {
- mWfdEnabling = true;
-
- WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
- wfdInfo.setWfdEnabled(true);
- wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
- wfdInfo.setSessionAvailable(true);
- wfdInfo.setControlPort(DEFAULT_CONTROL_PORT);
- wfdInfo.setMaxThroughput(MAX_THROUGHPUT);
- mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
- @Override
- public void onSuccess() {
- if (DEBUG) {
- Slog.d(TAG, "Successfully set WFD info.");
- }
- if (mWfdEnabling) {
- mWfdEnabling = false;
- setWfdEnabled(true);
+ private void updateWfdEnableState() {
+ if (mWifiDisplayOnSetting && mWifiP2pEnabled) {
+ // WFD should be enabled.
+ if (!mWfdEnabled && !mWfdEnabling) {
+ mWfdEnabling = true;
+
+ WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
+ wfdInfo.setWfdEnabled(true);
+ wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
+ wfdInfo.setSessionAvailable(true);
+ wfdInfo.setControlPort(DEFAULT_CONTROL_PORT);
+ wfdInfo.setMaxThroughput(MAX_THROUGHPUT);
+ mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
+ @Override
+ public void onSuccess() {
+ if (DEBUG) {
+ Slog.d(TAG, "Successfully set WFD info.");
+ }
+ if (mWfdEnabling) {
+ mWfdEnabling = false;
+ mWfdEnabled = true;
+ reportFeatureState();
+ }
}
- }
- @Override
- public void onFailure(int reason) {
- if (DEBUG) {
- Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
+ @Override
+ public void onFailure(int reason) {
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
+ }
+ mWfdEnabling = false;
}
- mWfdEnabling = false;
- }
- });
+ });
+ }
+ } else {
+ // WFD should be disabled.
+ mWfdEnabling = false;
+ mWfdEnabled = false;
+ reportFeatureState();
+ disconnect();
}
}
- private void setWfdEnabled(final boolean enabled) {
- if (mWfdEnabled != enabled) {
- mWfdEnabled = enabled;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onEnablementChanged(enabled);
- }
- });
+ private void reportFeatureState() {
+ final int featureState = computeFeatureState();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onFeatureStateChanged(featureState);
+ }
+ });
+ }
+
+ private int computeFeatureState() {
+ if (!mWifiP2pEnabled) {
+ return WifiDisplayStatus.FEATURE_STATE_DISABLED;
}
+ return mWifiDisplayOnSetting ? WifiDisplayStatus.FEATURE_STATE_ON :
+ WifiDisplayStatus.FEATURE_STATE_OFF;
}
private void discoverPeers() {
@@ -296,14 +355,14 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.d(TAG, "Received list of peers.");
}
- mKnownWifiDisplayPeers.clear();
+ mAvailableWifiDisplayPeers.clear();
for (WifiP2pDevice device : peers.getDeviceList()) {
if (DEBUG) {
Slog.d(TAG, " " + describeWifiP2pDevice(device));
}
if (isWifiDisplay(device)) {
- mKnownWifiDisplayPeers.add(device);
+ mAvailableWifiDisplayPeers.add(device);
}
}
@@ -322,10 +381,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private void handleScanFinished() {
- final int count = mKnownWifiDisplayPeers.size();
+ final int count = mAvailableWifiDisplayPeers.size();
final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
for (int i = 0; i < count; i++) {
- displays[i] = createWifiDisplay(mKnownWifiDisplayPeers.get(i));
+ displays[i] = createWifiDisplay(mAvailableWifiDisplayPeers.get(i));
}
mHandler.post(new Runnable() {
@@ -368,18 +427,11 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private void retryConnection() {
- if (mDesiredDevice != null && mConnectedDevice != mDesiredDevice
- && mConnectionRetriesLeft > 0) {
- mConnectionRetriesLeft -= 1;
- Slog.i(TAG, "Retrying Wifi display connection. Retries left: "
- + mConnectionRetriesLeft);
-
- // Cheap hack. Make a new instance of the device object so that we
- // can distinguish it from the previous connection attempt.
- // This will cause us to tear everything down before we try again.
- mDesiredDevice = new WifiP2pDevice(mDesiredDevice);
- updateConnection();
- }
+ // Cheap hack. Make a new instance of the device object so that we
+ // can distinguish it from the previous connection attempt.
+ // This will cause us to tear everything down before we try again.
+ mDesiredDevice = new WifiP2pDevice(mDesiredDevice);
+ updateConnection();
}
/**
@@ -401,13 +453,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
mHandler.removeCallbacks(mRtspTimeout);
setRemoteSubmixOn(false);
-
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onDisplayDisconnected();
- }
- });
+ unadvertiseDisplay();
// continue to next step
}
@@ -416,6 +462,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
+ unadvertiseDisplay();
+
final WifiP2pDevice oldDevice = mConnectedDevice;
mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
@Override
@@ -446,6 +494,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
+ unadvertiseDisplay();
mHandler.removeCallbacks(mConnectionTimeout);
final WifiP2pDevice oldDevice = mConnectingDevice;
@@ -475,6 +524,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
// Step 4. If we wanted to disconnect, then mission accomplished.
if (mDesiredDevice == null) {
+ unadvertiseDisplay();
return; // done
}
@@ -485,14 +535,11 @@ final class WifiDisplayController implements DumpUtils.Dump {
mConnectingDevice = mDesiredDevice;
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = mConnectingDevice.deviceAddress;
+ // Helps with STA & P2P concurrency
+ config.groupOwnerIntent = WifiP2pConfig.MAX_GROUP_OWNER_INTENT;
- final WifiDisplay display = createWifiDisplay(mConnectingDevice);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onDisplayConnecting(display);
- }
- });
+ WifiDisplay display = createWifiDisplay(mConnectingDevice);
+ advertiseDisplay(display, null, 0, 0, 0);
final WifiP2pDevice newDevice = mDesiredDevice;
mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() {
@@ -541,8 +588,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
@Override
- public void onDisplayConnected(final Surface surface,
- final int width, final int height, final int flags) {
+ public void onDisplayConnected(Surface surface,
+ int width, int height, int flags) {
if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
Slog.i(TAG, "Opened RTSP connection with Wifi display: "
+ mConnectedDevice.deviceName);
@@ -550,13 +597,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
mHandler.removeCallbacks(mRtspTimeout);
final WifiDisplay display = createWifiDisplay(mConnectedDevice);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onDisplayConnected(display,
- surface, width, height, flags);
- }
- });
+ advertiseDisplay(display, surface, width, height, flags);
}
}
@@ -593,26 +634,13 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private void handleStateChanged(boolean enabled) {
- if (mWifiP2pEnabled != enabled) {
- mWifiP2pEnabled = enabled;
- if (enabled) {
- if (!mWfdEnabled) {
- enableWfd();
- }
- } else {
- setWfdEnabled(false);
- disconnect();
- }
- }
+ mWifiP2pEnabled = enabled;
+ updateWfdEnableState();
}
private void handlePeersChanged() {
- if (mWifiP2pEnabled) {
- if (mWfdEnabled) {
- requestPeers();
- } else {
- enableWfd();
- }
+ if (mWfdEnabled) {
+ requestPeers();
}
}
@@ -630,7 +658,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
if (mConnectingDevice != null && !info.contains(mConnectingDevice)) {
Slog.i(TAG, "Aborting connection to Wifi display because "
+ "the current P2P group does not contain the device "
- + "we expected to find: " + mConnectingDevice.deviceName);
+ + "we expected to find: " + mConnectingDevice.deviceName
+ + ", group info was: " + describeWifiP2pGroup(info));
handleConnectionFailure(false);
return;
}
@@ -693,19 +722,18 @@ final class WifiDisplayController implements DumpUtils.Dump {
private void handleConnectionFailure(boolean timeoutOccurred) {
Slog.i(TAG, "Wifi display connection failed!");
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onDisplayConnectionFailed();
- }
- });
-
if (mDesiredDevice != null) {
if (mConnectionRetriesLeft > 0) {
+ final WifiP2pDevice oldDevice = mDesiredDevice;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
- retryConnection();
+ if (mDesiredDevice == oldDevice && mConnectionRetriesLeft > 0) {
+ mConnectionRetriesLeft -= 1;
+ Slog.i(TAG, "Retrying Wifi display connection. Retries left: "
+ + mConnectionRetriesLeft);
+ retryConnection();
+ }
}
}, timeoutOccurred ? 0 : CONNECT_RETRY_DELAY_MILLIS);
} else {
@@ -714,6 +742,48 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
+ private void advertiseDisplay(final WifiDisplay display,
+ final Surface surface, final int width, final int height, final int flags) {
+ if (!Objects.equal(mAdvertisedDisplay, display)
+ || mAdvertisedDisplaySurface != surface
+ || mAdvertisedDisplayWidth != width
+ || mAdvertisedDisplayHeight != height
+ || mAdvertisedDisplayFlags != flags) {
+ final WifiDisplay oldDisplay = mAdvertisedDisplay;
+ final Surface oldSurface = mAdvertisedDisplaySurface;
+
+ mAdvertisedDisplay = display;
+ mAdvertisedDisplaySurface = surface;
+ mAdvertisedDisplayWidth = width;
+ mAdvertisedDisplayHeight = height;
+ mAdvertisedDisplayFlags = flags;
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (oldSurface != null && surface != oldSurface) {
+ mListener.onDisplayDisconnected();
+ } else if (oldDisplay != null && !Objects.equal(display, oldDisplay)) {
+ mListener.onDisplayConnectionFailed();
+ }
+
+ if (display != null) {
+ if (!Objects.equal(display, oldDisplay)) {
+ mListener.onDisplayConnecting(display);
+ }
+ if (surface != null && surface != oldSurface) {
+ mListener.onDisplayConnected(display, surface, width, height, flags);
+ }
+ }
+ }
+ });
+ }
+ }
+
+ private void unadvertiseDisplay() {
+ advertiseDisplay(null, null, 0, 0, 0);
+ }
+
private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
NetworkInterface iface;
try {
@@ -766,7 +836,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private static WifiDisplay createWifiDisplay(WifiP2pDevice device) {
- return new WifiDisplay(device.deviceAddress, device.deviceName);
+ return new WifiDisplay(device.deviceAddress, device.deviceName, null);
}
private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() {
@@ -774,6 +844,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
+ // This broadcast is sticky so we'll always get the initial Wifi P2P state
+ // on startup.
boolean enabled = (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE,
WifiP2pManager.WIFI_P2P_STATE_DISABLED)) ==
WifiP2pManager.WIFI_P2P_STATE_ENABLED;
@@ -806,10 +878,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
* Called on the handler thread when displays are connected or disconnected.
*/
public interface Listener {
- void onEnablementChanged(boolean enabled);
+ void onFeatureStateChanged(int featureState);
void onScanStarted();
- void onScanFinished(WifiDisplay[] knownDisplays);
+ void onScanFinished(WifiDisplay[] availableDisplays);
void onDisplayConnecting(WifiDisplay display);
void onDisplayConnectionFailed();
diff --git a/services/java/com/android/server/net/LockdownVpnTracker.java b/services/java/com/android/server/net/LockdownVpnTracker.java
index f2d6745..f32dd09 100644
--- a/services/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/java/com/android/server/net/LockdownVpnTracker.java
@@ -268,9 +268,11 @@ public class LockdownVpnTracker {
}
public NetworkInfo augmentNetworkInfo(NetworkInfo info) {
- final NetworkInfo vpnInfo = mVpn.getNetworkInfo();
- info = new NetworkInfo(info);
- info.setDetailedState(vpnInfo.getDetailedState(), vpnInfo.getReason(), null);
+ if (info.isConnected()) {
+ final NetworkInfo vpnInfo = mVpn.getNetworkInfo();
+ info = new NetworkInfo(info);
+ info.setDetailedState(vpnInfo.getDetailedState(), vpnInfo.getReason(), null);
+ }
return info;
}
diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java
index 60666b4..3169035 100644
--- a/services/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/java/com/android/server/net/NetworkStatsCollection.java
@@ -31,6 +31,7 @@ import android.net.TrafficStats;
import android.text.format.DateUtils;
import android.util.AtomicFile;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Objects;
@@ -431,13 +432,13 @@ public class NetworkStatsCollection implements FileRotator.Reader {
* moving any {@link NetworkStats#TAG_NONE} series to
* {@link TrafficStats#UID_REMOVED}.
*/
- public void removeUid(int uid) {
+ public void removeUids(int[] uids) {
final ArrayList<Key> knownKeys = Lists.newArrayList();
knownKeys.addAll(mStats.keySet());
// migrate all UID stats into special "removed" bucket
for (Key key : knownKeys) {
- if (key.uid == uid) {
+ if (ArrayUtils.contains(uids, key.uid)) {
// only migrate combined TAG_NONE history
if (key.tag == TAG_NONE) {
final NetworkStatsHistory uidHistory = mStats.get(key);
diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java
index c3ecf54..2b32b41 100644
--- a/services/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/java/com/android/server/net/NetworkStatsRecorder.java
@@ -42,6 +42,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
@@ -233,23 +234,27 @@ public class NetworkStatsRecorder {
* Remove the given UID from all {@link FileRotator} history, migrating it
* to {@link TrafficStats#UID_REMOVED}.
*/
- public void removeUidLocked(int uid) {
+ public void removeUidsLocked(int[] uids) {
try {
- // process all existing data to migrate uid
- mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uid));
+ // Rewrite all persisted data to migrate UID stats
+ mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
} catch (IOException e) {
- Log.wtf(TAG, "problem removing UID " + uid, e);
+ Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
recoverFromWtf();
}
- // clear UID from current stats snapshot
+ // Remove any pending stats
+ mPending.removeUids(uids);
+ mSinceBoot.removeUids(uids);
+
+ // Clear UID from current stats snapshot
if (mLastSnapshot != null) {
- mLastSnapshot = mLastSnapshot.withoutUid(uid);
+ mLastSnapshot = mLastSnapshot.withoutUids(uids);
}
final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
if (complete != null) {
- complete.removeUid(uid);
+ complete.removeUids(uids);
}
}
@@ -293,11 +298,11 @@ public class NetworkStatsRecorder {
*/
public static class RemoveUidRewriter implements FileRotator.Rewriter {
private final NetworkStatsCollection mTemp;
- private final int mUid;
+ private final int[] mUids;
- public RemoveUidRewriter(long bucketDuration, int uid) {
+ public RemoveUidRewriter(long bucketDuration, int[] uids) {
mTemp = new NetworkStatsCollection(bucketDuration);
- mUid = uid;
+ mUids = uids;
}
@Override
@@ -309,7 +314,7 @@ public class NetworkStatsRecorder {
public void read(InputStream in) throws IOException {
mTemp.read(in);
mTemp.clearDirty();
- mTemp.removeUid(mUid);
+ mTemp.removeUids(mUids);
}
@Override
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 3a593e4..f2748a3 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -23,6 +23,7 @@ import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.content.Intent.ACTION_SHUTDOWN;
import static android.content.Intent.ACTION_UID_REMOVED;
+import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
@@ -76,6 +77,8 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
@@ -112,6 +115,7 @@ import android.util.Slog;
import android.util.SparseIntArray;
import android.util.TrustedTime;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
@@ -122,8 +126,10 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
/**
* Collect and persist detailed network statistics, and provide this data to
@@ -322,6 +328,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
+ // listen for user changes to clean stats
+ final IntentFilter userFilter = new IntentFilter(ACTION_USER_REMOVED);
+ mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
+
// persist stats during clean shutdown
final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN);
mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
@@ -739,11 +749,34 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public void onReceive(Context context, Intent intent) {
// on background handler thread, and UID_REMOVED is protected
// broadcast.
- final int uid = intent.getIntExtra(EXTRA_UID, 0);
+
+ final int uid = intent.getIntExtra(EXTRA_UID, -1);
+ if (uid == -1) return;
+
+ synchronized (mStatsLock) {
+ mWakeLock.acquire();
+ try {
+ removeUidsLocked(uid);
+ } finally {
+ mWakeLock.release();
+ }
+ }
+ }
+ };
+
+ private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // On background handler thread, and USER_REMOVED is protected
+ // broadcast.
+
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (userId == -1) return;
+
synchronized (mStatsLock) {
mWakeLock.acquire();
try {
- removeUidLocked(uid);
+ removeUserLocked(userId);
} finally {
mWakeLock.release();
}
@@ -1034,15 +1067,37 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
/**
* Clean up {@link #mUidRecorder} after UID is removed.
*/
- private void removeUidLocked(int uid) {
- // perform one last poll before removing
+ private void removeUidsLocked(int... uids) {
+ if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
+
+ // Perform one last poll before removing
performPollLocked(FLAG_PERSIST_ALL);
- mUidRecorder.removeUidLocked(uid);
- mUidTagRecorder.removeUidLocked(uid);
+ mUidRecorder.removeUidsLocked(uids);
+ mUidTagRecorder.removeUidsLocked(uids);
+
+ // Clear kernel stats associated with UID
+ for (int uid : uids) {
+ resetKernelUidStats(uid);
+ }
+ }
+
+ /**
+ * Clean up {@link #mUidRecorder} after user is removed.
+ */
+ private void removeUserLocked(int userId) {
+ if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId);
+
+ // Build list of UIDs that we should clean up
+ int[] uids = new int[0];
+ final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
+ PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
+ for (ApplicationInfo app : apps) {
+ final int uid = UserHandle.getUid(userId, app.uid);
+ uids = ArrayUtils.appendInt(uids, uid);
+ }
- // clear kernel stats associated with UID
- resetKernelUidStats(uid);
+ removeUidsLocked(uids);
}
@Override
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 536c612..f0cc083 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -8044,13 +8044,13 @@ public class PackageManagerService extends IPackageManager.Stub {
IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
try {
- if (dpm != null && dpm.packageHasActiveAdmins(packageName)) {
+ if (dpm != null && dpm.packageHasActiveAdmins(packageName, UserHandle.getUserId(uid))) {
Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
} catch (RemoteException e) {
}
-
+
synchronized (mInstallLock) {
res = deletePackageLI(packageName,
(flags & PackageManager.DELETE_ALL_USERS) != 0
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 690d7c9..2dc9a6a 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -29,6 +29,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
@@ -37,6 +39,7 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
@@ -83,8 +86,6 @@ public class UserManagerService extends IUserManager.Stub {
private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
- private final int mUserLimit;
-
private int[] mUserIds;
private boolean mGuestEnabled;
private int mNextSerialNumber;
@@ -127,8 +128,6 @@ public class UserManagerService extends IUserManager.Stub {
mPm = pm;
mInstallLock = installLock;
mPackagesLock = packagesLock;
- mUserLimit = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_multiuserMaximumUsers);
mUsersDir = new File(dataDir, USER_INFO_DIR);
mUsersDir.mkdirs();
// Make zeroth user directory, for services to migrate their files to that location
@@ -188,30 +187,35 @@ public class UserManagerService extends IUserManager.Stub {
writeUserLocked(info);
}
}
+ sendUserInfoChangedBroadcast(userId);
}
@Override
- public ParcelFileDescriptor setUserIcon(int userId) {
+ public void setUserIcon(int userId, Bitmap bitmap) {
checkManageUsersPermission("update users");
synchronized (mPackagesLock) {
UserInfo info = mUsers.get(userId);
- if (info == null) return null;
- ParcelFileDescriptor fd = openIconBitmapLocked(info, true /* write */);
- if (fd != null) {
- writeUserLocked(info);
- }
- return fd;
+ if (info == null) return;
+ writeBitmapLocked(info, bitmap);
+ writeUserLocked(info);
}
+ sendUserInfoChangedBroadcast(userId);
+ }
+
+ private void sendUserInfoChangedBroadcast(int userId) {
+ Intent changedIntent = new Intent(Intent.ACTION_USER_INFO_CHANGED);
+ changedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ changedIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(changedIntent, new UserHandle(userId));
}
@Override
- public ParcelFileDescriptor getUserIcon(int userId) {
+ public Bitmap getUserIcon(int userId) {
checkManageUsersPermission("read users");
synchronized (mPackagesLock) {
UserInfo info = mUsers.get(userId);
if (info == null || info.iconPath == null) return null;
- ParcelFileDescriptor fd = openIconBitmapLocked(info, false /* read */);
- return fd;
+ return BitmapFactory.decodeFile(info.iconPath);
}
}
@@ -268,7 +272,7 @@ public class UserManagerService extends IUserManager.Stub {
*/
private boolean isUserLimitReachedLocked() {
int nUsers = mUsers.size();
- return nUsers >= mUserLimit;
+ return nUsers >= UserManager.getMaxSupportedUsers();
}
/**
@@ -289,7 +293,7 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- private ParcelFileDescriptor openIconBitmapLocked(UserInfo info, boolean toWrite) {
+ private void writeBitmapLocked(UserInfo info, Bitmap bitmap) {
try {
File dir = new File(mUsersDir, Integer.toString(info.id));
File file = new File(dir, USER_PHOTO_FILENAME);
@@ -300,16 +304,18 @@ public class UserManagerService extends IUserManager.Stub {
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-1, -1);
}
- ParcelFileDescriptor fd = ParcelFileDescriptor.open(file,
- toWrite ? MODE_CREATE|MODE_READ_WRITE : MODE_READ_WRITE);
- if (toWrite) {
+ FileOutputStream os;
+ if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, os = new FileOutputStream(file))) {
info.iconPath = file.getAbsolutePath();
}
- return fd;
+ try {
+ os.close();
+ } catch (IOException ioe) {
+ // What the ... !
+ }
} catch (FileNotFoundException e) {
Slog.w(LOG_TAG, "Error setting photo for user ", e);
}
- return null;
}
/**
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index fda619c..7052ed5 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -50,6 +50,7 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.WorkSource;
import android.provider.Settings;
+import android.service.dreams.Dream;
import android.service.dreams.IDreamManager;
import android.util.EventLog;
import android.util.Log;
@@ -98,6 +99,8 @@ public final class PowerManagerService extends IPowerManager.Stub
private static final int DIRTY_STAY_ON = 1 << 7;
// Dirty bit: battery state changed
private static final int DIRTY_BATTERY_STATE = 1 << 8;
+ // Dirty bit: dream ended
+ private static final int DIRTY_DREAM_ENDED = 1 << 9;
// Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
// The screen should be off or in the process of being turned off by the display controller.
@@ -364,6 +367,10 @@ public final class PowerManagerService extends IPowerManager.Stub
filter.addAction(Intent.ACTION_DOCK_EVENT);
mContext.registerReceiver(new DockReceiver(), filter);
+ filter = new IntentFilter();
+ filter.addAction(Dream.ACTION_DREAMING_STOPPED);
+ mContext.registerReceiver(new DreamReceiver(), filter);
+
// Register for settings changes.
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -1146,8 +1153,12 @@ public final class PowerManagerService extends IPowerManager.Stub
* Determines whether to post a message to the sandman to update the dream state.
*/
private void updateDreamLocked(int dirty) {
- if ((dirty & (DIRTY_WAKEFULNESS | DIRTY_SETTINGS
- | DIRTY_IS_POWERED | DIRTY_STAY_ON | DIRTY_BATTERY_STATE)) != 0) {
+ if ((dirty & (DIRTY_WAKEFULNESS
+ | DIRTY_SETTINGS
+ | DIRTY_IS_POWERED
+ | DIRTY_STAY_ON
+ | DIRTY_BATTERY_STATE
+ | DIRTY_DREAM_ENDED)) != 0) {
scheduleSandmanLocked();
}
}
@@ -1230,15 +1241,15 @@ public final class PowerManagerService extends IPowerManager.Stub
handleDreamFinishedLocked();
}
- // Allow the sandman to detect when the dream has ended.
- // FIXME: The DreamManagerService should tell us explicitly.
+ // In addition to listening for the intent, poll the sandman periodically to detect
+ // when the dream has ended (as a watchdog only, ensuring our state is always correct).
if (mWakefulness == WAKEFULNESS_DREAMING
|| mWakefulness == WAKEFULNESS_NAPPING) {
if (!mSandmanScheduled) {
mSandmanScheduled = true;
Message msg = mHandler.obtainMessage(MSG_SANDMAN);
msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg, 1000);
+ mHandler.sendMessageDelayed(msg, 5000);
}
}
}
@@ -1472,6 +1483,11 @@ public final class PowerManagerService extends IPowerManager.Stub
// TODO
}
+ private void handleDreamEndedLocked() {
+ mDirty |= DIRTY_DREAM_ENDED;
+ updatePowerStateLocked();
+ }
+
/**
* Reboot the device immediately, passing 'reason' (may be null)
* to the underlying __reboot system call. Should not return.
@@ -1937,6 +1953,15 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
+ private final class DreamReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (mLock) {
+ handleDreamEndedLocked();
+ }
+ }
+ }
+
private final class SettingsObserver extends ContentObserver {
public SettingsObserver(Handler handler) {
super(handler);
diff --git a/services/java/com/android/server/updatable/CertPinInstallReceiver.java b/services/java/com/android/server/updates/CertPinInstallReceiver.java
index c03fbc3..c03fbc3 100644
--- a/services/java/com/android/server/updatable/CertPinInstallReceiver.java
+++ b/services/java/com/android/server/updates/CertPinInstallReceiver.java
diff --git a/services/java/com/android/server/updatable/ConfigUpdateInstallReceiver.java b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
index a74a648..5da612a 100644
--- a/services/java/com/android/server/updatable/ConfigUpdateInstallReceiver.java
+++ b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
@@ -89,8 +89,7 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
// get the hash of the currently used value
String currentHash = getCurrentHash(getCurrentContent());
if (!verifyVersion(currentVersion, altVersion)) {
- EventLog.writeEvent(EventLogTags.CONFIG_INSTALL_FAILED,
- "New version is not greater than current version");
+ Slog.i(TAG, "Not installing, new version is <= current version");
} else if (!verifyPreviousHash(currentHash, altRequiredHash)) {
EventLog.writeEvent(EventLogTags.CONFIG_INSTALL_FAILED,
"Current hash did not match required value");
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 3ef6d4c..392d5e7 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -91,6 +91,7 @@ public class UsbDeviceManager {
private static final int MSG_SET_CURRENT_FUNCTIONS = 2;
private static final int MSG_SYSTEM_READY = 3;
private static final int MSG_BOOT_COMPLETED = 4;
+ private static final int MSG_USER_SWITCHED = 5;
private static final int AUDIO_MODE_NONE = 0;
private static final int AUDIO_MODE_SOURCE = 1;
@@ -295,14 +296,24 @@ public class UsbDeviceManager {
private UsbAccessory mCurrentAccessory;
private int mUsbNotificationId;
private boolean mAdbNotificationShown;
+ private int mCurrentUser = UserHandle.USER_NULL;
private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Slog.d(TAG, "boot completed");
mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
}
};
+ private final BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget();
+ }
+ };
+
public UsbHandler(Looper looper) {
super(looper);
try {
@@ -347,8 +358,10 @@ public class UsbDeviceManager {
mUEventObserver.startObserving(USB_STATE_MATCH);
mUEventObserver.startObserving(ACCESSORY_START_MATCH);
- mContext.registerReceiver(mBootCompletedReceiver,
- new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ mContext.registerReceiver(
+ mBootCompletedReceiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ mContext.registerReceiver(
+ mUserSwitchedReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
} catch (Exception e) {
Slog.e(TAG, "Error initializing UsbHandler", e);
}
@@ -611,6 +624,18 @@ public class UsbDeviceManager {
mDebuggingManager.setAdbEnabled(mAdbEnabled);
}
break;
+ case MSG_USER_SWITCHED: {
+ final boolean mtpActive =
+ containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)
+ || containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP);
+ if (mtpActive && mCurrentUser != UserHandle.USER_NULL) {
+ Slog.v(TAG, "Current user switched; resetting USB host stack for MTP");
+ setUsbConfig("none");
+ setUsbConfig(mCurrentFunctions);
+ }
+ mCurrentUser = msg.arg1;
+ break;
+ }
}
}
diff --git a/services/java/com/android/server/wm/KeyguardDisableHandler.java b/services/java/com/android/server/wm/KeyguardDisableHandler.java
index d935b8b..859df51 100644
--- a/services/java/com/android/server/wm/KeyguardDisableHandler.java
+++ b/services/java/com/android/server/wm/KeyguardDisableHandler.java
@@ -16,12 +16,15 @@
package com.android.server.wm;
+import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
+import android.os.RemoteException;
import android.os.TokenWatcher;
+import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
import android.view.WindowManagerPolicy;
@@ -87,9 +90,14 @@ public class KeyguardDisableHandler extends Handler {
DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
Context.DEVICE_POLICY_SERVICE);
if (dpm != null) {
- mAllowDisableKeyguard = dpm.getPasswordQuality(null)
- == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?
- ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;
+ try {
+ mAllowDisableKeyguard = dpm.getPasswordQuality(null,
+ ActivityManagerNative.getDefault().getCurrentUser().id)
+ == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?
+ ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;
+ } catch (RemoteException re) {
+ // Nothing much we can do
+ }
}
}
if (mAllowDisableKeyguard == ALLOW_DISABLE_YES) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 55a7c46..73cc7ed 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -292,9 +292,6 @@ public class WindowManagerService extends IWindowManager.Stub
if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) {
mKeyguardDisableHandler.sendEmptyMessage(
KeyguardDisableHandler.KEYGUARD_POLICY_CHANGED);
- } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- final int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- mCurrentUserId = newUserId;
}
}
};
@@ -811,8 +808,6 @@ public class WindowManagerService extends IWindowManager.Stub
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
IntentFilter filter = new IntentFilter();
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- // Track user switching.
- filter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(mBroadcastReceiver, filter);
mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
@@ -1648,7 +1643,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- if (mWallpaperTarget != foundW) {
+ if (mWallpaperTarget != foundW
+ && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != foundW)) {
if (DEBUG_WALLPAPER) {
Slog.v(TAG, "New wallpaper target: " + foundW
+ " oldTarget: " + mWallpaperTarget);
@@ -3391,7 +3387,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Exiting app
if (scaleUp) {
// noop animation
- a = new AlphaAnimation(1, 1);
+ a = new AlphaAnimation(1, 0);
a.setDuration(duration);
} else {
float scaleW = thumbWidth / displayInfo.appWidth;
@@ -3440,7 +3436,7 @@ public class WindowManagerService extends IWindowManager.Stub
"applyAnimation: atoken=" + atoken
+ " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
+ " transit=" + transit + " isEntrance=" + enter
- + " Callers " + Debug.getCallers(3));
+ + " Callers=" + Debug.getCallers(3));
} else if (mNextAppTransitionType == ActivityOptions.ANIM_SCALE_UP) {
a = createScaleUpAnimationLocked(transit, enter);
initialized = true;
@@ -3448,7 +3444,7 @@ public class WindowManagerService extends IWindowManager.Stub
"applyAnimation: atoken=" + atoken
+ " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
+ " transit=" + transit + " isEntrance=" + enter
- + " Callers " + Debug.getCallers(3));
+ + " Callers=" + Debug.getCallers(3));
} else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP ||
mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN) {
boolean scaleUp = (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP);
@@ -3459,7 +3455,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.v(TAG, "applyAnimation: atoken=" + atoken
+ " anim=" + a + " nextAppTransition=" + animName
+ " transit=" + transit + " isEntrance=" + enter
- + " Callers " + Debug.getCallers(3));
+ + " Callers=" + Debug.getCallers(3));
}
} else {
int animAttr = 0;
@@ -3521,7 +3517,7 @@ public class WindowManagerService extends IWindowManager.Stub
+ " anim=" + a
+ " animAttr=0x" + Integer.toHexString(animAttr)
+ " transit=" + transit + " isEntrance=" + enter
- + " Callers " + Debug.getCallers(3));
+ + " Callers=" + Debug.getCallers(3));
}
if (a != null) {
if (DEBUG_ANIM) {
@@ -4193,7 +4189,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
if (DEBUG_STARTING_WINDOW) Slog.v(
- TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg
+ TAG, "setAppStartingWindow: token=" + token + " pkg=" + pkg
+ " transferFrom=" + transferFrom);
AppWindowToken wtoken = findAppWindowToken(token);
@@ -4225,7 +4221,7 @@ public class WindowManagerService extends IWindowManager.Stub
mSkipAppTransitionAnimation = true;
}
if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
- "Moving existing starting from " + ttoken
+ "Moving existing starting " + startingWindow + " from " + ttoken
+ " to " + wtoken);
final long origId = Binder.clearCallingIdentity();
@@ -4234,6 +4230,7 @@ public class WindowManagerService extends IWindowManager.Stub
wtoken.startingData = ttoken.startingData;
wtoken.startingView = ttoken.startingView;
wtoken.startingDisplayed = ttoken.startingDisplayed;
+ ttoken.startingDisplayed = false;
wtoken.startingWindow = startingWindow;
wtoken.reportedVisible = ttoken.reportedVisible;
ttoken.startingData = null;
@@ -4243,6 +4240,8 @@ public class WindowManagerService extends IWindowManager.Stub
startingWindow.mToken = wtoken;
startingWindow.mRootToken = wtoken;
startingWindow.mAppToken = wtoken;
+ startingWindow.mWinAnimator.mAppAnimator = wtoken.mAppAnimator;
+
if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) {
Slog.v(TAG, "Removing starting window: " + startingWindow);
}
@@ -4550,9 +4549,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
wtoken.hiddenRequested = !visible;
- if (DEBUG_APP_TRANSITIONS) Slog.v(
- TAG, "Setting dummy animation on: " + wtoken);
if (!wtoken.startingDisplayed) {
+ if (DEBUG_APP_TRANSITIONS) Slog.v(
+ TAG, "Setting dummy animation on: " + wtoken);
wtoken.mAppAnimator.setDummyAnimation();
}
mOpeningApps.remove(wtoken);
@@ -5396,6 +5395,13 @@ public class WindowManagerService extends IWindowManager.Stub
mInputManager.setInputFilter(filter);
}
+ public void setCurrentUser(final int newUserId) {
+ synchronized (mWindowMap) {
+ mCurrentUserId = newUserId;
+ mPolicy.setCurrentUserLw(newUserId);
+ }
+ }
+
public void enableScreenAfterBoot() {
synchronized(mWindowMap) {
if (DEBUG_BOOT) {
@@ -8147,7 +8153,11 @@ public class WindowManagerService extends IWindowManager.Stub
updateLayoutToAnimationLocked();
}
if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
- + winAnimator.mAnimLayer);
+ + "mBase=" + w.mBaseLayer
+ + " mLayer=" + w.mLayer
+ + (w.mAppToken == null ?
+ "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
+ + " =mAnimLayer=" + winAnimator.mAnimLayer);
//System.out.println(
// "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
}
@@ -8539,7 +8549,7 @@ public class WindowManagerService extends IWindowManager.Stub
transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New transit away from wallpaper: " + transit);
- } else if (mWallpaperTarget != null) {
+ } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {
// We are transitioning from an activity without
// a wallpaper to now showing the wallpaper
transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
@@ -8596,7 +8606,7 @@ public class WindowManagerService extends IWindowManager.Stub
for (i=0; i<NN; i++) {
AppWindowToken wtoken = mClosingApps.get(i);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Now closing app" + wtoken);
+ "Now closing app " + wtoken);
wtoken.mAppAnimator.clearThumbnail();
wtoken.inPendingTransaction = false;
wtoken.mAppAnimator.animation = null;
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index b62028e..ac958b8 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -518,11 +518,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
MagnificationSpec spec = mDisplayContent.mMagnificationSpec;
if (spec != null && !spec.isNop()) {
if (mAttachedWindow != null) {
- if (!mPolicy.canMagnifyWindow(mAttachedWindow.mAttrs)) {
+ if (!mPolicy.canMagnifyWindowLw(mAttachedWindow.mAttrs)) {
return null;
}
}
- if (!mPolicy.canMagnifyWindow(mAttrs)) {
+ if (!mPolicy.canMagnifyWindowLw(mAttrs)) {
return null;
}
}
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 000a191..5f40709 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -62,7 +62,7 @@ class WindowStateAnimator {
final WindowState mWin;
final WindowStateAnimator mAttachedWinAnimator;
final WindowAnimator mAnimator;
- final AppWindowAnimator mAppAnimator;
+ AppWindowAnimator mAppAnimator;
final Session mSession;
final WindowManagerPolicy mPolicy;
final Context mContext;
@@ -1520,7 +1520,7 @@ class WindowStateAnimator {
"applyAnimation: win=" + this
+ " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
+ " a=" + a
- + " mAnimation=" + mAnimation
+ + " transit=" + transit
+ " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
if (a != null) {
if (WindowManagerService.DEBUG_ANIM) {