diff options
Diffstat (limited to 'services/java')
24 files changed, 1219 insertions, 469 deletions
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index 5ffcdc5..b8c44d9 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -477,7 +477,7 @@ class AlarmManagerService extends IAlarmManager.Stub { : bs.filterStats.entrySet()) { pw.print(" "); pw.print(fe.getValue().count); pw.print(" alarms: "); - pw.println(fe.getKey().getIntent().toShortString(true, false)); + pw.println(fe.getKey().getIntent().toShortString(false, true, false)); } } } diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 2938c45..6ac6c98 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -34,6 +34,7 @@ import android.app.backup.IRestoreSession; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -4765,6 +4766,11 @@ class BackupManagerService extends IBackupManager.Stub { } } + boolean deviceIsProvisioned() { + final ContentResolver resolver = mContext.getContentResolver(); + return (Settings.Secure.getInt(resolver, Settings.Secure.DEVICE_PROVISIONED, 0) != 0); + } + // Run a *full* backup pass for the given package, writing the resulting data stream // to the supplied file descriptor. This method is synchronous and does not return // to the caller until the backup has been completed. @@ -4785,12 +4791,19 @@ class BackupManagerService extends IBackupManager.Stub { } } - if (DEBUG) Slog.v(TAG, "Requesting full backup: apks=" + includeApks - + " shared=" + includeShared + " all=" + doAllApps - + " pkgs=" + pkgList); - long oldId = Binder.clearCallingIdentity(); try { + // Doesn't make sense to do a full backup prior to setup + if (!deviceIsProvisioned()) { + Slog.i(TAG, "Full backup not supported before setup"); + return; + } + + if (DEBUG) Slog.v(TAG, "Requesting full backup: apks=" + includeApks + + " shared=" + includeShared + " all=" + doAllApps + + " pkgs=" + pkgList); + Slog.i(TAG, "Beginning full backup..."); + FullBackupParams params = new FullBackupParams(fd, includeApks, includeShared, doAllApps, pkgList); final int token = generateToken(); @@ -4822,17 +4835,25 @@ class BackupManagerService extends IBackupManager.Stub { // just eat it } Binder.restoreCallingIdentity(oldId); + Slog.d(TAG, "Full backup processing complete."); } - if (MORE_DEBUG) Slog.d(TAG, "Full backup done; returning to caller"); } public void fullRestore(ParcelFileDescriptor fd) { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore"); - Slog.i(TAG, "Beginning full restore..."); long oldId = Binder.clearCallingIdentity(); try { + // Check whether the device has been provisioned -- we don't handle + // full restores prior to completing the setup process. + if (!deviceIsProvisioned()) { + Slog.i(TAG, "Full restore not permitted before setup"); + return; + } + + Slog.i(TAG, "Beginning full restore..."); + FullRestoreParams params = new FullRestoreParams(fd); final int token = generateToken(); synchronized (mFullConfirmations) { @@ -4863,7 +4884,7 @@ class BackupManagerService extends IBackupManager.Stub { Slog.w(TAG, "Error trying to close fd after full restore: " + e); } Binder.restoreCallingIdentity(oldId); - Slog.i(TAG, "Full restore completed"); + Slog.i(TAG, "Full restore processing complete."); } } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 0153613..991b7da 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -35,6 +35,7 @@ import android.net.EthernetDataTracker; import android.net.IConnectivityManager; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyManager; +import android.net.INetworkStatsService; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.LinkProperties.CompareResult; @@ -306,8 +307,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // the set of network types that can only be enabled by system/sig apps List mProtectedNetworks; - public ConnectivityService( - Context context, INetworkManagementService netd, INetworkPolicyManager policyManager) { + public ConnectivityService(Context context, INetworkManagementService netd, + INetworkStatsService statsService, INetworkPolicyManager policyManager) { if (DBG) log("ConnectivityService starting up"); HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread"); @@ -319,7 +320,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { String id = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); if (id != null && id.length() > 0) { - String name = new String("android_").concat(id); + String name = new String("android-").concat(id); SystemProperties.set("net.hostname", name); } } @@ -496,7 +497,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b); - mTethering = new Tethering(mContext, nmService, mHandler.getLooper()); + mTethering = new Tethering(mContext, nmService, statsService, mHandler.getLooper()); mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 || mTethering.getTetherableWifiRegexs().length != 0 || mTethering.getTetherableBluetoothRegexs().length != 0) && diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index bb21d81..78dbbd6 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -79,6 +79,8 @@ public class PowerManagerService extends IPowerManager.Stub private static final String TAG = "PowerManagerService"; static final String PARTIAL_NAME = "PowerManagerService"; + static final boolean DEBUG_SCREEN_ON = false; + private static final boolean LOG_PARTIAL_WL = false; // Indicates whether touch-down cycles should be logged as part of the @@ -161,7 +163,9 @@ public class PowerManagerService extends IPowerManager.Stub private int mStayOnConditions = 0; private final int[] mBroadcastQueue = new int[] { -1, -1, -1 }; private final int[] mBroadcastWhy = new int[3]; - private boolean mBroadcastingScreenOff = false; + private boolean mPreparingForScreenOn = false; + private boolean mSkippedScreenOn = false; + private boolean mInitialized = false; private int mPartialCount = 0; private int mPowerState; // mScreenOffReason can be WindowManagerPolicy.OFF_BECAUSE_OF_USER, @@ -557,6 +561,10 @@ public class PowerManagerService extends IPowerManager.Stub nativeInit(); synchronized (mLocks) { updateNativePowerStateLocked(); + // We make sure to start out with the screen on due to user activity. + // (They did just boot their device, after all.) + forceUserActivityLocked(); + mInitialized = true; } } @@ -1122,7 +1130,9 @@ public class PowerManagerService extends IPowerManager.Stub pw.println(" mNextTimeout=" + mNextTimeout + " now=" + now + " " + ((mNextTimeout-now)/1000) + "s from now"); pw.println(" mDimScreen=" + mDimScreen - + " mStayOnConditions=" + mStayOnConditions); + + " mStayOnConditions=" + mStayOnConditions + + " mPreparingForScreenOn=" + mPreparingForScreenOn + + " mSkippedScreenOn=" + mSkippedScreenOn); pw.println(" mScreenOffReason=" + mScreenOffReason + " mUserState=" + mUserState); pw.println(" mBroadcastQueue={" + mBroadcastQueue[0] + ',' + mBroadcastQueue[1] @@ -1311,8 +1321,23 @@ public class PowerManagerService extends IPowerManager.Stub } } - private void sendNotificationLocked(boolean on, int why) - { + private void sendNotificationLocked(boolean on, int why) { + if (!mInitialized) { + // No notifications sent until first initialization is done. + // This is so that when we are moving from our initial state + // which looks like the screen was off to it being on, we do not + // go through the process of waiting for the higher-level user + // space to be ready before turning up the display brightness. + // (And also do not send needless broadcasts about the screen.) + return; + } + + if (DEBUG_SCREEN_ON) { + RuntimeException here = new RuntimeException("here"); + here.fillInStackTrace(); + Slog.i(TAG, "sendNotificationLocked: " + on, here); + } + if (!on) { mStillNeedSleepNotification = false; } @@ -1341,7 +1366,9 @@ public class PowerManagerService extends IPowerManager.Stub mBroadcastQueue[0] = on ? 1 : 0; mBroadcastQueue[1] = -1; mBroadcastQueue[2] = -1; + EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount); mBroadcastWakeLock.release(); + EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount); mBroadcastWakeLock.release(); index = 0; } @@ -1357,7 +1384,9 @@ public class PowerManagerService extends IPowerManager.Stub // The broadcast queue has changed; make sure the screen is on if it // is now possible for it to be. - updateNativePowerStateLocked(); + if (mSkippedScreenOn) { + updateLightsLocked(mPowerState, SCREEN_ON_BIT); + } // Now send the message. if (index >= 0) { @@ -1371,6 +1400,21 @@ public class PowerManagerService extends IPowerManager.Stub } } + private WindowManagerPolicy.ScreenOnListener mScreenOnListener = + new WindowManagerPolicy.ScreenOnListener() { + @Override public void onScreenOn() { + synchronized (mLocks) { + if (mPreparingForScreenOn) { + mPreparingForScreenOn = false; + updateLightsLocked(mPowerState, SCREEN_ON_BIT); + EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, + 4, mBroadcastWakeLock.mCount); + mBroadcastWakeLock.release(); + } + } + } + }; + private Runnable mNotificationTask = new Runnable() { public void run() @@ -1387,14 +1431,17 @@ public class PowerManagerService extends IPowerManager.Stub mBroadcastWhy[i] = mBroadcastWhy[i+1]; } policy = getPolicyLocked(); - if (value == 0) { - mBroadcastingScreenOff = true; + if (value == 1 && !mPreparingForScreenOn) { + mPreparingForScreenOn = true; + mBroadcastWakeLock.acquire(); + EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, + mBroadcastWakeLock.mCount); } } if (value == 1) { mScreenOnStart = SystemClock.uptimeMillis(); - policy.screenTurnedOn(); + policy.screenTurningOn(mScreenOnListener); try { ActivityManagerNative.getDefault().wakingUp(); } catch (RemoteException e) { @@ -1432,8 +1479,7 @@ public class PowerManagerService extends IPowerManager.Stub synchronized (mLocks) { EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, mBroadcastWakeLock.mCount); - mBroadcastingScreenOff = false; - updateNativePowerStateLocked(); + updateLightsLocked(mPowerState, SCREEN_ON_BIT); mBroadcastWakeLock.release(); } } @@ -1464,10 +1510,6 @@ public class PowerManagerService extends IPowerManager.Stub synchronized (mLocks) { EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0, SystemClock.uptimeMillis() - mScreenOffStart, mBroadcastWakeLock.mCount); - synchronized (mLocks) { - mBroadcastingScreenOff = false; - updateNativePowerStateLocked(); - } mBroadcastWakeLock.release(); } } @@ -1630,6 +1672,11 @@ public class PowerManagerService extends IPowerManager.Stub }; private int setScreenStateLocked(boolean on) { + if (DEBUG_SCREEN_ON) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Slog.i(TAG, "Set screen state: " + on, e); + } int err = Power.setScreenState(on); if (err == 0) { mLastScreenOnTime = (on ? SystemClock.elapsedRealtime() : 0); @@ -1680,7 +1727,7 @@ public class PowerManagerService extends IPowerManager.Stub } else { newState &= ~BATTERY_LOW_BIT; } - if (newState == mPowerState) { + if (newState == mPowerState && mInitialized) { return; } @@ -1706,10 +1753,7 @@ public class PowerManagerService extends IPowerManager.Stub + " newBatteryLow=" + ((newState & BATTERY_LOW_BIT) != 0)); } - if (mPowerState != newState) { - updateLightsLocked(newState, 0); - mPowerState = (mPowerState & ~LIGHTS_MASK) | (newState & LIGHTS_MASK); - } + final boolean stateChanged = mPowerState != newState; if (oldScreenOn != newScreenOn) { if (newScreenOn) { @@ -1761,10 +1805,24 @@ public class PowerManagerService extends IPowerManager.Stub EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, reason, mTotalTouchDownTime, mTouchCycles); if (err == 0) { - mPowerState |= SCREEN_ON_BIT; sendNotificationLocked(true, -1); + // Update the lights *after* taking care of turning the + // screen on, so we do this after our notifications are + // enqueued and thus will delay turning on the screen light + // until the windows are correctly displayed. + if (stateChanged) { + updateLightsLocked(newState, 0); + } + mPowerState |= SCREEN_ON_BIT; } + } else { + // Update the lights *before* taking care of turning the + // screen off, so we can initiate any animations that are desired. + if (stateChanged) { + updateLightsLocked(newState, 0); + } + // cancel light sensor task mHandler.removeCallbacks(mAutoBrightnessTask); mLightSensorPendingDecrease = false; @@ -1787,29 +1845,18 @@ public class PowerManagerService extends IPowerManager.Stub mLastTouchDown = 0; } } + } else if (stateChanged) { + // Screen on/off didn't change, but lights may have. + updateLightsLocked(newState, 0); } - + + mPowerState = (mPowerState & ~LIGHTS_MASK) | (newState & LIGHTS_MASK); + updateNativePowerStateLocked(); } } - + private void updateNativePowerStateLocked() { - if ((mPowerState & SCREEN_ON_BIT) != 0) { - // Don't turn screen on if we are currently reporting a screen off. - // This is to avoid letting the screen go on before things like the - // lock screen have been displayed due to it going off. - if (mBroadcastingScreenOff) { - // Currently broadcasting that the screen is off. Don't - // allow screen to go on until that is done. - return; - } - for (int i=0; i<mBroadcastQueue.length; i++) { - if (mBroadcastQueue[i] == 0) { - // A screen off is currently enqueued. - return; - } - } - } nativeSetPowerState( (mPowerState & SCREEN_ON_BIT) != 0, (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT); @@ -1835,8 +1882,43 @@ public class PowerManagerService extends IPowerManager.Stub mBatteryService.getBatteryLevel() <= Power.LOW_BATTERY_THRESHOLD); } + private boolean shouldDeferScreenOnLocked() { + if (mPreparingForScreenOn) { + // Currently waiting for confirmation from the policy that it + // is okay to turn on the screen. Don't allow the screen to go + // on until that is done. + if (DEBUG_SCREEN_ON) Slog.i(TAG, + "updateLights: delaying screen on due to mPreparingForScreenOn"); + return true; + } else { + // If there is a screen-on command in the notification queue, we + // can't turn the screen on until it has been processed (and we + // have set mPreparingForScreenOn) or it has been dropped. + for (int i=0; i<mBroadcastQueue.length; i++) { + if (mBroadcastQueue[i] == 1) { + if (DEBUG_SCREEN_ON) Slog.i(TAG, + "updateLights: delaying screen on due to notification queue"); + return true; + } + } + } + return false; + } + private void updateLightsLocked(int newState, int forceState) { final int oldState = mPowerState; + + // If the screen is not currently on, we will want to delay actually + // turning the lights on if we are still getting the UI put up. + if ((oldState&SCREEN_ON_BIT) == 0 || mSkippedScreenOn) { + // Don't turn screen on until we know we are really ready to. + // This is to avoid letting the screen go on before things like the + // lock screen have been displayed. + if ((mSkippedScreenOn=shouldDeferScreenOnLocked())) { + newState &= ~(SCREEN_ON_BIT|SCREEN_BRIGHT_BIT); + } + } + if ((newState & SCREEN_ON_BIT) != 0) { // Only turn on the buttons or keyboard if the screen is also on. // We should never see the buttons on but not the screen. @@ -1943,6 +2025,13 @@ public class PowerManagerService extends IPowerManager.Stub } mScreenBrightness.setTargetLocked(brightness, steps, INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue); + if (DEBUG_SCREEN_ON) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Slog.i(TAG, "Setting screen brightness: " + brightness, e); + mScreenBrightness.setTargetLocked(brightness, steps, + INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue); + } } if (mSpew) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index cdefa00..5006de7 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -370,7 +370,8 @@ class ServerThread extends Thread { try { Slog.i(TAG, "Connectivity Service"); - connectivity = new ConnectivityService(context, networkManagement, networkPolicy); + connectivity = new ConnectivityService( + context, networkManagement, networkStats, networkPolicy); ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity); networkStats.bindConnectivityManager(connectivity); networkPolicy.bindConnectivityManager(connectivity); diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index 6ceccaf..253e741 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -120,7 +120,8 @@ class WallpaperManagerService extends IWallpaperManager.Stub { notifyCallbacksLocked(); if (mWallpaperComponent == null || mImageWallpaperPending) { mImageWallpaperPending = false; - bindWallpaperComponentLocked(mImageWallpaperComponent, true); + bindWallpaperComponentLocked(mImageWallpaperComponent, + true, false); saveSettingsLocked(); } } @@ -201,7 +202,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { if (!mWallpaperUpdating && (mLastDiedTime+MIN_WALLPAPER_CRASH_TIME) > SystemClock.uptimeMillis()) { Slog.w(TAG, "Reverting to built-in wallpaper!"); - bindWallpaperComponentLocked(null, true); + clearWallpaperLocked(true); } } } @@ -230,9 +231,23 @@ class WallpaperManagerService extends IWallpaperManager.Stub { mWallpaperUpdating = false; ComponentName comp = mWallpaperComponent; clearWallpaperComponentLocked(); - bindWallpaperComponentLocked(comp, false); + if (!bindWallpaperComponentLocked(comp, false, false)) { + Slog.w(TAG, "Wallpaper no longer available; reverting to default"); + clearWallpaperLocked(false); + } + } + } + } + + @Override + public void onPackageModified(String packageName) { + synchronized (mLock) { + if (mWallpaperComponent == null || + !mWallpaperComponent.getPackageName().equals(packageName)) { + return; } } + doPackagesChanged(true); } @Override @@ -265,7 +280,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { changed = true; if (doit) { Slog.w(TAG, "Wallpaper uninstalled, removing: " + mWallpaperComponent); - clearWallpaperLocked(); + clearWallpaperLocked(false); } } } @@ -283,7 +298,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { mWallpaperComponent, 0); } catch (NameNotFoundException e) { Slog.w(TAG, "Wallpaper component gone, removing: " + mWallpaperComponent); - clearWallpaperLocked(); + clearWallpaperLocked(false); } } if (mNextWallpaperComponent != null @@ -321,45 +336,51 @@ class WallpaperManagerService extends IWallpaperManager.Stub { public void systemReady() { if (DEBUG) Slog.v(TAG, "systemReady"); synchronized (mLock) { + RuntimeException e = null; try { - bindWallpaperComponentLocked(mNextWallpaperComponent, false); - } catch (RuntimeException e) { - Slog.w(TAG, "Failure starting previous wallpaper", e); - try { - bindWallpaperComponentLocked(null, false); - } catch (RuntimeException e2) { - Slog.w(TAG, "Failure starting default wallpaper", e2); - clearWallpaperComponentLocked(); + if (bindWallpaperComponentLocked(mNextWallpaperComponent, false, false)) { + return; } + } catch (RuntimeException e1) { + e = e1; } + Slog.w(TAG, "Failure starting previous wallpaper", e); + clearWallpaperLocked(false); } } public void clearWallpaper() { if (DEBUG) Slog.v(TAG, "clearWallpaper"); synchronized (mLock) { - clearWallpaperLocked(); + clearWallpaperLocked(false); } } - public void clearWallpaperLocked() { + public void clearWallpaperLocked(boolean defaultFailed) { File f = WALLPAPER_FILE; if (f.exists()) { f.delete(); } final long ident = Binder.clearCallingIdentity(); + RuntimeException e = null; try { mImageWallpaperPending = false; - bindWallpaperComponentLocked(null, false); - } catch (IllegalArgumentException e) { - // This can happen if the default wallpaper component doesn't - // exist. This should be a system configuration problem, but - // let's not let it crash the system and just live with no - // wallpaper. - Slog.e(TAG, "Default wallpaper component not found!", e); + if (bindWallpaperComponentLocked(defaultFailed + ? mImageWallpaperComponent : null, true, false)) { + return; + } + } catch (IllegalArgumentException e1) { + e = e1; } finally { Binder.restoreCallingIdentity(ident); } + + // This can happen if the default wallpaper component doesn't + // exist. This should be a system configuration problem, but + // let's not let it crash the system and just live with no + // wallpaper. + Slog.e(TAG, "Default wallpaper component not found!", e); + clearWallpaperComponentLocked(); } public void setDimensionHints(int width, int height) throws RemoteException { @@ -469,14 +490,14 @@ class WallpaperManagerService extends IWallpaperManager.Stub { final long ident = Binder.clearCallingIdentity(); try { mImageWallpaperPending = false; - bindWallpaperComponentLocked(name, false); + bindWallpaperComponentLocked(name, false, true); } finally { Binder.restoreCallingIdentity(ident); } } } - void bindWallpaperComponentLocked(ComponentName componentName, boolean force) { + boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force, boolean fromUser) { if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName); // Has the component changed? @@ -486,12 +507,12 @@ class WallpaperManagerService extends IWallpaperManager.Stub { if (componentName == null) { if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default"); // Still using default wallpaper. - return; + return true; } } else if (mWallpaperComponent.equals(componentName)) { // Changing to same wallpaper. if (DEBUG) Slog.v(TAG, "same wallpaper"); - return; + return true; } } } @@ -516,9 +537,14 @@ class WallpaperManagerService extends IWallpaperManager.Stub { ServiceInfo si = mContext.getPackageManager().getServiceInfo(componentName, PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS); if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) { - throw new SecurityException("Selected service does not require " + String msg = "Selected service does not require " + android.Manifest.permission.BIND_WALLPAPER - + ": " + componentName); + + ": " + componentName; + if (fromUser) { + throw new SecurityException(msg); + } + Slog.w(TAG, msg); + return false; } WallpaperInfo wi = null; @@ -535,16 +561,29 @@ class WallpaperManagerService extends IWallpaperManager.Stub { try { wi = new WallpaperInfo(mContext, ris.get(i)); } catch (XmlPullParserException e) { - throw new IllegalArgumentException(e); + if (fromUser) { + throw new IllegalArgumentException(e); + } + Slog.w(TAG, e); + return false; } catch (IOException e) { - throw new IllegalArgumentException(e); + if (fromUser) { + throw new IllegalArgumentException(e); + } + Slog.w(TAG, e); + return false; } break; } } if (wi == null) { - throw new SecurityException("Selected service is not a wallpaper: " - + componentName); + String msg = "Selected service is not a wallpaper: " + + componentName; + if (fromUser) { + throw new SecurityException(msg); + } + Slog.w(TAG, msg); + return false; } } @@ -561,8 +600,13 @@ class WallpaperManagerService extends IWallpaperManager.Stub { 0)); if (!mContext.bindService(intent, newConn, Context.BIND_AUTO_CREATE)) { - throw new IllegalArgumentException("Unable to bind service: " - + componentName); + String msg = "Unable to bind service: " + + componentName; + if (fromUser) { + throw new IllegalArgumentException(msg); + } + Slog.w(TAG, msg); + return false; } clearWallpaperComponentLocked(); @@ -577,8 +621,14 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } } catch (PackageManager.NameNotFoundException e) { - throw new IllegalArgumentException("Unknown component " + componentName); + String msg = "Unknown component " + componentName; + if (fromUser) { + throw new IllegalArgumentException(msg); + } + Slog.w(TAG, msg); + return false; } + return true; } void clearWallpaperComponentLocked() { @@ -611,7 +661,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } catch (RemoteException e) { Slog.w(TAG, "Failed attaching wallpaper; clearing", e); if (!mWallpaperUpdating) { - bindWallpaperComponentLocked(null, false); + bindWallpaperComponentLocked(null, false, false); } } } @@ -765,13 +815,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub { loadSettingsLocked(); if (mNextWallpaperComponent != null && !mNextWallpaperComponent.equals(mImageWallpaperComponent)) { - try { - bindWallpaperComponentLocked(mNextWallpaperComponent, false); - } catch (IllegalArgumentException e) { + if (!bindWallpaperComponentLocked(mNextWallpaperComponent, false, false)) { // No such live wallpaper or other failure; fall back to the default // live wallpaper (since the profile being restored indicated that the // user had selected a live rather than static one). - bindWallpaperComponentLocked(null, false); + bindWallpaperComponentLocked(null, false, false); } success = true; } else { @@ -786,7 +834,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success); if (success) { - bindWallpaperComponentLocked(null, false); + bindWallpaperComponentLocked(null, false, false); } } } diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index 6830055..ed8fa40 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -718,8 +718,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub */ private void manageServicesLocked() { populateEnabledServicesLocked(mEnabledServices); - updateServicesStateLocked(mInstalledServices, mEnabledServices); - disableAccessibilityIfNoEnabledServices(mEnabledServices); + final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices, + mEnabledServices); + // No enabled installed services => disable accessibility to avoid + // sending accessibility events with no recipient across processes. + if (mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_ENABLED, 0); + } } /** @@ -771,13 +777,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * * @param installedServices All installed {@link AccessibilityService}s. * @param enabledServices The {@link ComponentName}s of the enabled services. + * @return The number of enabled installed services. */ - private void updateServicesStateLocked(List<AccessibilityServiceInfo> installedServices, + private int updateServicesStateLocked(List<AccessibilityServiceInfo> installedServices, Set<ComponentName> enabledServices) { Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap; boolean isEnabled = mIsAccessibilityEnabled; + int enabledInstalledServices = 0; for (int i = 0, count = installedServices.size(); i < count; i++) { AccessibilityServiceInfo installedService = installedServices.get(i); ComponentName componentName = ComponentName.unflattenFromString( @@ -790,6 +798,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub service = new Service(componentName, installedService, false); } service.bind(); + enabledInstalledServices++; } else { if (service != null) { service.unbind(); @@ -801,19 +810,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } } - } - /** - * Disables accessibility if there are no enabled accessibility services which - * to consume the generated accessibility events. - * - * @param enabledServices The set of enabled services. - */ - private void disableAccessibilityIfNoEnabledServices(Set<ComponentName> enabledServices) { - if (enabledServices.isEmpty()) { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_ENABLED, 0); - } + return enabledInstalledServices; } /** diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 41af137..2942c28 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -1631,8 +1631,8 @@ public final class ActivityManagerService extends ActivityManagerNative } if (app.conProviders.size() > 0) { for (ContentProviderRecord cpr : app.conProviders.keySet()) { - if (cpr.app != null && cpr.app.lruSeq != mLruSeq) { - updateLruProcessInternalLocked(cpr.app, oomAdj, + if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) { + updateLruProcessInternalLocked(cpr.proc, oomAdj, updateActivityTime, i+1); } } @@ -3334,6 +3334,11 @@ public final class ActivityManagerService extends ActivityManagerNative if ((samePackage || r.task == lastTask) && (r.app == null || evenPersistent || !r.app.persistent)) { if (!doit) { + if (r.finishing) { + // If this activity is just finishing, then it is not + // interesting as far as something to stop. + continue; + } return true; } didSomething = true; @@ -3373,7 +3378,24 @@ public final class ActivityManagerService extends ActivityManagerNative for (i=0; i<N; i++) { bringDownServiceLocked(services.get(i), true); } - + + ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>(); + for (ContentProviderRecord provider : mProvidersByClass.values()) { + if (provider.info.packageName.equals(name) + && (provider.proc == null || evenPersistent || !provider.proc.persistent)) { + if (!doit) { + return true; + } + didSomething = true; + providers.add(provider); + } + } + + N = providers.size(); + for (i=0; i<N; i++) { + removeDyingProviderLocked(null, providers.get(i)); + } + if (doit) { if (purgeCache) { AttributeCache ac = AttributeCache.instance(); @@ -3382,6 +3404,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } mMainStack.resumeTopActivityLocked(null); + mMainStack.scheduleIdleLocked(); } return didSomething; @@ -3761,6 +3784,12 @@ public final class ActivityManagerService extends ActivityManagerNative mWindowManager.showBootMessage(msg, always); } + public void dismissKeyguardOnNextActivity() { + synchronized (this) { + mMainStack.dismissKeyguardOnNextActivityLocked(); + } + } + final void finishBooting() { IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); @@ -5485,7 +5514,7 @@ public final class ActivityManagerService extends ActivityManagerNative ComponentName comp = new ComponentName(cpi.packageName, cpi.name); ContentProviderRecord cpr = mProvidersByClass.get(comp); if (cpr == null) { - cpr = new ContentProviderRecord(cpi, app.info); + cpr = new ContentProviderRecord(cpi, app.info, comp); mProvidersByClass.put(comp, cpr); } app.pubProviders.put(cpi.name, cpr); @@ -5643,25 +5672,25 @@ public final class ActivityManagerService extends ActivityManagerNative // return it right away. final boolean countChanged = incProviderCount(r, cpr); if (countChanged) { - if (cpr.app != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) { + if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) { // If this is a perceptible app accessing the provider, // make sure to count it as being accessed and thus // back up on the LRU list. This is good because // content providers are often expensive to start. - updateLruProcessLocked(cpr.app, false, true); + updateLruProcessLocked(cpr.proc, false, true); } } - if (cpr.app != null) { + if (cpr.proc != null) { if (false) { if (cpr.name.flattenToShortString().equals( "com.android.providers.calendar/.CalendarProvider2")) { Slog.v(TAG, "****************** KILLING " + cpr.name.flattenToShortString()); - Process.killProcess(cpr.app.pid); + Process.killProcess(cpr.proc.pid); } } - boolean success = updateOomAdjLocked(cpr.app); + boolean success = updateOomAdjLocked(cpr.proc); if (DEBUG_PROVIDER) Slog.i(TAG, "Adjust success: " + success); // NOTE: there is still a race here where a signal could be // pending on the process even though we managed to update its @@ -5676,7 +5705,7 @@ public final class ActivityManagerService extends ActivityManagerNative "Existing provider " + cpr.name.flattenToShortString() + " is crashing; detaching " + r); boolean lastRef = decProviderCount(r, cpr); - appDiedLocked(cpr.app, cpr.app.pid, cpr.app.thread); + appDiedLocked(cpr.proc, cpr.proc.pid, cpr.proc.thread); if (!lastRef) { // This wasn't the last ref our process had on // the provider... we have now been killed, bail. @@ -5729,7 +5758,7 @@ public final class ActivityManagerService extends ActivityManagerNative + cpi.name); return null; } - cpr = new ContentProviderRecord(cpi, ai); + cpr = new ContentProviderRecord(cpi, ai, comp); } catch (RemoteException ex) { // pm is in same process, this will never happen. } @@ -5864,7 +5893,7 @@ public final class ActivityManagerService extends ActivityManagerNative //update content provider record entry info ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name); ContentProviderRecord localCpr = mProvidersByClass.get(comp); - if (localCpr.app == r) { + if (localCpr.proc == r) { //should not happen. taken care of as a local provider Slog.w(TAG, "removeContentProvider called on local provider: " + cpr.info.name + " in process " + r.processName); @@ -5940,7 +5969,7 @@ public final class ActivityManagerService extends ActivityManagerNative } synchronized (dst) { dst.provider = src.provider; - dst.app = r; + dst.proc = r; dst.notifyAll(); } updateOomAdjLocked(r); @@ -7884,6 +7913,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (dumpAll) { pw.println(" mLastPausedActivity: " + mMainStack.mLastPausedActivity); pw.println(" mSleepTimeout: " + mMainStack.mSleepTimeout); + pw.println(" mDismissKeyguardOnNextActivity: " + + mMainStack.mDismissKeyguardOnNextActivity); } if (mRecentTasks.size() > 0) { @@ -8524,7 +8555,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i<N; i++) { sb.setLength(0); sb.append(" Intent: "); - intents.get(i).toShortString(sb, true, false); + intents.get(i).toShortString(sb, false, true, false); pw.println(sb.toString()); Bundle bundle = intents.get(i).getExtras(); if (bundle != null) { @@ -8706,9 +8737,9 @@ public final class ActivityManagerService extends ActivityManagerNative r.dump(pw, " "); } else { pw.print(" * "); pw.print(e.getKey().flattenToShortString()); - if (r.app != null) { + if (r.proc != null) { pw.println(":"); - pw.print(" "); pw.println(r.app); + pw.print(" "); pw.println(r.proc); } else { pw.println(); } @@ -8817,7 +8848,8 @@ public final class ActivityManagerService extends ActivityManagerNative } else if (complete) { // Complete + brief == give a summary. Isn't that obvious?!? if (lastTask.intent != null) { - pw.print(prefix); pw.print(" "); pw.println(lastTask.intent); + pw.print(prefix); pw.print(" "); + pw.println(lastTask.intent.toInsecureString()); } } } @@ -8828,7 +8860,7 @@ public final class ActivityManagerService extends ActivityManagerNative r.dump(pw, innerPrefix); } else if (complete) { // Complete + brief == give a summary. Isn't that obvious?!? - pw.print(innerPrefix); pw.println(r.intent); + pw.print(innerPrefix); pw.println(r.intent.toInsecureString()); if (r.app != null) { pw.print(innerPrefix); pw.println(r.app); } @@ -9440,7 +9472,7 @@ public final class ActivityManagerService extends ActivityManagerNative cpr.notifyAll(); } - mProvidersByClass.remove(cpr.info.name); + mProvidersByClass.remove(cpr.name); String names[] = cpr.info.authority.split(";"); for (int j = 0; j < names.length; j++) { mProvidersByName.remove(names[j]); @@ -9454,9 +9486,10 @@ public final class ActivityManagerService extends ActivityManagerNative && capp.pid != MY_PID) { Slog.i(TAG, "Kill " + capp.processName + " (pid " + capp.pid + "): provider " + cpr.info.name - + " in dying process " + proc.processName); + + " in dying process " + (proc != null ? proc.processName : "??")); EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid, - capp.processName, capp.setAdj, "dying provider " + proc.processName); + capp.processName, capp.setAdj, "dying provider " + + cpr.name.toShortString()); Process.killProcessQuiet(capp.pid); } } @@ -9515,7 +9548,7 @@ public final class ActivityManagerService extends ActivityManagerNative while (it.hasNext()) { ContentProviderRecord cpr = it.next(); cpr.provider = null; - cpr.app = null; + cpr.proc = null; // See if someone is waiting for this provider... in which // case we don't remove it, but just let it restart. @@ -10029,7 +10062,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean created = false; try { mStringBuilder.setLength(0); - r.intent.getIntent().toShortString(mStringBuilder, false, true); + r.intent.getIntent().toShortString(mStringBuilder, true, false, true); EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE, System.identityHashCode(r), r.shortName, mStringBuilder.toString(), r.app.pid); diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 73ffafb..ce45bfb 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -122,7 +122,7 @@ final class ActivityRecord extends IApplicationToken.Stub { pw.print(" processName="); pw.println(processName); pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid); pw.print(" app="); pw.println(app); - pw.print(prefix); pw.println(intent); + pw.print(prefix); pw.println(intent.toInsecureString()); pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask); pw.print(" task="); pw.println(task); pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity); diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index a0aedf9..7bc19ab 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -259,6 +259,11 @@ final class ActivityStack { */ boolean mSleepTimeout = false; + /** + * Dismiss the keyguard after the next activity is displayed? + */ + boolean mDismissKeyguardOnNextActivity = false; + int mThumbnailWidth = -1; int mThumbnailHeight = -1; @@ -765,9 +770,7 @@ final class ActivityStack { // Still need to tell some activities to stop; can't sleep yet. if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to stop " + mStoppingActivities.size() + " activities"); - Message msg = Message.obtain(); - msg.what = IDLE_NOW_MSG; - mHandler.sendMessage(msg); + scheduleIdleLocked(); return; } @@ -978,9 +981,7 @@ final class ActivityStack { // then give up on things going idle and start clearing // them out. if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle"); - Message msg = Message.obtain(); - msg.what = IDLE_NOW_MSG; - mHandler.sendMessage(msg); + scheduleIdleLocked(); } else { checkReadyForSleepLocked(); } @@ -2173,7 +2174,7 @@ final class ActivityStack { } if (err == START_SUCCESS) { - Slog.i(TAG, "Starting: " + intent + " from pid " + Slog.i(TAG, "START {" + intent.toShortString(true, true, true) + "} from pid " + (callerApp != null ? callerApp.pid : callingPid)); } @@ -2228,6 +2229,7 @@ final class ActivityStack { resultRecord, resultWho, requestCode, Activity.RESULT_CANCELED, null); } + mDismissKeyguardOnNextActivity = false; return err; } @@ -2239,6 +2241,7 @@ final class ActivityStack { resultRecord, resultWho, requestCode, Activity.RESULT_CANCELED, null); } + mDismissKeyguardOnNextActivity = false; String msg; if (!aInfo.exported) { msg = "Permission Denial: starting " + intent.toString() @@ -2276,6 +2279,7 @@ final class ActivityStack { } // We pretend to the caller that it was really started, but // they will just get a cancel result. + mDismissKeyguardOnNextActivity = false; return START_SUCCESS; } } @@ -2299,6 +2303,7 @@ final class ActivityStack { pal.grantedMode = grantedMode; pal.onlyIfNeeded = onlyIfNeeded; mService.mPendingActivityLaunches.add(pal); + mDismissKeyguardOnNextActivity = false; return START_SWITCHES_CANCELED; } } @@ -2317,8 +2322,17 @@ final class ActivityStack { mService.doPendingActivityLaunchesLocked(false); } - return startActivityUncheckedLocked(r, sourceRecord, + err = startActivityUncheckedLocked(r, sourceRecord, grantedUriPermissions, grantedMode, onlyIfNeeded, true); + if (mDismissKeyguardOnNextActivity && mPausingActivity == null) { + // Someone asked to have the keyguard dismissed on the next + // activity start, but we are not actually doing an activity + // switch... just dismiss the keyguard now, because we + // probably want to see whatever is behind it. + mDismissKeyguardOnNextActivity = false; + mService.mWindowManager.dismissKeyguard(); + } + return err; } final void moveHomeToFrontFromLaunchLocked(int launchFlags) { @@ -2987,6 +3001,11 @@ final class ActivityStack { w.thisTime = w.totalTime; } mService.notifyAll(); + + if (mDismissKeyguardOnNextActivity) { + mDismissKeyguardOnNextActivity = false; + mService.mWindowManager.dismissKeyguard(); + } } void sendActivityResultLocked(int callingUid, ActivityRecord r, @@ -3103,6 +3122,12 @@ final class ActivityStack { return stops; } + final void scheduleIdleLocked() { + Message msg = Message.obtain(); + msg.what = IDLE_NOW_MSG; + mHandler.sendMessage(msg); + } + final ActivityRecord activityIdleInternal(IBinder token, boolean fromTimeout, Configuration config) { if (localLOGV) Slog.v(TAG, "Activity idle: " + token); @@ -3413,9 +3438,7 @@ final class ActivityStack { // If we already have a few activities waiting to stop, // then give up on things going idle and start clearing // them out. - Message msg = Message.obtain(); - msg.what = IDLE_NOW_MSG; - mHandler.sendMessage(msg); + scheduleIdleLocked(); } else { checkReadyForSleepLocked(); } @@ -4126,4 +4149,8 @@ final class ActivityStack { return true; } + + public void dismissKeyguardOnNextActivityLocked() { + mDismissKeyguardOnNextActivity = true; + } } diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java index db235ee..9c55597 100644 --- a/services/java/com/android/server/am/ContentProviderRecord.java +++ b/services/java/com/android/server/am/ContentProviderRecord.java @@ -32,15 +32,15 @@ class ContentProviderRecord extends ContentProviderHolder { final ApplicationInfo appInfo; final ComponentName name; int externals; // number of non-framework processes supported by this provider - ProcessRecord app; // if non-null, hosting application + ProcessRecord proc; // if non-null, hosting process. ProcessRecord launchingApp; // if non-null, waiting for this app to be launched. String stringName; - public ContentProviderRecord(ProviderInfo _info, ApplicationInfo ai) { + public ContentProviderRecord(ProviderInfo _info, ApplicationInfo ai, ComponentName _name) { super(_info); uid = ai.uid; appInfo = ai; - name = new ComponentName(_info.packageName, _info.name); + name = _name; noReleaseNeeded = uid == 0 || uid == Process.SYSTEM_UID; } @@ -61,7 +61,7 @@ class ContentProviderRecord extends ContentProviderHolder { pw.print(prefix); pw.print("package="); pw.print(info.applicationInfo.packageName); pw.print(" process="); pw.println(info.processName); - pw.print(prefix); pw.print("app="); pw.println(app); + pw.print(prefix); pw.print("proc="); pw.println(proc); if (launchingApp != null) { pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp); } diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java index 3a5ca66..2618c77 100644 --- a/services/java/com/android/server/am/IntentBindRecord.java +++ b/services/java/com/android/server/am/IntentBindRecord.java @@ -54,7 +54,7 @@ class IntentBindRecord { void dumpInService(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("intent={"); - pw.print(intent.getIntent().toShortString(true, false)); + pw.print(intent.getIntent().toShortString(false, true, false)); pw.println('}'); pw.print(prefix); pw.print("binder="); pw.println(binder); pw.print(prefix); pw.print("requested="); pw.print(requested); @@ -89,7 +89,7 @@ class IntentBindRecord { sb.append(service.shortName); sb.append(':'); if (intent != null) { - intent.getIntent().toShortString(sb, false, false); + intent.getIntent().toShortString(sb, false, false, false); } sb.append('}'); return stringName = sb.toString(); diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java index 8ed0cc1..abd2a1f 100644 --- a/services/java/com/android/server/am/PendingIntentRecord.java +++ b/services/java/com/android/server/am/PendingIntentRecord.java @@ -150,7 +150,8 @@ class PendingIntentRecord extends IIntentSender.Stub { public String toString() { return "Key{" + typeName() + " pkg=" + packageName + " intent=" - + (requestIntent != null ? requestIntent.toShortString(true, false) : "<null>") + + (requestIntent != null + ? requestIntent.toShortString(false, true, false) : "<null>") + " flags=0x" + Integer.toHexString(flags) + "}"; } @@ -317,7 +318,7 @@ class PendingIntentRecord extends IIntentSender.Stub { } if (key.requestIntent != null) { pw.print(prefix); pw.print("requestIntent="); - pw.println(key.requestIntent.toShortString(true, true)); + pw.println(key.requestIntent.toShortString(false, true, true)); } if (sent || canceled) { pw.print(prefix); pw.print("sent="); pw.print(sent); diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index 004e963..257113b 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -192,7 +192,7 @@ class ServiceRecord extends Binder { void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("intent={"); - pw.print(intent.getIntent().toShortString(true, false)); + pw.print(intent.getIntent().toShortString(false, true, false)); pw.println('}'); pw.print(prefix); pw.print("packageName="); pw.println(packageName); pw.print(prefix); pw.print("processName="); pw.println(processName); diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java index 87129ea..a860763 100644 --- a/services/java/com/android/server/am/TaskRecord.java +++ b/services/java/com/android/server/am/TaskRecord.java @@ -94,14 +94,14 @@ class TaskRecord extends ThumbnailHolder { if (intent != null) { StringBuilder sb = new StringBuilder(128); sb.append(prefix); sb.append("intent={"); - intent.toShortString(sb, true, false); + intent.toShortString(sb, false, true, false); sb.append('}'); pw.println(sb.toString()); } if (affinityIntent != null) { StringBuilder sb = new StringBuilder(128); sb.append(prefix); sb.append("affinityIntent={"); - affinityIntent.toShortString(sb, true, false); + affinityIntent.toShortString(sb, false, true, false); sb.append('}'); pw.println(sb.toString()); } diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index 10f6d2c..6b9c088 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -29,6 +29,7 @@ import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; +import android.net.INetworkStatsService; import android.net.InterfaceConfiguration; import android.net.LinkAddress; import android.net.LinkProperties; @@ -88,7 +89,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { // upstream type list and the DUN_REQUIRED secure-setting private int mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_NONE; - private INetworkManagementService mNMService; + private final INetworkManagementService mNMService; + private final INetworkStatsService mStatsService; private Looper mLooper; private HandlerThread mThread; @@ -124,9 +126,11 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private boolean mUsbTetherRequested; // true if USB tethering should be started // when RNDIS is enabled - public Tethering(Context context, INetworkManagementService nmService, Looper looper) { + public Tethering(Context context, INetworkManagementService nmService, + INetworkStatsService statsService, Looper looper) { mContext = context; mNMService = nmService; + mStatsService = statsService; mLooper = looper; mIfaces = new HashMap<String, TetherInterfaceSM>(); @@ -913,6 +917,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub { case CMD_INTERFACE_DOWN: if (mMyUpstreamIfaceName != null) { try { + // about to tear down NAT; gather remaining statistics + mStatsService.forceUpdate(); + mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName); mMyUpstreamIfaceName = null; } catch (Exception e) { @@ -957,6 +964,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } if (mMyUpstreamIfaceName != null) { try { + // about to tear down NAT; gather remaining statistics + mStatsService.forceUpdate(); + mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName); mMyUpstreamIfaceName = null; } catch (Exception e) { @@ -995,6 +1005,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub { case CMD_TETHER_MODE_DEAD: if (mMyUpstreamIfaceName != null) { try { + // about to tear down NAT; gather remaining statistics + mStatsService.forceUpdate(); + mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName); mMyUpstreamIfaceName = null; } catch (Exception e) { diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index bc65205..aa46795 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -24,8 +24,8 @@ import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; -import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; @@ -43,9 +43,12 @@ import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL; import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY; +import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE; +import static android.telephony.PhoneStateListener.LISTEN_NONE; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; +import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; @@ -80,6 +83,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; +import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.EventLog; import android.util.Log; @@ -121,7 +125,7 @@ import libcore.io.IoUtils; */ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String TAG = "NetworkStats"; - private static final boolean LOGD = true; + private static final boolean LOGD = false; private static final boolean LOGV = false; /** File header magic number: "ANET" */ @@ -132,7 +136,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int VERSION_UID_WITH_TAG = 3; private static final int VERSION_UID_WITH_SET = 4; - private static final int MSG_PERFORM_POLL = 0x1; + private static final int MSG_PERFORM_POLL = 1; + private static final int MSG_UPDATE_IFACES = 2; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x10; @@ -144,6 +149,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final INetworkManagementService mNetworkManager; private final IAlarmManager mAlarmManager; private final TrustedTime mTime; + private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; private final PowerManager.WakeLock mWakeLock; @@ -227,6 +233,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager"); mTime = checkNotNull(time, "missing TrustedTime"); + mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager"); mSettings = checkNotNull(settings, "missing NetworkStatsSettings"); final PowerManager powerManager = (PowerManager) context.getSystemService( @@ -279,6 +286,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // ignored; service lives in system_server } + // watch for networkType changes that aren't broadcast through + // CONNECTIVITY_ACTION_IMMEDIATE above. + mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE); + registerPollAlarmLocked(); registerGlobalAlert(); @@ -288,10 +299,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void shutdownLocked() { mContext.unregisterReceiver(mConnReceiver); + mContext.unregisterReceiver(mTetherReceiver); mContext.unregisterReceiver(mPollReceiver); mContext.unregisterReceiver(mRemovedReceiver); mContext.unregisterReceiver(mShutdownReceiver); + mTeleManager.listen(mPhoneListener, LISTEN_NONE); + writeNetworkStatsLocked(); if (mUidStatsLoaded) { writeUidStatsLocked(); @@ -535,14 +549,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified CONNECTIVITY_INTERNAL // permission above. - synchronized (mStatsLock) { - mWakeLock.acquire(); - try { - updateIfacesLocked(); - } finally { - mWakeLock.release(); - } - } + updateIfaces(); } }; @@ -619,6 +626,46 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + private int mLastPhoneState = TelephonyManager.DATA_UNKNOWN; + private int mLastPhoneNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + + /** + * Receiver that watches for {@link TelephonyManager} changes, such as + * transitioning between network types. + */ + private PhoneStateListener mPhoneListener = new PhoneStateListener() { + @Override + public void onDataConnectionStateChanged(int state, int networkType) { + final boolean stateChanged = state != mLastPhoneState; + final boolean networkTypeChanged = networkType != mLastPhoneNetworkType; + + if (networkTypeChanged && !stateChanged) { + // networkType changed without a state change, which means we + // need to roll our own update. delay long enough for + // ConnectivityManager to process. + // TODO: add direct event to ConnectivityService instead of + // relying on this delay. + if (LOGV) Slog.v(TAG, "triggering delayed updateIfaces()"); + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); + } + + mLastPhoneState = state; + mLastPhoneNetworkType = networkType; + } + }; + + private void updateIfaces() { + synchronized (mStatsLock) { + mWakeLock.acquire(); + try { + updateIfacesLocked(); + } finally { + mWakeLock.release(); + } + } + } + /** * Inspect all current {@link NetworkState} to derive mapping from {@code * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo} @@ -713,19 +760,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long threshold = mSettings.getPersistThreshold(); try { - // record network stats - final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); - performNetworkPollLocked(networkSnapshot, currentTime); - - // persist when enough network data has occurred - final NetworkStats persistNetworkDelta = computeStatsDelta( - mLastPersistNetworkSnapshot, networkSnapshot, true); - final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold; - if (persistForce || (persistNetwork && networkPastThreshold)) { - writeNetworkStatsLocked(); - mLastPersistNetworkSnapshot = networkSnapshot; - } - // record tethering stats; persisted during normal UID cycle below final String[] ifacePairs = mConnManager.getTetheredIfacePairs(); final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( @@ -744,6 +778,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { writeUidStatsLocked(); mLastPersistUidSnapshot = uidSnapshot; } + + // record network stats + final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); + performNetworkPollLocked(networkSnapshot, currentTime); + + // persist when enough network data has occurred + final NetworkStats persistNetworkDelta = computeStatsDelta( + mLastPersistNetworkSnapshot, networkSnapshot, true); + final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold; + if (persistForce || (persistNetwork && networkPastThreshold)) { + writeNetworkStatsLocked(); + mLastPersistNetworkSnapshot = networkSnapshot; + } } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); } catch (RemoteException e) { @@ -1356,6 +1403,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performPoll(flags); return true; } + case MSG_UPDATE_IFACES: { + updateIfaces(); + return true; + } default: { return false; } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 105e603..eb135b7 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -72,6 +72,7 @@ import android.content.pm.Signature; import android.content.pm.UserInfo; import android.content.pm.ManifestDigest; import android.content.pm.VerifierDeviceIdentity; +import android.content.pm.VerifierInfo; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -113,6 +114,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.cert.CertificateException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -158,6 +161,7 @@ public class PackageManagerService extends IPackageManager.Stub { private static final boolean DEBUG_INTENT_MATCHING = false; private static final boolean DEBUG_PACKAGE_SCANNING = false; private static final boolean DEBUG_APP_DIR_OBSERVER = false; + private static final boolean DEBUG_VERIFY = false; static final boolean MULTIPLE_APPLICATION_UIDS = true; private static final int RADIO_UID = Process.PHONE_UID; @@ -208,6 +212,8 @@ public class PackageManagerService extends IPackageManager.Stub { DEFAULT_CONTAINER_PACKAGE, "com.android.defcontainer.DefaultContainerService"); + private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; + private static final String LIB_DIR_NAME = "lib"; static final String mTempContainerPrefix = "smdl2tmp"; @@ -349,7 +355,8 @@ public class PackageManagerService extends IPackageManager.Stub { final HashSet<String> mProtectedBroadcasts = new HashSet<String>(); /** List of packages waiting for verification. */ - final SparseArray<InstallArgs> mPendingVerification = new SparseArray<InstallArgs>(); + final SparseArray<PackageVerificationState> mPendingVerification + = new SparseArray<PackageVerificationState>(); final ArrayList<PackageParser.Package> mDeferredDexOpt = new ArrayList<PackageParser.Package>(); @@ -427,6 +434,8 @@ public class PackageManagerService extends IPackageManager.Stub { final SparseArray<PostInstallData> mRunningInstalls = new SparseArray<PostInstallData>(); int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows + private final String mRequiredVerifierPackage; + class PackageHandler extends Handler { private boolean mBound = false; final ArrayList<HandlerParams> mPendingInstalls = @@ -740,9 +749,10 @@ public class PackageManagerService extends IPackageManager.Stub { } break; case CHECK_PENDING_VERIFICATION: { final int verificationId = msg.arg1; - final InstallArgs args = mPendingVerification.get(verificationId); + final PackageVerificationState state = mPendingVerification.get(verificationId); - if (args != null) { + if (state != null) { + final InstallArgs args = state.getInstallArgs(); Slog.i(TAG, "Validation timed out for " + args.packageURI.toString()); mPendingVerification.remove(verificationId); @@ -756,31 +766,38 @@ public class PackageManagerService extends IPackageManager.Stub { } case PACKAGE_VERIFIED: { final int verificationId = msg.arg1; - final boolean verified = msg.arg2 == 1 ? true : false; - final InstallArgs args = mPendingVerification.get(verificationId); - if (args == null) { + final PackageVerificationState state = mPendingVerification.get(verificationId); + if (state == null) { Slog.w(TAG, "Invalid validation token " + verificationId + " received"); break; } - mPendingVerification.remove(verificationId); + final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj; - int ret; - if (verified) { - ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; - try { - ret = args.copyApk(mContainerService, true); - } catch (RemoteException e) { - Slog.e(TAG, "Could not contact the ContainerService"); + state.setVerifierResponse(response.callerUid, response.code); + + if (state.isVerificationComplete()) { + mPendingVerification.remove(verificationId); + + final InstallArgs args = state.getInstallArgs(); + + int ret; + if (state.isInstallAllowed()) { + ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; + try { + ret = args.copyApk(mContainerService, true); + } catch (RemoteException e) { + Slog.e(TAG, "Could not contact the ContainerService"); + } + } else { + ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE; } - } else { - ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE; - } - processPendingInstall(args, ret); + processPendingInstall(args, ret); - mHandler.sendEmptyMessage(MCS_UNBIND); + mHandler.sendEmptyMessage(MCS_UNBIND); + } break; } @@ -945,7 +962,8 @@ public class PackageManagerService extends IPackageManager.Stub { } catch (FileNotFoundException e) { Slog.w(TAG, "Boot class path not found: " + paths[i]); } catch (IOException e) { - Slog.w(TAG, "Exception reading boot class path: " + paths[i], e); + Slog.w(TAG, "Cannot dexopt " + paths[i] + "; is it an APK or JAR? " + + e.getMessage()); } } } else { @@ -968,7 +986,8 @@ public class PackageManagerService extends IPackageManager.Stub { } catch (FileNotFoundException e) { Slog.w(TAG, "Library not found: " + lib); } catch (IOException e) { - Slog.w(TAG, "Exception reading library: " + lib, e); + Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? " + + e.getMessage()); } } } @@ -1132,10 +1151,49 @@ public class PackageManagerService extends IPackageManager.Stub { // are all flushed. Not really needed, but keeps things nice and // tidy. Runtime.getRuntime().gc(); + + mRequiredVerifierPackage = getRequiredVerifierLPr(); } // synchronized (mPackages) } // synchronized (mInstallLock) } + private String getRequiredVerifierLPr() { + final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); + final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE, + PackageManager.GET_DISABLED_COMPONENTS); + + String requiredVerifier = null; + + final int N = receivers.size(); + for (int i = 0; i < N; i++) { + final ResolveInfo info = receivers.get(i); + + if (info.activityInfo == null) { + continue; + } + + final String packageName = info.activityInfo.packageName; + + final PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps == null) { + continue; + } + + if (!ps.grantedPermissions + .contains(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT)) { + continue; + } + + if (requiredVerifier != null) { + throw new RuntimeException("There can be only one required verifier"); + } + + requiredVerifier = packageName; + } + + return requiredVerifier; + } + @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { @@ -4350,7 +4408,10 @@ public class PackageManagerService extends IPackageManager.Stub { if (p != null) { PackageSetting ps = (PackageSetting)p.mExtras; if (ps != null) { - return ps.stopped; + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return ps.stopped && (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0; } } return false; @@ -4522,7 +4583,10 @@ public class PackageManagerService extends IPackageManager.Stub { if (p != null) { PackageSetting ps = (PackageSetting)p.mExtras; if (ps != null) { - return ps.stopped; + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return ps.stopped && (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0; } } return false; @@ -4849,17 +4913,110 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override - public void verifyPendingInstall(int id, int verificationCode) - throws RemoteException { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, null); - + public void verifyPendingInstall(int id, int verificationCode) throws RemoteException { final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED); + final PackageVerificationResponse response = new PackageVerificationResponse( + verificationCode, Binder.getCallingUid()); msg.arg1 = id; - msg.arg2 = verificationCode; + msg.obj = response; mHandler.sendMessage(msg); } + private ComponentName matchComponentForVerifier(String packageName, + List<ResolveInfo> receivers) { + ActivityInfo targetReceiver = null; + + final int NR = receivers.size(); + for (int i = 0; i < NR; i++) { + final ResolveInfo info = receivers.get(i); + if (info.activityInfo == null) { + continue; + } + + if (packageName.equals(info.activityInfo.packageName)) { + targetReceiver = info.activityInfo; + break; + } + } + + if (targetReceiver == null) { + return null; + } + + return new ComponentName(targetReceiver.packageName, targetReceiver.name); + } + + private List<ComponentName> matchVerifiers(PackageInfoLite pkgInfo, + List<ResolveInfo> receivers, final PackageVerificationState verificationState) { + if (pkgInfo.verifiers.length == 0) { + return null; + } + + final int N = pkgInfo.verifiers.length; + final List<ComponentName> sufficientVerifiers = new ArrayList<ComponentName>(N + 1); + for (int i = 0; i < N; i++) { + final VerifierInfo verifierInfo = pkgInfo.verifiers[i]; + + final ComponentName comp = matchComponentForVerifier(verifierInfo.packageName, + receivers); + if (comp == null) { + continue; + } + + final int verifierUid = getUidForVerifier(verifierInfo); + if (verifierUid == -1) { + continue; + } + + if (DEBUG_VERIFY) { + Slog.d(TAG, "Added sufficient verifier " + verifierInfo.packageName + + " with the correct signature"); + } + sufficientVerifiers.add(comp); + verificationState.addSufficientVerifier(verifierUid); + } + + return sufficientVerifiers; + } + + private int getUidForVerifier(VerifierInfo verifierInfo) { + synchronized (mPackages) { + final PackageParser.Package pkg = mPackages.get(verifierInfo.packageName); + if (pkg == null) { + return -1; + } else if (pkg.mSignatures.length != 1) { + Slog.i(TAG, "Verifier package " + verifierInfo.packageName + + " has more than one signature; ignoring"); + return -1; + } + + /* + * If the public key of the package's signature does not match + * our expected public key, then this is a different package and + * we should skip. + */ + + final byte[] expectedPublicKey; + try { + final Signature verifierSig = pkg.mSignatures[0]; + final PublicKey publicKey = verifierSig.getPublicKey(); + expectedPublicKey = publicKey.getEncoded(); + } catch (CertificateException e) { + return -1; + } + + final byte[] actualPublicKey = verifierInfo.publicKey.getEncoded(); + + if (!Arrays.equals(actualPublicKey, expectedPublicKey)) { + Slog.i(TAG, "Verifier package " + verifierInfo.packageName + + " does not have the expected public key; ignoring"); + return -1; + } + + return pkg.applicationInfo.uid; + } + } + public void finishPackageInstall(int token) { enforceSystemOrRoot("Only the system is allowed to finish installs"); @@ -5229,9 +5386,11 @@ public class PackageManagerService extends IPackageManager.Stub { */ public void handleStartCopy() throws RemoteException { int ret = PackageManager.INSTALL_SUCCEEDED; - boolean fwdLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0; - boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0; - boolean onInt = (flags & PackageManager.INSTALL_INTERNAL) != 0; + final boolean fwdLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0; + final boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0; + final boolean onInt = (flags & PackageManager.INSTALL_INTERNAL) != 0; + PackageInfoLite pkgLite = null; + if (onInt && onSd) { // Check if both bits are set. Slog.w(TAG, "Conflicting flags specified for installing on both internal and external"); @@ -5253,7 +5412,6 @@ public class PackageManagerService extends IPackageManager.Stub { } // Remote call to find out default install location - final PackageInfoLite pkgLite; try { mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION); @@ -5296,21 +5454,27 @@ public class PackageManagerService extends IPackageManager.Stub { } final InstallArgs args = createInstallArgs(this); + mArgs = args; + if (ret == PackageManager.INSTALL_SUCCEEDED) { /* * Determine if we have any installed package verifiers. If we * do, then we'll defer to them to verify the packages. */ - final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION, - packageURI); - verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - final List<ResolveInfo> receivers = queryIntentReceivers(verification, null, - PackageManager.GET_DISABLED_COMPONENTS); - if (isVerificationEnabled() && receivers.size() > 0) { - if (DEBUG_INSTALL) { + final int requiredUid = mRequiredVerifierPackage == null ? -1 + : getPackageUid(mRequiredVerifierPackage); + if (requiredUid != -1 && isVerificationEnabled()) { + final Intent verification = new Intent( + Intent.ACTION_PACKAGE_NEEDS_VERIFICATION, packageURI); + verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + final List<ResolveInfo> receivers = queryIntentReceivers(verification, null, + PackageManager.GET_DISABLED_COMPONENTS); + + if (DEBUG_VERIFY) { Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent " - + verification.toString()); + + verification.toString() + " with " + pkgLite.verifiers.length + + " optional verifiers"); } final int verificationId = mPendingVerificationToken++; @@ -5327,35 +5491,70 @@ public class PackageManagerService extends IPackageManager.Stub { verificationURI); } - mPendingVerification.append(verificationId, args); + final PackageVerificationState verificationState = new PackageVerificationState( + requiredUid, args); + + mPendingVerification.append(verificationId, verificationState); + + final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite, + receivers, verificationState); /* - * Send the intent to the registered verification agents, - * but only start the verification timeout after the target - * BroadcastReceivers have run. + * If any sufficient verifiers were listed in the package + * manifest, attempt to ask them. */ - mContext.sendOrderedBroadcast(verification, - android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final Message msg = mHandler - .obtainMessage(CHECK_PENDING_VERIFICATION); - msg.arg1 = verificationId; - mHandler.sendMessageDelayed(msg, getVerificationTimeout()); - } - }, - null, 0, null, null); + if (sufficientVerifiers != null) { + final int N = sufficientVerifiers.size(); + if (N == 0) { + Slog.i(TAG, "Additional verifiers required, but none installed."); + ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE; + } else { + for (int i = 0; i < N; i++) { + final ComponentName verifierComponent = sufficientVerifiers.get(i); + + final Intent sufficientIntent = new Intent(verification); + sufficientIntent.setComponent(verifierComponent); + + mContext.sendBroadcast(sufficientIntent); + } + } + } + + final ComponentName requiredVerifierComponent = matchComponentForVerifier( + mRequiredVerifierPackage, receivers); + if (ret == PackageManager.INSTALL_SUCCEEDED + && mRequiredVerifierPackage != null) { + /* + * Send the intent to the required verification agent, + * but only start the verification timeout after the + * target BroadcastReceivers have run. + */ + verification.setComponent(requiredVerifierComponent); + mContext.sendOrderedBroadcast(verification, + android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final Message msg = mHandler + .obtainMessage(CHECK_PENDING_VERIFICATION); + msg.arg1 = verificationId; + mHandler.sendMessageDelayed(msg, getVerificationTimeout()); + } + }, null, 0, null, null); + + /* + * We don't want the copy to proceed until verification + * succeeds, so null out this field. + */ + mArgs = null; + } } else { - // Create copy only if we are not in an erroneous state. - // Remote call to initiate copy using temporary file - mArgs = args; + /* + * No package verification is enabled, so immediately start + * the remote call to initiate copy using temporary file. + */ ret = args.copyApk(mContainerService, true); } - } else { - // There was an error, so let the processPendingInstall() break - // the bad news... uh, through a call in handleReturnCode() - mArgs = args; } mRet = ret; @@ -7541,6 +7740,8 @@ public class PackageManagerService extends IPackageManager.Stub { public static final int DUMP_PROVIDERS = 1 << 7; + public static final int DUMP_VERIFIERS = 1 << 8; + public static final int OPTION_SHOW_FILTERS = 1 << 0; private int mTypes; @@ -7633,6 +7834,7 @@ public class PackageManagerService extends IPackageManager.Stub { pw.println(" p[ackages]: dump installed packages"); pw.println(" s[hared-users]: dump shared user IDs"); pw.println(" m[essages]: print collected runtime messages"); + pw.println(" v[erifiers]: print package verifier info"); pw.println(" <package.name>: info about given package"); return; } else if ("-f".equals(opt)) { @@ -7665,11 +7867,24 @@ public class PackageManagerService extends IPackageManager.Stub { dumpState.setDump(DumpState.DUMP_PROVIDERS); } else if ("m".equals(cmd) || "messages".equals(cmd)) { dumpState.setDump(DumpState.DUMP_MESSAGES); + } else if ("v".equals(cmd) || "verifiers".equals(cmd)) { + dumpState.setDump(DumpState.DUMP_VERIFIERS); } } // reader synchronized (mPackages) { + if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) { + if (dumpState.onTitlePrinted()) + pw.println(" "); + pw.println("Verifiers:"); + pw.print(" Required: "); + pw.print(mRequiredVerifierPackage); + pw.print(" (uid="); + pw.print(getPackageUid(mRequiredVerifierPackage)); + pw.println(")"); + } + if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) { if (dumpState.onTitlePrinted()) pw.println(" "); diff --git a/services/java/com/android/server/pm/PackageVerificationResponse.java b/services/java/com/android/server/pm/PackageVerificationResponse.java new file mode 100644 index 0000000..b2ae0dd --- /dev/null +++ b/services/java/com/android/server/pm/PackageVerificationResponse.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2011 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.pm; + +public class PackageVerificationResponse { + public final int code; + + public final int callerUid; + + public PackageVerificationResponse(int code, int callerUid) { + this.code = code; + this.callerUid = callerUid; + } +} diff --git a/services/java/com/android/server/pm/PackageVerificationState.java b/services/java/com/android/server/pm/PackageVerificationState.java new file mode 100644 index 0000000..e5b89c1 --- /dev/null +++ b/services/java/com/android/server/pm/PackageVerificationState.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2011 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.pm; + +import com.android.server.pm.PackageManagerService.InstallArgs; + +import android.content.pm.PackageManager; +import android.util.SparseBooleanArray; + +/** + * Tracks the package verification state for a particular package. Each package + * verification has a required verifier and zero or more sufficient verifiers. + * Only one of the sufficient verifier list must return affirmative to allow the + * package to be considered verified. If there are zero sufficient verifiers, + * then package verification is considered complete. + */ +class PackageVerificationState { + private final InstallArgs mArgs; + + private final SparseBooleanArray mSufficientVerifierUids; + + private final int mRequiredVerifierUid; + + private boolean mSufficientVerificationComplete; + + private boolean mSufficientVerificationPassed; + + private boolean mRequiredVerificationComplete; + + private boolean mRequiredVerificationPassed; + + /** + * Create a new package verification state where {@code requiredVerifierUid} + * is the user ID for the package that must reply affirmative before things + * can continue. + * + * @param requiredVerifierUid user ID of required package verifier + * @param args + */ + public PackageVerificationState(int requiredVerifierUid, InstallArgs args) { + mRequiredVerifierUid = requiredVerifierUid; + mArgs = args; + mSufficientVerifierUids = new SparseBooleanArray(); + } + + public InstallArgs getInstallArgs() { + return mArgs; + } + + /** + * Add a verifier which is added to our sufficient list. + * + * @param uid user ID of sufficient verifier + */ + public void addSufficientVerifier(int uid) { + mSufficientVerifierUids.put(uid, true); + } + + /** + * Should be called when a verification is received from an agent so the + * state of the package verification can be tracked. + * + * @param uid user ID of the verifying agent + * @return {@code true} if the verifying agent actually exists in our list + */ + public boolean setVerifierResponse(int uid, int code) { + if (uid == mRequiredVerifierUid) { + mRequiredVerificationComplete = true; + switch (code) { + case PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT: + mSufficientVerifierUids.clear(); + // fall through + case PackageManager.VERIFICATION_ALLOW: + mRequiredVerificationPassed = true; + break; + default: + mRequiredVerificationPassed = false; + } + return true; + } else { + if (mSufficientVerifierUids.get(uid)) { + if (code == PackageManager.VERIFICATION_ALLOW) { + mSufficientVerificationComplete = true; + mSufficientVerificationPassed = true; + } + + mSufficientVerifierUids.delete(uid); + if (mSufficientVerifierUids.size() == 0) { + mSufficientVerificationComplete = true; + } + + return true; + } + } + + return false; + } + + /** + * Returns whether verification is considered complete. This means that the + * required verifier and at least one of the sufficient verifiers has + * returned a positive verification. + * + * @return {@code true} when verification is considered complete + */ + public boolean isVerificationComplete() { + if (!mRequiredVerificationComplete) { + return false; + } + + if (mSufficientVerifierUids.size() == 0) { + return true; + } + + return mSufficientVerificationComplete; + } + + /** + * Returns whether installation should be allowed. This should only be + * called after {@link #isVerificationComplete()} returns {@code true}. + * + * @return {@code true} if installation should be allowed + */ + public boolean isInstallAllowed() { + if (!mRequiredVerificationPassed) { + return false; + } + + if (mSufficientVerificationComplete) { + return mSufficientVerificationPassed; + } + + return true; + } +} diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java index bfa2b39..61c96bb 100644 --- a/services/java/com/android/server/wm/AppWindowToken.java +++ b/services/java/com/android/server/wm/AppWindowToken.java @@ -194,7 +194,7 @@ class AppWindowToken extends WindowToken { // This must be called while inside a transaction. boolean stepAnimationLocked(long currentTime, int dw, int dh) { - if (!service.mDisplayFrozen && service.mPolicy.isScreenOn()) { + if (!service.mDisplayFrozen && service.mPolicy.isScreenOnFully()) { // We will run animations as long as the display isn't frozen. if (animation == WindowManagerService.sDummyAnimation) { diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java index dd440bf..f2e7485 100644 --- a/services/java/com/android/server/wm/DragState.java +++ b/services/java/com/android/server/wm/DragState.java @@ -125,6 +125,12 @@ class DragState { mDragWindowHandle.frameTop = 0; mDragWindowHandle.frameRight = mService.mCurDisplayWidth; mDragWindowHandle.frameBottom = mService.mCurDisplayHeight; + + // Pause rotations before a drag. + if (WindowManagerService.DEBUG_ORIENTATION) { + Slog.d(WindowManagerService.TAG, "Pausing rotation during drag"); + } + mService.pauseRotationLocked(); } } @@ -142,6 +148,12 @@ class DragState { mDragWindowHandle = null; mDragApplicationHandle = null; + + // Resume rotations after a drag. + if (WindowManagerService.DEBUG_ORIENTATION) { + Slog.d(WindowManagerService.TAG, "Resuming rotation after drag"); + } + mService.resumeRotationLocked(); } } @@ -257,13 +269,6 @@ class DragState { // free our resources and drop all the object references mService.mDragState.reset(); mService.mDragState = null; - - if (WindowManagerService.DEBUG_ORIENTATION) Slog.d(WindowManagerService.TAG, "Performing post-drag rotation"); - boolean changed = mService.setRotationUncheckedLocked( - WindowManagerPolicy.USE_LAST_ROTATION, 0, false); - if (changed) { - mService.mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); - } } void notifyMoveLw(float x, float y) { diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 609016b..3ea9e81 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -73,6 +73,7 @@ import android.os.Bundle; import android.os.Debug; import android.os.Handler; import android.os.IBinder; +import android.os.IRemoteCallback; import android.os.LocalPowerManager; import android.os.Looper; import android.os.Message; @@ -91,6 +92,7 @@ import android.provider.Settings; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; +import android.util.Pair; import android.util.Slog; import android.util.SparseIntArray; import android.util.TypedValue; @@ -384,6 +386,12 @@ public class WindowManagerService extends IWindowManager.Stub ArrayList<WindowState> mForceRemoves; /** + * Windows that clients are waiting to have drawn. + */ + ArrayList<Pair<WindowState, IRemoteCallback>> mWaitingForDrawn + = new ArrayList<Pair<WindowState, IRemoteCallback>>(); + + /** * Used when rebuilding window list to keep track of windows that have * been removed. */ @@ -419,14 +427,11 @@ public class WindowManagerService extends IWindowManager.Stub int mAppDisplayWidth = 0; int mAppDisplayHeight = 0; int mRotation = 0; - int mRequestedRotation = 0; int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; boolean mAltOrientation = false; - int mLastRotationFlags; ArrayList<IRotationWatcher> mRotationWatchers = new ArrayList<IRotationWatcher>(); - int mDeferredRotation; - int mDeferredRotationAnimFlags; + int mDeferredRotationPauseCount; boolean mLayoutNeeded = true; boolean mAnimationPending = false; @@ -2191,7 +2196,8 @@ public class WindowManagerService extends IWindowManager.Stub // to hold off on removing the window until the animation is done. // If the display is frozen, just remove immediately, since the // animation wouldn't be seen. - if (win.mSurface != null && !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { + if (win.mSurface != null && !mDisplayFrozen && mDisplayEnabled + && mPolicy.isScreenOnFully()) { // If we are not currently running the exit animation, we // need to see about starting one. if (wasVisible=win.isWinVisibleLw()) { @@ -2569,7 +2575,7 @@ public class WindowManagerService extends IWindowManager.Stub if (displayed) { if (win.mSurface != null && !win.mDrawPending && !win.mCommitDrawPending && !mDisplayFrozen - && mDisplayEnabled && mPolicy.isScreenOn()) { + && mDisplayEnabled && mPolicy.isScreenOnFully()) { applyEnterAnimationLocked(win); } if ((win.mAttrs.flags @@ -2862,7 +2868,7 @@ public class WindowManagerService extends IWindowManager.Stub // frozen, there is no reason to animate and it can cause strange // artifacts when we unfreeze the display if some different animation // is running. - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) { int anim = mPolicy.selectAnimationLw(win, transit); int attr = -1; Animation a = null; @@ -2948,7 +2954,7 @@ public class WindowManagerService extends IWindowManager.Stub // frozen, there is no reason to animate and it can cause strange // artifacts when we unfreeze the display if some different animation // is running. - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) { Animation a; if (mNextAppTransitionPackage != null) { a = loadAnimation(mNextAppTransitionPackage, enter ? @@ -3405,9 +3411,7 @@ public class WindowManagerService extends IWindowManager.Stub //send a message to Policy indicating orientation change to take //action like disabling/enabling sensors etc., mPolicy.setCurrentOrientationLw(req); - if (setRotationUncheckedLocked(WindowManagerPolicy.USE_LAST_ROTATION, - mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE, - inTransaction)) { + if (updateRotationUncheckedLocked(inTransaction)) { changed = true; } } @@ -3514,7 +3518,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_APP_TRANSITIONS) Slog.v( TAG, "Prepare app transition: transit=" + transit + " mNextAppTransition=" + mNextAppTransition); - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) { if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) { mNextAppTransition = transit; @@ -3598,7 +3602,7 @@ public class WindowManagerService extends IWindowManager.Stub // If the display is frozen, we won't do anything until the // actual window is displayed so there is no reason to put in // the starting window. - if (mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOn()) { + if (mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully()) { return; } @@ -3880,7 +3884,7 @@ public class WindowManagerService extends IWindowManager.Stub // If we are preparing an app transition, then delay changing // the visibility of this token until we execute that transition. - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn() + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully() && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { // Already in requested state, don't do anything more. if (wtoken.hiddenRequested != visible) { @@ -4008,7 +4012,7 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized(mWindowMap) { - if (configChanges == 0 && !mDisplayFrozen && mPolicy.isScreenOn()) { + if (configChanges == 0 && !mDisplayFrozen && mPolicy.isScreenOnFully()) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping set freeze of " + token); return; } @@ -4521,6 +4525,16 @@ public class WindowManagerService extends IWindowManager.Stub return mPolicy.isKeyguardSecure(); } + public void dismissKeyguard() { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires DISABLE_KEYGUARD permission"); + } + synchronized(mWindowMap) { + mPolicy.dismissKeyguardLw(); + } + } + public void closeSystemDialogs(String reason) { synchronized(mWindowMap) { for (int i=mWindows.size()-1; i>=0; i--) { @@ -4814,8 +4828,7 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.enableScreenAfterBoot(); // Make sure the last requested orientation has been applied. - setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, - mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); + updateRotationUnchecked(false); } public void showBootMessage(final CharSequence msg, final boolean always) { @@ -5034,6 +5047,10 @@ public class WindowManagerService extends IWindowManager.Stub return bm; } + /** + * Freeze rotation changes. (Enable "rotation lock".) + * Persists across reboots. + */ public void freezeRotation() { if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, "freezeRotation()")) { @@ -5043,9 +5060,13 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation); mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED, mRotation); - setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0); + updateRotationUnchecked(false); } + /** + * Thaw rotation changes. (Disable "rotation lock".) + * Persists across reboots. + */ public void thawRotation() { if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, "thawRotation()")) { @@ -5055,30 +5076,56 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation); mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used - setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0); + updateRotationUnchecked(false); } - public void setRotation(int rotation, - boolean alwaysSendConfiguration, int animFlags) { - if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, - "setRotation()")) { - throw new SecurityException("Requires SET_ORIENTATION permission"); - } + /** + * Recalculate the current rotation. + * + * Called by the window manager policy whenever the state of the system changes + * such that the current rotation might need to be updated, such as when the + * device is docked or rotated into a new posture. + */ + public void updateRotation(boolean alwaysSendConfiguration) { + updateRotationUnchecked(alwaysSendConfiguration); + } - setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags); + /** + * Temporarily pauses rotation changes until resumed. + * + * This can be used to prevent rotation changes from occurring while the user is + * performing certain operations, such as drag and drop. + * + * This call nests and must be matched by an equal number of calls to {@link #resumeRotation}. + */ + void pauseRotationLocked() { + mDeferredRotationPauseCount += 1; } - public void setRotationUnchecked(int rotation, - boolean alwaysSendConfiguration, int animFlags) { - if(DEBUG_ORIENTATION) Slog.v(TAG, - "setRotationUnchecked(rotation=" + rotation + - " alwaysSendConfiguration=" + alwaysSendConfiguration + - " animFlags=" + animFlags); + /** + * Resumes normal rotation changes after being paused. + */ + void resumeRotationLocked() { + if (mDeferredRotationPauseCount > 0) { + mDeferredRotationPauseCount -= 1; + if (mDeferredRotationPauseCount == 0) { + boolean changed = updateRotationUncheckedLocked(false); + if (changed) { + mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); + } + } + } + } + + public void updateRotationUnchecked( + boolean alwaysSendConfiguration) { + if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked(" + + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")"); long origId = Binder.clearCallingIdentity(); boolean changed; synchronized(mWindowMap) { - changed = setRotationUncheckedLocked(rotation, animFlags, false); + changed = updateRotationUncheckedLocked(false); } if (changed || alwaysSendConfiguration) { @@ -5089,152 +5136,114 @@ public class WindowManagerService extends IWindowManager.Stub } /** - * Apply a new rotation to the screen, respecting the requests of - * applications. Use WindowManagerPolicy.USE_LAST_ROTATION to simply - * re-evaluate the desired rotation. - * - * Returns null if the rotation has been changed. In this case YOU - * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN. + * Updates the current rotation. + * + * Returns true if the rotation has been changed. In this case YOU + * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN. */ - public boolean setRotationUncheckedLocked(int rotation, int animFlags, boolean inTransaction) { - if (mDragState != null - || (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating())) { - // Potential rotation during a drag or while waiting for a previous orientation - // change to finish (rotation animation will be dismissed). - // Don't do the rotation now, but make a note to perform the rotation later. - if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation."); - if (rotation != WindowManagerPolicy.USE_LAST_ROTATION) { - mDeferredRotation = rotation; - mDeferredRotationAnimFlags = animFlags; - } + public boolean updateRotationUncheckedLocked(boolean inTransaction) { + if (mDeferredRotationPauseCount > 0) { + // Rotation updates have been paused temporarily. Defer the update until + // updates have been resumed. + if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused."); return false; } - boolean changed; - if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) { - if (mDeferredRotation != WindowManagerPolicy.USE_LAST_ROTATION) { - rotation = mDeferredRotation; - mRequestedRotation = rotation; - mLastRotationFlags = mDeferredRotationAnimFlags; - } - rotation = mRequestedRotation; - } else { - mRequestedRotation = rotation; - mLastRotationFlags = animFlags; - } - mDeferredRotation = WindowManagerPolicy.USE_LAST_ROTATION; - if (DEBUG_ORIENTATION) Slog.v(TAG, "Overwriting rotation value from " + rotation); - rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, - mRotation, mDisplayEnabled); - if (DEBUG_ORIENTATION) Slog.v(TAG, "new rotation is set to " + rotation); - - int desiredRotation = rotation; - int lockedRotation = mPolicy.getLockedRotationLw(); - if (lockedRotation >= 0 && rotation != lockedRotation) { - // We are locked in a rotation but something is requesting - // a different rotation... we will either keep the locked - // rotation if it results in the same orientation, or have to - // switch into an emulated orientation mode. - - // First, we know that our rotation is actually going to be - // the locked rotation. - rotation = lockedRotation; - - // Now the difference between the desired and lockedRotation - // may mean that the orientation is different... if that is - // not the case, we can just make the desired rotation be the - // same as the new locked rotation. - switch (lockedRotation) { - case Surface.ROTATION_0: - if (rotation == Surface.ROTATION_180) { - desiredRotation = lockedRotation; - } - break; - case Surface.ROTATION_90: - if (rotation == Surface.ROTATION_270) { - desiredRotation = lockedRotation; - } - break; - case Surface.ROTATION_180: - if (rotation == Surface.ROTATION_0) { - desiredRotation = lockedRotation; - } - break; - case Surface.ROTATION_270: - if (rotation == Surface.ROTATION_90) { - desiredRotation = lockedRotation; - } - break; - } + if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) { + // Rotation updates cannot be performed while the previous rotation change + // animation is still in progress. Skip this update. We will try updating + // again after the animation is finished and the display is unfrozen. + if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress."); + return false; } - changed = mDisplayEnabled && mRotation != rotation; - if (mAltOrientation != (rotation != desiredRotation)) { - changed = true; - mAltOrientation = rotation != desiredRotation; + if (!mDisplayEnabled) { + // No point choosing a rotation if the display is not enabled. + if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled."); + return false; } - if (changed) { - if (DEBUG_ORIENTATION) Slog.v(TAG, - "Rotation changed to " + rotation - + " from " + mRotation - + " (forceApp=" + mForcedAppOrientation - + ", req=" + mRequestedRotation + ")"); - mRotation = rotation; - mWindowsFreezingScreen = true; - mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); - mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), - 2000); - mWaitingForConfig = true; - mLayoutNeeded = true; - startFreezingDisplayLocked(inTransaction); - //Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags); - mInputManager.setDisplayOrientation(0, rotation); - if (mDisplayEnabled) { - // NOTE: We disable the rotation in the emulator because - // it doesn't support hardware OpenGL emulation yet. - if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null - && mScreenRotationAnimation.hasScreenshot()) { - Surface.freezeDisplay(0); - if (!inTransaction) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, - ">>> OPEN TRANSACTION setRotationUnchecked"); - Surface.openTransaction(); - } - try { - if (mScreenRotationAnimation != null) { - mScreenRotationAnimation.setRotation(rotation); - } - } finally { - if (!inTransaction) { - Surface.closeTransaction(); - if (SHOW_TRANSACTIONS) Slog.i(TAG, - "<<< CLOSE TRANSACTION setRotationUnchecked"); - } - } - Surface.setOrientation(0, rotation, animFlags); - Surface.unfreezeDisplay(0); - } else { - Surface.setOrientation(0, rotation, animFlags); - } - rebuildBlackFrame(inTransaction); - } + // TODO: Implement forced rotation changes. + // Set mAltOrientation to indicate that the application is receiving + // an orientation that has different metrics than it expected. + // eg. Portrait instead of Landscape. - for (int i=mWindows.size()-1; i>=0; i--) { - WindowState w = mWindows.get(i); - if (w.mSurface != null) { - w.mOrientationChanging = true; - } + int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation); + boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw( + mForcedAppOrientation, rotation); + + if (DEBUG_ORIENTATION) { + Slog.v(TAG, "Application requested orientation " + + mForcedAppOrientation + ", got rotation " + rotation + + " which has " + (altOrientation ? "incompatible" : "compatible") + + " metrics"); + } + + if (mRotation == rotation && mAltOrientation == altOrientation) { + // No change. + return false; + } + + if (DEBUG_ORIENTATION) { + Slog.v(TAG, + "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "") + + " from " + mRotation + (mAltOrientation ? " (alt)" : "") + + ", forceApp=" + mForcedAppOrientation); + } + + mRotation = rotation; + mAltOrientation = altOrientation; + mPolicy.setRotationLw(mRotation); + + mWindowsFreezingScreen = true; + mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); + mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), 2000); + mWaitingForConfig = true; + mLayoutNeeded = true; + startFreezingDisplayLocked(inTransaction); + mInputManager.setDisplayOrientation(0, rotation); + + // NOTE: We disable the rotation in the emulator because + // it doesn't support hardware OpenGL emulation yet. + if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null + && mScreenRotationAnimation.hasScreenshot()) { + Surface.freezeDisplay(0); + if (!inTransaction) { + if (SHOW_TRANSACTIONS) Slog.i(TAG, + ">>> OPEN TRANSACTION setRotationUnchecked"); + Surface.openTransaction(); } - for (int i=mRotationWatchers.size()-1; i>=0; i--) { - try { - mRotationWatchers.get(i).onRotationChanged(rotation); - } catch (RemoteException e) { + try { + if (mScreenRotationAnimation != null) { + mScreenRotationAnimation.setRotation(rotation); + } + } finally { + if (!inTransaction) { + Surface.closeTransaction(); + if (SHOW_TRANSACTIONS) Slog.i(TAG, + "<<< CLOSE TRANSACTION setRotationUnchecked"); } } - } //end if changed + Surface.setOrientation(0, rotation); + Surface.unfreezeDisplay(0); + } else { + Surface.setOrientation(0, rotation); + } + rebuildBlackFrame(inTransaction); - return changed; + for (int i=mWindows.size()-1; i>=0; i--) { + WindowState w = mWindows.get(i); + if (w.mSurface != null) { + w.mOrientationChanging = true; + } + } + for (int i=mRotationWatchers.size()-1; i>=0; i--) { + try { + mRotationWatchers.get(i).onRotationChanged(rotation); + } catch (RemoteException e) { + } + } + return true; } public int getRotation() { @@ -5723,9 +5732,9 @@ public class WindowManagerService extends IWindowManager.Stub unrotDh = dh; } int sw = reduceConfigWidthSize(unrotDw, Surface.ROTATION_0, density, unrotDw, unrotDh); - sw = reduceConfigWidthSize(sw, Surface.ROTATION_90, density, unrotDw, unrotDh); + sw = reduceConfigWidthSize(sw, Surface.ROTATION_90, density, unrotDh, unrotDw); sw = reduceConfigWidthSize(sw, Surface.ROTATION_180, density, unrotDw, unrotDh); - sw = reduceConfigWidthSize(sw, Surface.ROTATION_270, density, unrotDw, unrotDh); + sw = reduceConfigWidthSize(sw, Surface.ROTATION_270, density, unrotDh, unrotDw); return sw; } @@ -6295,6 +6304,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int DRAG_END_TIMEOUT = 21; public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22; public static final int BOOT_TIMEOUT = 23; + public static final int WAITING_FOR_DRAWN_TIMEOUT = 24; private Session mLastReportedHold; @@ -6605,11 +6615,6 @@ public class WindowManagerService extends IWindowManager.Stub break; } - case BOOT_TIMEOUT: { - performBootTimeout(); - break; - } - case APP_FREEZE_TIMEOUT: { synchronized (mWindowMap) { Slog.w(TAG, "App freeze timeout expired."); @@ -6678,6 +6683,27 @@ public class WindowManagerService extends IWindowManager.Stub notifyHardKeyboardStatusChange(); break; } + + case BOOT_TIMEOUT: { + performBootTimeout(); + break; + } + + case WAITING_FOR_DRAWN_TIMEOUT: { + Pair<WindowState, IRemoteCallback> pair; + synchronized (mWindowMap) { + pair = (Pair<WindowState, IRemoteCallback>)msg.obj; + Slog.w(TAG, "Timeout waiting for drawn: " + pair.first); + if (!mWaitingForDrawn.remove(pair)) { + return; + } + } + try { + pair.second.sendResult(null); + } catch (RemoteException e) { + } + break; + } } } } @@ -8112,10 +8138,10 @@ public class WindowManagerService extends IWindowManager.Stub w.mLastContentInsets.set(w.mContentInsets); w.mLastVisibleInsets.set(w.mVisibleInsets); - // If the screen is currently frozen, then keep - // it frozen until this window draws at its new + // If the screen is currently frozen or off, then keep + // it frozen/off until this window draws at its new // orientation. - if (mDisplayFrozen) { + if (mDisplayFrozen || !mPolicy.isScreenOnFully()) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Resizing while display frozen: " + w); w.mOrientationChanging = true; @@ -8383,7 +8409,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mDimAnimator != null && mDimAnimator.mDimShown) { animating |= mDimAnimator.updateSurface(dimming, currentTime, - mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOn()); + mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully()); } if (!blurring && mBlurShown) { @@ -8575,50 +8601,68 @@ public class WindowManagerService extends IWindowManager.Stub if (updateRotation) { if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation"); - boolean changed = setRotationUncheckedLocked( - WindowManagerPolicy.USE_LAST_ROTATION, 0, false); + boolean changed = updateRotationUncheckedLocked(false); if (changed) { mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); + } else { + updateRotation = false; } } - mWindowMap.notifyAll(); + if (orientationChangeComplete && !needRelayout && !updateRotation) { + checkDrawnWindowsLocked(); + } // Check to see if we are now in a state where the screen should // be enabled, because the window obscured flags have changed. enableScreenIfNeededLocked(); } - public void waitForAllDrawn() { - synchronized (mWindowMap) { - while (true) { - final int N = mWindows.size(); - boolean okay = true; - for (int i=0; i<N && okay; i++) { - WindowState w = mWindows.get(i); - if (DEBUG_SCREEN_ON) { - Slog.i(TAG, "Window " + w + " vis=" + w.isVisibleLw() - + " obscured=" + w.mObscured + " drawn=" + w.isDrawnLw()); + void checkDrawnWindowsLocked() { + if (mWaitingForDrawn.size() > 0) { + for (int j=mWaitingForDrawn.size()-1; j>=0; j--) { + Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j); + WindowState win = pair.first; + //Slog.i(TAG, "Waiting for drawn " + win + ": removed=" + // + win.mRemoved + " visible=" + win.isVisibleLw() + // + " shown=" + win.mSurfaceShown); + if (win.mRemoved || !win.isVisibleLw()) { + // Window has been removed or made invisible; no draw + // will now happen, so stop waiting. + Slog.w(TAG, "Aborted waiting for drawn: " + pair.first); + try { + pair.second.sendResult(null); + } catch (RemoteException e) { } - if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { - if (DEBUG_SCREEN_ON) { - Slog.i(TAG, "Window not yet drawn: " + w); - } - okay = false; - break; + mWaitingForDrawn.remove(pair); + mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair); + } else if (win.mSurfaceShown) { + // Window is now drawn (and shown). + try { + pair.second.sendResult(null); + } catch (RemoteException e) { } - } - if (okay) { - return; - } - try { - mWindowMap.wait(); - } catch (InterruptedException e) { + mWaitingForDrawn.remove(pair); + mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair); } } } } + public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) { + synchronized (mWindowMap) { + WindowState win = windowForClientLocked(null, token, true); + if (win != null) { + Pair<WindowState, IRemoteCallback> pair = + new Pair<WindowState, IRemoteCallback>(win, callback); + Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair); + mH.sendMessageDelayed(m, 2000); + mWaitingForDrawn.add(pair); + checkDrawnWindowsLocked(); + } + } + } + /** * Must be called with the main window manager lock held. */ @@ -8885,7 +8929,7 @@ public class WindowManagerService extends IWindowManager.Stub return; } - if (mDisplay == null || !mPolicy.isScreenOn()) { + if (mDisplay == null || !mPolicy.isScreenOnFully()) { // No need to freeze the screen before the system is ready or if // the screen is off. return; @@ -8984,8 +9028,7 @@ public class WindowManagerService extends IWindowManager.Stub if (updateRotation) { if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation"); - configChanged |= setRotationUncheckedLocked( - WindowManagerPolicy.USE_LAST_ROTATION, 0, false); + configChanged |= updateRotationUncheckedLocked(false); } if (configChanged) { @@ -9284,6 +9327,15 @@ public class WindowManagerService extends IWindowManager.Stub } } } + if (mWaitingForDrawn.size() > 0) { + pw.println(); + pw.println(" Clients waiting for these windows to be drawn:"); + for (int i=mWaitingForDrawn.size()-1; i>=0; i--) { + Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i); + pw.print(" Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first); + pw.print(": "); pw.println(pair.second); + } + } pw.println(); if (mDisplay != null) { pw.print(" Display: init="); pw.print(mInitialDisplayWidth); pw.print("x"); @@ -9349,12 +9401,10 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen); pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig); pw.print(" mRotation="); pw.print(mRotation); - pw.print(" mRequestedRotation="); pw.print(mRequestedRotation); pw.print(" mAltOrientation="); pw.println(mAltOrientation); pw.print(" mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation); pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation); - pw.print(" mDeferredRotation="); pw.print(mDeferredRotation); - pw.print(", mDeferredRotationAnimFlags="); pw.println(mDeferredRotationAnimFlags); + pw.print(" mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount); pw.print(" mAnimationPending="); pw.print(mAnimationPending); pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale); pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale); diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 0ee3f17..455d664 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -870,7 +870,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { // This must be called while inside a transaction. Returns true if // there is more animation to run. boolean stepAnimationLocked(long currentTime, int dw, int dh) { - if (!mService.mDisplayFrozen && mService.mPolicy.isScreenOn()) { + if (!mService.mDisplayFrozen && mService.mPolicy.isScreenOnFully()) { // We will run animations as long as the display isn't frozen. if (!mDrawPending && !mCommitDrawPending && mAnimation != null) { @@ -1101,7 +1101,20 @@ final class WindowState implements WindowManagerPolicy.WindowState { final Matrix tmpMatrix = mTmpMatrix; // Compute the desired transformation. - tmpMatrix.setTranslate(0, 0); + if (screenAnimation) { + // 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 + // to see what is behind them. An unsightly mess. This... + // thing... magically makes it call good: scale each window + // slightly (two pixels larger in each dimension, from the + // window's center). + final float w = frame.width(); + final float h = frame.height(); + tmpMatrix.setScale(1 + 2/w, 1 + 2/h, w/2, h/2); + } else { + tmpMatrix.reset(); + } tmpMatrix.postScale(mGlobalScale, mGlobalScale); if (selfTransformation) { tmpMatrix.postConcat(mTransformation.getMatrix()); @@ -1204,11 +1217,18 @@ final class WindowState implements WindowManagerPolicy.WindowState { * mPolicyVisibility. Ungh. */ public boolean isVisibleOrBehindKeyguardLw() { + if (mRootToken.waitingToShow && + mService.mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { + return false; + } final AppWindowToken atoken = mAppToken; - return mSurface != null && !mAttachedHidden + final boolean animating = atoken != null + ? (atoken.animation != null) : false; + return mSurface != null && !mDestroying && !mExiting && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested) - && !mDrawPending && !mCommitDrawPending - && !mExiting && !mDestroying; + && ((!mAttachedHidden && mViewVisibility == View.VISIBLE + && !mRootToken.hidden) + || mAnimation != null || animating); } /** @@ -1351,7 +1371,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { && (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left) && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove()) - && mService.mPolicy.isScreenOn(); + && mService.mPolicy.isScreenOnFully(); } boolean isFullscreen(int screenWidth, int screenHeight) { @@ -1436,7 +1456,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (doAnimation) { if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "doAnimation: mPolicyVisibility=" + mPolicyVisibility + " mAnimation=" + mAnimation); - if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOn()) { + if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOnFully()) { doAnimation = false; } else if (mPolicyVisibility && mAnimation == null) { // Check for the case where we are currently visible and @@ -1462,7 +1482,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean hideLw(boolean doAnimation, boolean requestAnim) { if (doAnimation) { - if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOn()) { + if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOnFully()) { doAnimation = false; } } |