diff options
Diffstat (limited to 'services')
53 files changed, 1482 insertions, 549 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 ad1dfb2..a7c4d73 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2686,18 +2686,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..8eb61dd 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; } @@ -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 89fa6d0..f21f826 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 100755 --- 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 d2cd646..49dc220 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; @@ -4764,6 +4763,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()"); @@ -7923,7 +7934,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 +12327,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 +14131,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 +14179,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 +14225,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); @@ -14229,6 +14240,7 @@ public final class ActivityManagerService extends ActivityManagerNative startHomeActivityLocked(userId); } + EventLogTags.writeAmSwitchUser(userId); getUserManagerLocked().userForeground(userId); sendUserSwitchBroadcastsLocked(oldUserId, userId); if (needStart) { @@ -14244,7 +14256,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 { @@ -14340,32 +14352,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(); } } @@ -14467,7 +14486,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); @@ -14532,6 +14551,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 100755 --- 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 6ee7507..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 @@ -83,3 +83,6 @@ option java_package com.android.server.am 30039 am_crash (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5) # Log.wtf() called 30040 am_wtf (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Tag|3),(Message|3) + +# User switched +30041 am_switch_user (id|1|5) 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 43ddf8d..b839331 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; @@ -2063,7 +2065,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 0efdead..546f2be 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 51edb44..5b9fc9a 100755 --- 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); @@ -4373,8 +4410,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. @@ -5777,50 +5814,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); @@ -9407,7 +9458,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); |