summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/AlarmManagerService.java232
-rw-r--r--services/java/com/android/server/AppWidgetService.java64
-rw-r--r--services/java/com/android/server/AppWidgetServiceImpl.java98
-rw-r--r--services/java/com/android/server/AttributeCache.java51
-rwxr-xr-xservices/java/com/android/server/BluetoothManagerService.java297
-rw-r--r--services/java/com/android/server/BootReceiver.java13
-rw-r--r--services/java/com/android/server/ConnectivityService.java14
-rw-r--r--services/java/com/android/server/DevicePolicyManagerService.java53
-rw-r--r--services/java/com/android/server/EntropyMixer.java7
-rw-r--r--services/java/com/android/server/EventLogTags.logtags8
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java57
-rw-r--r--services/java/com/android/server/LocationManagerService.java11
-rw-r--r--services/java/com/android/server/MountService.java26
-rw-r--r--services/java/com/android/server/NativeDaemonConnector.java3
-rw-r--r--services/java/com/android/server/NotificationManagerService.java52
-rw-r--r--services/java/com/android/server/StatusBarManagerService.java4
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/java/com/android/server/TelephonyRegistry.java2
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java2
-rw-r--r--services/java/com/android/server/Watchdog.java12
-rw-r--r--services/java/com/android/server/am/ActiveServices.java12
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java125
-rw-r--r--services/java/com/android/server/am/ActivityRecord.java2
-rw-r--r--services/java/com/android/server/am/ActivityStack.java12
-rw-r--r--services/java/com/android/server/am/BroadcastQueue.java16
-rw-r--r--services/java/com/android/server/am/EventLogTags.logtags4
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java40
-rw-r--r--services/java/com/android/server/display/DisplayTransactionListener.java26
-rw-r--r--services/java/com/android/server/display/PersistentDataStore.java25
-rw-r--r--services/java/com/android/server/display/WifiDisplayAdapter.java85
-rw-r--r--services/java/com/android/server/display/WifiDisplayController.java78
-rw-r--r--services/java/com/android/server/dreams/DreamController.java18
-rw-r--r--services/java/com/android/server/dreams/DreamManagerService.java44
-rw-r--r--services/java/com/android/server/net/NetworkPolicyManagerService.java12
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java5
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java30
-rw-r--r--services/java/com/android/server/pm/Settings.java7
-rw-r--r--services/java/com/android/server/pm/UserManagerService.java80
-rw-r--r--services/java/com/android/server/power/DisplayPowerController.java11
-rw-r--r--services/java/com/android/server/power/ElectronBeam.java107
-rw-r--r--services/java/com/android/server/power/Notifier.java41
-rw-r--r--services/java/com/android/server/power/PowerManagerService.java25
-rw-r--r--services/java/com/android/server/power/RampAnimator.java18
-rw-r--r--services/java/com/android/server/usb/UsbDeviceManager.java4
-rw-r--r--services/java/com/android/server/usb/UsbHostManager.java4
-rw-r--r--services/java/com/android/server/usb/UsbService.java3
-rw-r--r--services/java/com/android/server/wm/AppWindowToken.java8
-rw-r--r--services/java/com/android/server/wm/ScreenRotationAnimation.java4
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java181
-rw-r--r--services/java/com/android/server/wm/WindowState.java23
-rw-r--r--services/java/com/android/server/wm/WindowStateAnimator.java8
-rw-r--r--services/java/com/android/server/wm/WindowToken.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java8
53 files changed, 1524 insertions, 552 deletions
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 440f8e1..cbd00f3 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -22,6 +22,7 @@ import android.app.AlarmManager;
import android.app.IAlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -38,6 +39,7 @@ import android.os.UserHandle;
import android.os.WorkSource;
import android.text.TextUtils;
import android.text.format.Time;
+import android.util.Pair;
import android.util.Slog;
import android.util.TimeUtils;
@@ -45,16 +47,18 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.Map;
import java.util.TimeZone;
+import com.android.internal.util.LocalLog;
+
class AlarmManagerService extends IAlarmManager.Stub {
// The threshold for how long an alarm can be late before we print a
// warning message. The time duration is in milliseconds.
@@ -79,7 +83,9 @@ class AlarmManagerService extends IAlarmManager.Stub {
= new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
private final Context mContext;
-
+
+ private final LocalLog mLog = new LocalLog(TAG);
+
private Object mLock = new Object();
private final ArrayList<Alarm> mRtcWakeupAlarms = new ArrayList<Alarm>();
@@ -91,7 +97,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
private int mDescriptor;
private int mBroadcastRefCount = 0;
private PowerManager.WakeLock mWakeLock;
- private LinkedList<PendingIntent> mInFlight = new LinkedList<PendingIntent>();
+ private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
private final AlarmThread mWaitThread = new AlarmThread();
private final AlarmHandler mHandler = new AlarmHandler();
private ClockReceiver mClockReceiver;
@@ -99,18 +105,59 @@ class AlarmManagerService extends IAlarmManager.Stub {
private final ResultReceiver mResultReceiver = new ResultReceiver();
private final PendingIntent mTimeTickSender;
private final PendingIntent mDateChangeSender;
-
+
+ private static final class InFlight extends Intent {
+ final PendingIntent mPendingIntent;
+ final Pair<String, ComponentName> mTarget;
+ final BroadcastStats mBroadcastStats;
+ final FilterStats mFilterStats;
+
+ InFlight(AlarmManagerService service, PendingIntent pendingIntent) {
+ mPendingIntent = pendingIntent;
+ Intent intent = pendingIntent.getIntent();
+ mTarget = intent != null
+ ? new Pair<String, ComponentName>(intent.getAction(), intent.getComponent())
+ : null;
+ mBroadcastStats = service.getStatsLocked(pendingIntent);
+ FilterStats fs = mBroadcastStats.filterStats.get(mTarget);
+ if (fs == null) {
+ fs = new FilterStats(mBroadcastStats, mTarget);
+ mBroadcastStats.filterStats.put(mTarget, fs);
+ }
+ mFilterStats = fs;
+ }
+ }
+
private static final class FilterStats {
+ final BroadcastStats mBroadcastStats;
+ final Pair<String, ComponentName> mTarget;
+
+ long aggregateTime;
int count;
+ int numWakeup;
+ long startTime;
+ int nesting;
+
+ FilterStats(BroadcastStats broadcastStats, Pair<String, ComponentName> target) {
+ mBroadcastStats = broadcastStats;
+ mTarget = target;
+ }
}
private static final class BroadcastStats {
+ final String mPackageName;
+
long aggregateTime;
+ int count;
int numWakeup;
long startTime;
int nesting;
- HashMap<Intent.FilterComparison, FilterStats> filterStats
- = new HashMap<Intent.FilterComparison, FilterStats>();
+ final HashMap<Pair<String, ComponentName>, FilterStats> filterStats
+ = new HashMap<Pair<String, ComponentName>, FilterStats>();
+
+ BroadcastStats(String packageName) {
+ mPackageName = packageName;
+ }
}
private final HashMap<String, BroadcastStats> mBroadcastStats
@@ -496,24 +543,104 @@ class AlarmManagerService extends IAlarmManager.Stub {
dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now);
}
}
-
- pw.println(" ");
+
+ pw.println();
pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
-
+ pw.println();
+
+ if (mLog.dump(pw, " Recent problems", " ")) {
+ pw.println();
+ }
+
+ final FilterStats[] topFilters = new FilterStats[10];
+ final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
+ @Override
+ public int compare(FilterStats lhs, FilterStats rhs) {
+ if (lhs.aggregateTime < rhs.aggregateTime) {
+ return 1;
+ } else if (lhs.aggregateTime > rhs.aggregateTime) {
+ return -1;
+ }
+ return 0;
+ }
+ };
+ int len = 0;
+ for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
+ BroadcastStats bs = be.getValue();
+ for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
+ : bs.filterStats.entrySet()) {
+ FilterStats fs = fe.getValue();
+ int pos = len > 0
+ ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
+ if (pos < 0) {
+ pos = -pos - 1;
+ }
+ if (pos < topFilters.length) {
+ int copylen = topFilters.length - pos - 1;
+ if (copylen > 0) {
+ System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+ }
+ topFilters[pos] = fs;
+ if (len < topFilters.length) {
+ len++;
+ }
+ }
+ }
+ }
+ if (len > 0) {
+ pw.println(" Top Alarms:");
+ for (int i=0; i<len; i++) {
+ FilterStats fs = topFilters[i];
+ pw.print(" ");
+ if (fs.nesting > 0) pw.print("*ACTIVE* ");
+ TimeUtils.formatDuration(fs.aggregateTime, pw);
+ pw.print(" running, "); pw.print(fs.numWakeup);
+ pw.print(" wakeups, "); pw.print(fs.count);
+ pw.print(" alarms: "); pw.print(fs.mBroadcastStats.mPackageName);
+ pw.println();
+ pw.print(" ");
+ if (fs.mTarget.first != null) {
+ pw.print(" act="); pw.print(fs.mTarget.first);
+ }
+ if (fs.mTarget.second != null) {
+ pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
+ }
+ pw.println();
+ }
+ }
+
pw.println(" ");
pw.println(" Alarm Stats:");
+ final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
BroadcastStats bs = be.getValue();
- pw.print(" "); pw.println(be.getKey());
- pw.print(" "); pw.print(bs.aggregateTime);
- pw.print("ms running, "); pw.print(bs.numWakeup);
- pw.println(" wakeups");
- for (Map.Entry<Intent.FilterComparison, FilterStats> fe
+ pw.print(" ");
+ if (bs.nesting > 0) pw.print("*ACTIVE* ");
+ pw.print(be.getKey());
+ pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
+ pw.print(" running, "); pw.print(bs.numWakeup);
+ pw.println(" wakeups:");
+ tmpFilters.clear();
+ for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
: bs.filterStats.entrySet()) {
- pw.print(" "); pw.print(fe.getValue().count);
- pw.print(" alarms: ");
- pw.println(fe.getKey().getIntent().toShortString(
- false, true, false, true));
+ tmpFilters.add(fe.getValue());
+ }
+ Collections.sort(tmpFilters, comparator);
+ for (int i=0; i<tmpFilters.size(); i++) {
+ FilterStats fs = tmpFilters.get(i);
+ pw.print(" ");
+ if (fs.nesting > 0) pw.print("*ACTIVE* ");
+ TimeUtils.formatDuration(fs.aggregateTime, pw);
+ pw.print(" "); pw.print(fs.numWakeup);
+ pw.print(" wakes " ); pw.print(fs.count);
+ pw.print(" alarms:");
+ if (fs.mTarget.first != null) {
+ pw.print(" act="); pw.print(fs.mTarget.first);
+ }
+ if (fs.mTarget.second != null) {
+ pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
+ }
+ pw.println();
}
}
}
@@ -708,18 +835,31 @@ class AlarmManagerService extends IAlarmManager.Stub {
setWakelockWorkSource(alarm.operation);
mWakeLock.acquire();
}
- mInFlight.add(alarm.operation);
+ final InFlight inflight = new InFlight(AlarmManagerService.this,
+ alarm.operation);
+ mInFlight.add(inflight);
mBroadcastRefCount++;
-
- BroadcastStats bs = getStatsLocked(alarm.operation);
+
+ final BroadcastStats bs = inflight.mBroadcastStats;
+ bs.count++;
if (bs.nesting == 0) {
+ bs.nesting = 1;
bs.startTime = nowELAPSED;
} else {
bs.nesting++;
}
+ final FilterStats fs = inflight.mFilterStats;
+ fs.count++;
+ if (fs.nesting == 0) {
+ fs.nesting = 1;
+ fs.startTime = nowELAPSED;
+ } else {
+ fs.nesting++;
+ }
if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP
|| alarm.type == AlarmManager.RTC_WAKEUP) {
bs.numWakeup++;
+ fs.numWakeup++;
ActivityManagerNative.noteWakeupAlarm(
alarm.operation);
}
@@ -908,44 +1048,58 @@ class AlarmManagerService extends IAlarmManager.Stub {
String pkg = pi.getTargetPackage();
BroadcastStats bs = mBroadcastStats.get(pkg);
if (bs == null) {
- bs = new BroadcastStats();
+ bs = new BroadcastStats(pkg);
mBroadcastStats.put(pkg, bs);
}
return bs;
}
-
+
class ResultReceiver implements PendingIntent.OnFinished {
public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
String resultData, Bundle resultExtras) {
synchronized (mLock) {
- BroadcastStats bs = getStatsLocked(pi);
- if (bs != null) {
+ InFlight inflight = null;
+ for (int i=0; i<mInFlight.size(); i++) {
+ if (mInFlight.get(i).mPendingIntent == pi) {
+ inflight = mInFlight.remove(i);
+ break;
+ }
+ }
+ if (inflight != null) {
+ final long nowELAPSED = SystemClock.elapsedRealtime();
+ BroadcastStats bs = inflight.mBroadcastStats;
bs.nesting--;
if (bs.nesting <= 0) {
bs.nesting = 0;
- bs.aggregateTime += SystemClock.elapsedRealtime()
- - bs.startTime;
- Intent.FilterComparison fc = new Intent.FilterComparison(intent);
- FilterStats fs = bs.filterStats.get(fc);
- if (fs == null) {
- fs = new FilterStats();
- bs.filterStats.put(fc, fs);
- }
- fs.count++;
+ bs.aggregateTime += nowELAPSED - bs.startTime;
+ }
+ FilterStats fs = inflight.mFilterStats;
+ fs.nesting--;
+ if (fs.nesting <= 0) {
+ fs.nesting = 0;
+ fs.aggregateTime += nowELAPSED - fs.startTime;
}
+ } else {
+ mLog.w("No in-flight alarm for " + pi + " " + intent);
}
- mInFlight.removeFirst();
mBroadcastRefCount--;
if (mBroadcastRefCount == 0) {
mWakeLock.release();
+ if (mInFlight.size() > 0) {
+ mLog.w("Finished all broadcasts with " + mInFlight.size()
+ + " remaining inflights");
+ for (int i=0; i<mInFlight.size(); i++) {
+ mLog.w(" Remaining #" + i + ": " + mInFlight.get(i));
+ }
+ mInFlight.clear();
+ }
} else {
// the next of our alarms is now in flight. reattribute the wakelock.
- final PendingIntent nowInFlight = mInFlight.peekFirst();
- if (nowInFlight != null) {
- setWakelockWorkSource(nowInFlight);
+ if (mInFlight.size() > 0) {
+ setWakelockWorkSource(mInFlight.get(0).mPendingIntent);
} else {
// should never happen
- Slog.e(TAG, "Alarm wakelock still held but sent queue empty");
+ mLog.w("Alarm wakelock still held but sent queue empty");
mWakeLock.setWorkSource(null);
}
}
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 06d37dc..06aeb29 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -26,6 +26,8 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -54,13 +56,19 @@ class AppWidgetService extends IAppWidgetService.Stub
Locale mLocale;
PackageManager mPackageManager;
boolean mSafeMode;
+ private final Handler mSaveStateHandler;
private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
AppWidgetService(Context context) {
mContext = context;
+
+ HandlerThread handlerThread = new HandlerThread("AppWidgetService -- Save state");
+ handlerThread.start();
+ mSaveStateHandler = new Handler(handlerThread.getLooper());
+
mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
- AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0);
+ AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler);
mAppWidgetServices.append(0, primary);
}
@@ -138,6 +146,11 @@ class AppWidgetService extends IAppWidgetService.Stub
return getImplForUser(getCallingOrCurrentUserId()).allocateAppWidgetId(
packageName, hostId);
}
+
+ @Override
+ public int[] getAppWidgetIdsForHost(int hostId) throws RemoteException {
+ return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIdsForHost(hostId);
+ }
@Override
public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
@@ -183,9 +196,14 @@ class AppWidgetService extends IAppWidgetService.Stub
}
@Override
- public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
- throws RemoteException {
- getImplForUser(getCallingOrCurrentUserId()).bindRemoteViewsService(
+ public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
+ int userId) throws RemoteException {
+ if (Binder.getCallingPid() != android.os.Process.myPid()
+ && userId != UserHandle.getCallingUserId()) {
+ throw new SecurityException("Call from non-system process. Calling uid = "
+ + Binder.getCallingUid());
+ }
+ getImplForUser(userId).bindRemoteViewsService(
appWidgetId, intent, connection);
}
@@ -196,6 +214,17 @@ class AppWidgetService extends IAppWidgetService.Stub
packageName, hostId, updatedViews);
}
+ @Override
+ public int[] startListeningAsUser(IAppWidgetHost host, String packageName, int hostId,
+ List<RemoteViews> updatedViews, int userId) throws RemoteException {
+ if (Binder.getCallingPid() != android.os.Process.myPid()
+ && userId != UserHandle.getCallingUserId()) {
+ throw new SecurityException("Call from non-system process. Calling uid = "
+ + Binder.getCallingUid());
+ }
+ return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews);
+ }
+
public void onUserRemoved(int userId) {
if (userId < 1) return;
synchronized (mAppWidgetServices) {
@@ -229,7 +258,7 @@ class AppWidgetService extends IAppWidgetService.Stub
if (service == null) {
Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
// TODO: Verify that it's a valid user
- service = new AppWidgetServiceImpl(mContext, userId);
+ service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler);
service.systemReady(mSafeMode);
// Assume that BOOT_COMPLETED was received, as this is a non-primary user.
mAppWidgetServices.append(userId, service);
@@ -268,8 +297,9 @@ class AppWidgetService extends IAppWidgetService.Stub
}
@Override
- public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
- return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders();
+ public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter)
+ throws RemoteException {
+ return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders(categoryFilter);
}
@Override
@@ -292,8 +322,24 @@ class AppWidgetService extends IAppWidgetService.Stub
}
@Override
- public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
- getImplForUser(getCallingOrCurrentUserId()).unbindRemoteViewsService(
+ public void stopListeningAsUser(int hostId, int userId) throws RemoteException {
+ if (Binder.getCallingPid() != android.os.Process.myPid()
+ && userId != UserHandle.getCallingUserId()) {
+ throw new SecurityException("Call from non-system process. Calling uid = "
+ + Binder.getCallingUid());
+ }
+ getImplForUser(userId).stopListening(hostId);
+ }
+
+ @Override
+ public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId)
+ throws RemoteException {
+ if (Binder.getCallingPid() != android.os.Process.myPid()
+ && userId != UserHandle.getCallingUserId()) {
+ throw new SecurityException("Call from non-system process. Calling uid = "
+ + Binder.getCallingUid());
+ }
+ getImplForUser(userId).unbindRemoteViewsService(
appWidgetId, intent);
}
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index daa82f2..e1e9eaf 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -41,7 +41,10 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -113,6 +116,15 @@ class AppWidgetServiceImpl {
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
int tag; // for use while saving state (the index)
+
+ boolean uidMatches(int callingUid) {
+ if (UserHandle.getAppId(callingUid) == Process.myUid()) {
+ // For a host that's in the system process, ignore the user id
+ return UserHandle.isSameApp(this.uid, callingUid);
+ } else {
+ return this.uid == callingUid;
+ }
+ }
}
static class AppWidgetId {
@@ -180,15 +192,18 @@ class AppWidgetServiceImpl {
boolean mStateLoaded;
int mMaxWidgetBitmapMemory;
+ private final Handler mSaveStateHandler;
+
// These are for debugging only -- widgets are going missing in some rare instances
ArrayList<Provider> mDeletedProviders = new ArrayList<Provider>();
ArrayList<Host> mDeletedHosts = new ArrayList<Host>();
- AppWidgetServiceImpl(Context context, int userId) {
+ AppWidgetServiceImpl(Context context, int userId, Handler saveStateHandler) {
mContext = context;
mPm = AppGlobals.getPackageManager();
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mUserId = userId;
+ mSaveStateHandler = saveStateHandler;
computeMaximumWidgetBitmapMemory();
}
@@ -236,7 +251,7 @@ class AppWidgetServiceImpl {
updateProvidersForPackageLocked(cn.getPackageName(), removedProviders);
}
}
- saveStateLocked();
+ saveStateAsync();
}
}
}
@@ -286,7 +301,7 @@ class AppWidgetServiceImpl {
providersModified |= addProvidersForPackageLocked(pkgName);
}
}
- saveStateLocked();
+ saveStateAsync();
}
} else {
Bundle extras = intent.getExtras();
@@ -297,7 +312,7 @@ class AppWidgetServiceImpl {
ensureStateLoadedLocked();
for (String pkgName : pkgList) {
providersModified |= removeProvidersForPackageLocked(pkgName);
- saveStateLocked();
+ saveStateAsync();
}
}
}
@@ -330,6 +345,7 @@ class AppWidgetServiceImpl {
pw.print(info.autoAdvanceViewId);
pw.print(" initialLayout=#");
pw.print(Integer.toHexString(info.initialLayout));
+ pw.print(" uid="); pw.print(p.uid);
pw.print(" zombie="); pw.println(p.zombie);
}
@@ -410,7 +426,7 @@ class AppWidgetServiceImpl {
private void ensureStateLoadedLocked() {
if (!mStateLoaded) {
- loadAppWidgetList();
+ loadAppWidgetListLocked();
loadStateLocked();
mStateLoaded = true;
}
@@ -431,7 +447,7 @@ class AppWidgetServiceImpl {
host.instances.add(id);
mAppWidgetIds.add(id);
- saveStateLocked();
+ saveStateAsync();
if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId
+ " id=" + appWidgetId);
return appWidgetId;
@@ -444,7 +460,7 @@ class AppWidgetServiceImpl {
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id != null) {
deleteAppWidgetLocked(id);
- saveStateLocked();
+ saveStateAsync();
}
}
}
@@ -456,7 +472,7 @@ class AppWidgetServiceImpl {
Host host = lookupHostLocked(callingUid, hostId);
if (host != null) {
deleteHostLocked(host);
- saveStateLocked();
+ saveStateAsync();
}
}
}
@@ -469,13 +485,13 @@ class AppWidgetServiceImpl {
boolean changed = false;
for (int i = N - 1; i >= 0; i--) {
Host host = mHosts.get(i);
- if (host.uid == callingUid) {
+ if (host.uidMatches(callingUid)) {
deleteHostLocked(host);
changed = true;
}
}
if (changed) {
- saveStateLocked();
+ saveStateAsync();
}
}
}
@@ -591,7 +607,7 @@ class AppWidgetServiceImpl {
// schedule the future updates
registerForBroadcastsLocked(p, getAppWidgetIds(p));
- saveStateLocked();
+ saveStateAsync();
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -655,8 +671,8 @@ class AppWidgetServiceImpl {
} else {
mPackagesWithBindWidgetPermission.remove(packageName);
}
+ saveStateAsync();
}
- saveStateLocked();
}
// Binds to a specific RemoteViewsService
@@ -693,6 +709,10 @@ class AppWidgetServiceImpl {
}
int userId = UserHandle.getUserId(id.provider.uid);
+ if (userId != mUserId) {
+ Slog.w(TAG, "AppWidgetServiceImpl of user " + mUserId
+ + " binding to provider on user " + userId);
+ }
// Bind to the RemoteViewsService (which will trigger a callback to the
// RemoteViewsAdapter.onServiceConnected())
final long token = Binder.clearCallingIdentity();
@@ -733,8 +753,6 @@ class AppWidgetServiceImpl {
conn.disconnect();
mContext.unbindService(conn);
mBoundRemoteViewsServices.remove(key);
- } else {
- Log.e("AppWidgetService", "Error (unbindRemoteViewsService): Connection not bound");
}
}
}
@@ -848,14 +866,14 @@ class AppWidgetServiceImpl {
}
}
- public List<AppWidgetProviderInfo> getInstalledProviders() {
+ public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
synchronized (mAppWidgetIds) {
ensureStateLoadedLocked();
final int N = mInstalledProviders.size();
ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N);
for (int i = 0; i < N; i++) {
Provider p = mInstalledProviders.get(i);
- if (!p.zombie) {
+ if (!p.zombie && (p.info.widgetCategory & categoryFilter) != 0) {
result.add(cloneIfLocalBinder(p.info));
}
}
@@ -893,6 +911,20 @@ class AppWidgetServiceImpl {
}
}
+ private void saveStateAsync() {
+ mSaveStateHandler.post(mSaveStateRunnable);
+ }
+
+ private final Runnable mSaveStateRunnable = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mAppWidgetIds) {
+ ensureStateLoadedLocked();
+ saveStateLocked();
+ }
+ }
+ };
+
public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
synchronized (mAppWidgetIds) {
options = cloneIfLocalBinder(options);
@@ -913,7 +945,7 @@ class AppWidgetServiceImpl {
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, id.options);
mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
- saveStateLocked();
+ saveStateAsync();
}
}
@@ -942,7 +974,9 @@ class AppWidgetServiceImpl {
ensureStateLoadedLocked();
for (int i = 0; i < N; i++) {
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
- if (id.views != null) {
+ if (id == null) {
+ Slog.w(TAG, "widget id " + appWidgetIds[i] + " not found!");
+ } else if (id.views != null) {
// Only trigger a partial update for a widget if it has received a full update
updateAppWidgetInstanceLocked(id, views, true);
}
@@ -1142,7 +1176,7 @@ class AppWidgetServiceImpl {
}
boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) {
- if (id.host.uid == callingUid) {
+ if (id.host.uidMatches(callingUid)) {
// Apps hosting the AppWidget have access to it.
return true;
}
@@ -1185,7 +1219,7 @@ class AppWidgetServiceImpl {
final int N = mHosts.size();
for (int i = 0; i < N; i++) {
Host h = mHosts.get(i);
- if (h.uid == uid && h.hostId == hostId) {
+ if (h.uidMatches(uid) && h.hostId == hostId) {
return h;
}
}
@@ -1214,7 +1248,7 @@ class AppWidgetServiceImpl {
}
}
- void loadAppWidgetList() {
+ void loadAppWidgetListLocked() {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
try {
List<ResolveInfo> broadcastReceivers = mPm.queryIntentReceivers(intent,
@@ -1334,6 +1368,28 @@ class AppWidgetServiceImpl {
}
}
+ static int[] getAppWidgetIds(Host h) {
+ int instancesSize = h.instances.size();
+ int appWidgetIds[] = new int[instancesSize];
+ for (int i = 0; i < instancesSize; i++) {
+ appWidgetIds[i] = h.instances.get(i).appWidgetId;
+ }
+ return appWidgetIds;
+ }
+
+ public int[] getAppWidgetIdsForHost(int hostId) {
+ synchronized (mAppWidgetIds) {
+ ensureStateLoadedLocked();
+ int callingUid = Binder.getCallingUid();
+ Host host = lookupHostLocked(callingUid, hostId);
+ if (host != null) {
+ return getAppWidgetIds(host);
+ } else {
+ return new int[0];
+ }
+ }
+ }
+
private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
Provider p = null;
diff --git a/services/java/com/android/server/AttributeCache.java b/services/java/com/android/server/AttributeCache.java
index 81378dc..81613c6 100644
--- a/services/java/com/android/server/AttributeCache.java
+++ b/services/java/com/android/server/AttributeCache.java
@@ -23,6 +23,7 @@ import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.os.UserHandle;
import android.util.SparseArray;
import java.util.HashMap;
@@ -34,52 +35,54 @@ import java.util.WeakHashMap;
*/
public final class AttributeCache {
private static AttributeCache sInstance = null;
-
+
private final Context mContext;
- private final WeakHashMap<String, Package> mPackages =
- new WeakHashMap<String, Package>();
+ private final SparseArray<WeakHashMap<String, Package>> mPackages =
+ new SparseArray<WeakHashMap<String, Package>>();
private final Configuration mConfiguration = new Configuration();
-
+
public final static class Package {
public final Context context;
private final SparseArray<HashMap<int[], Entry>> mMap
= new SparseArray<HashMap<int[], Entry>>();
-
+
public Package(Context c) {
context = c;
}
}
-
+
public final static class Entry {
public final Context context;
public final TypedArray array;
-
+
public Entry(Context c, TypedArray ta) {
context = c;
array = ta;
}
}
-
+
public static void init(Context context) {
if (sInstance == null) {
sInstance = new AttributeCache(context);
}
}
-
+
public static AttributeCache instance() {
return sInstance;
}
-
+
public AttributeCache(Context context) {
mContext = context;
}
-
+
public void removePackage(String packageName) {
synchronized (this) {
- mPackages.remove(packageName);
+ for (int i=0; i<mPackages.size(); i++) {
+ mPackages.valueAt(i).remove(packageName);
+ }
}
}
-
+
public void updateConfiguration(Configuration config) {
synchronized (this) {
int changes = mConfiguration.updateFrom(config);
@@ -93,10 +96,21 @@ public final class AttributeCache {
}
}
}
-
- public Entry get(String packageName, int resId, int[] styleable) {
+
+ public void removeUser(int userId) {
+ synchronized (this) {
+ mPackages.remove(userId);
+ }
+ }
+
+ public Entry get(int userId, String packageName, int resId, int[] styleable) {
synchronized (this) {
- Package pkg = mPackages.get(packageName);
+ WeakHashMap<String, Package> packages = mPackages.get(userId);
+ if (packages == null) {
+ packages = new WeakHashMap<String, Package>();
+ mPackages.put(userId, packages);
+ }
+ Package pkg = packages.get(packageName);
HashMap<int[], Entry> map = null;
Entry ent = null;
if (pkg != null) {
@@ -110,7 +124,8 @@ public final class AttributeCache {
} else {
Context context;
try {
- context = mContext.createPackageContext(packageName, 0);
+ context = mContext.createPackageContextAsUser(packageName, 0,
+ new UserHandle(userId));
if (context == null) {
return null;
}
@@ -118,7 +133,7 @@ public final class AttributeCache {
return null;
}
pkg = new Package(context);
- mPackages.put(packageName, pkg);
+ packages.put(packageName, pkg);
}
if (map == null) {
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index 69ccbc7..5a2088c 100755
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -43,8 +43,6 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
-import java.util.ArrayList;
-import java.util.List;
class BluetoothManagerService extends IBluetoothManager.Stub {
private static final String TAG = "BluetoothManagerService";
private static final boolean DBG = true;
@@ -79,6 +77,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
private static final int MESSAGE_USER_SWITCHED = 300;
private static final int MAX_SAVE_RETRIES=3;
+ // Bluetooth persisted setting is off
+ private static final int BLUETOOTH_OFF=0;
+ // Bluetooth persisted setting is on
+ // and Airplane mode won't affect Bluetooth state at start up
+ private static final int BLUETOOTH_ON_BLUETOOTH=1;
+ // Bluetooth persisted setting is on
+ // but Airplane mode will affect Bluetooth state at start up
+ // and Airplane mode will have higher priority.
+ private static final int BLUETOOTH_ON_AIRPLANE=2;
private final Context mContext;
@@ -92,7 +99,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private IBluetooth mBluetooth;
private boolean mBinding;
private boolean mUnbinding;
+ // used inside handler thread
private boolean mQuietEnable = false;
+ // configuarion from external IBinder call which is used to
+ // synchronize with broadcast receiver.
+ private boolean mQuietEnableExternal;
+ // configuarion from external IBinder call which is used to
+ // synchronize with broadcast receiver.
+ private boolean mEnableExternal;
+ // used inside handler thread
private boolean mEnable;
private int mState;
private HandlerThread mThread;
@@ -130,18 +145,39 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
storeNameAndAddress(newName, null);
}
} else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
- if (isAirplaneModeOn()) {
- // disable without persisting the setting
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE,
- 0, 0));
- } else if (isBluetoothPersistedStateOn()) {
- // enable without persisting the setting
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
- 0, 0));
+ synchronized(mReceiver) {
+ if (isBluetoothPersistedStateOn()) {
+ if (isAirplaneModeOn()) {
+ persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
+ } else {
+ persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
+ }
+ }
+ if (isAirplaneModeOn()) {
+ // disable without persisting the setting
+ sendDisableMsg();
+ } else if (mEnableExternal) {
+ // enable without persisting the setting
+ sendEnableMsg(mQuietEnableExternal);
+ }
}
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
+ } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ synchronized(mReceiver) {
+ if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
+ //Enable
+ if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
+ sendEnableMsg(mQuietEnableExternal);
+ }
+ }
+
+ if (!isNameAndAddressSet()) {
+ //Sync the Bluetooth name and address from the Bluetooth Adapter
+ if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
+ getNameAndAddress();
+ }
}
}
};
@@ -157,30 +193,21 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mUnbinding = false;
mEnable = false;
mState = BluetoothAdapter.STATE_OFF;
+ mQuietEnableExternal = false;
+ mEnableExternal = false;
mAddress = null;
mName = null;
mContentResolver = context.getContentResolver();
mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
- IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+ IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
registerForAirplaneMode(filter);
mContext.registerReceiver(mReceiver, filter);
- boolean airplaneModeOn = isAirplaneModeOn();
- boolean bluetoothOn = isBluetoothPersistedStateOn();
loadStoredNameAndAddress();
- if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
- if (bluetoothOn) {
- //Enable
- if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
- enableHelper();
- }
-
- if (!isNameAndAddressSet()) {
- //Sync the Bluetooth name and address from the Bluetooth Adapter
- if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
- getNameAndAddress();
+ if (isBluetoothPersistedStateOn()) {
+ mEnableExternal = true;
}
}
@@ -197,17 +224,25 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
*/
private final boolean isBluetoothPersistedStateOn() {
return Settings.Global.getInt(mContentResolver,
- Settings.Global.BLUETOOTH_ON, 0) ==1;
+ Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
+ }
+
+ /**
+ * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
+ */
+ private final boolean isBluetoothPersistedStateOnBluetooth() {
+ return Settings.Global.getInt(mContentResolver,
+ Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
}
/**
* Save the Bluetooth on/off state
*
*/
- private void persistBluetoothSetting(boolean setOn) {
+ private void persistBluetoothSetting(int value) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.BLUETOOTH_ON,
- setOn ? 1 : 0);
+ value);
}
/**
@@ -297,8 +332,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
public boolean isEnabled() {
- if (!checkIfCallerIsForegroundUser()) {
- Log.w(TAG,"isEnabled(): not allowed for non-active user");
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+ (!checkIfCallerIsForegroundUser())) {
+ Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
return false;
}
@@ -325,40 +361,57 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
- if (!checkIfCallerIsForegroundUser()) {
- Log.w(TAG,"enableNoAutoConnect(): not allowed for non-active user");
- return false;
- }
-
if (DBG) {
Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
" mBinding = " + mBinding);
}
- if (Binder.getCallingUid() != Process.NFC_UID) {
+ int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
+
+ if (callingAppId != Process.NFC_UID) {
throw new SecurityException("no permission to enable Bluetooth quietly");
}
- Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
- msg.arg1=0; //No persist
- msg.arg2=1; //Quiet mode
- mHandler.sendMessage(msg);
+
+ synchronized(mReceiver) {
+ mQuietEnableExternal = true;
+ mEnableExternal = true;
+ sendEnableMsg(true);
+ }
return true;
}
public boolean enable() {
- if (!checkIfCallerIsForegroundUser()) {
- Log.w(TAG,"enable(): not allowed for non-active user");
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+ (!checkIfCallerIsForegroundUser())) {
+ Log.w(TAG,"enable(): not allowed for non-active and non system user");
return false;
}
- return enableHelper();
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH ADMIN permission");
+ if (DBG) {
+ Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
+ " mBinding = " + mBinding);
+ }
+
+ synchronized(mReceiver) {
+ mQuietEnableExternal = false;
+ mEnableExternal = true;
+ // waive WRITE_SECURE_SETTINGS permission check
+ long callingIdentity = Binder.clearCallingIdentity();
+ persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
+ Binder.restoreCallingIdentity(callingIdentity);
+ sendEnableMsg(false);
+ }
+ return true;
}
public boolean disable(boolean persist) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
- if (!checkIfCallerIsForegroundUser()) {
- Log.w(TAG,"disable(): not allowed for non-active user");
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+ (!checkIfCallerIsForegroundUser())) {
+ Log.w(TAG,"disable(): not allowed for non-active and non system user");
return false;
}
@@ -367,9 +420,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
" mBinding = " + mBinding);
}
- Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
- msg.arg1=(persist?1:0);
- mHandler.sendMessage(msg);
+ synchronized(mReceiver) {
+ if (persist) {
+ // waive WRITE_SECURE_SETTINGS permission check
+ long callingIdentity = Binder.clearCallingIdentity();
+ persistBluetoothSetting(BLUETOOTH_OFF);
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ mEnableExternal = false;
+ sendDisableMsg();
+ }
return true;
}
@@ -453,12 +513,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
public String getAddress() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
+ "Need BLUETOOTH permission");
- if (!checkIfCallerIsForegroundUser()) {
- Log.w(TAG,"getAddress(): not allowed for non-active user");
- return mAddress;
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+ (!checkIfCallerIsForegroundUser())) {
+ Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
+ return null;
}
synchronized(mConnection) {
@@ -477,12 +538,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
public String getName() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
+ "Need BLUETOOTH permission");
- if (!checkIfCallerIsForegroundUser()) {
- Log.w(TAG,"getName(): not allowed for non-active user");
- return mName;
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+ (!checkIfCallerIsForegroundUser())) {
+ Log.w(TAG,"getName(): not allowed for non-active and non system user");
+ return null;
}
synchronized(mConnection) {
@@ -640,7 +702,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mEnable = true;
- handleEnable(msg.arg1 == 1, msg.arg2 ==1);
+ handleEnable(msg.arg1 == 1);
break;
case MESSAGE_DISABLE:
@@ -648,11 +710,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
if (mEnable && mBluetooth != null) {
waitForOnOff(true, false);
mEnable = false;
- handleDisable(msg.arg1 == 1);
+ handleDisable();
waitForOnOff(false, false);
} else {
mEnable = false;
- handleDisable(msg.arg1 == 1);
+ handleDisable();
}
break;
@@ -731,7 +793,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
if (!mEnable) {
waitForOnOff(true, false);
- handleDisable(false);
+ handleDisable();
waitForOnOff(false, false);
}
break;
@@ -775,8 +837,18 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// Send BT state broadcast to update
// the BT icon correctly
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
- BluetoothAdapter.STATE_TURNING_OFF);
+ if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
+ (mState == BluetoothAdapter.STATE_ON)) {
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
+ BluetoothAdapter.STATE_TURNING_OFF);
+ mState = BluetoothAdapter.STATE_TURNING_OFF;
+ }
+ if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
+ BluetoothAdapter.STATE_OFF);
+ }
+
+ mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
mState = BluetoothAdapter.STATE_OFF;
}
break;
@@ -789,7 +861,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
it doesnt change when IBluetooth
service restarts */
mEnable = true;
- handleEnable(false, mQuietEnable);
+ handleEnable(mQuietEnable);
break;
}
@@ -820,20 +892,33 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
}
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
+
+ if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
+ // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
+ bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
+ mState = BluetoothAdapter.STATE_OFF;
+ }
+ if (mState == BluetoothAdapter.STATE_OFF) {
+ bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
+ mState = BluetoothAdapter.STATE_TURNING_ON;
+ }
waitForOnOff(true, false);
- bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
+ if (mState == BluetoothAdapter.STATE_TURNING_ON) {
+ bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
+ }
// disable
- handleDisable(false);
+ handleDisable();
+ // Pbap service need receive STATE_TURNING_OFF intent to close
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
+ BluetoothAdapter.STATE_TURNING_OFF);
waitForOnOff(false, true);
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
BluetoothAdapter.STATE_OFF);
- mState = BluetoothAdapter.STATE_OFF;
sendBluetoothServiceDownCallback();
synchronized (mConnection) {
if (mBluetooth != null) {
@@ -844,8 +929,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
SystemClock.sleep(100);
+ mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
+ mState = BluetoothAdapter.STATE_OFF;
// enable
- handleEnable(false, mQuietEnable);
+ handleEnable(mQuietEnable);
} else if (mBinding || mBluetooth != null) {
Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
userMsg.arg2 = 1 + msg.arg2;
@@ -862,11 +949,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
- private void handleEnable(boolean persist, boolean quietMode) {
- if (persist) {
- persistBluetoothSetting(true);
- }
-
+ private void handleEnable(boolean quietMode) {
mQuietEnable = quietMode;
synchronized(mConnection) {
@@ -918,11 +1001,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
- private void handleDisable(boolean persist) {
- if (persist) {
- persistBluetoothSetting(false);
- }
-
+ private void handleDisable() {
synchronized(mConnection) {
// don't need to disable if GetNameAddressOnly is set,
// service will be unbinded after Name and Address are saved
@@ -943,11 +1022,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private boolean checkIfCallerIsForegroundUser() {
int foregroundUser;
int callingUser = UserHandle.getCallingUserId();
+ int callingUid = Binder.getCallingUid();
long callingIdentity = Binder.clearCallingIdentity();
+ int callingAppId = UserHandle.getAppId(callingUid);
boolean valid = false;
try {
foregroundUser = ActivityManager.getCurrentUser();
- valid = (callingUser == foregroundUser);
+ valid = (callingUser == foregroundUser) ||
+ callingAppId == Process.NFC_UID;
if (DBG) {
Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
+ " callingUser=" + callingUser
@@ -959,21 +1041,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return valid;
}
- private boolean enableHelper() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
- if (DBG) {
- Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
- " mBinding = " + mBinding);
- }
-
- Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
- msg.arg1=1; //persist
- msg.arg2=0; //No Quiet Mode
- mHandler.sendMessage(msg);
- return true;
- }
-
private void bluetoothStateChangeHandler(int prevState, int newState) {
if (prevState != newState) {
//Notify all proxy objects first of adapter state change
@@ -982,14 +1049,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
sendBluetoothStateCallback(isUp);
//If Bluetooth is off, send service down event to proxy objects, and unbind
- if (!isUp) {
- //Only unbind with mEnable flag not set
- //For race condition: disable and enable back-to-back
- //Avoid unbind right after enable due to callback from disable
- if ((!mEnable) && (mBluetooth != null)) {
- sendBluetoothServiceDownCallback();
- unbindAndFinish();
- }
+ if (!isUp && canUnbindBluetoothService()) {
+ sendBluetoothServiceDownCallback();
+ unbindAndFinish();
}
}
@@ -1037,4 +1099,31 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
Log.e(TAG,"waitForOnOff time out");
return false;
}
+
+ private void sendDisableMsg() {
+ mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
+ }
+
+ private void sendEnableMsg(boolean quietMode) {
+ mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
+ quietMode ? 1 : 0, 0));
+ }
+
+ private boolean canUnbindBluetoothService() {
+ synchronized(mConnection) {
+ //Only unbind with mEnable flag not set
+ //For race condition: disable and enable back-to-back
+ //Avoid unbind right after enable due to callback from disable
+ //Only unbind with Bluetooth at OFF state
+ //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
+ try {
+ if (mEnable || (mBluetooth == null)) return false;
+ if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
+ return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
+ } catch (RemoteException e) {
+ Log.e(TAG, "getState()", e);
+ }
+ }
+ return false;
+ }
}
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index 7e1de5a..235c662 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -20,11 +20,14 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.IPackageManager;
import android.os.Build;
import android.os.DropBoxManager;
import android.os.FileObserver;
import android.os.FileUtils;
import android.os.RecoverySystem;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Downloads;
import android.util.Slog;
@@ -69,7 +72,15 @@ public class BootReceiver extends BroadcastReceiver {
Slog.e(TAG, "Can't log boot events", e);
}
try {
- removeOldUpdatePackages(context);
+ boolean onlyCore = false;
+ try {
+ onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService(
+ "package")).isOnlyCoreApps();
+ } catch (RemoteException e) {
+ }
+ if (!onlyCore) {
+ removeOldUpdatePackages(context);
+ }
} catch (Exception e) {
Slog.e(TAG, "Can't remove old update packages", e);
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index ec682e8..cccaf1c 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -2689,18 +2689,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
state + "/" + info.getDetailedState());
}
- // Connectivity state changed:
- // [31-14] Reserved for future use
- // [13-10] Network subtype (for mobile network, as defined
- // by TelephonyManager)
- // [9-4] Detailed state ordinal (as defined by
- // NetworkInfo.DetailedState)
- // [3-0] Network type (as defined by ConnectivityManager)
- int eventLogParam = (info.getType() & 0xf) |
- ((info.getDetailedState().ordinal() & 0x3f) << 4) |
- (info.getSubtype() << 10);
- EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
- eventLogParam);
+ EventLogTags.writeConnectivityStateChanged(
+ info.getType(), info.getSubtype(), info.getDetailedState().ordinal());
if (info.getDetailedState() ==
NetworkInfo.DetailedState.FAILED) {
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index a5e26a8..6a62809 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -146,8 +146,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getSendingUserId());
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
- Slog.v(TAG, "Sending password expiration notifications for action " + action
- + " for user " + userHandle);
+ if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
+ + action + " for user " + userHandle);
mHandler.post(new Runnable() {
public void run() {
handlePasswordExpirationNotification(getUserData(userHandle));
@@ -468,7 +468,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void handlePackagesChanged(int userHandle) {
boolean removed = false;
- Slog.d(TAG, "Handling package changes for user " + userHandle);
+ if (DBG) 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--) {
@@ -982,7 +982,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long token = Binder.clearCallingIdentity();
try {
String value = cameraDisabled ? "1" : "0";
- Slog.v(TAG, "Change in camera state ["
+ if (DBG) Slog.v(TAG, "Change in camera state ["
+ SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
} finally {
@@ -1682,10 +1682,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
if (numbers < neededNumbers) {
- Slog
- .w(TAG, "resetPassword: number of numerical digits " + numbers
- + " does not meet required number of numerical digits "
- + neededNumbers);
+ Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
+ + " does not meet required number of numerical digits "
+ + neededNumbers);
return false;
}
int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
@@ -1875,28 +1874,32 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_WIPE_DATA);
long ident = Binder.clearCallingIdentity();
try {
- 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
- }
- }
- });
- }
+ wipeDeviceOrUserLocked(flags, userHandle);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
+ private void wipeDeviceOrUserLocked(int flags, final int userHandle) {
+ 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
+ }
+ }
+ });
+ }
+ }
+
public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
@@ -1996,7 +1999,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
saveSettingsLocked(userHandle);
int max = getMaximumFailedPasswordsForWipe(null, userHandle);
if (max > 0 && policy.mFailedPasswordAttempts >= max) {
- wipeDataLocked(0);
+ wipeDeviceOrUserLocked(0, userHandle);
}
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
diff --git a/services/java/com/android/server/EntropyMixer.java b/services/java/com/android/server/EntropyMixer.java
index b63a70e..4632374 100644
--- a/services/java/com/android/server/EntropyMixer.java
+++ b/services/java/com/android/server/EntropyMixer.java
@@ -17,6 +17,7 @@
package com.android.server;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -97,8 +98,10 @@ public class EntropyMixer extends Binder {
private void loadInitialEntropy() {
try {
RandomBlock.fromFile(entropyFile).toFile(randomDevice, false);
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "No existing entropy file -- first boot?");
} catch (IOException e) {
- Slog.w(TAG, "unable to load initial entropy (first boot?)", e);
+ Slog.w(TAG, "Failure loading existing entropy file", e);
}
}
@@ -106,7 +109,7 @@ public class EntropyMixer extends Binder {
try {
RandomBlock.fromFile(randomDevice).toFile(entropyFile, true);
} catch (IOException e) {
- Slog.w(TAG, "unable to write entropy", e);
+ Slog.w(TAG, "Unable to write entropy", e);
}
}
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 0fe66fc..8bc2da2 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -135,12 +135,8 @@ option java_package com.android.server
# ---------------------------
# ConnectivityService.java
# ---------------------------
-# Connectivity state changed:
-# [31-14] Reserved for future use
-# [13-10] Network subtype (for mobile network, as defined by TelephonyManager)
-# [ 9- 4] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
-# [ 3- 0] Network type (as defined by ConnectivityManager)
-50020 connectivity_state_changed (custom|1|5)
+# Connectivity state changed
+50020 connectivity_state_changed (type|1),(subtype|1),(state|1)
# ---------------------------
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index c9ff595..cd920b1 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -386,6 +386,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private Locale mLastSystemLocale;
private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
private final IPackageManager mIPackageManager;
+ private boolean mInputBoundToKeyguard;
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
@@ -443,7 +444,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final int userId = getChangingUserId();
final boolean retval = userId == mSettings.getCurrentUserId();
if (DEBUG) {
- Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
+ if (!retval) {
+ Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
+ }
}
return retval;
}
@@ -599,12 +602,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mHandler = new Handler(this);
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
- mCaller = new HandlerCaller(context, new HandlerCaller.Callback() {
+ mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
@Override
public void executeMessage(Message msg) {
handleMessage(msg);
}
- });
+ }, true /*asyncHandler*/);
mWindowManagerService = windowManager;
mHardKeyboardListener = new HardKeyboardListener();
@@ -657,7 +660,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
} catch (RemoteException e) {
Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
}
- mMyPackageMonitor.register(mContext, null, true);
+ mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
// mSettings should be created before buildInputMethodListLocked
mSettings = new InputMethodSettings(
@@ -779,6 +782,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (!isSystemIme(imi)) {
return false;
}
+ if (imi.isAuxiliaryIme()) {
+ return false;
+ }
if (imi.getIsDefaultResourceId() != 0) {
try {
Resources res = context.createPackageContext(
@@ -802,6 +808,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (!isSystemIme(imi)) {
return false;
}
+ if (imi.isAuxiliaryIme()) {
+ return false;
+ }
return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage());
}
@@ -877,10 +886,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final boolean hardKeyShown = haveHardKeyboard
&& conf.hardKeyboardHidden
!= Configuration.HARDKEYBOARDHIDDEN_YES;
- final boolean isScreenLocked = mKeyguardManager != null
- && mKeyguardManager.isKeyguardLocked()
- && mKeyguardManager.isKeyguardSecure();
- mImeWindowVis = (!isScreenLocked && (mInputShown || hardKeyShown)) ?
+ final boolean isScreenLocked =
+ mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+ final boolean isScreenSecurelyLocked =
+ isScreenLocked && mKeyguardManager.isKeyguardSecure();
+ final boolean inputShown = mInputShown && (!isScreenLocked || mInputBoundToKeyguard);
+ mImeWindowVis = (!isScreenSecurelyLocked && (inputShown || hardKeyShown)) ?
(InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE) : 0;
updateImeWindowStatusLocked();
}
@@ -1124,6 +1135,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return mNoBinding;
}
+ if (mCurClient == null) {
+ mInputBoundToKeyguard = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+ if (DEBUG) {
+ Slog.v(TAG, "New bind. keyguard = " + mInputBoundToKeyguard);
+ }
+ }
+
if (mCurClient != cs) {
// If the client is changing, we need to switch over to the new
// one.
@@ -1814,9 +1832,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public InputBindResult windowGainedFocus(IInputMethodClient client, IBinder windowToken,
int controlFlags, int softInputMode, int windowFlags,
EditorInfo attribute, IInputContext inputContext) {
- if (!calledFromValidUser()) {
- return null;
- }
+ // Needs to check the validity before clearing calling identity
+ final boolean calledFromValidUser = calledFromValidUser();
+
InputBindResult res = null;
long ident = Binder.clearCallingIdentity();
try {
@@ -1846,6 +1864,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
} catch (RemoteException e) {
}
+ if (!calledFromValidUser) {
+ Slog.w(TAG, "A background user is requesting window. Hiding IME.");
+ Slog.w(TAG, "If you want to interect with IME, you need "
+ + "android.permission.INTERACT_ACROSS_USERS_FULL");
+ hideCurrentInputLocked(0, null);
+ return null;
+ }
+
if (mCurFocusedWindow == windowToken) {
Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
+ " attribute=" + attribute + ", token = " + windowToken);
@@ -2486,10 +2512,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
map.put(id, p);
// Valid system default IMEs and IMEs that have English subtypes are enabled
- // by default, unless there's a hard keyboard and the system IME was explicitly
- // disabled
- if ((isValidSystemDefaultIme(p, mContext) || isSystemImeThatHasEnglishSubtype(p))
- && (!haveHardKeyboard || disabledSysImes.indexOf(id) < 0)) {
+ // by default
+ if ((isValidSystemDefaultIme(p, mContext) || isSystemImeThatHasEnglishSubtype(p))) {
setInputMethodEnabledLocked(id, true);
}
@@ -2838,6 +2862,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
.getEnabledInputMethodsAndSubtypeListLocked();
+ if (DEBUG) {
+ Slog.d(TAG, (enabled ? "Enable " : "Disable ") + id);
+ }
if (enabled) {
for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
if (pair.first.equals(id)) {
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index f497b23..0f08c56 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -506,7 +506,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} else {
Intent statusChanged = new Intent();
- statusChanged.putExtras(extras);
+ statusChanged.putExtras(new Bundle(extras));
statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
try {
synchronized (this) {
@@ -531,7 +531,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mListener.onLocationChanged(location);
+ mListener.onLocationChanged(new Location(location));
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
@@ -541,7 +541,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} else {
Intent locationChanged = new Intent();
- locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
+ locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
try {
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
@@ -1323,10 +1323,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
if (noGPSLocation != null) {
- return mLocationFudger.getOrCreate(noGPSLocation);
+ return new Location(mLocationFudger.getOrCreate(noGPSLocation));
}
} else {
- return location;
+ return new Location(location);
}
}
return null;
@@ -1710,6 +1710,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
for (UpdateRecord r : deadUpdateRecords) {
r.disposeLocked(true);
}
+ applyRequirementsLocked(provider);
}
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index c512bc1..2e0c977 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -57,6 +57,8 @@ import android.util.AttributeSet;
import android.util.Slog;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
@@ -103,9 +105,9 @@ class MountService extends IMountService.Stub
// TODO: listen for user creation/deletion
- private static final boolean LOCAL_LOGD = true;
- private static final boolean DEBUG_UNMOUNT = true;
- private static final boolean DEBUG_EVENTS = true;
+ private static final boolean LOCAL_LOGD = false;
+ private static final boolean DEBUG_UNMOUNT = false;
+ private static final boolean DEBUG_EVENTS = false;
private static final boolean DEBUG_OBB = false;
// Disable this since it messes up long-running cryptfs operations.
@@ -181,13 +183,13 @@ class MountService extends IMountService.Stub
/** When defined, base template for user-specific {@link StorageVolume}. */
private StorageVolume mEmulatedTemplate;
- // @GuardedBy("mVolumesLock")
+ @GuardedBy("mVolumesLock")
private final ArrayList<StorageVolume> mVolumes = Lists.newArrayList();
/** Map from path to {@link StorageVolume} */
- // @GuardedBy("mVolumesLock")
+ @GuardedBy("mVolumesLock")
private final HashMap<String, StorageVolume> mVolumesByPath = Maps.newHashMap();
/** Map from path to state */
- // @GuardedBy("mVolumesLock")
+ @GuardedBy("mVolumesLock")
private final HashMap<String, String> mVolumeStates = Maps.newHashMap();
private volatile boolean mSystemReady = false;
@@ -198,8 +200,8 @@ class MountService extends IMountService.Stub
// Used as a lock for methods that register/unregister listeners.
final private ArrayList<MountServiceBinderListener> mListeners =
new ArrayList<MountServiceBinderListener>();
- private CountDownLatch mConnectedSignal = new CountDownLatch(1);
- private CountDownLatch mAsecsScanned = new CountDownLatch(1);
+ private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
+ private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
private boolean mSendUmsConnectedOnBoot = false;
/**
@@ -495,10 +497,6 @@ class MountService extends IMountService.Stub
}
private void waitForLatch(CountDownLatch latch) {
- if (latch == null) {
- return;
- }
-
for (;;) {
try {
if (latch.await(5000, TimeUnit.MILLISECONDS)) {
@@ -738,14 +736,12 @@ class MountService extends IMountService.Stub
* the hounds!
*/
mConnectedSignal.countDown();
- mConnectedSignal = null;
// Let package manager load internal ASECs.
mPms.scanAvailableAsecs();
// Notify people waiting for ASECs to be scanned that it's done.
mAsecsScanned.countDown();
- mAsecsScanned = null;
}
}.start();
}
@@ -2571,7 +2567,7 @@ class MountService extends IMountService.Stub
}
}
- // @VisibleForTesting
+ @VisibleForTesting
public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) {
// TODO: allow caller to provide Environment for full testing
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 92af9a9..5e94a9f 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -25,6 +25,7 @@ import android.os.SystemClock;
import android.util.LocalLog;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.google.android.collect.Lists;
import java.nio.charset.Charsets;
@@ -400,7 +401,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
* Append the given argument to {@link StringBuilder}, escaping as needed,
* and surrounding with quotes when it contains spaces.
*/
- // @VisibleForTesting
+ @VisibleForTesting
static void appendEscaped(StringBuilder builder, String arg) {
final boolean hasSpaces = arg.indexOf(' ') >= 0;
if (hasSpaces) {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 70d37bf..37d7ce7 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -110,6 +110,11 @@ public class NotificationManagerService extends INotificationManager.Stub
private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
private static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
+ // Notifications with scores below this will not interrupt the user, either via LED or
+ // sound or vibration
+ private static final int SCORE_INTERRUPTION_THRESHOLD =
+ Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
+
private static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
private static final boolean ENABLE_BLOCKED_TOASTS = true;
@@ -991,6 +996,9 @@ public class NotificationManagerService extends INotificationManager.Stub
return;
}
+ // Should this notification make noise, vibe, or use the LED?
+ final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD);
+
synchronized (mNotificationList) {
NotificationRecord r = new NotificationRecord(pkg, tag, id,
callingUid, callingPid, userId,
@@ -1042,7 +1050,8 @@ public class NotificationManagerService extends INotificationManager.Stub
long identity = Binder.clearCallingIdentity();
try {
r.statusBarKey = mStatusBar.addNotification(n);
- if ((n.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
+ if ((n.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
+ && canInterrupt) {
mAttentionLight.pulse();
}
}
@@ -1073,20 +1082,32 @@ public class NotificationManagerService extends INotificationManager.Stub
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
&& (r.userId == UserHandle.USER_ALL ||
(r.userId == userId && r.userId == currentUser))
+ && canInterrupt
&& mSystemReady) {
final AudioManager audioManager = (AudioManager) mContext
.getSystemService(Context.AUDIO_SERVICE);
+
// sound
final boolean useDefaultSound =
(notification.defaults & Notification.DEFAULT_SOUND) != 0;
- if (useDefaultSound || notification.sound != null) {
- Uri uri;
- if (useDefaultSound) {
- uri = Settings.System.DEFAULT_NOTIFICATION_URI;
- } else {
- uri = notification.sound;
- }
+
+ Uri soundUri = null;
+ boolean hasValidSound = false;
+
+ if (useDefaultSound) {
+ soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
+
+ // check to see if the default notification sound is silent
+ ContentResolver resolver = mContext.getContentResolver();
+ hasValidSound = Settings.System.getString(resolver,
+ Settings.System.NOTIFICATION_SOUND) != null;
+ } else if (notification.sound != null) {
+ soundUri = notification.sound;
+ hasValidSound = (soundUri != null);
+ }
+
+ if (hasValidSound) {
boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
int audioStreamType;
if (notification.audioStreamType >= 0) {
@@ -1103,7 +1124,7 @@ public class NotificationManagerService extends INotificationManager.Stub
try {
final IRingtonePlayer player = mAudioService.getRingtonePlayer();
if (player != null) {
- player.playAsync(uri, user, looping, audioStreamType);
+ player.playAsync(soundUri, user, looping, audioStreamType);
}
} catch (RemoteException e) {
} finally {
@@ -1117,13 +1138,13 @@ public class NotificationManagerService extends INotificationManager.Stub
final boolean hasCustomVibrate = notification.vibrate != null;
// new in 4.2: if there was supposed to be a sound and we're in vibrate mode,
- // and no other vibration is specified, we apply the default vibration anyway
+ // and no other vibration is specified, we fall back to vibration
final boolean convertSoundToVibration =
!hasCustomVibrate
- && (useDefaultSound || notification.sound != null)
+ && hasValidSound
&& (audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE);
- // The DEFAULT_VIBRATE flag trumps any custom vibration.
+ // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
final boolean useDefaultVibrate =
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
@@ -1136,8 +1157,8 @@ public class NotificationManagerService extends INotificationManager.Stub
// does not have the VIBRATE permission.
long identity = Binder.clearCallingIdentity();
try {
- mVibrator.vibrate(convertSoundToVibration ? mFallbackVibrationPattern
- : mDefaultVibrationPattern,
+ mVibrator.vibrate(useDefaultVibrate ? mDefaultVibrationPattern
+ : mFallbackVibrationPattern,
((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -1160,7 +1181,8 @@ public class NotificationManagerService extends INotificationManager.Stub
}
//Slog.i(TAG, "notification.lights="
// + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
- if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
+ if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
+ && canInterrupt) {
mLights.add(r);
updateLightsLocked();
} else {
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 439eebe..1fe98af 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -170,7 +170,9 @@ public class StatusBarManagerService extends IStatusBarService.Stub
// so they are paired correctly. The messages on the handler will be
// handled in the order they were enqueued, but will be outside the lock.
manageDisableListLocked(userId, what, token, pkg);
- final int net = gatherDisableActionsLocked(userId);
+
+ // Ensure state for the current user is applied, even if passed a non-current user.
+ final int net = gatherDisableActionsLocked(mCurrentUserId);
if (net != mDisabled) {
mDisabled = net;
mHandler.post(new Runnable() {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 894c4d0..55885e6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1005,7 +1005,7 @@ class ServerThread extends Thread {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
- Slog.d(TAG, "Starting service: " + intent);
+ //Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.OWNER);
}
}
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 26684de..17260d5 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -139,7 +139,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_USER_SWITCHED: {
- Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
+ if (DBG) Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
TelephonyRegistry.this.notifyCellLocation(mCellLocation);
break;
}
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 82dbf54..21a1956 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -1096,6 +1096,8 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
} while (type != XmlPullParser.END_DOCUMENT);
success = true;
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "no current wallpaper -- first boot?");
} catch (NullPointerException e) {
Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (NumberFormatException e) {
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 8bbf923..b2a8ad8 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -39,6 +39,8 @@ import android.util.Log;
import android.util.Slog;
import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
@@ -439,6 +441,16 @@ public class Watchdog extends Thread {
dumpKernelStackTraces();
}
+ // Trigger the kernel to dump all blocked threads to the kernel log
+ try {
+ FileWriter sysrq_trigger = new FileWriter("/proc/sysrq-trigger");
+ sysrq_trigger.write("w");
+ sysrq_trigger.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to write to /proc/sysrq-trigger");
+ Slog.e(TAG, e.getMessage());
+ }
+
// Try to add the error to the dropbox, but assuming that the ActivityManager
// itself may be deadlocked. (which has happened, causing this statement to
// deadlock and the watchdog as a whole to be ineffective)
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 35999ea..5c24e67 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -1090,11 +1090,8 @@ public class ActiveServices {
boolean created = false;
try {
- mAm.mStringBuilder.setLength(0);
- r.intent.getIntent().toShortString(mAm.mStringBuilder, true, false, true, false);
- EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
- r.userId, System.identityHashCode(r), r.shortName,
- mAm.mStringBuilder.toString(), r.app.pid);
+ EventLogTags.writeAmCreateService(
+ r.userId, System.identityHashCode(r), r.shortName, r.app.pid);
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
@@ -1242,9 +1239,8 @@ public class ActiveServices {
}
if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent);
- EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
- r.userId, System.identityHashCode(r), r.shortName,
- (r.app != null) ? r.app.pid : -1);
+ EventLogTags.writeAmDestroyService(
+ r.userId, System.identityHashCode(r), (r.app != null) ? r.app.pid : -1);
mServiceMap.removeServiceByName(r.name, r.userId);
mServiceMap.removeServiceByIntent(r.intent, r.userId);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index db64a9a..2ba9a10 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -21,7 +21,6 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import com.android.internal.R;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessStats;
-import com.android.internal.widget.LockPatternUtils;
import com.android.server.AttributeCache;
import com.android.server.IntentResolver;
import com.android.server.ProcessMap;
@@ -116,6 +115,7 @@ import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UpdateLock;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.format.Time;
@@ -192,6 +192,7 @@ public final class ActivityManagerService extends ActivityManagerNative
static final boolean DEBUG_POWER = localLOGV || false;
static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
static final boolean DEBUG_MU = localLOGV || false;
+ static final boolean DEBUG_IMMERSIVE = localLOGV || false;
static final boolean VALIDATE_TOKENS = false;
static final boolean SHOW_ACTIVITY_START_TIME = true;
@@ -828,6 +829,12 @@ public final class ActivityManagerService extends ActivityManagerNative
long mLastWriteTime = 0;
/**
+ * Used to retain an update lock when the foreground activity is in
+ * immersive mode.
+ */
+ final UpdateLock mUpdateLock = new UpdateLock("immersive");
+
+ /**
* Set to true after the system has finished booting.
*/
boolean mBooted = false;
@@ -896,6 +903,7 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int REPORT_USER_SWITCH_MSG = 34;
static final int CONTINUE_USER_SWITCH_MSG = 35;
static final int USER_SWITCH_TIMEOUT_MSG = 36;
+ static final int IMMERSIVE_MODE_LOCK_MSG = 37;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1357,6 +1365,21 @@ public final class ActivityManagerService extends ActivityManagerNative
timeoutUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
break;
}
+ case IMMERSIVE_MODE_LOCK_MSG: {
+ final boolean nextState = (msg.arg1 != 0);
+ if (mUpdateLock.isHeld() != nextState) {
+ if (DEBUG_IMMERSIVE) {
+ final ActivityRecord r = (ActivityRecord) msg.obj;
+ Slog.d(TAG, "Applying new update lock state '" + nextState + "' for " + r);
+ }
+ if (nextState) {
+ mUpdateLock.acquire();
+ } else {
+ mUpdateLock.release();
+ }
+ }
+ break;
+ }
}
}
};
@@ -1823,9 +1846,20 @@ public final class ActivityManagerService extends ActivityManagerNative
if (r != null) {
mWindowManager.setFocusedApp(r.appToken, true);
}
+ applyUpdateLockStateLocked(r);
}
}
+ final void applyUpdateLockStateLocked(ActivityRecord r) {
+ // Modifications to the UpdateLock state are done on our handler, outside
+ // the activity manager's locks. The new state is determined based on the
+ // state *now* of the relevant activity record. The object is passed to
+ // the handler solely for logging detail, not to be consulted/modified.
+ final boolean nextState = r != null && r.immersive;
+ mHandler.sendMessage(
+ mHandler.obtainMessage(IMMERSIVE_MODE_LOCK_MSG, (nextState) ? 1 : 0, 0, r));
+ }
+
private final void updateLruProcessInternalLocked(ProcessRecord app, int bestPos) {
// put it on the LRU to keep track of when it should be exited.
int lrui = mLruProcesses.indexOf(app);
@@ -4764,6 +4798,18 @@ public final class ActivityManagerService extends ActivityManagerNative
return false;
}
+ public Intent getIntentForIntentSender(IIntentSender pendingResult) {
+ if (!(pendingResult instanceof PendingIntentRecord)) {
+ return null;
+ }
+ try {
+ PendingIntentRecord res = (PendingIntentRecord)pendingResult;
+ return res.key.requestIntent != null ? new Intent(res.key.requestIntent) : null;
+ } catch (ClassCastException e) {
+ }
+ return null;
+ }
+
public void setProcessLimit(int max) {
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
"setProcessLimit()");
@@ -7410,11 +7456,19 @@ public final class ActivityManagerService extends ActivityManagerNative
public void setImmersive(IBinder token, boolean immersive) {
synchronized(this) {
- ActivityRecord r = mMainStack.isInStackLocked(token);
+ final ActivityRecord r = mMainStack.isInStackLocked(token);
if (r == null) {
throw new IllegalArgumentException();
}
r.immersive = immersive;
+
+ // update associated state if we're frontmost
+ if (r == mFocusedActivity) {
+ if (DEBUG_IMMERSIVE) {
+ Slog.d(TAG, "Frontmost changed immersion: "+ r);
+ }
+ applyUpdateLockStateLocked(r);
+ }
}
}
@@ -7923,7 +7977,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}, 0, null, null,
android.Manifest.permission.INTERACT_ACROSS_USERS,
- false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -12316,7 +12370,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
newConfig.seq = mConfigurationSeq;
mConfiguration = newConfig;
- Slog.i(TAG, "Config changed: " + newConfig);
+ Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);
final Configuration configCopy = new Configuration(mConfiguration);
@@ -14120,7 +14174,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Multi-user methods
@Override
- public boolean switchUser(int userId) {
+ public boolean switchUser(final int userId) {
if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: switchUser() from pid="
@@ -14168,7 +14222,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Once the internal notion of the active user has switched, we lock the device
// with the option to show the user switcher on the keyguard.
- mWindowManager.lockNow(LockPatternUtils.USER_SWITCH_LOCK_OPTIONS);
+ mWindowManager.lockNow(null);
final UserStartedState uss = mStartedUsers.get(userId);
@@ -14214,7 +14268,7 @@ public final class ActivityManagerService extends ActivityManagerNative
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky, int sendingUser) {
- userInitialized(uss);
+ userInitialized(uss, userId);
}
}, 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID,
userId);
@@ -14245,7 +14299,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}, 0, null, null,
android.Manifest.permission.INTERACT_ACROSS_USERS,
- false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
}
} finally {
@@ -14341,32 +14395,39 @@ public final class ActivityManagerService extends ActivityManagerNative
oldUserId, newUserId, uss));
}
- void userInitialized(UserStartedState uss) {
- synchronized (ActivityManagerService.this) {
- getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
- uss.initializing = false;
- completeSwitchAndInitalizeLocked(uss);
- }
+ void userInitialized(UserStartedState uss, int newUserId) {
+ completeSwitchAndInitalize(uss, newUserId, true, false);
}
void continueUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {
- final int N = mUserSwitchObservers.beginBroadcast();
- for (int i=0; i<N; i++) {
- try {
- mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(newUserId);
- } catch (RemoteException e) {
- }
- }
- mUserSwitchObservers.finishBroadcast();
- synchronized (this) {
- uss.switching = false;
- completeSwitchAndInitalizeLocked(uss);
- }
+ completeSwitchAndInitalize(uss, newUserId, false, true);
}
- void completeSwitchAndInitalizeLocked(UserStartedState uss) {
- if (!uss.switching && !uss.initializing) {
- mWindowManager.stopFreezingScreen();
+ void completeSwitchAndInitalize(UserStartedState uss, int newUserId,
+ boolean clearInitializing, boolean clearSwitching) {
+ boolean unfrozen = false;
+ synchronized (this) {
+ if (clearInitializing) {
+ uss.initializing = false;
+ getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
+ }
+ if (clearSwitching) {
+ uss.switching = false;
+ }
+ if (!uss.switching && !uss.initializing) {
+ mWindowManager.stopFreezingScreen();
+ unfrozen = true;
+ }
+ }
+ if (unfrozen) {
+ final int N = mUserSwitchObservers.beginBroadcast();
+ for (int i=0; i<N; i++) {
+ try {
+ mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(newUserId);
+ } catch (RemoteException e) {
+ }
+ }
+ mUserSwitchObservers.finishBroadcast();
}
}
@@ -14468,7 +14529,7 @@ public final class ActivityManagerService extends ActivityManagerNative
long ident = Binder.clearCallingIdentity();
try {
// We are going to broadcast ACTION_USER_STOPPING and then
- // once that is down send a final ACTION_SHUTDOWN and then
+ // once that is done send a final ACTION_SHUTDOWN and then
// stop the user.
final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING);
stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -14533,6 +14594,10 @@ public final class ActivityManagerService extends ActivityManagerNative
// Clean up all state and processes associated with the user.
// Kill all the processes for the user.
forceStopUserLocked(userId);
+ AttributeCache ac = AttributeCache.instance();
+ if (ac != null) {
+ ac.removeUser(userId);
+ }
}
}
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 749dc66..de0f9ca 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -407,7 +407,7 @@ final class ActivityRecord {
packageName = aInfo.applicationInfo.packageName;
launchMode = aInfo.launchMode;
- AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
+ AttributeCache.Entry ent = AttributeCache.instance().get(userId, packageName,
realTheme, com.android.internal.R.styleable.Window);
fullscreen = ent != null && !ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsFloating, false)
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 4546dc3..27dd732 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1810,8 +1810,8 @@ final class ActivityStack {
}
mHistory.add(addPos, r);
r.putInHistory();
- mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
- r.info.screenOrientation, r.fullscreen,
+ mService.mWindowManager.addAppToken(addPos, r.userId, r.appToken,
+ r.task.taskId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
@@ -1875,8 +1875,8 @@ final class ActivityStack {
mNoAnimActivities.remove(r);
}
r.updateOptionsLocked(options);
- mService.mWindowManager.addAppToken(
- addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen,
+ mService.mWindowManager.addAppToken(addPos, r.userId, r.appToken,
+ r.task.taskId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
boolean doShow = true;
if (newTask) {
@@ -1914,8 +1914,8 @@ final class ActivityStack {
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
- mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
- r.info.screenOrientation, r.fullscreen,
+ mService.mWindowManager.addAppToken(addPos, r.userId, r.appToken,
+ r.task.taskId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
ActivityOptions.abort(options);
}
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index f9630ae..bada7f0 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -38,6 +38,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.EventLog;
+import android.util.Log;
import android.util.Slog;
/**
@@ -779,6 +780,21 @@ public class BroadcastQueue {
} catch (RemoteException e) {
Slog.w(TAG, "Exception when sending broadcast to "
+ r.curComponent, e);
+ } catch (RuntimeException e) {
+ Log.wtf(TAG, "Failed sending broadcast to "
+ + r.curComponent + " with " + r.intent, e);
+ // If some unexpected exception happened, just skip
+ // this broadcast. At this point we are not in the call
+ // from a client, so throwing an exception out from here
+ // will crash the entire system instead of just whoever
+ // sent the broadcast.
+ logBroadcastReceiverDiscardLocked(r);
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ scheduleBroadcastsLocked();
+ // We need to reset the state if we failed to start the receiver.
+ r.state = BroadcastRecord.IDLE;
+ return;
}
// If a dead object exception was thrown -- fall through to
diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/java/com/android/server/am/EventLogTags.logtags
index 88c0c03..f784861 100644
--- a/services/java/com/android/server/am/EventLogTags.logtags
+++ b/services/java/com/android/server/am/EventLogTags.logtags
@@ -63,9 +63,9 @@ option java_package com.android.server.am
30024 am_broadcast_discard_filter (User|1|5),(Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5)
30025 am_broadcast_discard_app (User|1|5),(Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3)
# A service is being created
-30030 am_create_service (User|1|5),(Service Record|1|5),(Name|3),(Intent|3),(PID|1|5)
+30030 am_create_service (User|1|5),(Service Record|1|5),(Name|3),(PID|1|5)
# A service is being destroyed
-30031 am_destroy_service (User|1|5),(Service Record|1|5),(Name|3),(PID|1|5)
+30031 am_destroy_service (User|1|5),(Service Record|1|5),(PID|1|5)
# A process has crashed too many times, it is being cleared
30032 am_process_crashed_too_much (User|1|5),(Name|3),(PID|1|5)
# An unknown process is trying to attach to the activity manager
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index e58a0a5..e09970e 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -41,6 +41,7 @@ import android.view.DisplayInfo;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* Manages attached displays.
@@ -152,6 +153,10 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
new SparseArray<LogicalDisplay>();
private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
+ // List of all display transaction listeners.
+ private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners =
+ new CopyOnWriteArrayList<DisplayTransactionListener>();
+
// Set to true if all displays have been blanked by the power manager.
private int mAllDisplayBlankStateFromPowerManager;
@@ -261,6 +266,36 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
/**
+ * Registers a display transaction listener to provide the client a chance to
+ * update its surfaces within the same transaction as any display layout updates.
+ *
+ * @param listener The listener to register.
+ */
+ public void registerDisplayTransactionListener(DisplayTransactionListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+
+ // List is self-synchronized copy-on-write.
+ mDisplayTransactionListeners.add(listener);
+ }
+
+ /**
+ * Unregisters a display transaction listener to provide the client a chance to
+ * update its surfaces within the same transaction as any display layout updates.
+ *
+ * @param listener The listener to unregister.
+ */
+ public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+
+ // List is self-synchronized copy-on-write.
+ mDisplayTransactionListeners.remove(listener);
+ }
+
+ /**
* Overrides the display information of a particular logical display.
* This is used by the window manager to control the size and characteristics
* of the default display. It is expected to apply the requested change
@@ -298,6 +333,11 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
performTraversalInTransactionLocked();
}
+
+ // List is self-synchronized copy-on-write.
+ for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
+ listener.onDisplayTransaction();
+ }
}
/**
diff --git a/services/java/com/android/server/display/DisplayTransactionListener.java b/services/java/com/android/server/display/DisplayTransactionListener.java
new file mode 100644
index 0000000..34eb8f9
--- /dev/null
+++ b/services/java/com/android/server/display/DisplayTransactionListener.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ * Called within a Surface transaction whenever the size or orientation of a
+ * display may have changed. Provides an opportunity for the client to
+ * update the position of its surfaces as part of the same transaction.
+ */
+public interface DisplayTransactionListener {
+ void onDisplayTransaction();
+}
diff --git a/services/java/com/android/server/display/PersistentDataStore.java b/services/java/com/android/server/display/PersistentDataStore.java
index 3a6e1a6..105c253 100644
--- a/services/java/com/android/server/display/PersistentDataStore.java
+++ b/services/java/com/android/server/display/PersistentDataStore.java
@@ -81,6 +81,15 @@ final class PersistentDataStore {
}
}
+ public WifiDisplay getRememberedWifiDisplay(String deviceAddress) {
+ loadIfNeeded();
+ int index = findRememberedWifiDisplay(deviceAddress);
+ if (index >= 0) {
+ return mRememberedWifiDisplays.get(index);
+ }
+ return null;
+ }
+
public WifiDisplay[] getRememberedWifiDisplays() {
loadIfNeeded();
return mRememberedWifiDisplays.toArray(new WifiDisplay[mRememberedWifiDisplays.size()]);
@@ -137,22 +146,6 @@ final class PersistentDataStore {
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) {
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index 45fff30..c8a44d2 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -45,6 +45,8 @@ import android.view.Surface;
import java.io.PrintWriter;
import java.util.Arrays;
+import libcore.util.Objects;
+
/**
* Connects to Wifi displays that implement the Miracast protocol.
* <p>
@@ -224,16 +226,18 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
}
- if (mPersistentDataStore.renameWifiDisplay(address, alias)) {
- mPersistentDataStore.saveIfNeeded();
- updateRememberedDisplaysLocked();
- scheduleStatusChangedBroadcastLocked();
+ WifiDisplay display = mPersistentDataStore.getRememberedWifiDisplay(address);
+ if (display != null && !Objects.equal(display.getDeviceAlias(), alias)) {
+ display = new WifiDisplay(address, display.getDeviceName(), alias);
+ if (mPersistentDataStore.rememberWifiDisplay(display)) {
+ mPersistentDataStore.saveIfNeeded();
+ updateRememberedDisplaysLocked();
+ scheduleStatusChangedBroadcastLocked();
+ }
}
- if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)
- && mDisplayDevice != null) {
- mDisplayDevice.setNameLocked(mActiveDisplay.getFriendlyDisplayName());
- sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
+ if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
+ renameDisplayDeviceLocked(mActiveDisplay.getFriendlyDisplayName());
}
}
@@ -272,9 +276,42 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
}
- private void handleConnectLocked(WifiDisplay display,
+ private void fixRememberedDisplayNamesFromAvailableDisplaysLocked() {
+ // It may happen that a display name has changed since it was remembered.
+ // Consult the list of available displays and update the name if needed.
+ // We don't do anything special for the active display here. The display
+ // controller will send a separate event when it needs to be updates.
+ boolean changed = false;
+ for (int i = 0; i < mRememberedDisplays.length; i++) {
+ WifiDisplay rememberedDisplay = mRememberedDisplays[i];
+ WifiDisplay availableDisplay = findAvailableDisplayLocked(
+ rememberedDisplay.getDeviceAddress());
+ if (availableDisplay != null && !rememberedDisplay.equals(availableDisplay)) {
+ if (DEBUG) {
+ Slog.d(TAG, "fixRememberedDisplayNamesFromAvailableDisplaysLocked: "
+ + "updating remembered display to " + availableDisplay);
+ }
+ mRememberedDisplays[i] = availableDisplay;
+ changed |= mPersistentDataStore.rememberWifiDisplay(availableDisplay);
+ }
+ }
+ if (changed) {
+ mPersistentDataStore.saveIfNeeded();
+ }
+ }
+
+ private WifiDisplay findAvailableDisplayLocked(String address) {
+ for (WifiDisplay display : mAvailableDisplays) {
+ if (display.getDeviceAddress().equals(address)) {
+ return display;
+ }
+ }
+ return null;
+ }
+
+ private void addDisplayDeviceLocked(WifiDisplay display,
Surface surface, int width, int height, int flags) {
- handleDisconnectLocked();
+ removeDisplayDeviceLocked();
if (mPersistentDataStore.rememberWifiDisplay(display)) {
mPersistentDataStore.saveIfNeeded();
@@ -303,7 +340,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
scheduleUpdateNotificationLocked();
}
- private void handleDisconnectLocked() {
+ private void removeDisplayDeviceLocked() {
if (mDisplayDevice != null) {
mDisplayDevice.clearSurfaceLocked();
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
@@ -313,6 +350,13 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
}
+ private void renameDisplayDeviceLocked(String name) {
+ if (mDisplayDevice != null && !mDisplayDevice.getNameLocked().equals(name)) {
+ mDisplayDevice.setNameLocked(name);
+ sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
+ }
+ }
+
private void scheduleStatusChangedBroadcastLocked() {
mCurrentStatus = null;
if (!mPendingStatusChangeBroadcast) {
@@ -446,6 +490,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
|| !Arrays.equals(mAvailableDisplays, availableDisplays)) {
mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
mAvailableDisplays = availableDisplays;
+ fixRememberedDisplayNamesFromAvailableDisplaysLocked();
scheduleStatusChangedBroadcastLocked();
}
}
@@ -483,7 +528,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
int width, int height, int flags) {
synchronized (getSyncRoot()) {
display = mPersistentDataStore.applyWifiDisplayAlias(display);
- handleConnectLocked(display, surface, width, height, flags);
+ addDisplayDeviceLocked(display, surface, width, height, flags);
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
|| mActiveDisplay == null
@@ -496,10 +541,24 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
@Override
+ public void onDisplayChanged(WifiDisplay display) {
+ synchronized (getSyncRoot()) {
+ display = mPersistentDataStore.applyWifiDisplayAlias(display);
+ if (mActiveDisplay != null
+ && mActiveDisplay.hasSameAddress(display)
+ && !mActiveDisplay.equals(display)) {
+ mActiveDisplay = display;
+ renameDisplayDeviceLocked(display.getFriendlyDisplayName());
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+
+ @Override
public void onDisplayDisconnected() {
// Stop listening.
synchronized (getSyncRoot()) {
- handleDisconnectLocked();
+ removeDisplayDeviceLocked();
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
|| mActiveDisplay != null) {
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 39d042f..a83675e 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -30,6 +30,7 @@ import android.media.AudioManager;
import android.media.RemoteDisplay;
import android.net.NetworkInfo;
import android.net.Uri;
+import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
@@ -120,6 +121,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
// or are not trying to connect.
private WifiP2pDevice mConnectingDevice;
+ // The device from which we are currently disconnecting.
+ private WifiP2pDevice mDisconnectingDevice;
+
+ // The device to which we were previously trying to connect and are now canceling.
+ private WifiP2pDevice mCancelingDevice;
+
// The device to which we are currently connected, which means we have an active P2P group.
private WifiP2pDevice mConnectedDevice;
@@ -186,6 +193,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
updateWfdEnableState();
}
+ @Override
public void dump(PrintWriter pw) {
pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
@@ -196,6 +204,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft);
pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
+ pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice));
+ pw.println("mCancelingDisplay=" + describeWifiP2pDevice(mCancelingDevice));
pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft);
pw.println("mRemoteDisplay=" + mRemoteDisplay);
@@ -384,7 +394,9 @@ final class WifiDisplayController implements DumpUtils.Dump {
final int count = mAvailableWifiDisplayPeers.size();
final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
for (int i = 0; i < count; i++) {
- displays[i] = createWifiDisplay(mAvailableWifiDisplayPeers.get(i));
+ WifiP2pDevice device = mAvailableWifiDisplayPeers.get(i);
+ displays[i] = createWifiDisplay(device);
+ updateDesiredDevice(device);
}
mHandler.post(new Runnable() {
@@ -395,6 +407,23 @@ final class WifiDisplayController implements DumpUtils.Dump {
});
}
+ private void updateDesiredDevice(WifiP2pDevice device) {
+ // Handle the case where the device to which we are connecting or connected
+ // may have been renamed or reported different properties in the latest scan.
+ final String address = device.deviceAddress;
+ if (mDesiredDevice != null && mDesiredDevice.deviceAddress.equals(address)) {
+ if (DEBUG) {
+ Slog.d(TAG, "updateDesiredDevice: new information "
+ + describeWifiP2pDevice(device));
+ }
+ mDesiredDevice.update(device);
+ if (mAdvertisedDisplay != null
+ && mAdvertisedDisplay.getDeviceAddress().equals(address)) {
+ readvertiseDisplay(createWifiDisplay(mDesiredDevice));
+ }
+ }
+ }
+
private void connect(final WifiP2pDevice device) {
if (mDesiredDevice != null
&& !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) {
@@ -459,12 +488,17 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
// Step 2. Before we try to connect to a new device, disconnect from the old one.
+ if (mDisconnectingDevice != null) {
+ return; // wait for asynchronous callback
+ }
if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
+ mDisconnectingDevice = mConnectedDevice;
+ mConnectedDevice = null;
unadvertiseDisplay();
- final WifiP2pDevice oldDevice = mConnectedDevice;
+ final WifiP2pDevice oldDevice = mDisconnectingDevice;
mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
@Override
public void onSuccess() {
@@ -480,8 +514,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private void next() {
- if (mConnectedDevice == oldDevice) {
- mConnectedDevice = null;
+ if (mDisconnectingDevice == oldDevice) {
+ mDisconnectingDevice = null;
updateConnection();
}
}
@@ -491,13 +525,18 @@ final class WifiDisplayController implements DumpUtils.Dump {
// Step 3. Before we try to connect to a new device, stop trying to connect
// to the old one.
+ if (mCancelingDevice != null) {
+ return; // wait for asynchronous callback
+ }
if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
+ mCancelingDevice = mConnectingDevice;
+ mConnectingDevice = null;
unadvertiseDisplay();
mHandler.removeCallbacks(mConnectionTimeout);
- final WifiP2pDevice oldDevice = mConnectingDevice;
+ final WifiP2pDevice oldDevice = mCancelingDevice;
mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() {
@Override
public void onSuccess() {
@@ -513,8 +552,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private void next() {
- if (mConnectingDevice == oldDevice) {
- mConnectingDevice = null;
+ if (mCancelingDevice == oldDevice) {
+ mCancelingDevice = null;
updateConnection();
}
}
@@ -534,6 +573,16 @@ final class WifiDisplayController implements DumpUtils.Dump {
mConnectingDevice = mDesiredDevice;
WifiP2pConfig config = new WifiP2pConfig();
+ WpsInfo wps = new WpsInfo();
+ if (mConnectingDevice.wpsPbcSupported()) {
+ wps.setup = WpsInfo.PBC;
+ } else if (mConnectingDevice.wpsDisplaySupported()) {
+ // We do keypad if peer does display
+ wps.setup = WpsInfo.KEYPAD;
+ } else {
+ wps.setup = WpsInfo.DISPLAY;
+ }
+ config.wps = wps;
config.deviceAddress = mConnectingDevice.deviceAddress;
// Helps with STA & P2P concurrency
config.groupOwnerIntent = WifiP2pConfig.MIN_GROUP_OWNER_INTENT;
@@ -763,13 +812,17 @@ final class WifiDisplayController implements DumpUtils.Dump {
public void run() {
if (oldSurface != null && surface != oldSurface) {
mListener.onDisplayDisconnected();
- } else if (oldDisplay != null && !Objects.equal(display, oldDisplay)) {
+ } else if (oldDisplay != null && !oldDisplay.hasSameAddress(display)) {
mListener.onDisplayConnectionFailed();
}
if (display != null) {
- if (!Objects.equal(display, oldDisplay)) {
+ if (!display.hasSameAddress(oldDisplay)) {
mListener.onDisplayConnecting(display);
+ } else if (!display.equals(oldDisplay)) {
+ // The address is the same but some other property such as the
+ // name must have changed.
+ mListener.onDisplayChanged(display);
}
if (surface != null && surface != oldSurface) {
mListener.onDisplayConnected(display, surface, width, height, flags);
@@ -784,6 +837,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
advertiseDisplay(null, null, 0, 0, 0);
}
+ private void readvertiseDisplay(WifiDisplay display) {
+ advertiseDisplay(display, mAdvertisedDisplaySurface,
+ mAdvertisedDisplayWidth, mAdvertisedDisplayHeight,
+ mAdvertisedDisplayFlags);
+ }
+
private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
NetworkInterface iface;
try {
@@ -885,6 +944,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
void onDisplayConnecting(WifiDisplay display);
void onDisplayConnectionFailed();
+ void onDisplayChanged(WifiDisplay display);
void onDisplayConnected(WifiDisplay display,
Surface surface, int width, int height, int flags);
void onDisplayDisconnected();
diff --git a/services/java/com/android/server/dreams/DreamController.java b/services/java/com/android/server/dreams/DreamController.java
index 1ab6a77..45ae2c5 100644
--- a/services/java/com/android/server/dreams/DreamController.java
+++ b/services/java/com/android/server/dreams/DreamController.java
@@ -44,6 +44,9 @@ import java.util.NoSuchElementException;
final class DreamController {
private static final String TAG = "DreamController";
+ // How long we wait for a newly bound dream to create the service connection
+ private static final int DREAM_CONNECTION_TIMEOUT = 5 * 1000;
+
private final Context mContext;
private final Handler mHandler;
private final Listener mListener;
@@ -58,6 +61,16 @@ final class DreamController {
private DreamRecord mCurrentDream;
+ private final Runnable mStopUnconnectedDreamRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mCurrentDream != null && mCurrentDream.mBound && !mCurrentDream.mConnected) {
+ Slog.w(TAG, "Bound dream did not connect in the time allotted");
+ stopDream();
+ }
+ }
+ };
+
public DreamController(Context context, Handler handler, Listener listener) {
mContext = context;
mHandler = handler;
@@ -116,6 +129,7 @@ final class DreamController {
}
mCurrentDream.mBound = true;
+ mHandler.postDelayed(mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT);
}
public void stopDream() {
@@ -128,6 +142,8 @@ final class DreamController {
Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
+ ", isTest=" + oldDream.mIsTest + ", userId=" + oldDream.mUserId);
+ mHandler.removeCallbacks(mStopUnconnectedDreamRunnable);
+
if (oldDream.mSentStartBroadcast) {
mContext.sendBroadcastAsUser(mDreamingStoppedIntent, UserHandle.ALL);
}
@@ -200,6 +216,7 @@ final class DreamController {
public final int mUserId;
public boolean mBound;
+ public boolean mConnected;
public IDreamService mService;
public boolean mSentStartBroadcast;
@@ -231,6 +248,7 @@ final class DreamController {
mHandler.post(new Runnable() {
@Override
public void run() {
+ mConnected = true;
if (mCurrentDream == DreamRecord.this && mService == null) {
attach(IDreamService.Stub.asInterface(service));
}
diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/java/com/android/server/dreams/DreamManagerService.java
index 1f40176..c9e0da5 100644
--- a/services/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/java/com/android/server/dreams/DreamManagerService.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -38,6 +39,8 @@ import android.util.Slog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
import libcore.util.Objects;
@@ -47,7 +50,7 @@ import libcore.util.Objects;
* @hide
*/
public final class DreamManagerService extends IDreamManager.Stub {
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final String TAG = "DreamManagerService";
private final Object mLock = new Object();
@@ -279,7 +282,37 @@ public final class DreamManagerService extends IDreamManager.Stub {
String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
Settings.Secure.SCREENSAVER_COMPONENTS,
userId);
- return names == null ? null : componentsFromString(names);
+ ComponentName[] components = componentsFromString(names);
+
+ // first, ensure components point to valid services
+ List<ComponentName> validComponents = new ArrayList<ComponentName>();
+ if (components != null) {
+ for (ComponentName component : components) {
+ if (serviceExists(component)) {
+ validComponents.add(component);
+ } else {
+ Slog.w(TAG, "Dream " + component + " does not exist");
+ }
+ }
+ }
+
+ // fallback to the default dream component if necessary
+ if (validComponents.isEmpty()) {
+ ComponentName defaultDream = getDefaultDreamComponent();
+ if (defaultDream != null) {
+ Slog.w(TAG, "Falling back to default dream " + defaultDream);
+ validComponents.add(defaultDream);
+ }
+ }
+ return validComponents.toArray(new ComponentName[validComponents.size()]);
+ }
+
+ private boolean serviceExists(ComponentName name) {
+ try {
+ return name != null && mContext.getPackageManager().getServiceInfo(name, 0) != null;
+ } catch (NameNotFoundException e) {
+ return false;
+ }
}
private void startDreamLocked(final ComponentName name,
@@ -292,7 +325,7 @@ public final class DreamManagerService extends IDreamManager.Stub {
stopDreamLocked();
- Slog.i(TAG, "Entering dreamland.");
+ if (DEBUG) Slog.i(TAG, "Entering dreamland.");
final Binder newToken = new Binder();
mCurrentDreamToken = newToken;
@@ -310,7 +343,7 @@ public final class DreamManagerService extends IDreamManager.Stub {
private void stopDreamLocked() {
if (mCurrentDreamToken != null) {
- Slog.i(TAG, "Leaving dreamland.");
+ if (DEBUG) Slog.i(TAG, "Leaving dreamland.");
cleanupDreamLocked();
@@ -352,6 +385,9 @@ public final class DreamManagerService extends IDreamManager.Stub {
}
private static ComponentName[] componentsFromString(String names) {
+ if (names == null) {
+ return null;
+ }
String[] namesArray = names.split(",");
ComponentName[] componentNames = new ComponentName[namesArray.length];
for (int i = 0; i < namesArray.length; i++) {
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 18fefda..b09390c 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -131,6 +131,7 @@ import android.util.TrustedTime;
import android.util.Xml;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Objects;
@@ -184,9 +185,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final int VERSION_SWITCH_UID = 10;
private static final int VERSION_LATEST = VERSION_SWITCH_UID;
- // @VisibleForTesting
+ @VisibleForTesting
public static final int TYPE_WARNING = 0x1;
+ @VisibleForTesting
public static final int TYPE_LIMIT = 0x2;
+ @VisibleForTesting
public static final int TYPE_LIMIT_SNOOZED = 0x3;
private static final String TAG_POLICY_LIST = "policy-list";
@@ -214,10 +217,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final String TAG_ALLOW_BACKGROUND = TAG + ":allowBackground";
- // @VisibleForTesting
- public static final String ACTION_ALLOW_BACKGROUND =
+ private static final String ACTION_ALLOW_BACKGROUND =
"com.android.server.net.action.ALLOW_BACKGROUND";
- public static final String ACTION_SNOOZE_WARNING =
+ private static final String ACTION_SNOOZE_WARNING =
"com.android.server.net.action.SNOOZE_WARNING";
private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
@@ -2061,7 +2063,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return intent;
}
- // @VisibleForTesting
+ @VisibleForTesting
public void addIdleHandler(IdleHandler handler) {
mHandler.getLooper().getQueue().addIdleHandler(handler);
}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index a3b44e2..74be472 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -115,6 +115,7 @@ import android.util.Slog;
import android.util.SparseIntArray;
import android.util.TrustedTime;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
@@ -165,7 +166,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private IConnectivityManager mConnManager;
- // @VisibleForTesting
+ @VisibleForTesting
public static final String ACTION_NETWORK_STATS_POLL =
"com.android.server.action.NETWORK_STATS_POLL";
public static final String ACTION_NETWORK_STATS_UPDATED =
@@ -902,7 +903,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state));
// remember any ifaces associated with mobile networks
- if (isNetworkTypeMobile(state.networkInfo.getType())) {
+ if (isNetworkTypeMobile(state.networkInfo.getType()) && iface != null) {
if (!contains(mMobileIfaces, iface)) {
mMobileIfaces = appendElement(String.class, mMobileIfaces, iface);
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 83672c5..2238f17 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1020,7 +1020,8 @@ public class PackageManagerService extends IPackageManager.Stub {
readPermissions();
- mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false));
+ mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false),
+ mSdkVersion, mOnlyCore);
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
@@ -1320,6 +1321,10 @@ public class PackageManagerService extends IPackageManager.Stub {
return !mRestoredSettings;
}
+ public boolean isOnlyCoreApps() {
+ return mOnlyCore;
+ }
+
private String getRequiredVerifierLPr() {
final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
@@ -4113,7 +4118,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- Slog.i(TAG, "Linking native library dir for " + path);
+ if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
final int[] userIds = sUserManager.getUserIds();
synchronized (mInstallLock) {
for (int userId : userIds) {
@@ -6301,20 +6306,21 @@ public class PackageManagerService extends IPackageManager.Stub {
final File packageFile;
if (encryptionParams != null || !"file".equals(mPackageURI.getScheme())) {
- ParcelFileDescriptor out = null;
-
mTempPackage = createTempPackageFile(mDrmAppPrivateInstallDir);
if (mTempPackage != null) {
+ ParcelFileDescriptor out;
try {
out = ParcelFileDescriptor.open(mTempPackage,
ParcelFileDescriptor.MODE_READ_WRITE);
} catch (FileNotFoundException e) {
+ out = null;
Slog.e(TAG, "Failed to create temporary file for : " + mPackageURI);
}
// Make a temporary file for decryption.
ret = mContainerService
.copyResource(mPackageURI, encryptionParams, out);
+ IoUtils.closeQuietly(out);
packageFile = mTempPackage;
@@ -6347,6 +6353,18 @@ public class PackageManagerService extends IPackageManager.Stub {
pkgLite = mContainerService.getMinimalPackageInfo(packageFilePath,
flags, lowThreshold);
}
+ /*
+ * The cache free must have deleted the file we
+ * downloaded to install.
+ *
+ * TODO: fix the "freeCache" call to not delete
+ * the file we care about.
+ */
+ if (pkgLite.recommendedInstallLocation
+ == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
+ pkgLite.recommendedInstallLocation
+ = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
+ }
}
}
} finally {
@@ -9079,10 +9097,8 @@ public class PackageManagerService extends IPackageManager.Stub {
if (removed.size() > 0) {
for (int j=0; j<removed.size(); j++) {
PreferredActivity pa = removed.get(i);
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
Slog.w(TAG, "Removing dangling preferred activity: "
- + pa.mPref.mComponent, here);
+ + pa.mPref.mComponent);
pir.removeFilter(pa);
}
mSettings.writePackageRestrictionsLPr(
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 94494ae..06f11bc 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1556,7 +1556,7 @@ final class Settings {
}
}
- boolean readLPw(List<UserInfo> users) {
+ boolean readLPw(List<UserInfo> users, int sdkVersion, boolean onlyCore) {
FileInputStream str = null;
if (mBackupSettingsFilename.exists()) {
try {
@@ -1586,7 +1586,10 @@ final class Settings {
mReadMessages.append("No settings file found\n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"No settings file; creating initial state");
- readDefaultPreferredAppsLPw(0);
+ if (!onlyCore) {
+ readDefaultPreferredAppsLPw(0);
+ }
+ mInternalSdkPlatform = mExternalSdkPlatform = sdkVersion;
return false;
}
str = new FileInputStream(mSettingsFilename);
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index e05442b..dbfe34d 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -16,8 +16,7 @@
package com.android.server.pm;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import android.app.Activity;
import android.app.ActivityManager;
@@ -26,7 +25,6 @@ import android.app.IStopUserCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
@@ -34,6 +32,7 @@ import android.graphics.BitmapFactory;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
+import android.os.Handler;
import android.os.IUserManager;
import android.os.Process;
import android.os.RemoteException;
@@ -42,9 +41,17 @@ import android.os.UserManager;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.Xml;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
@@ -54,13 +61,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
public class UserManagerService extends IUserManager.Stub {
private static final String LOG_TAG = "UserManagerService";
@@ -86,7 +88,7 @@ public class UserManagerService extends IUserManager.Stub {
private static final int MIN_USER_ID = 10;
- private static final int USER_VERSION = 1;
+ private static final int USER_VERSION = 2;
private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
@@ -95,19 +97,24 @@ public class UserManagerService extends IUserManager.Stub {
private final Object mInstallLock;
private final Object mPackagesLock;
+ private final Handler mHandler;
+
private final File mUsersDir;
private final File mUserListFile;
private final File mBaseUserPath;
- private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
- private HashSet<Integer> mRemovingUserIds = new HashSet<Integer>();
+ private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+
+ /**
+ * Set of user IDs being actively removed. Removed IDs linger in this set
+ * for several seconds to work around a VFS caching issue.
+ */
+ // @GuardedBy("mPackagesLock")
+ private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray();
private int[] mUserIds;
private boolean mGuestEnabled;
private int mNextSerialNumber;
- // This resets on a reboot. Otherwise it keeps incrementing so that user ids are
- // not reused in quick succession
- private int mNextUserId = MIN_USER_ID;
private int mUserVersion = 0;
private static UserManagerService sInstance;
@@ -147,6 +154,7 @@ public class UserManagerService extends IUserManager.Stub {
mPm = pm;
mInstallLock = installLock;
mPackagesLock = packagesLock;
+ mHandler = new Handler();
synchronized (mInstallLock) {
synchronized (mPackagesLock) {
mUsersDir = new File(dataDir, USER_INFO_DIR);
@@ -190,7 +198,7 @@ public class UserManagerService extends IUserManager.Stub {
if (ui.partial) {
continue;
}
- if (!excludeDying || !mRemovingUserIds.contains(ui.id)) {
+ if (!excludeDying || !mRemovingUserIds.get(ui.id)) {
users.add(ui);
}
}
@@ -212,7 +220,7 @@ public class UserManagerService extends IUserManager.Stub {
private UserInfo getUserInfoLocked(int userId) {
UserInfo ui = mUsers.get(userId);
// If it is partial and not in the process of being removed, return as unknown user.
- if (ui != null && ui.partial && !mRemovingUserIds.contains(userId)) {
+ if (ui != null && ui.partial && !mRemovingUserIds.get(userId)) {
Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
return null;
}
@@ -476,8 +484,7 @@ public class UserManagerService extends IUserManager.Stub {
}
/**
- * This fixes an incorrect initialization of user name for the owner.
- * TODO: Remove in the next release.
+ * Upgrade steps between versions, either for fixing bugs or changing the data format.
*/
private void upgradeIfNecessary() {
int userVersion = mUserVersion;
@@ -491,6 +498,16 @@ public class UserManagerService extends IUserManager.Stub {
userVersion = 1;
}
+ if (userVersion < 2) {
+ // Owner should be marked as initialized
+ UserInfo user = mUsers.get(UserHandle.USER_OWNER);
+ if ((user.flags & UserInfo.FLAG_INITIALIZED) == 0) {
+ user.flags |= UserInfo.FLAG_INITIALIZED;
+ writeUserLocked(user);
+ }
+ userVersion = 2;
+ }
+
if (userVersion < USER_VERSION) {
Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
+ USER_VERSION);
@@ -502,7 +519,7 @@ public class UserManagerService extends IUserManager.Stub {
private void fallbackToSingleUserLocked() {
// Create the primary user
- UserInfo primary = new UserInfo(0,
+ UserInfo primary = new UserInfo(0,
mContext.getResources().getString(com.android.internal.R.string.owner_name), null,
UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED);
mUsers.put(0, primary);
@@ -749,7 +766,7 @@ public class UserManagerService extends IUserManager.Stub {
if (userHandle == 0 || user == null) {
return false;
}
- mRemovingUserIds.add(userHandle);
+ mRemovingUserIds.put(userHandle, true);
// Set this to a partially created user, so that the user will be purged
// on next startup, in case the runtime stops now before stopping and
// removing the user completely.
@@ -813,13 +830,25 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- private void removeUserStateLocked(int userHandle) {
+ private void removeUserStateLocked(final int userHandle) {
// Cleanup package manager settings
mPm.cleanUpUserLILPw(userHandle);
// Remove this user from the list
mUsers.remove(userHandle);
- mRemovingUserIds.remove(userHandle);
+
+ // Have user ID linger for several seconds to let external storage VFS
+ // cache entries expire. This must be greater than the 'entry_valid'
+ // timeout used by the FUSE daemon.
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mPackagesLock) {
+ mRemovingUserIds.delete(userHandle);
+ }
+ }
+ }, MINUTE_IN_MILLIS);
+
// Remove user file
AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
userFile.delete();
@@ -906,14 +935,13 @@ public class UserManagerService extends IUserManager.Stub {
*/
private int getNextAvailableIdLocked() {
synchronized (mPackagesLock) {
- int i = mNextUserId;
+ int i = MIN_USER_ID;
while (i < Integer.MAX_VALUE) {
- if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) {
+ if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
break;
}
i++;
}
- mNextUserId = i + 1;
return i;
}
}
@@ -938,7 +966,7 @@ public class UserManagerService extends IUserManager.Stub {
UserInfo user = mUsers.valueAt(i);
if (user == null) continue;
pw.print(" "); pw.print(user); pw.print(" serialNo="); pw.print(user.serialNumber);
- if (mRemovingUserIds.contains(mUsers.keyAt(i))) pw.print(" <removing> ");
+ if (mRemovingUserIds.get(mUsers.keyAt(i))) pw.print(" <removing> ");
if (user.partial) pw.print(" <partial>");
pw.println();
pw.print(" Created: ");
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 317fec0..724e126 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -19,6 +19,7 @@ package com.android.server.power;
import com.android.server.LightsService;
import com.android.server.TwilightService;
import com.android.server.TwilightService.TwilightState;
+import com.android.server.display.DisplayManagerService;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -29,7 +30,6 @@ import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.SystemSensorManager;
-import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -40,7 +40,6 @@ import android.util.FloatMath;
import android.util.Slog;
import android.util.Spline;
import android.util.TimeUtils;
-import android.view.Display;
import java.io.PrintWriter;
@@ -183,7 +182,7 @@ final class DisplayPowerController {
private final TwilightService mTwilight;
// The display manager.
- private final DisplayManager mDisplayManager;
+ private final DisplayManagerService mDisplayManager;
// The sensor manager.
private final SensorManager mSensorManager;
@@ -346,6 +345,7 @@ final class DisplayPowerController {
*/
public DisplayPowerController(Looper looper, Context context, Notifier notifier,
LightsService lights, TwilightService twilight,
+ DisplayManagerService displayManager,
DisplayBlanker displayBlanker,
Callbacks callbacks, Handler callbackHandler) {
mHandler = new DisplayControllerHandler(looper);
@@ -357,7 +357,7 @@ final class DisplayPowerController {
mLights = lights;
mTwilight = twilight;
mSensorManager = new SystemSensorManager(mHandler.getLooper());
- mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
+ mDisplayManager = displayManager;
final Resources resources = context.getResources();
@@ -518,9 +518,8 @@ final class DisplayPowerController {
}
private void initialize() {
- Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
mPowerState = new DisplayPowerState(
- new ElectronBeam(display), mDisplayBlanker,
+ new ElectronBeam(mDisplayManager), mDisplayBlanker,
mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT));
mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java
index 9a53648..8e19e11 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -16,6 +16,9 @@
package com.android.server.power;
+import com.android.server.display.DisplayManagerService;
+import com.android.server.display.DisplayTransactionListener;
+
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.opengl.EGL14;
@@ -72,14 +75,13 @@ final class ElectronBeam {
private boolean mPrepared;
private int mMode;
- private final Display mDisplay;
- private final DisplayInfo mDisplayInfo = new DisplayInfo();
+ private final DisplayManagerService mDisplayManager;
private int mDisplayLayerStack; // layer stack associated with primary display
- private int mDisplayRotation;
private int mDisplayWidth; // real width, not rotated
private int mDisplayHeight; // real height, not rotated
private SurfaceSession mSurfaceSession;
private Surface mSurface;
+ private NaturalSurfaceLayout mSurfaceLayout;
private EGLDisplay mEglDisplay;
private EGLConfig mEglConfig;
private EGLContext mEglContext;
@@ -111,8 +113,8 @@ final class ElectronBeam {
*/
public static final int MODE_FADE = 2;
- public ElectronBeam(Display display) {
- mDisplay = display;
+ public ElectronBeam(DisplayManagerService displayManager) {
+ mDisplayManager = displayManager;
}
/**
@@ -129,18 +131,12 @@ final class ElectronBeam {
mMode = mode;
- // Get the display size and adjust it for rotation.
- mDisplay.getDisplayInfo(mDisplayInfo);
- mDisplayLayerStack = mDisplay.getLayerStack();
- mDisplayRotation = mDisplayInfo.rotation;
- if (mDisplayRotation == Surface.ROTATION_90
- || mDisplayRotation == Surface.ROTATION_270) {
- mDisplayWidth = mDisplayInfo.logicalHeight;
- mDisplayHeight = mDisplayInfo.logicalWidth;
- } else {
- mDisplayWidth = mDisplayInfo.logicalWidth;
- mDisplayHeight = mDisplayInfo.logicalHeight;
- }
+ // Get the display size and layer stack.
+ // This is not expected to change while the electron beam surface is showing.
+ DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY);
+ mDisplayLayerStack = displayInfo.layerStack;
+ mDisplayWidth = displayInfo.getNaturalWidth();
+ mDisplayHeight = displayInfo.getNaturalHeight();
// Prepare the surface for drawing.
if (!tryPrepare()) {
@@ -551,24 +547,8 @@ final class ElectronBeam {
mSurface.setLayerStack(mDisplayLayerStack);
mSurface.setSize(mDisplayWidth, mDisplayHeight);
- switch (mDisplayRotation) {
- case Surface.ROTATION_0:
- mSurface.setPosition(0, 0);
- mSurface.setMatrix(1, 0, 0, 1);
- break;
- case Surface.ROTATION_90:
- mSurface.setPosition(0, mDisplayWidth);
- mSurface.setMatrix(0, -1, 1, 0);
- break;
- case Surface.ROTATION_180:
- mSurface.setPosition(mDisplayWidth, mDisplayHeight);
- mSurface.setMatrix(-1, 0, 0, -1);
- break;
- case Surface.ROTATION_270:
- mSurface.setPosition(mDisplayHeight, 0);
- mSurface.setMatrix(0, 1, -1, 0);
- break;
- }
+ mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurface);
+ mSurfaceLayout.onDisplayTransaction();
} finally {
Surface.closeTransaction();
}
@@ -601,6 +581,8 @@ final class ElectronBeam {
private void destroySurface() {
if (mSurface != null) {
+ mSurfaceLayout.dispose();
+ mSurfaceLayout = null;
Surface.openTransaction();
try {
mSurface.destroy();
@@ -711,10 +693,63 @@ final class ElectronBeam {
pw.println(" mPrepared=" + mPrepared);
pw.println(" mMode=" + mMode);
pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
- pw.println(" mDisplayRotation=" + mDisplayRotation);
pw.println(" mDisplayWidth=" + mDisplayWidth);
pw.println(" mDisplayHeight=" + mDisplayHeight);
pw.println(" mSurfaceVisible=" + mSurfaceVisible);
pw.println(" mSurfaceAlpha=" + mSurfaceAlpha);
}
+
+ /**
+ * Keeps a surface aligned with the natural orientation of the device.
+ * Updates the position and transformation of the matrix whenever the display
+ * is rotated. This is a little tricky because the display transaction
+ * callback can be invoked on any thread, not necessarily the thread that
+ * owns the electron beam.
+ */
+ private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
+ private final DisplayManagerService mDisplayManager;
+ private Surface mSurface;
+
+ public NaturalSurfaceLayout(DisplayManagerService displayManager, Surface surface) {
+ mDisplayManager = displayManager;
+ mSurface = surface;
+ mDisplayManager.registerDisplayTransactionListener(this);
+ }
+
+ public void dispose() {
+ synchronized (this) {
+ mSurface = null;
+ }
+ mDisplayManager.unregisterDisplayTransactionListener(this);
+ }
+
+ @Override
+ public void onDisplayTransaction() {
+ synchronized (this) {
+ if (mSurface == null) {
+ return;
+ }
+
+ DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY);
+ switch (displayInfo.rotation) {
+ case Surface.ROTATION_0:
+ mSurface.setPosition(0, 0);
+ mSurface.setMatrix(1, 0, 0, 1);
+ break;
+ case Surface.ROTATION_90:
+ mSurface.setPosition(0, displayInfo.logicalHeight);
+ mSurface.setMatrix(0, -1, 1, 0);
+ break;
+ case Surface.ROTATION_180:
+ mSurface.setPosition(displayInfo.logicalWidth, displayInfo.logicalHeight);
+ mSurface.setMatrix(-1, 0, 0, -1);
+ break;
+ case Surface.ROTATION_270:
+ mSurface.setPosition(displayInfo.logicalWidth, 0);
+ mSurface.setMatrix(0, 1, -1, 0);
+ break;
+ }
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java
index 5e05693..d99d523 100644
--- a/services/java/com/android/server/power/Notifier.java
+++ b/services/java/com/android/server/power/Notifier.java
@@ -23,6 +23,10 @@ import android.app.ActivityManagerNative;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
import android.os.BatteryStats;
import android.os.Handler;
import android.os.Looper;
@@ -32,6 +36,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.provider.Settings;
import android.util.EventLog;
import android.util.Slog;
import android.view.WindowManagerPolicy;
@@ -64,6 +69,7 @@ final class Notifier {
private static final int MSG_USER_ACTIVITY = 1;
private static final int MSG_BROADCAST = 2;
+ private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
private final Object mLock = new Object();
@@ -312,6 +318,20 @@ final class Notifier {
}
}
+ /**
+ * Called when wireless charging has started so as to provide user feedback.
+ */
+ public void onWirelessChargingStarted() {
+ if (DEBUG) {
+ Slog.d(TAG, "onWirelessChargingStarted");
+ }
+
+ mSuspendBlocker.acquire();
+ Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
+ }
+
private void updatePendingBroadcastLocked() {
if (!mBroadcastInProgress
&& mActualPowerState != POWER_STATE_UNKNOWN
@@ -473,6 +493,23 @@ final class Notifier {
}
};
+ private void playWirelessChargingStartedSound() {
+ final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
+ if (soundPath != null) {
+ final Uri soundUri = Uri.parse("file://" + soundPath);
+ if (soundUri != null) {
+ final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+ if (sfx != null) {
+ sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+ sfx.play();
+ }
+ }
+ }
+
+ mSuspendBlocker.release();
+ }
+
private final class NotifierHandler extends Handler {
public NotifierHandler(Looper looper) {
super(looper, null, true /*async*/);
@@ -488,6 +525,10 @@ final class Notifier {
case MSG_BROADCAST:
sendNextBroadcast();
break;
+
+ case MSG_WIRELESS_CHARGING_STARTED:
+ playWirelessChargingStartedSound();
+ break;
}
}
}
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 8650192..5a5d910 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -432,7 +432,7 @@ public final class PowerManagerService extends IPowerManager.Stub
// The display power controller runs on the power manager service's
// own handler thread.
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
- mContext, mNotifier, mLightsService, twilight,
+ mContext, mNotifier, mLightsService, twilight, mDisplayManagerService,
mDisplayBlanker, mDisplayPowerControllerCallbacks, mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
@@ -618,8 +618,19 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
+ private static boolean isScreenLock(final WakeLock wakeLock) {
+ switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+ case PowerManager.FULL_WAKE_LOCK:
+ case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+ case PowerManager.SCREEN_DIM_WAKE_LOCK:
+ return true;
+ }
+ return false;
+ }
+
private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock) {
- if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
+ if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0 &&
+ isScreenLock(wakeLock)) {
wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
}
}
@@ -1139,6 +1150,16 @@ public final class PowerManagerService extends IPowerManager.Stub
}
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
+
+ // Tell the notifier whether wireless charging has started so that
+ // it can provide feedback to the user. Refer to
+ // shouldWakeUpWhenPluggedOrUnpluggedLocked for justification of the
+ // heuristics used here.
+ if (!wasPowered && mIsPowered
+ && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
+ && mBatteryLevel < WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) {
+ mNotifier.onWirelessChargingStarted();
+ }
}
}
}
diff --git a/services/java/com/android/server/power/RampAnimator.java b/services/java/com/android/server/power/RampAnimator.java
index 6f063c3..4a4f080 100644
--- a/services/java/com/android/server/power/RampAnimator.java
+++ b/services/java/com/android/server/power/RampAnimator.java
@@ -102,20 +102,26 @@ final class RampAnimator<T> {
final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
final float timeDelta = (frameTimeNanos - mLastFrameTimeNanos)
* 0.000000001f;
- final float amount = timeDelta * mRate / ValueAnimator.getDurationScale();
mLastFrameTimeNanos = frameTimeNanos;
// Advance the animated value towards the target at the specified rate
// and clamp to the target. This gives us the new current value but
// we keep the animated value around to allow for fractional increments
// towards the target.
- int oldCurrentValue = mCurrentValue;
- if (mTargetValue > mCurrentValue) {
- mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue);
+ final float scale = ValueAnimator.getDurationScale();
+ if (scale == 0) {
+ // Animation off.
+ mAnimatedValue = mTargetValue;
} else {
- mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue);
+ final float amount = timeDelta * mRate / scale;
+ if (mTargetValue > mCurrentValue) {
+ mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue);
+ } else {
+ mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue);
+ }
}
- mCurrentValue = (int)Math.round(mAnimatedValue);
+ final int oldCurrentValue = mCurrentValue;
+ mCurrentValue = Math.round(mAnimatedValue);
if (oldCurrentValue != mCurrentValue) {
mProperty.setValue(mObject, mCurrentValue);
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index f34a52d..c7c2c62 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -47,6 +47,8 @@ import android.provider.Settings;
import android.util.Pair;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
@@ -105,7 +107,7 @@ public class UsbDeviceManager {
private final Context mContext;
private final ContentResolver mContentResolver;
- // @GuardedBy("mLock")
+ @GuardedBy("mLock")
private UsbSettingsManager mCurrentSettings;
private NotificationManager mNotificationManager;
private final boolean mHasUsbAccessory;
diff --git a/services/java/com/android/server/usb/UsbHostManager.java b/services/java/com/android/server/usb/UsbHostManager.java
index 175ae6f..10272f2 100644
--- a/services/java/com/android/server/usb/UsbHostManager.java
+++ b/services/java/com/android/server/usb/UsbHostManager.java
@@ -26,6 +26,8 @@ import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -46,7 +48,7 @@ public class UsbHostManager {
private final Context mContext;
private final Object mLock = new Object();
- // @GuardedBy("mLock")
+ @GuardedBy("mLock")
private UsbSettingsManager mCurrentSettings;
public UsbHostManager(Context context) {
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 629f5fa..3918d15 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -30,6 +30,7 @@ import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import java.io.File;
@@ -52,7 +53,7 @@ public class UsbService extends IUsbManager.Stub {
private final Object mLock = new Object();
/** Map from {@link UserHandle} to {@link UsbSettingsManager} */
- // @GuardedBy("mLock")
+ @GuardedBy("mLock")
private final SparseArray<UsbSettingsManager>
mSettingsByUser = new SparseArray<UsbSettingsManager>();
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 7efffe5..2802ad7 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -37,6 +37,8 @@ import java.util.ArrayList;
* really activity) that is displaying windows.
*/
class AppWindowToken extends WindowToken {
+ // The user who owns this app window token.
+ final int userId;
// Non-null only for application tokens.
final IApplicationToken appToken;
@@ -98,9 +100,10 @@ class AppWindowToken extends WindowToken {
// Input application handle used by the input dispatcher.
final InputApplicationHandle mInputApplicationHandle;
- AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
+ AppWindowToken(WindowManagerService _service, int _userId, IApplicationToken _token) {
super(_service, _token.asBinder(),
WindowManager.LayoutParams.TYPE_APPLICATION, true);
+ userId = _userId;
appWindowToken = this;
appToken = _token;
mInputApplicationHandle = new InputApplicationHandle(this);
@@ -225,7 +228,8 @@ class AppWindowToken extends WindowToken {
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
if (appToken != null) {
- pw.print(prefix); pw.println("app=true");
+ pw.print(prefix); pw.print("app=true");
+ pw.print(" userId="); pw.println(userId);
}
if (allAppWindows.size() > 0) {
pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 8d2e2e8..cfcf841 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -668,6 +668,10 @@ class ScreenRotationAnimation {
return hasAnimations() || (TWO_PHASE_ANIMATION && mFinishAnimReady);
}
+ public boolean isRotating() {
+ return mCurRotation != mOriginalRotation;
+ }
+
private boolean hasAnimations() {
return (TWO_PHASE_ANIMATION &&
(mStartEnterAnimation != null || mStartExitAnimation != null
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index a1fc4e0..0466c15 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -268,6 +268,9 @@ public class WindowManagerService extends IWindowManager.Stub
/** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */
static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000;
+ /** Fraction of animation at which the recents thumbnail becomes completely transparent */
+ static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.25f;
+
/**
* If true, the window manager will do its own custom freezing and general
* management of the screen during rotation.
@@ -821,7 +824,7 @@ public class WindowManagerService extends IWindowManager.Stub
mTransitionAnimationScale = Settings.Global.getFloat(context.getContentResolver(),
Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
setAnimatorDurationScale(Settings.Global.getFloat(context.getContentResolver(),
- Settings.Global.ANIMATOR_DURATION_SCALE, mTransitionAnimationScale));
+ Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale));
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
IntentFilter filter = new IntentFilter();
@@ -919,6 +922,27 @@ public class WindowManagerService extends IWindowManager.Stub
return windowList;
}
+ /**
+ * Recursive search through a WindowList and all of its windows' children.
+ * @param targetWin The window to search for.
+ * @param windows The list to search.
+ * @return The index of win in windows or of the window that is an ancestor of win.
+ */
+ private int indexOfWinInWindowList(WindowState targetWin, WindowList windows) {
+ for (int i = windows.size() - 1; i >= 0; i--) {
+ final WindowState w = windows.get(i);
+ if (w == targetWin) {
+ return i;
+ }
+ if (!w.mChildWindows.isEmpty()) {
+ if (indexOfWinInWindowList(targetWin, w.mChildWindows) >= 0) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
final IWindow client = win.mClient;
final WindowToken token = win.mToken;
@@ -942,13 +966,13 @@ public class WindowManagerService extends IWindowManager.Stub
// Base windows go behind everything else.
WindowState lowestWindow = tokenWindowList.get(0);
placeWindowBefore(lowestWindow, win);
- tokenWindowsPos = token.windows.indexOf(lowestWindow);
+ tokenWindowsPos = indexOfWinInWindowList(lowestWindow, token.windows);
} else {
AppWindowToken atoken = win.mAppToken;
WindowState lastWindow = tokenWindowList.get(index);
if (atoken != null && lastWindow == atoken.startingWindow) {
placeWindowBefore(lastWindow, win);
- tokenWindowsPos = token.windows.indexOf(lastWindow);
+ tokenWindowsPos = indexOfWinInWindowList(lastWindow, token.windows);
} else {
int newIdx = findIdxBasedOnAppTokens(win);
//there is a window above this one associated with the same
@@ -964,7 +988,8 @@ public class WindowManagerService extends IWindowManager.Stub
// No window from token found on win's display.
tokenWindowsPos = 0;
} else {
- tokenWindowsPos = token.windows.indexOf(windows.get(newIdx)) + 1;
+ tokenWindowsPos = indexOfWinInWindowList(
+ windows.get(newIdx), token.windows) + 1;
}
mWindowsChanged = true;
}
@@ -2848,7 +2873,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (win.isConfigChanged()) {
if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + win
- + " visible with new config: " + win.mConfiguration);
+ + " visible with new config: " + mCurConfiguration);
outConfig.setTo(mCurConfiguration);
}
}
@@ -3178,7 +3203,7 @@ public class WindowManagerService extends IWindowManager.Stub
return info;
}
- private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
+ private AttributeCache.Entry getCachedAnimations(int userId, WindowManager.LayoutParams lp) {
if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
+ (lp != null ? lp.packageName : null)
+ " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
@@ -3193,13 +3218,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
+ packageName);
- return AttributeCache.instance().get(packageName, resId,
+ return AttributeCache.instance().get(userId, packageName, resId,
com.android.internal.R.styleable.WindowAnimation);
}
return null;
}
- private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
+ private AttributeCache.Entry getCachedAnimations(int userId, String packageName, int resId) {
if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
+ packageName + " resId=0x" + Integer.toHexString(resId));
if (packageName != null) {
@@ -3208,17 +3233,17 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
+ packageName);
- return AttributeCache.instance().get(packageName, resId,
+ return AttributeCache.instance().get(userId, packageName, resId,
com.android.internal.R.styleable.WindowAnimation);
}
return null;
}
- Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
+ Animation loadAnimation(int userId, WindowManager.LayoutParams lp, int animAttr) {
int anim = 0;
Context context = mContext;
if (animAttr >= 0) {
- AttributeCache.Entry ent = getCachedAnimations(lp);
+ AttributeCache.Entry ent = getCachedAnimations(userId, lp);
if (ent != null) {
context = ent.context;
anim = ent.array.getResourceId(animAttr, 0);
@@ -3230,11 +3255,11 @@ public class WindowManagerService extends IWindowManager.Stub
return null;
}
- private Animation loadAnimation(String packageName, int resId) {
+ private Animation loadAnimation(int userId, String packageName, int resId) {
int anim = 0;
Context context = mContext;
if (resId >= 0) {
- AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
+ AttributeCache.Entry ent = getCachedAnimations(userId, packageName, resId);
if (ent != null) {
context = ent.context;
anim = resId;
@@ -3361,13 +3386,24 @@ public class WindowManagerService extends IWindowManager.Stub
Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
computePivot(mNextAppTransitionStartX, 1 / scaleW),
computePivot(mNextAppTransitionStartY, 1 / scaleH));
- AnimationSet set = new AnimationSet(true);
+ AnimationSet set = new AnimationSet(false);
Animation alpha = new AlphaAnimation(1, 0);
scale.setDuration(duration);
- scale.setInterpolator(
- new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
+ scale.setInterpolator(AnimationUtils.loadInterpolator(mContext,
+ com.android.internal.R.interpolator.decelerate_quad));
set.addAnimation(scale);
alpha.setDuration(duration);
+ alpha.setInterpolator(new Interpolator() {
+ @Override
+ public float getInterpolation(float input) {
+ if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
+ // linear response
+ return input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
+ }
+ // complete
+ return 1;
+ }
+ });
set.addAnimation(alpha);
set.setFillBefore(true);
a = set;
@@ -3462,7 +3498,7 @@ public class WindowManagerService extends IWindowManager.Stub
Animation a;
boolean initialized = false;
if (mNextAppTransitionType == ActivityOptions.ANIM_CUSTOM) {
- a = loadAnimation(mNextAppTransitionPackage, enter ?
+ a = loadAnimation(atoken.userId, mNextAppTransitionPackage, enter ?
mNextAppTransitionEnter : mNextAppTransitionExit);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
"applyAnimation: atoken=" + atoken
@@ -3543,7 +3579,7 @@ public class WindowManagerService extends IWindowManager.Stub
: com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
break;
}
- a = animAttr != 0 ? loadAnimation(lp, animAttr) : null;
+ a = animAttr != 0 ? loadAnimation(atoken.userId, lp, animAttr) : null;
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
"applyAnimation: atoken=" + atoken
+ " anim=" + a
@@ -3730,7 +3766,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void addAppToken(int addPos, IApplicationToken token,
+ public void addAppToken(int addPos, int userId, IApplicationToken token,
int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
@@ -3757,7 +3793,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.w(TAG, "Attempted to add existing app token: " + token);
return;
}
- atoken = new AppWindowToken(this, token);
+ atoken = new AppWindowToken(this, userId, token);
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
atoken.groupId = groupId;
atoken.appFullscreen = fullscreen;
@@ -3808,22 +3844,23 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowList windows = getDefaultWindowListLocked();
int pos = windows.size() - 1;
while (pos >= 0) {
- WindowState wtoken = windows.get(pos);
+ WindowState win = windows.get(pos);
pos--;
- if (wtoken.mAppToken != null) {
+ if (win.mAppToken != null) {
// We hit an application window. so the orientation will be determined by the
// app window. No point in continuing further.
return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
- if (!wtoken.isVisibleLw() || !wtoken.mPolicyVisibilityAfterAnim) {
+ if (!win.isVisibleLw() || !win.mPolicyVisibilityAfterAnim) {
continue;
}
- int req = wtoken.mAttrs.screenOrientation;
+ int req = win.mAttrs.screenOrientation;
if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
(req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
continue;
}
+ if (DEBUG_ORIENTATION) Slog.v(TAG, win + " forcing orientation to " + req);
return (mLastWindowForcedOrientation=req);
}
return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
@@ -4372,8 +4409,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Checking theme of starting window: 0x"
+ Integer.toHexString(theme));
if (theme != 0) {
- AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
- com.android.internal.R.styleable.Window);
+ AttributeCache.Entry ent = AttributeCache.instance().get(wtoken.userId,
+ pkg, theme, com.android.internal.R.styleable.Window);
if (ent == null) {
// Whoops! App doesn't exist. Um. Okay. We'll just
// pretend like we didn't see that.
@@ -5773,50 +5810,64 @@ public class WindowManagerService extends IWindowManager.Stub
// Figure out the part of the screen that is actually the app.
boolean including = false;
final WindowList windows = displayContent.getWindowList();
- for (int i = windows.size() - 1; i >= 0; i--) {
- WindowState ws = windows.get(i);
- if (!ws.mHasSurface) {
- continue;
- }
- if (ws.mLayer >= aboveAppLayer) {
- continue;
- }
- // When we will skip windows: when we are not including
- // ones behind a window we didn't skip, and we are actually
- // taking a screenshot of a specific app.
- if (!including && appToken != null) {
- // Also, we can possibly skip this window if it is not
- // an IME target or the application for the screenshot
- // is not the current IME target.
- if (!ws.mIsImWindow || !isImeTarget) {
- // And finally, this window is of no interest if it
- // is not associated with the screenshot app.
- if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
- continue;
+ try {
+ Surface.openTransaction();
+ for (int i = windows.size() - 1; i >= 0; i--) {
+ WindowState ws = windows.get(i);
+ if (!ws.mHasSurface) {
+ continue;
+ }
+ if (ws.mLayer >= aboveAppLayer) {
+ continue;
+ }
+ // When we will skip windows: when we are not including
+ // ones behind a window we didn't skip, and we are actually
+ // taking a screenshot of a specific app.
+ if (!including && appToken != null) {
+ // Also, we can possibly skip this window if it is not
+ // an IME target or the application for the screenshot
+ // is not the current IME target.
+ if (!ws.mIsImWindow || !isImeTarget) {
+ // And finally, this window is of no interest if it
+ // is not associated with the screenshot app.
+ if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
+ continue;
+ }
}
}
- }
- // We keep on including windows until we go past a full-screen
- // window.
- including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
+ // We keep on including windows until we go past a full-screen
+ // window.
+ including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
- if (maxLayer < ws.mWinAnimator.mSurfaceLayer) {
- maxLayer = ws.mWinAnimator.mSurfaceLayer;
- }
-
- // Don't include wallpaper in bounds calculation
- if (!ws.mIsWallpaper) {
- final Rect wf = ws.mFrame;
- final Rect cr = ws.mContentInsets;
- int left = wf.left + cr.left;
- int top = wf.top + cr.top;
- int right = wf.right - cr.right;
- int bottom = wf.bottom - cr.bottom;
- frame.union(left, top, right, bottom);
+ final WindowStateAnimator winAnimator = ws.mWinAnimator;
+
+ // The setSize() method causes all previous Surface transactions to sync to
+ // the SurfaceFlinger. This will force any outstanding setLayer calls to be
+ // synced as well for screen capture. Without this we can get black bitmaps.
+ Surface surface = winAnimator.mSurface;
+ surface.setSize(surface.getWidth(), surface.getHeight());
+
+
+ if (maxLayer < winAnimator.mSurfaceLayer) {
+ maxLayer = winAnimator.mSurfaceLayer;
+ }
+
+ // Don't include wallpaper in bounds calculation
+ if (!ws.mIsWallpaper) {
+ final Rect wf = ws.mFrame;
+ final Rect cr = ws.mContentInsets;
+ int left = wf.left + cr.left;
+ int top = wf.top + cr.top;
+ int right = wf.right - cr.right;
+ int bottom = wf.bottom - cr.bottom;
+ frame.union(left, top, right, bottom);
+ }
}
+ } finally {
+ Surface.closeTransaction();
+ Binder.restoreCallingIdentity(ident);
}
- Binder.restoreCallingIdentity(ident);
// Constrain frame to the screen size.
frame.intersect(0, 0, dw, dh);
@@ -9402,7 +9453,7 @@ public class WindowManagerService extends IWindowManager.Stub
+ " / " + mCurConfiguration + " / 0x"
+ Integer.toHexString(diff));
}
- win.mConfiguration = mCurConfiguration;
+ win.setConfiguration(mCurConfiguration);
if (DEBUG_ORIENTATION &&
winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
TAG, "Resizing " + win + " WITH DRAW PENDING");
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 35bebbe..81eac20 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -21,6 +21,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import com.android.server.input.InputWindowHandle;
@@ -78,7 +79,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams();
final DeathRecipient mDeathRecipient;
final WindowState mAttachedWindow;
- final ArrayList<WindowState> mChildWindows = new ArrayList<WindowState>();
+ final WindowList mChildWindows = new WindowList();
final int mBaseLayer;
final int mSubLayer;
final boolean mLayoutAttached;
@@ -112,6 +113,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
int mLayoutSeq = -1;
Configuration mConfiguration = null;
+ // Sticky answer to isConfigChanged(), remains true until new Configuration is assigned.
+ // Used only on {@link #TYPE_KEYGUARD}.
+ private boolean mConfigHasChanged;
/**
* Actual frame shown on-screen (may be modified by animation). These
@@ -627,6 +631,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
: WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
}
+ @Override
public boolean hasAppShownWindows() {
return mAppToken != null && (mAppToken.firstWindowDrawn || mAppToken.startingDisplayed);
}
@@ -857,9 +862,17 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
boolean isConfigChanged() {
- return mConfiguration != mService.mCurConfiguration
+ boolean configChanged = mConfiguration != mService.mCurConfiguration
&& (mConfiguration == null
|| (mConfiguration.diff(mService.mCurConfiguration) != 0));
+
+ if (mAttrs.type == TYPE_KEYGUARD) {
+ // Retain configuration changed status until resetConfiguration called.
+ mConfigHasChanged |= configChanged;
+ configChanged = mConfigHasChanged;
+ }
+
+ return configChanged;
}
boolean isConfigDiff(int mask) {
@@ -886,6 +899,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
}
+ void setConfiguration(final Configuration newConfig) {
+ mConfiguration = newConfig;
+ mConfigHasChanged = false;
+ }
+
void setInputChannel(InputChannel inputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
@@ -907,6 +925,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
private class DeathRecipient implements IBinder.DeathRecipient {
+ @Override
public void binderDied() {
try {
synchronized(mService.mWindowMap) {
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 7b30c89..10784fe 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -14,6 +14,7 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Debug;
+import android.os.UserHandle;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.Surface;
@@ -803,7 +804,7 @@ class WindowStateAnimator {
mSurfaceShown = false;
mSurface = null;
- mWin.mHasSurface =false;
+ mWin.mHasSurface = false;
mDrawState = NO_SURFACE;
}
}
@@ -876,7 +877,7 @@ class WindowStateAnimator {
final Matrix tmpMatrix = mWin.mTmpMatrix;
// Compute the desired transformation.
- if (screenAnimation) {
+ if (screenAnimation && screenRotationAnimation.isRotating()) {
// If we are doing a screen animation, the global rotation
// applied to windows can result in windows that are carefully
// aligned with each other to slightly separate, allowing you
@@ -1533,7 +1534,8 @@ class WindowStateAnimator {
break;
}
if (attr >= 0) {
- a = mService.loadAnimation(mWin.mAttrs, attr);
+ a = mService.loadAnimation(UserHandle.getUserId(mWin.mOwnerUid),
+ mWin.mAttrs, attr);
}
}
if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
diff --git a/services/java/com/android/server/wm/WindowToken.java b/services/java/com/android/server/wm/WindowToken.java
index e581915..bd0ace8 100644
--- a/services/java/com/android/server/wm/WindowToken.java
+++ b/services/java/com/android/server/wm/WindowToken.java
@@ -48,7 +48,7 @@ class WindowToken {
AppWindowToken appWindowToken;
// All of the windows associated with this token.
- final ArrayList<WindowState> windows = new ArrayList<WindowState>();
+ final WindowList windows = new WindowList();
// Is key dispatching paused for this token?
boolean paused = false;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 5f93e6f..0f531b7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -139,7 +139,7 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
Settings settings = new Settings(getContext(), getContext().getFilesDir());
- assertEquals(true, settings.readLPw(null));
+ assertEquals(true, settings.readLPw(null, 0, false));
assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3));
assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1));
@@ -157,11 +157,11 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
Settings settings = new Settings(getContext(), getContext().getFilesDir());
- assertEquals(true, settings.readLPw(null));
+ assertEquals(true, settings.readLPw(null, 0, false));
// Create Settings again to make it read from the new files
settings = new Settings(getContext(), getContext().getFilesDir());
- assertEquals(true, settings.readLPw(null));
+ assertEquals(true, settings.readLPw(null, 0, false));
PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2);
assertEquals(COMPONENT_ENABLED_STATE_DISABLED_USER, ps.getEnabled(0));
@@ -172,7 +172,7 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
Settings settings = new Settings(getContext(), getContext().getFilesDir());
- assertEquals(true, settings.readLPw(null));
+ assertEquals(true, settings.readLPw(null, 0, false));
// Enable/Disable a package
PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);