diff options
Diffstat (limited to 'services/java/com/android')
26 files changed, 1021 insertions, 465 deletions
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index eb75ebc..2af5103 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -751,10 +751,13 @@ class AppWidgetService extends IAppWidgetService.Stub return; } ArrayList<AppWidgetId> instances = p.instances; + final int callingUid = getCallingUid(); final int N = instances.size(); for (int i=0; i<N; i++) { AppWidgetId id = instances.get(i); - updateAppWidgetInstanceLocked(id, views); + if (canAccessAppWidgetId(id, callingUid)) { + updateAppWidgetInstanceLocked(id, views); + } } } } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 8c42f31..6e4aca7 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -26,8 +26,10 @@ import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import android.bluetooth.BluetoothTetheringDataTracker; import android.content.ContentResolver; import android.content.Context; +import android.content.ContextWrapper; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.database.ContentObserver; import android.net.ConnectivityManager; import android.net.DummyDataStateTracker; @@ -51,6 +53,7 @@ import android.net.Proxy; import android.net.ProxyProperties; import android.net.RouteInfo; import android.net.wifi.WifiStateTracker; +import android.net.wimax.WimaxManagerConstants; import android.os.Binder; import android.os.FileUtils; import android.os.Handler; @@ -78,10 +81,14 @@ import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.google.android.collect.Lists; import com.google.android.collect.Sets; - +import dalvik.system.DexClassLoader; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.InvocationTargetException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; @@ -491,6 +498,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance(); mNetTrackers[netType].startMonitoring(context, mHandler); break; + case ConnectivityManager.TYPE_WIMAX: + mNetTrackers[netType] = makeWimaxStateTracker(); + if (mNetTrackers[netType]!= null) { + mNetTrackers[netType].startMonitoring(context, mHandler); + } + break; case ConnectivityManager.TYPE_ETHERNET: mNetTrackers[netType] = EthernetDataTracker.getInstance(); mNetTrackers[netType].startMonitoring(context, mHandler); @@ -501,7 +514,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { continue; } mCurrentLinkProperties[netType] = null; - if (mNetConfigs[netType].isDefault()) mNetTrackers[netType].reconnect(); + if (mNetTrackers[netType] != null && mNetConfigs[netType].isDefault()) { + mNetTrackers[netType].reconnect(); + } } IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); @@ -531,7 +546,81 @@ public class ConnectivityService extends IConnectivityManager.Stub { loadGlobalProxy(); } +private NetworkStateTracker makeWimaxStateTracker() { + //Initialize Wimax + DexClassLoader wimaxClassLoader; + Class wimaxStateTrackerClass = null; + Class wimaxServiceClass = null; + Class wimaxManagerClass; + String wimaxJarLocation; + String wimaxLibLocation; + String wimaxManagerClassName; + String wimaxServiceClassName; + String wimaxStateTrackerClassName; + + NetworkStateTracker wimaxStateTracker = null; + + boolean isWimaxEnabled = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_wimaxEnabled); + + if (isWimaxEnabled) { + try { + wimaxJarLocation = mContext.getResources().getString( + com.android.internal.R.string.config_wimaxServiceJarLocation); + wimaxLibLocation = mContext.getResources().getString( + com.android.internal.R.string.config_wimaxNativeLibLocation); + wimaxManagerClassName = mContext.getResources().getString( + com.android.internal.R.string.config_wimaxManagerClassname); + wimaxServiceClassName = mContext.getResources().getString( + com.android.internal.R.string.config_wimaxServiceClassname); + wimaxStateTrackerClassName = mContext.getResources().getString( + com.android.internal.R.string.config_wimaxStateTrackerClassname); + + log("wimaxJarLocation: " + wimaxJarLocation); + wimaxClassLoader = new DexClassLoader(wimaxJarLocation, + new ContextWrapper(mContext).getCacheDir().getAbsolutePath(), + wimaxLibLocation, ClassLoader.getSystemClassLoader()); + + try { + wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName); + wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName); + wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName); + } catch (ClassNotFoundException ex) { + loge("Exception finding Wimax classes: " + ex.toString()); + return null; + } + } catch(Resources.NotFoundException ex) { + loge("Wimax Resources does not exist!!! "); + return null; + } + + try { + log("Starting Wimax Service... "); + + Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor + (new Class[] {Context.class, Handler.class}); + wimaxStateTracker = (NetworkStateTracker)wmxStTrkrConst.newInstance(mContext, + mHandler); + + Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor + (new Class[] {Context.class, wimaxStateTrackerClass}); + wmxSrvConst.setAccessible(true); + IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(mContext, wimaxStateTracker); + wmxSrvConst.setAccessible(false); + + ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker); + } catch(Exception ex) { + loge("Exception creating Wimax classes: " + ex.toString()); + return null; + } + } else { + loge("Wimax is not enabled or not added to the network attributes!!! "); + return null; + } + + return wimaxStateTracker; + } /** * Sets the preferred network. * @param preference the new preference @@ -1508,6 +1597,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (checkType == prevNetType) continue; if (mNetConfigs[checkType] == null) continue; if (!mNetConfigs[checkType].isDefault()) continue; + if (mNetTrackers[checkType] == null) continue; // Enabling the isAvailable() optimization caused mobile to not get // selected if it was in the middle of error handling. Specifically diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java index dea9007..64789d3 100644 --- a/services/java/com/android/server/DockObserver.java +++ b/services/java/com/android/server/DockObserver.java @@ -82,7 +82,9 @@ class DockObserver extends UEventObserver { // Don't force screen on when undocking from the desk dock. // The change in power state will do this anyway. // FIXME - we should be configurable. - if (mPreviousDockState != Intent.EXTRA_DOCK_STATE_DESK || + if ((mPreviousDockState != Intent.EXTRA_DOCK_STATE_DESK + && mPreviousDockState != Intent.EXTRA_DOCK_STATE_LE_DESK + && mPreviousDockState != Intent.EXTRA_DOCK_STATE_HE_DESK) || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) { mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(), false, true); diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 6ddbf5a..ddac35c 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -161,6 +161,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans = new LruCache<SuggestionSpan, InputMethodInfo>(SECURE_SUGGESTION_SPANS_MAX_SIZE); + // Used to bring IME service up to visible adjustment while it is being shown. + final ServiceConnection mVisibleConnection = new ServiceConnection() { + @Override public void onServiceConnected(ComponentName name, IBinder service) { + } + + @Override public void onServiceDisconnected(ComponentName name) { + } + }; + boolean mVisibleBound = false; + // Ongoing notification private NotificationManager mNotificationManager; private KeyguardManager mKeyguardManager; @@ -374,6 +384,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mScreenOn = true; } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { mScreenOn = false; + setImeWindowVisibilityStatusHiddenLocked(); } else if (intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { hideInputMethodMenu(); return; @@ -468,8 +479,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // Uh oh, current input method is no longer around! // Pick another one... Slog.i(TAG, "Current input method removed: " + curInputMethodId); - mImeWindowVis = 0; - updateImeWindowStatusLocked(); + setImeWindowVisibilityStatusHiddenLocked(); if (!chooseNewDefaultIMELocked()) { changed = true; curIm = null; @@ -493,11 +503,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - class MethodCallback extends IInputMethodCallback.Stub { - final IInputMethod mMethod; + private static class MethodCallback extends IInputMethodCallback.Stub { + private final IInputMethod mMethod; + private final InputMethodManagerService mParentIMMS; - MethodCallback(IInputMethod method) { + MethodCallback(final IInputMethod method, final InputMethodManagerService imms) { mMethod = method; + mParentIMMS = imms; } @Override @@ -506,7 +518,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public void sessionCreated(IInputMethodSession session) throws RemoteException { - onSessionCreated(mMethod, session); + mParentIMMS.onSessionCreated(mMethod, session); } } @@ -623,7 +635,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - void updateImeWindowStatusLocked() { + private void setImeWindowVisibilityStatusHiddenLocked() { + mImeWindowVis = 0; + updateImeWindowStatusLocked(); + } + + private void updateImeWindowStatusLocked() { setImeWindowStatus(mCurToken, mImeWindowVis, mBackDisposition); } @@ -837,7 +854,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs); executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( MSG_CREATE_SESSION, mCurMethod, - new MethodCallback(mCurMethod))); + new MethodCallback(mCurMethod, this))); } // Return to client, and we will get back with it when // we have had a session made for it. @@ -886,7 +903,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub com.android.internal.R.string.input_method_binding_label); mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0)); - if (mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE)) { + if (mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE + | Context.BIND_NOT_VISIBLE)) { mLastBindTime = SystemClock.uptimeMillis(); mHaveConnection = true; mCurId = info.getId(); @@ -943,7 +961,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + mCurClient); executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( MSG_CREATE_SESSION, mCurMethod, - new MethodCallback(mCurMethod))); + new MethodCallback(mCurMethod, this))); } } } @@ -968,6 +986,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } void unbindCurrentMethodLocked(boolean reportToClient) { + if (mVisibleBound) { + mContext.unbindService(mVisibleConnection); + mVisibleBound = false; + } + if (mHaveConnection) { mContext.unbindService(this); mHaveConnection = false; @@ -997,8 +1020,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub sessionState.session.finishSession(); } catch (RemoteException e) { Slog.w(TAG, "Session failed to close due to remote exception", e); - mImeWindowVis = 0; - updateImeWindowStatusLocked(); + setImeWindowVisibilityStatusHiddenLocked(); } } } @@ -1360,6 +1382,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod, resultReceiver)); mInputShown = true; + if (mHaveConnection && !mVisibleBound) { + mContext.bindService(mCurIntent, mVisibleConnection, Context.BIND_AUTO_CREATE); + mVisibleBound = true; + } res = true; } else if (mHaveConnection && SystemClock.uptimeMillis() >= (mLastBindTime+TIME_TO_RECONNECT)) { @@ -1371,7 +1397,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub SystemClock.uptimeMillis()-mLastBindTime,1); Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()"); mContext.unbindService(this); - mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE); + mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE + | Context.BIND_NOT_VISIBLE); } return res; @@ -1393,13 +1420,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (!mIWindowManager.inputMethodClientHasFocus(client)) { if (DEBUG) Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client); - mImeWindowVis = 0; - updateImeWindowStatusLocked(); + setImeWindowVisibilityStatusHiddenLocked(); return false; } } catch (RemoteException e) { - mImeWindowVis = 0; - updateImeWindowStatusLocked(); + setImeWindowVisibilityStatusHiddenLocked(); return false; } } @@ -1432,6 +1457,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } else { res = false; } + if (mHaveConnection && mVisibleBound) { + mContext.unbindService(mVisibleConnection); + mVisibleBound = false; + } mInputShown = false; mShowRequested = false; mShowExplicitlyRequested = false; diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index 4c26dbb..da960ae 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -247,6 +247,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub * Notify our observers of an interface removal. */ private void notifyInterfaceRemoved(String iface) { + // netd already clears out quota and alerts for removed ifaces; update + // our sanity-checking state. + mActiveAlertIfaces.remove(iface); + mActiveQuotaIfaces.remove(iface); + for (INetworkManagementEventObserver obs : mObservers) { try { obs.interfaceRemoved(iface); @@ -1131,12 +1136,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub final StringBuilder command = new StringBuilder(); command.append("bandwidth removeiquota ").append(iface); + mActiveQuotaIfaces.remove(iface); + mActiveAlertIfaces.remove(iface); + try { // TODO: support quota shared across interfaces mConnector.doCommand(command.toString()); - mActiveQuotaIfaces.remove(iface); - mActiveAlertIfaces.remove(iface); } catch (NativeDaemonConnectorException e) { + // TODO: include current iptables state throw new IllegalStateException("Error communicating to native daemon", e); } } diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index fdae4bd..6b23b33 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -100,10 +100,13 @@ public class PowerManagerService extends IPowerManager.Stub private static final int LONG_KEYLIGHT_DELAY = 6000; // t+6 sec private static final int LONG_DIM_TIME = 7000; // t+N-5 sec - // How long to wait to debounce light sensor changes. + // How long to wait to debounce light sensor changes in milliseconds private static final int LIGHT_SENSOR_DELAY = 2000; - // For debouncing the proximity sensor. + // light sensor events rate in microseconds + private static final int LIGHT_SENSOR_RATE = 1000000; + + // For debouncing the proximity sensor in milliseconds private static final int PROXIMITY_SENSOR_DELAY = 1000; // trigger proximity if distance is less than 5 cm @@ -2198,25 +2201,21 @@ public class PowerManagerService extends IPowerManager.Stub } public void run() { - if (mAnimateScreenLights) { - synchronized (mLocks) { + synchronized (mLocks) { + // we're turning off + final boolean turningOff = animating && targetValue == Power.BRIGHTNESS_OFF; + if (mAnimateScreenLights || !turningOff) { long now = SystemClock.uptimeMillis(); boolean more = mScreenBrightness.stepLocked(); if (more) { mScreenOffHandler.postAtTime(this, now+(1000/60)); } - } - } else { - synchronized (mLocks) { - // we're turning off - final boolean animate = animating && targetValue == Power.BRIGHTNESS_OFF; - if (animate) { - // It's pretty scary to hold mLocks for this long, and we should - // redesign this, but it works for now. - nativeStartSurfaceFlingerAnimation( - mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR - ? 0 : mAnimationSetting); - } + } else { + // It's pretty scary to hold mLocks for this long, and we should + // redesign this, but it works for now. + nativeStartSurfaceFlingerAnimation( + mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR + ? 0 : mAnimationSetting); mScreenBrightness.jumpToTargetLocked(); } } @@ -3053,7 +3052,7 @@ public class PowerManagerService extends IPowerManager.Stub try { if (enable) { mSensorManager.registerListener(mLightListener, mLightSensor, - SensorManager.SENSOR_DELAY_NORMAL); + LIGHT_SENSOR_RATE); } else { mSensorManager.unregisterListener(mLightListener); mHandler.removeCallbacks(mAutoBrightnessTask); diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java index 1976eba..af9152d 100644 --- a/services/java/com/android/server/TextServicesManagerService.java +++ b/services/java/com/android/server/TextServicesManagerService.java @@ -40,6 +40,8 @@ import android.provider.Settings; import android.service.textservice.SpellCheckerService; import android.text.TextUtils; import android.util.Slog; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; import android.view.textservice.SpellCheckerInfo; import android.view.textservice.SpellCheckerSubtype; @@ -222,20 +224,40 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { if (hashCode == 0 && !allowImplicitlySelectedSubtype) { return null; } - final String systemLocale = - mContext.getResources().getConfiguration().locale.toString(); + String candidateLocale = null; + if (hashCode == 0) { + // Spell checker language settings == "auto" + final InputMethodManager imm = + (InputMethodManager)mContext.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + final InputMethodSubtype currentInputMethodSubtype = + imm.getCurrentInputMethodSubtype(); + if (currentInputMethodSubtype != null) { + final String localeString = currentInputMethodSubtype.getLocale(); + if (!TextUtils.isEmpty(localeString)) { + // 1. Use keyboard locale if available in the spell checker + candidateLocale = localeString; + } + } + } + if (candidateLocale == null) { + // 2. Use System locale if available in the spell checker + candidateLocale = mContext.getResources().getConfiguration().locale.toString(); + } + } SpellCheckerSubtype candidate = null; for (int i = 0; i < sci.getSubtypeCount(); ++i) { final SpellCheckerSubtype scs = sci.getSubtypeAt(i); if (hashCode == 0) { - if (systemLocale.equals(locale)) { + if (candidateLocale.equals(locale)) { return scs; } else if (candidate == null) { final String scsLocale = scs.getLocale(); - if (systemLocale.length() >= 2 + if (candidateLocale.length() >= 2 && scsLocale.length() >= 2 - && systemLocale.substring(0, 2).equals( + && candidateLocale.substring(0, 2).equals( scsLocale.substring(0, 2))) { + // Fall back to the applicable language candidate = scs; } } @@ -244,9 +266,13 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale + ", " + scs.getLocale()); } + // 3. Use the user specified spell check language return scs; } } + // 4. Fall back to the applicable language and return it if not null + // 5. Simply just return it even if it's null which means we could find no suitable + // spell check languages return candidate; } } @@ -635,7 +661,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { if (DBG) { Slog.w(TAG, "Remove " + removeList.get(i)); } - mListeners.remove(removeList.get(i)); + final InternalDeathRecipient idr = removeList.get(i); + idr.mScListener.asBinder().unlinkToDeath(idr, 0); + mListeners.remove(idr); } cleanLocked(); } @@ -664,6 +692,11 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { public void removeAll() { Slog.e(TAG, "Remove the spell checker bind unexpectedly."); synchronized(mSpellCheckerMap) { + final int size = mListeners.size(); + for (int i = 0; i < size; ++i) { + final InternalDeathRecipient idr = mListeners.get(i); + idr.mScListener.asBinder().unlinkToDeath(idr, 0); + } mListeners.clear(); cleanLocked(); } diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java index 431cc39..280b329 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/java/com/android/server/UiModeManagerService.java @@ -123,6 +123,10 @@ class UiModeManagerService extends IUiModeManager.Stub { @Override public void onReceive(Context context, Intent intent) { if (getResultCode() != Activity.RESULT_OK) { + if (LOG) { + Slog.v(TAG, "Handling broadcast result for action " + intent.getAction() + + ": canceled: " + getResultCode()); + } return; } @@ -151,6 +155,12 @@ class UiModeManagerService extends IUiModeManager.Stub { category = Intent.CATEGORY_HOME; } } + + if (LOG) { + Slog.v(TAG, String.format( + "Handling broadcast result for action %s: enable=0x%08x disable=0x%08x category=%s", + intent.getAction(), enableFlags, disableFlags, category)); + } if (category != null) { // This is the new activity that will serve as home while @@ -424,11 +434,22 @@ class UiModeManagerService extends IUiModeManager.Stub { } } + final static boolean isDeskDockState(int state) { + switch (state) { + case Intent.EXTRA_DOCK_STATE_DESK: + case Intent.EXTRA_DOCK_STATE_LE_DESK: + case Intent.EXTRA_DOCK_STATE_HE_DESK: + return true; + default: + return false; + } + } + final void updateConfigurationLocked(boolean sendIt) { int uiMode = Configuration.UI_MODE_TYPE_NORMAL; if (mCarModeEnabled) { uiMode = Configuration.UI_MODE_TYPE_CAR; - } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { + } else if (isDeskDockState(mDockState)) { uiMode = Configuration.UI_MODE_TYPE_DESK; } if (mCarModeEnabled) { @@ -477,7 +498,7 @@ class UiModeManagerService extends IUiModeManager.Stub { if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) { adjustStatusBarCarModeLocked(); oldAction = UiModeManager.ACTION_EXIT_CAR_MODE; - } else if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_DESK) { + } else if (isDeskDockState(mLastBroadcastState)) { oldAction = UiModeManager.ACTION_EXIT_DESK_MODE; } @@ -491,12 +512,12 @@ class UiModeManagerService extends IUiModeManager.Stub { mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR; action = UiModeManager.ACTION_ENTER_CAR_MODE; } - } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { - if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_DESK) { + } else if (isDeskDockState(mDockState)) { + if (!isDeskDockState(mLastBroadcastState)) { if (oldAction != null) { mContext.sendBroadcast(new Intent(oldAction)); } - mLastBroadcastState = Intent.EXTRA_DOCK_STATE_DESK; + mLastBroadcastState = mDockState; action = UiModeManager.ACTION_ENTER_DESK_MODE; } } else { @@ -505,6 +526,12 @@ class UiModeManagerService extends IUiModeManager.Stub { } if (action != null) { + if (LOG) { + Slog.v(TAG, String.format( + "updateLocked: preparing broadcast: action=%s enable=0x%08x disable=0x%08x", + action, enableFlags, disableFlags)); + } + // Send the ordered broadcast; the result receiver will receive after all // broadcasts have been sent. If any broadcast receiver changes the result // code from the initial value of RESULT_OK, then the result receiver will @@ -526,7 +553,7 @@ class UiModeManagerService extends IUiModeManager.Stub { if ((enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) { homeIntent = buildHomeIntent(Intent.CATEGORY_CAR_DOCK); } - } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { + } else if (isDeskDockState(mDockState)) { if ((enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) { homeIntent = buildHomeIntent(Intent.CATEGORY_DESK_DOCK); } @@ -535,6 +562,12 @@ class UiModeManagerService extends IUiModeManager.Stub { homeIntent = buildHomeIntent(Intent.CATEGORY_HOME); } } + + if (LOG) { + Slog.v(TAG, "updateLocked: null action, mDockState=" + + mDockState +", firing homeIntent: " + homeIntent); + } + if (homeIntent != null) { try { mContext.startActivity(homeIntent); diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java index 2d3ac00..728fb26 100644 --- a/services/java/com/android/server/Watchdog.java +++ b/services/java/com/android/server/Watchdog.java @@ -451,7 +451,8 @@ public class Watchdog extends Thread { Thread dropboxThread = new Thread("watchdogWriteToDropbox") { public void run() { mActivity.addErrorToDropBox( - "watchdog", null, null, null, name, null, stack, null); + "watchdog", null, "system_server", null, null, + name, null, stack, null); } }; dropboxThread.start(); diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 5bfe6f8..3c65255 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -619,12 +619,7 @@ public class WifiService extends IWifiManager.Stub { */ public WifiConfiguration getWifiApConfiguration() { enforceAccessPermission(); - if (mWifiStateMachineChannel != null) { - return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel); - } else { - Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); - return null; - } + return mWifiStateMachine.syncGetWifiApConfiguration(); } /** @@ -921,18 +916,14 @@ public class WifiService extends IWifiManager.Stub { Slog.d(TAG, "ACTION_SCREEN_ON"); } mAlarmManager.cancel(mIdleIntent); - mDeviceIdle = false; mScreenOff = false; - // Once the screen is on, we are not keeping WIFI running - // because of any locks so clear that tracking immediately. - reportStartWorkSource(); evaluateTrafficStatsPolling(); mWifiStateMachine.enableRssiPolling(true); if (mBackgroundScanSupported) { mWifiStateMachine.enableBackgroundScanCommand(false); } mWifiStateMachine.enableAllNetworks(); - updateWifiState(); + setDeviceIdleAndUpdateWifi(false); } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { if (DBG) { Slog.d(TAG, "ACTION_SCREEN_OFF"); @@ -950,36 +941,17 @@ public class WifiService extends IWifiManager.Stub { * or plugged in to AC). */ if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) { - WifiInfo info = mWifiStateMachine.syncRequestConnectionInfo(); - if (info.getSupplicantState() != SupplicantState.COMPLETED) { - // we used to go to sleep immediately, but this caused some race conditions - // we don't have time to track down for this release. Delay instead, - // but not as long as we would if connected (below) - // TODO - fix the race conditions and switch back to the immediate turn-off - long triggerTime = System.currentTimeMillis() + (2*60*1000); // 2 min - if (DBG) { - Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for 120,000 ms"); - } - mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); - // // do not keep Wifi awake when screen is off if Wifi is not associated - // mDeviceIdle = true; - // updateWifiState(); + //Delayed shutdown if wifi is connected + if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { + if (DBG) Slog.d(TAG, "setting ACTION_DEVICE_IDLE: " + idleMillis + " ms"); + mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + + idleMillis, mIdleIntent); } else { - long triggerTime = System.currentTimeMillis() + idleMillis; - if (DBG) { - Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis - + "ms"); - } - mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); + setDeviceIdleAndUpdateWifi(true); } } } else if (action.equals(ACTION_DEVICE_IDLE)) { - if (DBG) { - Slog.d(TAG, "got ACTION_DEVICE_IDLE"); - } - mDeviceIdle = true; - reportStartWorkSource(); - updateWifiState(); + setDeviceIdleAndUpdateWifi(true); } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { /* * Set a timer to put Wi-Fi to sleep, but only if the screen is off @@ -1056,6 +1028,12 @@ public class WifiService extends IWifiManager.Stub { } }; + private void setDeviceIdleAndUpdateWifi(boolean deviceIdle) { + mDeviceIdle = deviceIdle; + reportStartWorkSource(); + updateWifiState(); + } + private synchronized void reportStartWorkSource() { mTmpWorkSource.clear(); if (mDeviceIdle) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 2a867af..cd63090 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -296,7 +296,7 @@ public final class ActivityManagerService extends ActivityManagerNative /** * Historical data of past broadcasts, for debugging. */ - static final int MAX_BROADCAST_HISTORY = 100; + static final int MAX_BROADCAST_HISTORY = 25; final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY]; @@ -411,6 +411,12 @@ public final class ActivityManagerService extends ActivityManagerNative ProcessRecord mHomeProcess; /** + * This is the process holding the activity the user last visited that + * is in a different process from the one they are currently in. + */ + ProcessRecord mPreviousProcess; + + /** * Packages that the user has asked to have run in screen size * compatibility mode instead of filling the screen. */ @@ -724,6 +730,13 @@ public final class ActivityManagerService extends ActivityManagerNative int mLruSeq = 0; /** + * Keep track of the number of service processes we last found, to + * determine on the next iteration which should be B services. + */ + int mNumServiceProcs = 0; + int mNewNumServiceProcs = 0; + + /** * System monitoring: number of processes that died since the last * N procs were started. */ @@ -1207,6 +1220,8 @@ public final class ActivityManagerService extends ActivityManagerNative } Thread thread = new Thread() { @Override public void run() { + StringBuilder dropBuilder = new StringBuilder(1024); + StringBuilder logBuilder = new StringBuilder(1024); try { java.lang.Process proc = Runtime.getRuntime().exec(new String[] { "procrank", }); @@ -1220,16 +1235,29 @@ public final class ActivityManagerService extends ActivityManagerNative break; } if (line.length() > 0) { - Slog.i(TAG, line); + logBuilder.append(line); + logBuilder.append('\n'); } + dropBuilder.append(line); + dropBuilder.append('\n'); } converter.close(); } catch (IOException e) { } StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); - dumpApplicationMemoryUsage(null, pw, " ", new String[] { }, true); - Slog.i(TAG, sw.toString()); + StringWriter catSw = new StringWriter(); + PrintWriter catPw = new PrintWriter(catSw); + dumpApplicationMemoryUsage(null, pw, " ", new String[] { }, true, catPw); + String memUsage = sw.toString(); + dropBuilder.append('\n'); + dropBuilder.append(memUsage); + dropBuilder.append(catSw.toString()); + logBuilder.append(memUsage); + addErrorToDropBox("watchdog", null, "system_server", null, + null, "Low on memory -- no more background processes", + dropBuilder.toString(), null, null); + Slog.i(TAG, logBuilder.toString()); synchronized (ActivityManagerService.this) { long now = SystemClock.uptimeMillis(); if (mLastMemUsageReportTime < now) { @@ -1381,7 +1409,7 @@ public final class ActivityManagerService extends ActivityManagerNative return; } - mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false); + mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null); } } @@ -1641,7 +1669,7 @@ public final class ActivityManagerService extends ActivityManagerNative final void setFocusedActivityLocked(ActivityRecord r) { if (mFocusedActivity != r) { mFocusedActivity = r; - mWindowManager.setFocusedApp(r, true); + mWindowManager.setFocusedApp(r.appToken, true); } } @@ -2318,7 +2346,8 @@ public final class ActivityManagerService extends ActivityManagerNative // XXX we are not dealing with propagating grantedUriPermissions... // those are not yet exposed to user code, so there is no need. int res = mMainStack.startActivityLocked(r.app.thread, intent, - r.resolvedType, null, 0, aInfo, resultTo, resultWho, + r.resolvedType, null, 0, aInfo, + resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1, r.launchedFromUid, false, false, null); Binder.restoreCallingIdentity(origId); @@ -2401,10 +2430,10 @@ public final class ActivityManagerService extends ActivityManagerNative return; } final long origId = Binder.clearCallingIdentity(); - mWindowManager.setAppOrientation(r, requestedOrientation); + mWindowManager.setAppOrientation(r.appToken, requestedOrientation); Configuration config = mWindowManager.updateOrientationFromAppTokens( mConfiguration, - r.mayFreezeScreenLocked(r.app) ? r : null); + r.mayFreezeScreenLocked(r.app) ? r.appToken : null); if (config != null) { r.frozenBeforeDestroy = true; if (!updateConfigurationLocked(config, r, false)) { @@ -2421,7 +2450,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (r == null) { return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } - return mWindowManager.getAppOrientation(r); + return mWindowManager.getAppOrientation(r.appToken); } } @@ -2487,7 +2516,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i<activities.size(); i++) { ActivityRecord r = activities.get(i); if (!r.finishing) { - int index = mMainStack.indexOfTokenLocked(r); + int index = mMainStack.indexOfTokenLocked(r.appToken); if (index >= 0) { mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED, null, "finish-heavy"); @@ -2589,7 +2618,7 @@ public final class ActivityManagerService extends ActivityManagerNative int i; for (i=mMainStack.mHistory.size()-1; i>=0; i--) { ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); - if (r == token) { + if (r.appToken == token) { return true; } if (r.fullscreen && !r.finishing) { @@ -2677,9 +2706,9 @@ public final class ActivityManagerService extends ActivityManagerNative r.makeFinishing(); mMainStack.mHistory.remove(i); r.takeFromHistory(); - mWindowManager.removeAppToken(r); + mWindowManager.removeAppToken(r.appToken); if (VALIDATE_TOKENS) { - mWindowManager.validateAppTokens(mMainStack.mHistory); + mMainStack.validateAppTokensLocked(); } r.removeUriPermissionsLocked(); @@ -3034,7 +3063,8 @@ public final class ActivityManagerService extends ActivityManagerNative Process.sendSignal(app.pid, Process.SIGNAL_QUIT); } - addErrorToDropBox("anr", app, activity, parent, annotation, cpuInfo, tracesFile, null); + addErrorToDropBox("anr", app, app.processName, activity, parent, annotation, + cpuInfo, tracesFile, null); if (mController != null) { try { @@ -3178,7 +3208,49 @@ public final class ActivityManagerService extends ActivityManagerNative return; } killPackageProcessesLocked(packageName, pkgUid, - ProcessList.SECONDARY_SERVER_ADJ, false, true, true, false); + ProcessList.SERVICE_ADJ, false, true, true, false, "kill background"); + } + } finally { + Binder.restoreCallingIdentity(callingId); + } + } + + public void killAllBackgroundProcesses() { + if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES) + != PackageManager.PERMISSION_GRANTED) { + String msg = "Permission Denial: killAllBackgroundProcesses() from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid() + + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + + long callingId = Binder.clearCallingIdentity(); + try { + synchronized(this) { + ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(); + for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) { + final int NA = apps.size(); + for (int ia=0; ia<NA; ia++) { + ProcessRecord app = apps.valueAt(ia); + if (app.persistent) { + // we don't kill persistent processes + continue; + } + if (app.removed) { + procs.add(app); + } else if (app.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) { + app.removed = true; + procs.add(app); + } + } + } + + int N = procs.size(); + for (int i=0; i<N; i++) { + removeProcessLocked(procs.get(i), false, true, "kill all background"); + } } } finally { Binder.restoreCallingIdentity(callingId); @@ -3350,7 +3422,7 @@ public final class ActivityManagerService extends ActivityManagerNative private final boolean killPackageProcessesLocked(String packageName, int uid, int minOomAdj, boolean callerWillRestart, boolean allowRestart, boolean doit, - boolean evenPersistent) { + boolean evenPersistent, String reason) { ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(); // Remove all processes this package may have touched: all with the @@ -3385,7 +3457,7 @@ public final class ActivityManagerService extends ActivityManagerNative int N = procs.size(); for (int i=0; i<N; i++) { - removeProcessLocked(procs.get(i), callerWillRestart, allowRestart); + removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason); } return N > 0; } @@ -3416,7 +3488,7 @@ public final class ActivityManagerService extends ActivityManagerNative } boolean didSomething = killPackageProcessesLocked(name, uid, -100, - callerWillRestart, false, doit, evenPersistent); + callerWillRestart, false, doit, evenPersistent, "force stop"); TaskRecord lastTask = null; for (i=0; i<mMainStack.mHistory.size(); i++) { @@ -3504,11 +3576,11 @@ public final class ActivityManagerService extends ActivityManagerNative } private final boolean removeProcessLocked(ProcessRecord app, - boolean callerWillRestart, boolean allowRestart) { + boolean callerWillRestart, boolean allowRestart, String reason) { final String name = app.processName; final int uid = app.info.uid; if (DEBUG_PROCESSES) Slog.d( - TAG, "Force removing process " + app + " (" + name + TAG, "Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")"); mProcessNames.remove(name, uid); @@ -3523,9 +3595,10 @@ public final class ActivityManagerService extends ActivityManagerNative mPidsSelfLocked.remove(pid); mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); } + Slog.i(TAG, "Killing proc " + app.toShortString() + ": " + reason); handleAppDiedLocked(app, true, allowRestart); mLruProcesses.remove(app); - Process.killProcess(pid); + Process.killProcessQuiet(pid); if (app.persistent) { if (!callerWillRestart) { @@ -4977,7 +5050,7 @@ public final class ActivityManagerService extends ActivityManagerNative outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((hiddenAppMem-homeAppMem)/2)); outInfo.hiddenAppThreshold = hiddenAppMem; outInfo.secondaryServerThreshold = mProcessList.getMemLevel( - ProcessList.SECONDARY_SERVER_ADJ); + ProcessList.SERVICE_ADJ); outInfo.visibleAppThreshold = mProcessList.getMemLevel( ProcessList.VISIBLE_APP_ADJ); outInfo.foregroundAppThreshold = mProcessList.getMemLevel( @@ -5101,10 +5174,10 @@ public final class ActivityManagerService extends ActivityManagerNative if (topThumbnail != null) { if (localLOGV) Slog.v(TAG, "Requesting top thumbnail"); try { - topThumbnail.requestThumbnail(topRecord); + topThumbnail.requestThumbnail(topRecord.appToken); } catch (Exception e) { Slog.w(TAG, "Exception thrown when requesting thumbnail", e); - sendPendingThumbnail(null, topRecord, null, null, true); + sendPendingThumbnail(null, topRecord.appToken, null, null, true); } } @@ -5475,7 +5548,7 @@ public final class ActivityManagerService extends ActivityManagerNative TaskRecord lastTask = null; for (int i=0; i<N; i++) { ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); - if (r == token) { + if (r.appToken == token) { if (!onlyRoot || lastTask != r.task) { return r.task.taskId; } @@ -5496,7 +5569,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i<N; i++) { ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); if (r.realActivity.equals(className) - && r != token && lastTask != r.task) { + && r.appToken != token && lastTask != r.task) { if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "others")) { i--; @@ -6168,7 +6241,7 @@ public final class ActivityManagerService extends ActivityManagerNative if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) { app.persistent = true; - app.maxAdj = ProcessList.CORE_SERVER_ADJ; + app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ; } if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); @@ -6566,14 +6639,15 @@ public final class ActivityManagerService extends ActivityManagerNative // If the worst oom_adj is somewhere in the hidden proc LRU range, // then constrain it so we will kill all hidden procs. - if (worstType < ProcessList.EMPTY_APP_ADJ && worstType > ProcessList.HIDDEN_APP_MIN_ADJ) { + if (worstType < ProcessList.HIDDEN_APP_MAX_ADJ + && worstType > ProcessList.HIDDEN_APP_MIN_ADJ) { worstType = ProcessList.HIDDEN_APP_MIN_ADJ; } // If this is not a secure call, don't let it kill processes that // are important. - if (!secure && worstType < ProcessList.SECONDARY_SERVER_ADJ) { - worstType = ProcessList.SECONDARY_SERVER_ADJ; + if (!secure && worstType < ProcessList.SERVICE_ADJ) { + worstType = ProcessList.SERVICE_ADJ; } Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType); @@ -6831,7 +6905,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=procsToKill.size()-1; i>=0; i--) { ProcessRecord proc = procsToKill.get(i); Slog.i(TAG, "Removing system update proc: " + proc); - removeProcessLocked(proc, true, false); + removeProcessLocked(proc, true, false, "system update done"); } } @@ -7027,7 +7101,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Don't let services in this process be restarted and potentially // annoy the user repeatedly. Unless it is persistent, since those // processes run critical code. - removeProcessLocked(app, false, false); + removeProcessLocked(app, false, false, "crash"); mMainStack.resumeTopActivityLocked(null); return false; } @@ -7039,7 +7113,7 @@ public final class ActivityManagerService extends ActivityManagerNative // process, then terminate it to avoid getting in a loop. Slog.w(TAG, " Force finishing activity " + r.intent.getComponent().flattenToShortString()); - int index = mMainStack.indexOfTokenLocked(r); + int index = mMainStack.indexOfActivityLocked(r); r.stack.finishActivityLocked(r, index, Activity.RESULT_CANCELED, null, "crashed"); // Also terminate any activities below it that aren't yet @@ -7138,16 +7212,18 @@ public final class ActivityManagerService extends ActivityManagerNative */ public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) { ProcessRecord r = findAppProcess(app, "Crash"); + final String processName = app == null ? "system_server" + : (r == null ? "unknown" : r.processName); EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(), - app == null ? "system" : (r == null ? "unknown" : r.processName), + processName, r == null ? -1 : r.info.flags, crashInfo.exceptionClassName, crashInfo.exceptionMessage, crashInfo.throwFileName, crashInfo.throwLineNumber); - addErrorToDropBox("crash", r, null, null, null, null, null, crashInfo); + addErrorToDropBox("crash", r, processName, null, null, null, null, null, crashInfo); crashApplication(r, crashInfo); } @@ -7220,6 +7296,7 @@ public final class ActivityManagerService extends ActivityManagerNative final boolean isSystemApp = process == null || (process.info.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0; + final String processName = process == null ? "unknown" : process.processName; final String dropboxTag = isSystemApp ? "system_app_strictmode" : "data_app_strictmode"; final DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE); @@ -7232,7 +7309,7 @@ public final class ActivityManagerService extends ActivityManagerNative final StringBuilder sb = isSystemApp ? mStrictModeBuffer : new StringBuilder(1024); synchronized (sb) { bufferWasEmpty = sb.length() == 0; - appendDropBoxProcessHeaders(process, sb); + appendDropBoxProcessHeaders(process, processName, sb); sb.append("Build: ").append(Build.FINGERPRINT).append("\n"); sb.append("System-App: ").append(isSystemApp).append("\n"); sb.append("Uptime-Millis: ").append(info.violationUptimeMillis).append("\n"); @@ -7334,13 +7411,15 @@ public final class ActivityManagerService extends ActivityManagerNative public boolean handleApplicationWtf(IBinder app, String tag, ApplicationErrorReport.CrashInfo crashInfo) { ProcessRecord r = findAppProcess(app, "WTF"); + final String processName = app == null ? "system_server" + : (r == null ? "unknown" : r.processName); EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(), - app == null ? "system" : (r == null ? "unknown" : r.processName), + processName, r == null ? -1 : r.info.flags, tag, crashInfo.exceptionMessage); - addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo); + addErrorToDropBox("wtf", r, processName, null, null, tag, null, null, crashInfo); if (r != null && r.pid != Process.myPid() && Settings.Secure.getInt(mContext.getContentResolver(), @@ -7383,7 +7462,8 @@ public final class ActivityManagerService extends ActivityManagerNative * Utility function for addErrorToDropBox and handleStrictModeViolation's logging * to append various headers to the dropbox log text. */ - private void appendDropBoxProcessHeaders(ProcessRecord process, StringBuilder sb) { + private void appendDropBoxProcessHeaders(ProcessRecord process, String processName, + StringBuilder sb) { // Watchdog thread ends up invoking this function (with // a null ProcessRecord) to add the stack file to dropbox. // Do not acquire a lock on this (am) in such cases, as it @@ -7391,18 +7471,14 @@ public final class ActivityManagerService extends ActivityManagerNative // is invoked due to unavailability of lock on am and it // would prevent watchdog from killing system_server. if (process == null) { - sb.append("Process: system_server\n"); + sb.append("Process: ").append(processName).append("\n"); return; } // Note: ProcessRecord 'process' is guarded by the service // instance. (notably process.pkgList, which could otherwise change // concurrently during execution of this method) synchronized (this) { - if (process.pid == MY_PID) { - sb.append("Process: system_server\n"); - } else { - sb.append("Process: ").append(process.processName).append("\n"); - } + sb.append("Process: ").append(processName).append("\n"); int flags = process.info.flags; IPackageManager pm = AppGlobals.getPackageManager(); sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n"); @@ -7446,7 +7522,8 @@ public final class ActivityManagerService extends ActivityManagerNative * @param crashInfo giving an application stack trace, null if absent */ public void addErrorToDropBox(String eventType, - ProcessRecord process, ActivityRecord activity, ActivityRecord parent, String subject, + ProcessRecord process, String processName, ActivityRecord activity, + ActivityRecord parent, String subject, final String report, final File logFile, final ApplicationErrorReport.CrashInfo crashInfo) { // NOTE -- this must never acquire the ActivityManagerService lock, @@ -7460,7 +7537,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return; final StringBuilder sb = new StringBuilder(1024); - appendDropBoxProcessHeaders(process, sb); + appendDropBoxProcessHeaders(process, processName, sb); if (activity != null) { sb.append("Activity: ").append(activity.shortComponentName).append("\n"); } @@ -7709,19 +7786,19 @@ public final class ActivityManagerService extends ActivityManagerNative } static int oomAdjToImportance(int adj, ActivityManager.RunningAppProcessInfo currApp) { - if (adj >= ProcessList.EMPTY_APP_ADJ) { - return ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY; - } else if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) { + if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) { if (currApp != null) { currApp.lru = adj - ProcessList.HIDDEN_APP_MIN_ADJ + 1; } return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; + } else if (adj >= ProcessList.SERVICE_B_ADJ) { + return ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; } else if (adj >= ProcessList.HOME_APP_ADJ) { if (currApp != null) { currApp.lru = 0; } return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; - } else if (adj >= ProcessList.SECONDARY_SERVER_ADJ) { + } else if (adj >= ProcessList.SERVICE_ADJ) { return ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) { return ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE; @@ -8158,6 +8235,7 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(); pw.println(" mHomeProcess: " + mHomeProcess); + pw.println(" mPreviousProcess: " + mPreviousProcess); if (mHeavyWeightProcess != null) { pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess); } @@ -8210,6 +8288,8 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" mGoingToSleep=" + mMainStack.mGoingToSleep); pw.println(" mLaunchingActivity=" + mMainStack.mLaunchingActivity); pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq); + pw.println(" mNumServiceProcs=" + mNumServiceProcs + + " mNewNumServiceProcs=" + mNewNumServiceProcs); } return true; @@ -8246,16 +8326,18 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" OOM levels:"); pw.print(" SYSTEM_ADJ: "); pw.println(ProcessList.SYSTEM_ADJ); - pw.print(" CORE_SERVER_ADJ: "); pw.println(ProcessList.CORE_SERVER_ADJ); + pw.print(" PERSISTENT_PROC_ADJ: "); pw.println(ProcessList.PERSISTENT_PROC_ADJ); pw.print(" FOREGROUND_APP_ADJ: "); pw.println(ProcessList.FOREGROUND_APP_ADJ); pw.print(" VISIBLE_APP_ADJ: "); pw.println(ProcessList.VISIBLE_APP_ADJ); pw.print(" PERCEPTIBLE_APP_ADJ: "); pw.println(ProcessList.PERCEPTIBLE_APP_ADJ); pw.print(" HEAVY_WEIGHT_APP_ADJ: "); pw.println(ProcessList.HEAVY_WEIGHT_APP_ADJ); pw.print(" BACKUP_APP_ADJ: "); pw.println(ProcessList.BACKUP_APP_ADJ); - pw.print(" SECONDARY_SERVER_ADJ: "); pw.println(ProcessList.SECONDARY_SERVER_ADJ); + pw.print(" SERVICE_ADJ: "); pw.println(ProcessList.SERVICE_ADJ); pw.print(" HOME_APP_ADJ: "); pw.println(ProcessList.HOME_APP_ADJ); + pw.print(" PREVIOUS_APP_ADJ: "); pw.println(ProcessList.PREVIOUS_APP_ADJ); + pw.print(" SERVICE_B_ADJ: "); pw.println(ProcessList.SERVICE_B_ADJ); pw.print(" HIDDEN_APP_MIN_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MIN_ADJ); - pw.print(" EMPTY_APP_ADJ: "); pw.println(ProcessList.EMPTY_APP_ADJ); + pw.print(" HIDDEN_APP_MAX_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MAX_ADJ); if (needSep) pw.println(" "); needSep = true; @@ -8269,6 +8351,7 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(); pw.println(" mHomeProcess: " + mHomeProcess); + pw.println(" mPreviousProcess: " + mPreviousProcess); if (mHeavyWeightProcess != null) { pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess); } @@ -8549,8 +8632,8 @@ public final class ActivityManagerService extends ActivityManagerNative try { TransferPipe tp = new TransferPipe(); try { - r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r, - innerPrefix, args); + r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), + r.appToken, innerPrefix, args); tp.go(fd); } finally { tp.kill(); @@ -8966,8 +9049,8 @@ public final class ActivityManagerService extends ActivityManagerNative try { TransferPipe tp = new TransferPipe(); try { - r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r, - innerPrefix, args); + r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), + r.appToken, innerPrefix, args); // Short timeout, since blocking here can // deadlock with the application. tp.go(fd, 2000); @@ -9046,14 +9129,16 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=N; i>=0; i--) { ProcessRecord r = list.get(i).first; String oomAdj; - if (r.setAdj >= ProcessList.EMPTY_APP_ADJ) { - oomAdj = buildOomTag("empty", null, r.setAdj, ProcessList.EMPTY_APP_ADJ); - } else if (r.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) { + if (r.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) { oomAdj = buildOomTag("bak", " ", r.setAdj, ProcessList.HIDDEN_APP_MIN_ADJ); + } else if (r.setAdj >= ProcessList.SERVICE_B_ADJ) { + oomAdj = buildOomTag("svcb ", null, r.setAdj, ProcessList.SERVICE_B_ADJ); + } else if (r.setAdj >= ProcessList.PREVIOUS_APP_ADJ) { + oomAdj = buildOomTag("prev ", null, r.setAdj, ProcessList.PREVIOUS_APP_ADJ); } else if (r.setAdj >= ProcessList.HOME_APP_ADJ) { oomAdj = buildOomTag("home ", null, r.setAdj, ProcessList.HOME_APP_ADJ); - } else if (r.setAdj >= ProcessList.SECONDARY_SERVER_ADJ) { - oomAdj = buildOomTag("svc", " ", r.setAdj, ProcessList.SECONDARY_SERVER_ADJ); + } else if (r.setAdj >= ProcessList.SERVICE_ADJ) { + oomAdj = buildOomTag("svc ", null, r.setAdj, ProcessList.SERVICE_ADJ); } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) { oomAdj = buildOomTag("bckup", null, r.setAdj, ProcessList.BACKUP_APP_ADJ); } else if (r.setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) { @@ -9064,8 +9149,8 @@ public final class ActivityManagerService extends ActivityManagerNative oomAdj = buildOomTag("vis ", null, r.setAdj, ProcessList.VISIBLE_APP_ADJ); } else if (r.setAdj >= ProcessList.FOREGROUND_APP_ADJ) { oomAdj = buildOomTag("fore ", null, r.setAdj, ProcessList.FOREGROUND_APP_ADJ); - } else if (r.setAdj >= ProcessList.CORE_SERVER_ADJ) { - oomAdj = buildOomTag("core ", null, r.setAdj, ProcessList.CORE_SERVER_ADJ); + } else if (r.setAdj >= ProcessList.PERSISTENT_PROC_ADJ) { + oomAdj = buildOomTag("pers ", null, r.setAdj, ProcessList.PERSISTENT_PROC_ADJ); } else if (r.setAdj >= ProcessList.SYSTEM_ADJ) { oomAdj = buildOomTag("sys ", null, r.setAdj, ProcessList.SYSTEM_ADJ); } else { @@ -9272,8 +9357,10 @@ public final class ActivityManagerService extends ActivityManagerNative } final void dumpApplicationMemoryUsage(FileDescriptor fd, - PrintWriter pw, String prefix, String[] args, boolean brief) { + PrintWriter pw, String prefix, String[] args, boolean brief, + PrintWriter categoryPw) { boolean dumpAll = false; + boolean oomOnly = false; int opti = 0; while (opti < args.length) { @@ -9284,9 +9371,12 @@ public final class ActivityManagerService extends ActivityManagerNative opti++; if ("-a".equals(opt)) { dumpAll = true; + } else if ("--oom".equals(opt)) { + oomOnly = true; } else if ("-h".equals(opt)) { - pw.println("meminfo dump options: [-a] [process]"); + pw.println("meminfo dump options: [-a] [--oom] [process]"); pw.println(" -a: include all available information for each process."); + pw.println(" --oom: only show processes organized by oom adj."); pw.println("If [process] is specified it can be the name or "); pw.println("pid of a specific process to dump."); return; @@ -9325,14 +9415,16 @@ public final class ActivityManagerService extends ActivityManagerNative long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS]; final int[] oomAdj = new int[] { - ProcessList.SYSTEM_ADJ, ProcessList.CORE_SERVER_ADJ, ProcessList.FOREGROUND_APP_ADJ, + ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ, ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ, - ProcessList.BACKUP_APP_ADJ, ProcessList.SECONDARY_SERVER_ADJ, ProcessList.HOME_APP_ADJ, ProcessList.EMPTY_APP_ADJ + ProcessList.BACKUP_APP_ADJ, ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ, + ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.HIDDEN_APP_MAX_ADJ }; final String[] oomLabel = new String[] { "System", "Persistent", "Foreground", "Visible", "Perceptible", "Heavy Weight", - "Backup", "Services", "Home", "Background" + "Backup", "A Services", "Home", "Previous", + "B Services", "Background" }; long oomPss[] = new long[oomLabel.length]; ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])new ArrayList[oomLabel.length]; @@ -9410,7 +9502,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - if (!brief) { + if (!brief && !oomOnly) { pw.println(); pw.println("Total PSS by process:"); dumpMemItems(pw, " ", procMems, true); @@ -9418,10 +9510,11 @@ public final class ActivityManagerService extends ActivityManagerNative } pw.println("Total PSS by OOM adjustment:"); dumpMemItems(pw, " ", oomMems, false); - if (!brief) { - pw.println(); - pw.println("Total PSS by category:"); - dumpMemItems(pw, " ", catMems, true); + if (!oomOnly) { + PrintWriter out = categoryPw != null ? categoryPw : pw; + out.println(); + out.println("Total PSS by category:"); + dumpMemItems(out, " ", catMems, true); } pw.println(); pw.print("Total PSS: "); pw.print(totalPss); pw.println(" Kb"); @@ -9758,7 +9851,10 @@ public final class ActivityManagerService extends ActivityManagerNative if (app == mHomeProcess) { mHomeProcess = null; } - + if (app == mPreviousProcess) { + mPreviousProcess = null; + } + if (restart) { // We have components that still need to be running in the // process, so re-launch it. @@ -12991,7 +13087,7 @@ public final class ActivityManagerService extends ActivityManagerNative // ========================================================= private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj, - ProcessRecord TOP_APP, boolean recursed) { + ProcessRecord TOP_APP, boolean recursed, boolean doingAll) { if (mAdjSeq == app.adjSeq) { // This adjustment has already been computed. If we are calling // from the top, we may have already computed our adjustment with @@ -13006,7 +13102,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (app.thread == null) { app.adjSeq = mAdjSeq; app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; - return (app.curAdj=ProcessList.EMPTY_APP_ADJ); + return (app.curAdj=ProcessList.HIDDEN_APP_MAX_ADJ); } app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN; @@ -13156,6 +13252,17 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "home"; } + if (adj > ProcessList.PREVIOUS_APP_ADJ && app == mPreviousProcess + && app.activities.size() > 0) { + // This was the previous process that showed UI to the user. + // We want to try to keep it around more aggressively, to give + // a good experience around switching between two apps. + adj = ProcessList.PREVIOUS_APP_ADJ; + schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; + app.hidden = false; + app.adjType = "previous"; + } + if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj + " reason=" + app.adjType); @@ -13190,7 +13297,7 @@ public final class ActivityManagerService extends ActivityManagerNative // go to the LRU list because it may be pretty heavy with // UI stuff. We'll tag it with a label just to help // debug and understand what is going on. - if (adj > ProcessList.SECONDARY_SERVER_ADJ) { + if (adj > ProcessList.SERVICE_ADJ) { app.adjType = "started-bg-ui-services"; } } else { @@ -13198,8 +13305,8 @@ public final class ActivityManagerService extends ActivityManagerNative // This service has seen some activity within // recent memory, so we will keep its process ahead // of the background processes. - if (adj > ProcessList.SECONDARY_SERVER_ADJ) { - adj = ProcessList.SECONDARY_SERVER_ADJ; + if (adj > ProcessList.SERVICE_ADJ) { + adj = ProcessList.SERVICE_ADJ; app.adjType = "started-services"; app.hidden = false; } @@ -13207,7 +13314,7 @@ public final class ActivityManagerService extends ActivityManagerNative // If we have let the service slide into the background // state, still have some text describing what it is doing // even though the service no longer has an impact. - if (adj > ProcessList.SECONDARY_SERVER_ADJ) { + if (adj > ProcessList.SERVICE_ADJ) { app.adjType = "started-bg-services"; } } @@ -13241,7 +13348,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } clientAdj = computeOomAdjLocked( - client, myHiddenAdj, TOP_APP, true); + client, myHiddenAdj, TOP_APP, true, doingAll); String adjType = null; if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) { // Not doing bind OOM management, so treat @@ -13285,10 +13392,17 @@ public final class ActivityManagerService extends ActivityManagerNative if ((cr.flags&(Context.BIND_ABOVE_CLIENT |Context.BIND_IMPORTANT)) != 0) { adj = clientAdj; - } else if (clientAdj >= ProcessList.VISIBLE_APP_ADJ) { + } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0 + && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ + && adj > ProcessList.PERCEPTIBLE_APP_ADJ) { + adj = ProcessList.PERCEPTIBLE_APP_ADJ; + } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) { adj = clientAdj; } else { - adj = ProcessList.VISIBLE_APP_ADJ; + app.pendingUiClean = true; + if (adj > ProcessList.VISIBLE_APP_ADJ) { + adj = ProcessList.VISIBLE_APP_ADJ; + } } if (!client.hidden) { app.hidden = false; @@ -13371,7 +13485,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } int clientAdj = computeOomAdjLocked( - client, myHiddenAdj, TOP_APP, true); + client, myHiddenAdj, TOP_APP, true, doingAll); if (adj > clientAdj) { if (app.hasShownUi && app != mHomeProcess && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { @@ -13442,11 +13556,23 @@ public final class ActivityManagerService extends ActivityManagerNative adj = ProcessList.PERCEPTIBLE_APP_ADJ; } else if (adj < ProcessList.HIDDEN_APP_MIN_ADJ) { adj = ProcessList.HIDDEN_APP_MIN_ADJ; - } else if (adj < ProcessList.EMPTY_APP_ADJ) { + } else if (adj < ProcessList.HIDDEN_APP_MAX_ADJ) { adj++; } } + if (adj == ProcessList.SERVICE_ADJ) { + if (doingAll) { + app.serviceb = mNewNumServiceProcs > (mNumServiceProcs/3); + mNewNumServiceProcs++; + } + if (app.serviceb) { + adj = ProcessList.SERVICE_B_ADJ; + } + } else { + app.serviceb = false; + } + app.curAdj = adj; app.curSchedGroup = schedGroup; @@ -13687,7 +13813,7 @@ public final class ActivityManagerService extends ActivityManagerNative } private final boolean updateOomAdjLocked( - ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) { + ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP, boolean doingAll) { app.hiddenAdj = hiddenAdj; if (app.thread == null) { @@ -13698,7 +13824,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean success = true; - computeOomAdjLocked(app, hiddenAdj, TOP_APP, false); + computeOomAdjLocked(app, hiddenAdj, TOP_APP, false, doingAll); if (app.curRawAdj != app.setRawAdj) { if (false) { @@ -13732,11 +13858,12 @@ public final class ActivityManagerService extends ActivityManagerNative app.setRawAdj = app.curRawAdj; } + if (app.curAdj != app.setAdj) { if (Process.setOomAdj(app.pid, app.curAdj)) { - if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v( - TAG, "Set app " + app.processName + - " oom adj to " + app.curAdj + " because " + app.adjType); + if (true || DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v( + TAG, "Set " + app.pid + " " + app.processName + + " adj " + app.curAdj + ": " + app.adjType); app.setAdj = app.curAdj; } else { success = false; @@ -13800,7 +13927,7 @@ public final class ActivityManagerService extends ActivityManagerNative mAdjSeq++; - boolean success = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP); + boolean success = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP, false); final boolean nowHidden = app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ && app.curAdj <= ProcessList.HIDDEN_APP_MAX_ADJ; if (nowHidden != wasHidden) { @@ -13822,6 +13949,7 @@ public final class ActivityManagerService extends ActivityManagerNative } mAdjSeq++; + mNewNumServiceProcs = 0; // Let's determine how many processes we have running vs. // how many slots we have for background processes; we may want @@ -13842,8 +13970,8 @@ public final class ActivityManagerService extends ActivityManagerNative i--; ProcessRecord app = mLruProcesses.get(i); //Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj); - updateOomAdjLocked(app, curHiddenAdj, TOP_APP); - if (curHiddenAdj < ProcessList.EMPTY_APP_ADJ + updateOomAdjLocked(app, curHiddenAdj, TOP_APP, true); + if (curHiddenAdj < ProcessList.HIDDEN_APP_MAX_ADJ && app.curAdj == curHiddenAdj) { step++; if (step >= factor) { @@ -13864,12 +13992,15 @@ public final class ActivityManagerService extends ActivityManagerNative } else { numBg++; } - } else if (app.curAdj >= ProcessList.HOME_APP_ADJ) { + } else if (app.curAdj >= ProcessList.HOME_APP_ADJ + && app.curAdj != ProcessList.SERVICE_B_ADJ) { numBg++; } } } + mNumServiceProcs = mNewNumServiceProcs; + // Now determine the memory trimming level of background processes. // Unfortunately we need to start at the back of the list to do this // properly. We only do this if the number of background apps we @@ -13892,7 +14023,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { // For these apps we will also finish their activities // to help them free memory. - mMainStack.destroyActivitiesLocked(app, false); + mMainStack.destroyActivitiesLocked(app, false, "trim"); } } app.trimMemoryLevel = curLevel; @@ -13956,7 +14087,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (mAlwaysFinishActivities) { - mMainStack.destroyActivitiesLocked(null, false); + mMainStack.destroyActivitiesLocked(null, false, "always-finish"); } } diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index ce45bfb..951a946 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -29,6 +29,7 @@ import android.content.res.Configuration; import android.graphics.Bitmap; import android.os.Build; import android.os.Bundle; +import android.os.IBinder; import android.os.Message; import android.os.Process; import android.os.RemoteException; @@ -48,9 +49,10 @@ import java.util.HashSet; /** * An entry in the history stack, representing an activity. */ -final class ActivityRecord extends IApplicationToken.Stub { +final class ActivityRecord { final ActivityManagerService service; // owner final ActivityStack stack; // owner + final IApplicationToken.Stub appToken; // window manager token final ActivityInfo info; // all about me final int launchedFromUid; // always the uid who started the activity. final Intent intent; // the original intent that generated us @@ -200,6 +202,70 @@ final class ActivityRecord extends IApplicationToken.Stub { } } + static class Token extends IApplicationToken.Stub { + final WeakReference<ActivityRecord> weakActivity; + + Token(ActivityRecord activity) { + weakActivity = new WeakReference<ActivityRecord>(activity); + } + + @Override public void windowsDrawn() throws RemoteException { + ActivityRecord activity = weakActivity.get(); + if (activity != null) { + activity.windowsDrawn(); + } + } + + @Override public void windowsVisible() throws RemoteException { + ActivityRecord activity = weakActivity.get(); + if (activity != null) { + activity.windowsVisible(); + } + } + + @Override public void windowsGone() throws RemoteException { + ActivityRecord activity = weakActivity.get(); + if (activity != null) { + activity.windowsGone(); + } + } + + @Override public boolean keyDispatchingTimedOut() throws RemoteException { + ActivityRecord activity = weakActivity.get(); + if (activity != null) { + return activity.keyDispatchingTimedOut(); + } + return false; + } + + @Override public long getKeyDispatchingTimeout() throws RemoteException { + ActivityRecord activity = weakActivity.get(); + if (activity != null) { + return activity.getKeyDispatchingTimeout(); + } + return 0; + } + + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("Token{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(weakActivity.get()); + sb.append('}'); + return sb.toString(); + } + } + + static ActivityRecord forToken(IBinder token) { + try { + return token != null ? ((Token)token).weakActivity.get() : null; + } catch (ClassCastException e) { + Slog.w(ActivityManagerService.TAG, "Bad activity token: " + token, e); + return null; + } + } + ActivityRecord(ActivityManagerService _service, ActivityStack _stack, ProcessRecord _caller, int _launchedFromUid, Intent _intent, String _resolvedType, ActivityInfo aInfo, Configuration _configuration, @@ -207,6 +273,7 @@ final class ActivityRecord extends IApplicationToken.Stub { boolean _componentSpecified) { service = _service; stack = _stack; + appToken = new Token(this); info = aInfo; launchedFromUid = _launchedFromUid; intent = _intent; @@ -445,7 +512,7 @@ final class ActivityRecord extends IApplicationToken.Stub { ar.add(intent); service.grantUriPermissionFromIntentLocked(callingUid, packageName, intent, getUriPermissionsLocked()); - app.thread.scheduleNewIntent(ar, this); + app.thread.scheduleNewIntent(ar, appToken); sent = true; } catch (RemoteException e) { Slog.w(ActivityManagerService.TAG, @@ -470,14 +537,14 @@ final class ActivityRecord extends IApplicationToken.Stub { void pauseKeyDispatchingLocked() { if (!keysPaused) { keysPaused = true; - service.mWindowManager.pauseKeyDispatching(this); + service.mWindowManager.pauseKeyDispatching(appToken); } } void resumeKeyDispatchingLocked() { if (keysPaused) { keysPaused = false; - service.mWindowManager.resumeKeyDispatching(this); + service.mWindowManager.resumeKeyDispatching(appToken); } } @@ -512,18 +579,18 @@ final class ActivityRecord extends IApplicationToken.Stub { public void startFreezingScreenLocked(ProcessRecord app, int configChanges) { if (mayFreezeScreenLocked(app)) { - service.mWindowManager.startAppFreezingScreen(this, configChanges); + service.mWindowManager.startAppFreezingScreen(appToken, configChanges); } } public void stopFreezingScreenLocked(boolean force) { if (force || frozenBeforeDestroy) { frozenBeforeDestroy = false; - service.mWindowManager.stopAppFreezingScreen(this, force); + service.mWindowManager.stopAppFreezingScreen(appToken, force); } } - public void windowsVisible() { + public void windowsDrawn() { synchronized(service) { if (launchTime != 0) { final long curTime = SystemClock.uptimeMillis(); @@ -555,6 +622,11 @@ final class ActivityRecord extends IApplicationToken.Stub { stack.mInitialStartTime = 0; } startTime = 0; + } + } + + public void windowsVisible() { + synchronized(service) { stack.reportActivityVisibleLocked(this); if (ActivityManagerService.DEBUG_SWITCH) Log.v( ActivityManagerService.TAG, "windowsVisible(): " + this); @@ -682,7 +754,7 @@ final class ActivityRecord extends IApplicationToken.Stub { } if (app != null && app.thread != null) { try { - app.thread.scheduleSleeping(this, _sleeping); + app.thread.scheduleSleeping(appToken, _sleeping); if (sleeping && !stack.mGoingToSleepActivities.contains(this)) { stack.mGoingToSleepActivities.add(this); } diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 28c3bae..c892cb1 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -145,7 +145,12 @@ final class ActivityStack { * running) activities. It contains HistoryRecord objects. */ final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>(); - + + /** + * Used for validating app tokens with window manager. + */ + final ArrayList<IBinder> mValidateAppTokens = new ArrayList<IBinder>(); + /** * List of running activities, sorted by recent usage. * The first entry in the list is the least recently used. @@ -294,11 +299,11 @@ final class ActivityStack { } } break; case PAUSE_TIMEOUT_MSG: { - IBinder token = (IBinder)msg.obj; + ActivityRecord r = (ActivityRecord)msg.obj; // We don't at this point know if the activity is fullscreen, // so we need to be conservative and assume it isn't. - Slog.w(TAG, "Activity pause timeout for " + token); - activityPaused(token, true); + Slog.w(TAG, "Activity pause timeout for " + r); + activityPaused(r != null ? r.appToken : null, true); } break; case IDLE_TIMEOUT_MSG: { if (mService.mDidDexOpt) { @@ -310,20 +315,20 @@ final class ActivityStack { } // We don't at this point know if the activity is fullscreen, // so we need to be conservative and assume it isn't. - IBinder token = (IBinder)msg.obj; - Slog.w(TAG, "Activity idle timeout for " + token); - activityIdleInternal(token, true, null); + ActivityRecord r = (ActivityRecord)msg.obj; + Slog.w(TAG, "Activity idle timeout for " + r); + activityIdleInternal(r != null ? r.appToken : null, true, null); } break; case DESTROY_TIMEOUT_MSG: { - IBinder token = (IBinder)msg.obj; + ActivityRecord r = (ActivityRecord)msg.obj; // We don't at this point know if the activity is fullscreen, // so we need to be conservative and assume it isn't. - Slog.w(TAG, "Activity destroy timeout for " + token); - activityDestroyed(token); + Slog.w(TAG, "Activity destroy timeout for " + r); + activityDestroyed(r != null ? r.appToken : null); } break; case IDLE_NOW_MSG: { - IBinder token = (IBinder)msg.obj; - activityIdleInternal(token, false, null); + ActivityRecord r = (ActivityRecord)msg.obj; + activityIdleInternal(r != null ? r.appToken : null, false, null); } break; case LAUNCH_TIMEOUT_MSG: { if (mService.mDidDexOpt) { @@ -397,7 +402,7 @@ final class ActivityStack { while (i >= 0) { ActivityRecord r = mHistory.get(i); // Note: the taskId check depends on real taskId fields being non-zero - if (!r.finishing && (token != r) && (taskId != r.task.taskId)) { + if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)) { return r; } i--; @@ -406,23 +411,17 @@ final class ActivityStack { } final int indexOfTokenLocked(IBinder token) { - try { - ActivityRecord r = (ActivityRecord)token; - return mHistory.indexOf(r); - } catch (ClassCastException e) { - Slog.w(TAG, "Bad activity token: " + token, e); - return -1; - } + return mHistory.indexOf(ActivityRecord.forToken(token)); + } + + final int indexOfActivityLocked(ActivityRecord r) { + return mHistory.indexOf(r); } final ActivityRecord isInStackLocked(IBinder token) { - try { - ActivityRecord r = (ActivityRecord)token; - if (mHistory.contains(r)) { - return r; - } - } catch (ClassCastException e) { - Slog.w(TAG, "Bad activity token: " + token, e); + ActivityRecord r = ActivityRecord.forToken(token); + if (mHistory.contains(r)) { + return r; } return null; } @@ -517,7 +516,7 @@ final class ActivityStack { throws RemoteException { r.startFreezingScreenLocked(app, 0); - mService.mWindowManager.setAppVisibility(r, true); + mService.mWindowManager.setAppVisibility(r.appToken, true); // Have the window manager re-evaluate the orientation of // the screen based on the new activity order. Note that @@ -528,7 +527,7 @@ final class ActivityStack { if (checkConfig) { Configuration config = mService.mWindowManager.updateOrientationFromAppTokens( mService.mConfiguration, - r.mayFreezeScreenLocked(app) ? r : null); + r.mayFreezeScreenLocked(app) ? r.appToken : null); mService.updateConfigurationLocked(config, r, false); } @@ -590,7 +589,7 @@ final class ActivityStack { profileFd = null; } } - app.thread.scheduleLaunchActivity(new Intent(r.intent), r, + app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, mService.mConfiguration, r.compat, r.icicle, results, newIntents, !andResume, mService.isNextTransitionForward(), profileFile, profileFd, @@ -624,7 +623,7 @@ final class ActivityStack { + r.intent.getComponent().flattenToShortString() + ", giving up", e); mService.appDiedLocked(app, app.pid, app.thread); - requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null, + requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null, "2nd-crash"); return false; } @@ -821,7 +820,7 @@ final class ActivityStack { } if (w > 0) { - return mService.mWindowManager.screenshotApplications(who, w, h); + return mService.mWindowManager.screenshotApplications(who.appToken, w, h); } return null; } @@ -856,8 +855,8 @@ final class ActivityStack { EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY, System.identityHashCode(prev), prev.shortComponentName); - prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving, - prev.configChangeFlags); + prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing, + userLeaving, prev.configChangeFlags); if (mMainStack) { mService.updateUsageStats(prev, false); } @@ -947,7 +946,7 @@ final class ActivityStack { r.state = ActivityState.STOPPED; if (!r.finishing) { if (r.configDestroy) { - destroyActivityLocked(r, true, false); + destroyActivityLocked(r, true, false, "stop-config"); resumeTopActivityLocked(null); } } @@ -976,7 +975,7 @@ final class ActivityStack { // instance right now, we need to first completely stop // the current instance before starting the new one. if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev); - destroyActivityLocked(prev, true, false); + destroyActivityLocked(prev, true, false, "pause-config"); } else { mStoppingActivities.add(prev); if (mStoppingActivities.size() > 3) { @@ -1129,7 +1128,7 @@ final class ActivityStack { if (!r.visible) { if (DEBUG_VISBILITY) Slog.v( TAG, "Starting and making visible: " + r); - mService.mWindowManager.setAppVisibility(r, true); + mService.mWindowManager.setAppVisibility(r.appToken, true); } if (r != starting) { startSpecificActivityLocked(r, false, false); @@ -1153,10 +1152,10 @@ final class ActivityStack { if (DEBUG_VISBILITY) Slog.v( TAG, "Making visible and scheduling visibility: " + r); try { - mService.mWindowManager.setAppVisibility(r, true); + mService.mWindowManager.setAppVisibility(r.appToken, true); r.sleeping = false; r.app.pendingUiClean = true; - r.app.thread.scheduleWindowVisibility(r, true); + r.app.thread.scheduleWindowVisibility(r.appToken, true); r.stopFreezingScreenLocked(false); } catch (Exception e) { // Just skip on any failure; we'll make it @@ -1195,13 +1194,13 @@ final class ActivityStack { TAG, "Making invisible: " + r); r.visible = false; try { - mService.mWindowManager.setAppVisibility(r, false); + mService.mWindowManager.setAppVisibility(r.appToken, false); if ((r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) && r.app != null && r.app.thread != null) { if (DEBUG_VISBILITY) Slog.v( TAG, "Scheduling invisibility: " + r); - r.app.thread.scheduleWindowVisibility(r, false); + r.app.thread.scheduleWindowVisibility(r.appToken, false); } } catch (Exception e) { // Just skip on any failure; we'll make it @@ -1351,7 +1350,7 @@ final class ActivityStack { // previous should actually be hidden depending on whether the // new one is found to be full-screen or not. if (prev.finishing) { - mService.mWindowManager.setAppVisibility(prev, false); + mService.mWindowManager.setAppVisibility(prev.appToken, false); if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: " + prev + ", waitingVisible=" + (prev != null ? prev.waitingVisible : null) @@ -1363,6 +1362,14 @@ final class ActivityStack { + ", nowVisible=" + next.nowVisible); } } + + if (!prev.finishing && prev.app != null && prev.app != next.app + && prev.app != mService.mHomeProcess) { + // We are switching to a new activity that is in a different + // process than the previous one. Note the previous process, + // so we can try to keep it around. + mService.mPreviousProcess = prev.app; + } } // Launching this app's activity, make sure the app is no longer @@ -1391,8 +1398,8 @@ final class ActivityStack { ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE : WindowManagerPolicy.TRANSIT_TASK_CLOSE, false); } - mService.mWindowManager.setAppWillBeHidden(prev); - mService.mWindowManager.setAppVisibility(prev, false); + mService.mWindowManager.setAppWillBeHidden(prev.appToken); + mService.mWindowManager.setAppVisibility(prev.appToken, false); } else { if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: prev=" + prev); @@ -1406,8 +1413,8 @@ final class ActivityStack { } } if (false) { - mService.mWindowManager.setAppWillBeHidden(prev); - mService.mWindowManager.setAppVisibility(prev, false); + mService.mWindowManager.setAppWillBeHidden(prev.appToken); + mService.mWindowManager.setAppVisibility(prev.appToken, false); } } else if (mHistory.size() > 1) { if (DEBUG_TRANSITION) Slog.v(TAG, @@ -1425,7 +1432,7 @@ final class ActivityStack { if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next); // This activity is now becoming visible. - mService.mWindowManager.setAppVisibility(next, true); + mService.mWindowManager.setAppVisibility(next.appToken, true); ActivityRecord lastResumedActivity = mResumedActivity; ActivityState lastState = next.state; @@ -1449,7 +1456,7 @@ final class ActivityStack { synchronized (mService) { Configuration config = mService.mWindowManager.updateOrientationFromAppTokens( mService.mConfiguration, - next.mayFreezeScreenLocked(next.app) ? next : null); + next.mayFreezeScreenLocked(next.app) ? next.appToken : null); if (config != null) { next.frozenBeforeDestroy = true; } @@ -1488,12 +1495,12 @@ final class ActivityStack { if (DEBUG_RESULTS) Slog.v( TAG, "Delivering results to " + next + ": " + a); - next.app.thread.scheduleSendResult(next, a); + next.app.thread.scheduleSendResult(next.appToken, a); } } if (next.newIntents != null) { - next.app.thread.scheduleNewIntent(next.newIntents, next); + next.app.thread.scheduleNewIntent(next.newIntents, next.appToken); } EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, @@ -1503,7 +1510,7 @@ final class ActivityStack { next.sleeping = false; showAskCompatModeDialogLocked(next); next.app.pendingUiClean = true; - next.app.thread.scheduleResumeActivity(next, + next.app.thread.scheduleResumeActivity(next.appToken, mService.isNextTransitionForward()); checkReadyForSleepLocked(); @@ -1520,7 +1527,7 @@ final class ActivityStack { } else { if (SHOW_APP_STARTING_PREVIEW && mMainStack) { mService.mWindowManager.setAppStartingWindow( - next, next.packageName, next.theme, + next.appToken, next.packageName, next.theme, mService.compatibilityInfoForPackageLocked( next.info.applicationInfo), next.nonLocalizedLabel, @@ -1541,7 +1548,7 @@ final class ActivityStack { // If any exception gets thrown, toss away this // activity and try the next one. Slog.w(TAG, "Exception thrown during resume of " + next, e); - requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null, + requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null, "resume-exception"); return true; } @@ -1559,7 +1566,7 @@ final class ActivityStack { } else { if (SHOW_APP_STARTING_PREVIEW) { mService.mWindowManager.setAppStartingWindow( - next, next.packageName, next.theme, + next.appToken, next.packageName, next.theme, mService.compatibilityInfoForPackageLocked( next.info.applicationInfo), next.nonLocalizedLabel, @@ -1602,10 +1609,10 @@ final class ActivityStack { } mHistory.add(addPos, r); r.putInHistory(); - mService.mWindowManager.addAppToken(addPos, r, r.task.taskId, + mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen); if (VALIDATE_TOKENS) { - mService.mWindowManager.validateAppTokens(mHistory); + validateAppTokensLocked(); } return; } @@ -1669,7 +1676,7 @@ final class ActivityStack { mNoAnimActivities.remove(r); } mService.mWindowManager.addAppToken( - addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen); + addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen); boolean doShow = true; if (newTask) { // Even though this activity is starting fresh, we still need @@ -1697,19 +1704,20 @@ final class ActivityStack { else if (prev.nowVisible) prev = null; } mService.mWindowManager.setAppStartingWindow( - r, r.packageName, r.theme, + r.appToken, r.packageName, r.theme, mService.compatibilityInfoForPackageLocked( r.info.applicationInfo), r.nonLocalizedLabel, - r.labelRes, r.icon, r.windowFlags, prev, showStartingIcon); + r.labelRes, r.icon, r.windowFlags, + prev != null ? prev.appToken : null, showStartingIcon); } } else { // If this is the first activity, don't do any fancy animations, // because there is nothing for it to animate on top of. - mService.mWindowManager.addAppToken(addPos, r, r.task.taskId, + mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen); } if (VALIDATE_TOKENS) { - mService.mWindowManager.validateAppTokens(mHistory); + validateAppTokensLocked(); } if (doResume) { @@ -1717,6 +1725,15 @@ final class ActivityStack { } } + final void validateAppTokensLocked() { + mValidateAppTokens.clear(); + mValidateAppTokens.ensureCapacity(mHistory.size()); + for (int i=0; i<mHistory.size(); i++) { + mValidateAppTokens.add(mHistory.get(i).appToken); + } + mService.mWindowManager.validateAppTokens(mValidateAppTokens); + } + /** * Perform a reset of the given task, if needed as part of launching it. * Returns the new HistoryRecord at the top of the task. @@ -1818,7 +1835,7 @@ final class ActivityStack { if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target + " out to new task " + target.task); } - mService.mWindowManager.setAppGroupId(target, task.taskId); + mService.mWindowManager.setAppGroupId(target.appToken, task.taskId); if (replyChainEnd < 0) { replyChainEnd = targetI; } @@ -1841,11 +1858,11 @@ final class ActivityStack { } mHistory.remove(srcPos); mHistory.add(dstPos, p); - mService.mWindowManager.moveAppToken(dstPos, p); - mService.mWindowManager.setAppGroupId(p, p.task.taskId); + mService.mWindowManager.moveAppToken(dstPos, p.appToken); + mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId); dstPos++; if (VALIDATE_TOKENS) { - mService.mWindowManager.validateAppTokens(mHistory); + validateAppTokensLocked(); } i++; } @@ -1977,10 +1994,10 @@ final class ActivityStack { mHistory.add(lastReparentPos, p); if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p + " in to resetting task " + task); - mService.mWindowManager.moveAppToken(lastReparentPos, p); - mService.mWindowManager.setAppGroupId(p, p.task.taskId); + mService.mWindowManager.moveAppToken(lastReparentPos, p.appToken); + mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId); if (VALIDATE_TOKENS) { - mService.mWindowManager.validateAppTokens(mHistory); + validateAppTokensLocked(); } } replyChainEnd = -1; @@ -2073,7 +2090,7 @@ final class ActivityStack { if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) { if (!ret.finishing) { - int index = indexOfTokenLocked(ret); + int index = indexOfTokenLocked(ret.appToken); if (index >= 0) { finishActivityLocked(ret, index, Activity.RESULT_CANCELED, null, "clear"); @@ -2999,7 +3016,7 @@ final class ActivityStack { return res; } - resultTo = outActivity[0]; + resultTo = outActivity[0] != null ? outActivity[0].appToken : null; } } } finally { @@ -3057,7 +3074,7 @@ final class ActivityStack { ArrayList<ResultInfo> list = new ArrayList<ResultInfo>(); list.add(new ResultInfo(resultWho, requestCode, resultCode, data)); - r.app.thread.scheduleSendResult(r, list); + r.app.thread.scheduleSendResult(r.appToken, list); return; } catch (Exception e) { Slog.w(TAG, "Exception thrown sending result to " + r, e); @@ -3072,7 +3089,7 @@ final class ActivityStack { if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) { if (!r.finishing) { - requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null, + requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null, "no-history"); } } else if (r.app != null && r.app.thread != null) { @@ -3090,9 +3107,9 @@ final class ActivityStack { if (DEBUG_VISBILITY) Slog.v( TAG, "Stopping visible=" + r.visible + " for " + r); if (!r.visible) { - mService.mWindowManager.setAppVisibility(r, false); + mService.mWindowManager.setAppVisibility(r.appToken, false); } - r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags); + r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags); if (mService.isSleeping()) { r.setSleeping(true); } @@ -3106,7 +3123,7 @@ final class ActivityStack { if (DEBUG_STATES) Slog.v(TAG, "Stop failed; moving to STOPPED: " + r); r.state = ActivityState.STOPPED; if (r.configDestroy) { - destroyActivityLocked(r, true, false); + destroyActivityLocked(r, true, false, "stop-except"); } } } @@ -3137,7 +3154,7 @@ final class ActivityStack { // normal flow and hide it once we determine that it is // hidden by the activities in front of it. if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s); - mService.mWindowManager.setAppVisibility(s, false); + mService.mWindowManager.setAppVisibility(s.appToken, false); } } if ((!s.waitingVisible || mService.isSleeping()) && remove) { @@ -3178,14 +3195,14 @@ final class ActivityStack { boolean enableScreen = false; synchronized (mService) { - if (token != null) { - mHandler.removeMessages(IDLE_TIMEOUT_MSG, token); + ActivityRecord r = ActivityRecord.forToken(token); + if (r != null) { + mHandler.removeMessages(IDLE_TIMEOUT_MSG, r); } // Get the activity record. - int index = indexOfTokenLocked(token); + int index = indexOfActivityLocked(r); if (index >= 0) { - ActivityRecord r = mHistory.get(index); res = r; if (fromTimeout) { @@ -3281,7 +3298,7 @@ final class ActivityStack { for (i=0; i<NF; i++) { ActivityRecord r = (ActivityRecord)finishes.get(i); synchronized (mService) { - destroyActivityLocked(r, true, false); + destroyActivityLocked(r, true, false, "finish-idle"); } } @@ -3405,7 +3422,7 @@ final class ActivityStack { : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE, false); // Tell window manager to prepare for this one to be removed. - mService.mWindowManager.setAppVisibility(r, false); + mService.mWindowManager.setAppVisibility(r.appToken, false); if (mPausingActivity == null) { if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r); @@ -3432,7 +3449,7 @@ final class ActivityStack { private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode) { - final int index = indexOfTokenLocked(r); + final int index = indexOfActivityLocked(r); if (index < 0) { return null; } @@ -3480,7 +3497,7 @@ final class ActivityStack { || prevState == ActivityState.INITIALIZING) { // If this activity is already stopped, we can just finish // it right now. - return destroyActivityLocked(r, true, true) ? null : r; + return destroyActivityLocked(r, true, true, "finish-imm") ? null : r; } else { // Need to go through the full pause cycle to get this // activity into the stopped state and then finish it. @@ -3562,9 +3579,9 @@ final class ActivityStack { if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (removed from history)"); r.state = ActivityState.DESTROYED; - mService.mWindowManager.removeAppToken(r); + mService.mWindowManager.removeAppToken(r.appToken); if (VALIDATE_TOKENS) { - mService.mWindowManager.validateAppTokens(mHistory); + validateAppTokensLocked(); } cleanUpActivityServicesLocked(r); r.removeUriPermissionsLocked(); @@ -3586,7 +3603,7 @@ final class ActivityStack { } } - final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj) { + final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj, String reason) { for (int i=mHistory.size()-1; i>=0; i--) { ActivityRecord r = mHistory.get(i); if (owner != null && r.app != owner) { @@ -3597,7 +3614,7 @@ final class ActivityStack { if (r.app != null && r.haveState && !r.visible && r.stopped && !r.finishing && r.state != ActivityState.DESTROYING && r.state != ActivityState.DESTROYED) { - destroyActivityLocked(r, true, oomAdj); + destroyActivityLocked(r, true, oomAdj, "trim"); } } } @@ -3609,13 +3626,13 @@ final class ActivityStack { * but then create a new client-side object for this same HistoryRecord. */ final boolean destroyActivityLocked(ActivityRecord r, - boolean removeFromApp, boolean oomAdj) { + boolean removeFromApp, boolean oomAdj, String reason) { if (DEBUG_SWITCH) Slog.v( TAG, "Removing activity: token=" + r + ", app=" + (r.app != null ? r.app.processName : "(null)")); EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY, System.identityHashCode(r), - r.task.taskId, r.shortComponentName); + r.task.taskId, r.shortComponentName, reason); boolean removedFromHistory = false; @@ -3645,7 +3662,7 @@ final class ActivityStack { try { if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r); - r.app.thread.scheduleDestroyActivity(r, r.finishing, + r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing, r.configChangeFlags); } catch (Exception e) { // We can just ignore exceptions here... if the process @@ -3704,11 +3721,13 @@ final class ActivityStack { final void activityDestroyed(IBinder token) { synchronized (mService) { - mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token); + ActivityRecord r = ActivityRecord.forToken(token); + if (r != null) { + mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r); + } - int index = indexOfTokenLocked(token); + int index = indexOfActivityLocked(r); if (index >= 0) { - ActivityRecord r = mHistory.get(index); if (r.state == ActivityState.DESTROYING) { final long origId = Binder.clearCallingIdentity(); removeActivityFromHistoryLocked(r); @@ -3773,7 +3792,7 @@ final class ActivityStack { return; } - ArrayList moved = new ArrayList(); + ArrayList<IBinder> moved = new ArrayList<IBinder>(); // Applying the affinities may have removed entries from the history, // so get the size again. @@ -3795,7 +3814,7 @@ final class ActivityStack { } mHistory.remove(pos); mHistory.add(top, r); - moved.add(0, r); + moved.add(0, r.appToken); top--; } pos--; @@ -3818,7 +3837,7 @@ final class ActivityStack { mService.mWindowManager.moveAppTokensToTop(moved); if (VALIDATE_TOKENS) { - mService.mWindowManager.validateAppTokens(mHistory); + validateAppTokensLocked(); } finishTaskMoveLocked(task); @@ -3865,7 +3884,7 @@ final class ActivityStack { } } - ArrayList moved = new ArrayList(); + ArrayList<IBinder> moved = new ArrayList<IBinder>(); if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to back transition: task=" + task); @@ -3890,7 +3909,7 @@ final class ActivityStack { } mHistory.remove(pos); mHistory.add(bottom, r); - moved.add(r); + moved.add(r.appToken); bottom++; } pos++; @@ -3910,7 +3929,7 @@ final class ActivityStack { } mService.mWindowManager.moveAppTokensToBottom(moved); if (VALIDATE_TOKENS) { - mService.mWindowManager.validateAppTokens(mHistory); + validateAppTokensLocked(); } finishTaskMoveLocked(task); @@ -4102,7 +4121,7 @@ final class ActivityStack { if (r.app == null || r.app.thread == null) { if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG, "Switch is destroying non-running " + r); - destroyActivityLocked(r, true, false); + destroyActivityLocked(r, true, false, "config"); } else if (r.state == ActivityState.PAUSING) { // A little annoying: we are waiting for this activity to // finish pausing. Let's not do anything now, but just @@ -4140,7 +4159,7 @@ final class ActivityStack { if (r.app != null && r.app.thread != null) { try { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r); - r.app.thread.scheduleActivityConfigurationChanged(r); + r.app.thread.scheduleActivityConfigurationChanged(r.appToken); } catch (RemoteException e) { // If process died, whatever. } @@ -4170,7 +4189,7 @@ final class ActivityStack { try { if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r); r.forceNewConfig = false; - r.app.thread.scheduleRelaunchActivity(r, results, newIntents, + r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes, !andResume, mService.mConfiguration); // Note: don't need to call pauseIfSleepingLocked() here, because // the caller will only pass in 'andResume' if this activity is diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/java/com/android/server/am/EventLogTags.logtags index aadd37d..a579f44 100644 --- a/services/java/com/android/server/am/EventLogTags.logtags +++ b/services/java/com/android/server/am/EventLogTags.logtags @@ -48,7 +48,7 @@ option java_package com.android.server.am # Reporting to applications that memory is low 30017 am_low_memory (Num Processes|1|1) # An activity is being destroyed: -30018 am_destroy_activity (Token|1|5),(Task ID|1|5),(Component Name|3) +30018 am_destroy_activity (Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3) # An activity has been relaunched, resumed, and is now in the foreground: 30019 am_relaunch_resume_activity (Token|1|5),(Task ID|1|5),(Component Name|3) # An activity has been relaunched: diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java index 131255f..af7b314 100644 --- a/services/java/com/android/server/am/ProcessList.java +++ b/services/java/com/android/server/am/ProcessList.java @@ -16,7 +16,6 @@ package com.android.server.am; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; @@ -24,7 +23,6 @@ import com.android.internal.util.MemInfoReader; import com.android.server.wm.WindowManagerService; import android.graphics.Point; -import android.os.StrictMode; import android.util.Slog; /** @@ -37,27 +35,31 @@ class ProcessList { // OOM adjustments for processes in various states: - // This is a process without anything currently running in it. Definitely - // the first to go! Value set in system/rootdir/init.rc on startup. - // This value is initalized in the constructor, careful when refering to - // this static variable externally. - static final int EMPTY_APP_ADJ = 15; - // This is a process only hosting activities that are not visible, - // so it can be killed without any disruption. Value set in - // system/rootdir/init.rc on startup. + // so it can be killed without any disruption. static final int HIDDEN_APP_MAX_ADJ = 15; - static int HIDDEN_APP_MIN_ADJ = 7; + static int HIDDEN_APP_MIN_ADJ = 9; + + // The B list of SERVICE_ADJ -- these are the old and decrepit + // services that aren't as shiny and interesting as the ones in the A list. + static final int SERVICE_B_ADJ = 8; + + // This is the process of the previous application that the user was in. + // This process is kept above other things, because it is very common to + // switch back to the previous app. This is important both for recent + // task switch (toggling between the two top recent apps) as well as normal + // UI flow such as clicking on a URI in the e-mail app to view in the browser, + // and then pressing back to return to e-mail. + static final int PREVIOUS_APP_ADJ = 7; // This is a process holding the home application -- we want to try // avoiding killing it, even if it would normally be in the background, // because the user interacts with it so much. static final int HOME_APP_ADJ = 6; - // This is a process holding a secondary server -- killing it will not - // have much of an impact as far as the user is concerned. Value set in - // system/rootdir/init.rc on startup. - static final int SECONDARY_SERVER_ADJ = 5; + // This is a process holding an application service -- killing it will not + // have much of an impact as far as the user is concerned. + static final int SERVICE_ADJ = 5; // This is a process currently hosting a backup operation. Killing it // is not entirely fatal but is generally a bad idea. @@ -70,22 +72,20 @@ class ProcessList { // This is a process only hosting components that are perceptible to the // user, and we really want to avoid killing them, but they are not - // immediately visible. An example is background music playback. Value set in - // system/rootdir/init.rc on startup. + // immediately visible. An example is background music playback. static final int PERCEPTIBLE_APP_ADJ = 2; // This is a process only hosting activities that are visible to the - // user, so we'd prefer they don't disappear. Value set in - // system/rootdir/init.rc on startup. + // user, so we'd prefer they don't disappear. static final int VISIBLE_APP_ADJ = 1; // This is the process running the current foreground app. We'd really - // rather not kill it! Value set in system/rootdir/init.rc on startup. + // rather not kill it! static final int FOREGROUND_APP_ADJ = 0; - // This is a process running a core server, such as telephony. Definitely + // This is a system persistent process, such as telephony. Definitely // don't want to kill it, but doing so is not completely fatal. - static final int CORE_SERVER_ADJ = -12; + static final int PERSISTENT_PROC_ADJ = -12; // The system process runs at the default adjustment. static final int SYSTEM_ADJ = -16; @@ -115,7 +115,7 @@ class ProcessList { // can't give it a different value for every possible kind of process. private final int[] mOomAdj = new int[] { FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ, - BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, EMPTY_APP_ADJ + BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, HIDDEN_APP_MAX_ADJ }; // These are the low-end OOM level limits. This is appropriate for an // HVGA or smaller phone with less than 512MB. Values are in KB. diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 9392bb4..72292be 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -63,6 +63,7 @@ class ProcessRecord { int curSchedGroup; // Currently desired scheduling class int setSchedGroup; // Last set to background scheduling class int trimMemoryLevel; // Last selected memory trimming level + boolean serviceb; // Process currently is on the service B list boolean keeping; // Actively running code so don't kill due to that? boolean setIsForeground; // Running foreground UI when last set? boolean foregroundServices; // Running any services that are foreground? @@ -179,6 +180,7 @@ class ProcessRecord { pw.print(prefix); pw.print("lastActivityTime="); TimeUtils.formatDuration(lastActivityTime, now, pw); pw.print(" lruWeight="); pw.print(lruWeight); + pw.print(" serviceb="); pw.print(serviceb); pw.print(" keeping="); pw.print(keeping); pw.print(" hidden="); pw.print(hidden); pw.print(" empty="); pw.println(empty); @@ -271,7 +273,7 @@ class ProcessRecord { processName = _processName; pkgList.add(_info.packageName); thread = _thread; - maxAdj = ProcessList.EMPTY_APP_ADJ; + maxAdj = ProcessList.HIDDEN_APP_MAX_ADJ; hiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ; curRawAdj = setRawAdj = -100; curAdj = setAdj = -100; diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index 423a78f..c344bc6 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -73,7 +73,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private Context mContext; private final static String TAG = "Tethering"; private final static boolean DBG = true; - private final static boolean VDBG = true; + private final static boolean VDBG = false; // TODO - remove both of these - should be part of interface inspection/selection stuff private String[] mTetherableUsbRegexs; @@ -228,7 +228,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { if (isUsb(iface)) { // ignore usb0 down after enabling RNDIS // we will handle disconnect in interfaceRemoved instead - if (VDBG) Log.d(TAG, "ignoring interface down for " + iface); + if (VDBG) Log.d(TAG, "ignore interface down for " + iface); } else if (sm != null) { sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN); mIfaces.remove(iface); @@ -298,7 +298,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { mIfaces.put(iface, sm); sm.start(); } - if (VDBG) Log.d(TAG, "interfaceAdded :" + iface); } public void interfaceRemoved(String iface) { @@ -415,7 +414,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER, erroredList); mContext.sendStickyBroadcast(broadcast); - if (VDBG) { + if (DBG) { Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " + activeList.size() + ", " + erroredList.size()); } @@ -865,7 +864,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { @Override public boolean processMessage(Message message) { - if (VDBG) Log.d(TAG, "InitialState.processMessage what=" + message.what); + if (DBG) Log.d(TAG, "InitialState.processMessage what=" + message.what); boolean retValue = true; switch (message.what) { case CMD_TETHER_REQUESTED: @@ -906,7 +905,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } @Override public boolean processMessage(Message message) { - if (VDBG) Log.d(TAG, "StartingState.processMessage what=" + message.what); + if (DBG) Log.d(TAG, "StartingState.processMessage what=" + message.what); boolean retValue = true; switch (message.what) { // maybe a parent class? @@ -985,7 +984,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { @Override public boolean processMessage(Message message) { - if (VDBG) Log.d(TAG, "TetheredState.processMessage what=" + message.what); + if (DBG) Log.d(TAG, "TetheredState.processMessage what=" + message.what); boolean retValue = true; boolean error = false; switch (message.what) { @@ -1061,7 +1060,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { ConnectivityManager.TETHER_ERROR_MASTER_ERROR); break; } - if (VDBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName); + if (DBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName); sendTetherStateChangedBroadcast(); if (mUsb) { if (!Tethering.this.configureUsbIface(false)) { @@ -1296,7 +1295,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } } - if (VDBG) { + if (DBG) { Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn =" + mPreferredUpstreamMobileApn + ", got type=" + upType); } @@ -1328,7 +1327,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } protected void notifyTetheredOfNewUpstreamIface(String ifaceName) { - if (VDBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName); + if (DBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName); mUpstreamIfaceName = ifaceName; for (Object o : mNotifyList) { TetherInterfaceSM sm = (TetherInterfaceSM)o; @@ -1344,7 +1343,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } @Override public boolean processMessage(Message message) { - if (VDBG) Log.d(TAG, "MasterInitialState.processMessage what=" + message.what); + if (DBG) Log.d(TAG, "MasterInitialState.processMessage what=" + message.what); boolean retValue = true; switch (message.what) { case CMD_TETHER_MODE_REQUESTED: @@ -1386,7 +1385,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } @Override public boolean processMessage(Message message) { - if (VDBG) Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what); + if (DBG) Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what); boolean retValue = true; switch (message.what) { case CMD_TETHER_MODE_REQUESTED: diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index bdad82a..2a1b1db 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -19,7 +19,6 @@ package com.android.server.net; import static android.Manifest.permission.ACCESS_NETWORK_STATE; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.DUMP; -import static android.Manifest.permission.MANAGE_APP_TOKENS; import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.READ_PHONE_STATE; @@ -93,6 +92,7 @@ import android.os.HandlerThread; import android.os.INetworkManagementService; import android.os.IPowerManager; import android.os.Message; +import android.os.MessageQueue.IdleHandler; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.provider.Settings; @@ -190,6 +190,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_METERED_IFACES_CHANGED = 2; private static final int MSG_FOREGROUND_ACTIVITIES_CHANGED = 3; private static final int MSG_PROCESS_DIED = 4; + private static final int MSG_LIMIT_REACHED = 5; private final Context mContext; private final IActivityManager mActivityManager; @@ -225,8 +226,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Set of currently active {@link Notification} tags. */ private HashSet<String> mActiveNotifs = Sets.newHashSet(); - /** Current values from {@link #setPolicyDataEnable(int, boolean)}. */ - private SparseBooleanArray mActiveNetworkEnabled = new SparseBooleanArray(); /** Foreground at both UID and PID granularity. */ private SparseBooleanArray mUidForeground = new SparseBooleanArray(); @@ -424,19 +423,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // only someone like NMS should be calling us mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); - synchronized (mRulesLock) { - if (mMeteredIfaces.contains(iface) && !LIMIT_GLOBAL_ALERT.equals(limitName)) { - try { - // force stats update to make sure we have numbers that - // caused alert to trigger. - mNetworkStats.forceUpdate(); - } catch (RemoteException e) { - // ignored; service lives in system_server - } - - updateNetworkEnabledLocked(); - updateNotificationsLocked(); - } + if (!LIMIT_GLOBAL_ALERT.equals(limitName)) { + mHandler.obtainMessage(MSG_LIMIT_REACHED, iface).sendToTarget(); } } }; @@ -1481,6 +1469,25 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } return true; } + case MSG_LIMIT_REACHED: { + final String iface = (String) msg.obj; + + synchronized (mRulesLock) { + if (mMeteredIfaces.contains(iface)) { + try { + // force stats update to make sure we have + // numbers that caused alert to trigger. + mNetworkStats.forceUpdate(); + } catch (RemoteException e) { + // ignored; service lives in system_server + } + + updateNetworkEnabledLocked(); + updateNotificationsLocked(); + } + } + return true; + } default: { return false; } @@ -1519,21 +1526,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** - * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}, - * dispatching only when actually changed. + * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}. */ private void setPolicyDataEnable(int networkType, boolean enabled) { - synchronized (mActiveNetworkEnabled) { - final boolean prevEnabled = mActiveNetworkEnabled.get(networkType, true); - if (prevEnabled == enabled) return; - - try { - mConnManager.setPolicyDataEnable(networkType, enabled); - } catch (RemoteException e) { - // ignored; service lives in system_server - } - - mActiveNetworkEnabled.put(networkType, enabled); + try { + mConnManager.setPolicyDataEnable(networkType, enabled); + } catch (RemoteException e) { + // ignored; service lives in system_server } } @@ -1583,6 +1582,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return intent; } + // @VisibleForTesting + public void addIdleHandler(IdleHandler handler) { + mHandler.getLooper().getQueue().addIdleHandler(handler); + } + private static void collectKeys(SparseIntArray source, SparseBooleanArray target) { final int size = source.size(); for (int i = 0; i < size; i++) { diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 789681e..6365525 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -32,7 +32,6 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static android.net.NetworkStatsHistory.randomLong; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.TrafficStats.UID_REMOVED; @@ -49,7 +48,6 @@ 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 android.text.format.DateUtils.WEEK_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; @@ -73,9 +71,11 @@ import android.net.NetworkIdentity; import android.net.NetworkInfo; import android.net.NetworkState; import android.net.NetworkStats; +import android.net.NetworkStats.NonMonotonicException; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.Binder; +import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -150,6 +150,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Sample recent usage after each poll event. */ private static final boolean ENABLE_SAMPLE_AFTER_POLL = true; + private static final String TAG_NETSTATS_ERROR = "netstats_error"; + private final Context mContext; private final INetworkManagementService mNetworkManager; private final IAlarmManager mAlarmManager; @@ -160,6 +162,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final PowerManager.WakeLock mWakeLock; private IConnectivityManager mConnManager; + private DropBoxManager mDropBox; // @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = @@ -271,6 +274,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { readNetworkXtStatsLocked(); } + // bootstrap initial stats to prevent double-counting later + bootstrapStats(); + // watch for network interfaces to be claimed final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); @@ -304,8 +310,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { registerPollAlarmLocked(); registerGlobalAlert(); - // bootstrap initial stats to prevent double-counting later - bootstrapStats(); + mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE); } private void shutdownLocked() { @@ -621,7 +626,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // broadcast. final int uid = intent.getIntExtra(EXTRA_UID, 0); synchronized (mStatsLock) { - // TODO: perform one last stats poll for UID mWakeLock.acquire(); try { removeUidLocked(uid); @@ -802,9 +806,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats networkDevSnapshot; try { // collect any tethering stats - final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs(); - final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( - tetheredIfacePairs); + final NetworkStats tetherSnapshot = getNetworkStatsTethering(); // record uid stats, folding in tethering stats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); @@ -829,9 +831,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // persist when enough network data has occurred final long persistNetworkDevDelta = computeStatsDelta( - mLastPersistNetworkDevSnapshot, networkDevSnapshot, true).getTotalBytes(); + mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, "devp").getTotalBytes(); final long persistNetworkXtDelta = computeStatsDelta( - mLastPersistNetworkXtSnapshot, networkXtSnapshot, true).getTotalBytes(); + mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, "xtp").getTotalBytes(); final boolean networkOverThreshold = persistNetworkDevDelta > threshold || persistNetworkXtDelta > threshold; if (persistForce || (persistNetwork && networkOverThreshold)) { @@ -842,8 +844,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // persist when enough uid data has occurred - final long persistUidDelta = computeStatsDelta(mLastPersistUidSnapshot, uidSnapshot, true) - .getTotalBytes(); + final long persistUidDelta = computeStatsDelta( + mLastPersistUidSnapshot, uidSnapshot, true, "uidp").getTotalBytes(); if (persistForce || (persistUid && persistUidDelta > threshold)) { writeUidStatsLocked(); mLastPersistUidSnapshot = uidSnapshot; @@ -872,7 +874,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HashSet<String> unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta( - mLastPollNetworkDevSnapshot, networkDevSnapshot, false); + mLastPollNetworkDevSnapshot, networkDevSnapshot, false, "dev"); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -902,7 +904,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HashSet<String> unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta( - mLastPollNetworkXtSnapshot, networkXtSnapshot, false); + mLastPollNetworkXtSnapshot, networkXtSnapshot, false, "xt"); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -931,9 +933,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) { ensureUidStatsLoadedLocked(); - final NetworkStats delta = computeStatsDelta(mLastPollUidSnapshot, uidSnapshot, false); + final NetworkStats delta = computeStatsDelta( + mLastPollUidSnapshot, uidSnapshot, false, "uid"); final NetworkStats operationsDelta = computeStatsDelta( - mLastPollOperationsSnapshot, mOperations, false); + mLastPollOperationsSnapshot, mOperations, false, "uidop"); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -962,8 +965,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } mLastPollUidSnapshot = uidSnapshot; - mLastPollOperationsSnapshot = mOperations; - mOperations = new NetworkStats(0L, 10); + mLastPollOperationsSnapshot = mOperations.clone(); } /** @@ -1014,6 +1016,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void removeUidLocked(int uid) { ensureUidStatsLoadedLocked(); + // perform one last poll before removing + performPollLocked(FLAG_PERSIST_ALL); + final ArrayList<UidStatsKey> knownKeys = Lists.newArrayList(); knownKeys.addAll(mUidStats.keySet()); @@ -1031,6 +1036,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + // clear UID from current stats snapshot + mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid); + mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot); + // clear kernel stats associated with UID resetKernelUidStats(uid); @@ -1490,10 +1499,30 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Return the delta between two {@link NetworkStats} snapshots, where {@code * before} can be {@code null}. */ - private static NetworkStats computeStatsDelta( - NetworkStats before, NetworkStats current, boolean collectStale) { + private NetworkStats computeStatsDelta( + NetworkStats before, NetworkStats current, boolean collectStale, String type) { if (before != null) { - return current.subtractClamped(before); + try { + return current.subtract(before, false); + } catch (NonMonotonicException e) { + Log.w(TAG, "found non-monotonic values; saving to dropbox"); + + // record error for debugging + final StringBuilder builder = new StringBuilder(); + builder.append("found non-monotonic " + type + " values at left[" + e.leftIndex + + "] - right[" + e.rightIndex + "]\n"); + builder.append("left=").append(e.left).append('\n'); + builder.append("right=").append(e.right).append('\n'); + mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString()); + + try { + // return clamped delta to help recover + return current.subtract(before, true); + } catch (NonMonotonicException e1) { + Log.wtf(TAG, "found non-monotonic values; returning empty delta", e1); + return new NetworkStats(0L, 10); + } + } } else if (collectStale) { // caller is okay collecting stale stats for first call. return current; @@ -1504,6 +1533,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + /** + * Return snapshot of current tethering statistics. Will return empty + * {@link NetworkStats} if any problems are encountered. + */ + private NetworkStats getNetworkStatsTethering() throws RemoteException { + try { + final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs(); + return mNetworkManager.getNetworkStatsTethering(tetheredIfacePairs); + } catch (IllegalStateException e) { + Log.wtf(TAG, "problem reading network stats", e); + return new NetworkStats(0L, 10); + } + } + private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) { return uidSnapshot.groupedByIface(); } diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index bfe6613..36442a0 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -63,6 +63,8 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import libcore.io.IoUtils; + /** * Holds information about dynamic settings. */ @@ -998,8 +1000,8 @@ final class Settings { FileUtils.sync(fstr); str.close(); journal.commit(); - } - catch (Exception e) { + } catch (Exception e) { + IoUtils.closeQuietly(str); journal.rollback(); } diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java index 61c96bb..0e3d20a 100644 --- a/services/java/com/android/server/wm/AppWindowToken.java +++ b/services/java/com/android/server/wm/AppWindowToken.java @@ -77,6 +77,9 @@ class AppWindowToken extends WindowToken { // Last visibility state we reported to the app token. boolean reportedVisible; + // Last drawn state we reported to the app token. + boolean reportedDrawn; + // Set to true when the token has been removed from the window mgr. boolean removed; @@ -277,6 +280,7 @@ class AppWindowToken extends WindowToken { int numInteresting = 0; int numVisible = 0; + int numDrawn = 0; boolean nowGone = true; if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Update reported visibility: " + this); @@ -307,6 +311,7 @@ class AppWindowToken extends WindowToken { } numInteresting++; if (win.isDrawnLw()) { + numDrawn++; if (!win.isAnimating()) { numVisible++; } @@ -316,9 +321,27 @@ class AppWindowToken extends WindowToken { } } + boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting; boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting; + if (!nowGone) { + // If the app is not yet gone, then it can only become visible/drawn. + if (!nowDrawn) { + nowDrawn = reportedDrawn; + } + if (!nowVisible) { + nowVisible = reportedVisible; + } + } if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "VIS " + this + ": interesting=" + numInteresting + " visible=" + numVisible); + if (nowDrawn != reportedDrawn) { + if (nowDrawn) { + Message m = service.mH.obtainMessage( + H.REPORT_APPLICATION_TOKEN_DRAWN, this); + service.mH.sendMessage(m); + } + reportedDrawn = nowDrawn; + } if (nowVisible != reportedVisible) { if (WindowManagerService.DEBUG_VISIBILITY) Slog.v( WindowManagerService.TAG, "Visibility changed in " + this @@ -360,6 +383,7 @@ class AppWindowToken extends WindowToken { pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested); pw.print(" clientHidden="); pw.print(clientHidden); pw.print(" willBeHidden="); pw.print(willBeHidden); + pw.print(" reportedDrawn="); pw.print(reportedDrawn); pw.print(" reportedVisible="); pw.println(reportedVisible); if (paused || freezingScreen) { pw.print(prefix); pw.print("paused="); pw.print(paused); diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java index df7e0e1..a4f0a0c 100644 --- a/services/java/com/android/server/wm/InputManager.java +++ b/services/java/com/android/server/wm/InputManager.java @@ -675,7 +675,13 @@ public class InputManager implements Watchdog.Monitor { } catch (NumberFormatException e) { } if (result < 1) { - result = 55; + // This number equates to the refresh rate * 1.5. The rate should be at least + // equal to the screen refresh rate. We increase the rate by 50% to compensate for + // the discontinuity between the actual rate that events come in at (they do + // not necessarily come in constantly and are not handled synchronously). + // Ideally, we would use Display.getRefreshRate(), but as this does not necessarily + // return a sensible result, we use '60' as our default assumed refresh rate. + result = 90; } return result; } diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java index 131f11c..8fc9a70 100644 --- a/services/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java @@ -88,13 +88,14 @@ class ScreenRotationAnimation { try { try { mSurface = new Surface(session, 0, "FreezeSurface", - -1, mWidth, mHeight, PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT); + -1, mWidth, mHeight, PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN); if (mSurface == null || !mSurface.isValid()) { // Screenshot failed, punt. mSurface = null; return; } mSurface.setLayer(FREEZE_LAYER + 1); + mSurface.show(); } catch (Surface.OutOfResourcesException e) { Slog.w(TAG, "Unable to allocate freeze surface", e); } diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java index 03b7546..ee62a56 100644 --- a/services/java/com/android/server/wm/Session.java +++ b/services/java/com/android/server/wm/Session.java @@ -306,7 +306,15 @@ final class Session extends IWindowSession.Stub synchronized (mService.mWindowMap) { long ident = Binder.clearCallingIdentity(); try { - if (mService.mDragState == null || mService.mDragState.mToken != token) { + if (mService.mDragState == null) { + // Most likely the drop recipient ANRed and we ended the drag + // out from under it. Log the issue and move on. + Slog.w(WindowManagerService.TAG, "Drop result given but no drag in progress"); + return; + } + + if (mService.mDragState.mToken != token) { + // We're in a drag, but the wrong window has responded. Slog.w(WindowManagerService.TAG, "Invalid drop-result claim by " + window); throw new IllegalStateException("reportDropResult() by non-recipient"); } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 122d515..50321b3 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -1836,7 +1836,8 @@ public class WindowManagerService extends IWindowManager.Stub rawChanged = true; } - if (rawChanged) { + if (rawChanged && (wallpaperWin.getAttrs().privateFlags & + WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) { try { if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset " + wallpaperWin + " x=" + wallpaperWin.mWallpaperX @@ -1886,12 +1887,10 @@ public class WindowManagerService extends IWindowManager.Stub } } - boolean updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) { + void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) { final int dw = mAppDisplayWidth; final int dh = mAppDisplayHeight; - boolean changed = false; - WindowState target = mWallpaperTarget; if (target != null) { if (target.mWallpaperX >= 0) { @@ -1916,14 +1915,31 @@ public class WindowManagerService extends IWindowManager.Stub WindowState wallpaper = token.windows.get(curWallpaperIndex); if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) { wallpaper.computeShownFrameLocked(); - changed = true; + // No need to lay out the windows - we can just set the wallpaper position + // directly. + if (wallpaper.mSurfaceX != wallpaper.mShownFrame.left + || wallpaper.mSurfaceY != wallpaper.mShownFrame.top) { + Surface.openTransaction(); + try { + if (SHOW_TRANSACTIONS) logSurface(wallpaper, + "POS " + wallpaper.mShownFrame.left + + ", " + wallpaper.mShownFrame.top, null); + wallpaper.mSurfaceX = wallpaper.mShownFrame.left; + wallpaper.mSurfaceY = wallpaper.mShownFrame.top; + wallpaper.mSurface.setPosition(wallpaper.mShownFrame.left, + wallpaper.mShownFrame.top); + } catch (RuntimeException e) { + Slog.w(TAG, "Error positioning surface of " + wallpaper + + " pos=(" + wallpaper.mShownFrame.left + + "," + wallpaper.mShownFrame.top + ")", e); + } + Surface.closeTransaction(); + } // We only want to be synchronous with one wallpaper. sync = false; } } } - - return changed; } void updateWallpaperVisibilityLocked() { @@ -2436,9 +2452,7 @@ public class WindowManagerService extends IWindowManager.Stub window.mWallpaperY = y; window.mWallpaperXStep = xStep; window.mWallpaperYStep = yStep; - if (updateWallpaperOffsetLocked(window, true)) { - performLayoutAndPlaceSurfacesLocked(); - } + updateWallpaperOffsetLocked(window, true); } } @@ -2578,11 +2592,7 @@ public class WindowManagerService extends IWindowManager.Stub (win.mAppToken == null || !win.mAppToken.clientHidden)) { displayed = !win.isVisibleLw(); if (win.mExiting) { - win.mExiting = false; - if (win.mAnimation != null) { - win.mAnimation.cancel(); - win.mAnimation = null; - } + win.cancelExitAnimationForNextAnimationLocked(); } if (win.mDestroying) { win.mDestroying = false; @@ -3060,7 +3070,7 @@ public class WindowManagerService extends IWindowManager.Stub // Application Window Tokens // ------------------------------------------------------------- - public void validateAppTokens(List tokens) { + public void validateAppTokens(List<IBinder> tokens) { int v = tokens.size()-1; int m = mAppTokens.size()-1; while (v >= 0 && m >= 0) { @@ -5799,7 +5809,87 @@ public class WindowManagerService extends IWindowManager.Stub return curSize; } - private int computeSmallestWidth(boolean rotated, int dw, int dh, float density) { + private int reduceConfigLayout(int curLayout, int rotation, float density, + int dw, int dh) { + // Get the app screen size at this rotation. + int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation); + int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation); + + // Compute the screen layout size class for this rotation. + int screenLayoutSize; + boolean screenLayoutLong; + boolean screenLayoutCompatNeeded; + int longSize = w; + int shortSize = h; + if (longSize < shortSize) { + int tmp = longSize; + longSize = shortSize; + shortSize = tmp; + } + longSize = (int)(longSize/density); + shortSize = (int)(shortSize/density); + + // These semi-magic numbers define our compatibility modes for + // applications with different screens. These are guarantees to + // app developers about the space they can expect for a particular + // configuration. DO NOT CHANGE! + if (longSize < 470) { + // This is shorter than an HVGA normal density screen (which + // is 480 pixels on its long side). + screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_SMALL; + screenLayoutLong = false; + screenLayoutCompatNeeded = false; + } else { + // What size is this screen screen? + if (longSize >= 960 && shortSize >= 720) { + // 1.5xVGA or larger screens at medium density are the point + // at which we consider it to be an extra large screen. + screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_XLARGE; + } else if (longSize >= 640 && shortSize >= 480) { + // VGA or larger screens at medium density are the point + // at which we consider it to be a large screen. + screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_LARGE; + } else { + screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_NORMAL; + } + + // If this screen is wider than normal HVGA, or taller + // than FWVGA, then for old apps we want to run in size + // compatibility mode. + if (shortSize > 321 || longSize > 570) { + screenLayoutCompatNeeded = true; + } else { + screenLayoutCompatNeeded = false; + } + + // Is this a long screen? + if (((longSize*3)/5) >= (shortSize-1)) { + // Anything wider than WVGA (5:3) is considering to be long. + screenLayoutLong = true; + } else { + screenLayoutLong = false; + } + } + + // Now reduce the last screenLayout to not be better than what we + // have found. + if (!screenLayoutLong) { + curLayout = (curLayout&~Configuration.SCREENLAYOUT_LONG_MASK) + | Configuration.SCREENLAYOUT_LONG_NO; + } + if (screenLayoutCompatNeeded) { + curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED; + } + int curSize = curLayout&Configuration.SCREENLAYOUT_SIZE_MASK; + if (screenLayoutSize < curSize) { + curLayout = (curLayout&~Configuration.SCREENLAYOUT_SIZE_MASK) + | screenLayoutSize; + } + return curLayout; + } + + private void computeSmallestWidthAndScreenLayout(boolean rotated, int dw, int dh, + float density, Configuration outConfig) { // We need to determine the smallest width that will occur under normal // operation. To this, start with the base screen size and compute the // width under the different possible rotations. We need to un-rotate @@ -5816,7 +5906,14 @@ public class WindowManagerService extends IWindowManager.Stub 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, unrotDh, unrotDw); - return sw; + int sl = Configuration.SCREENLAYOUT_SIZE_XLARGE + | Configuration.SCREENLAYOUT_LONG_YES; + sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh); + sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw); + sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh); + sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw); + outConfig.smallestScreenWidthDp = sw; + outConfig.screenLayout = sl; } private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm, @@ -5914,64 +6011,12 @@ public class WindowManagerService extends IWindowManager.Stub / dm.density); config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation) / dm.density); - config.smallestScreenWidthDp = computeSmallestWidth(rotated, dw, dh, dm.density); + computeSmallestWidthAndScreenLayout(rotated, dw, dh, dm.density, config); config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale); config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale); config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh); - // Compute the screen layout size class. - int screenLayout; - int longSize = mAppDisplayWidth; - int shortSize = mAppDisplayHeight; - if (longSize < shortSize) { - int tmp = longSize; - longSize = shortSize; - shortSize = tmp; - } - longSize = (int)(longSize/dm.density); - shortSize = (int)(shortSize/dm.density); - - // These semi-magic numbers define our compatibility modes for - // applications with different screens. These are guarantees to - // app developers about the space they can expect for a particular - // configuration. DO NOT CHANGE! - if (longSize < 470) { - // This is shorter than an HVGA normal density screen (which - // is 480 pixels on its long side). - screenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL - | Configuration.SCREENLAYOUT_LONG_NO; - } else { - // What size is this screen screen? - if (longSize >= 960 && shortSize >= 720) { - // 1.5xVGA or larger screens at medium density are the point - // at which we consider it to be an extra large screen. - screenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE; - } else if (longSize >= 640 && shortSize >= 480) { - // VGA or larger screens at medium density are the point - // at which we consider it to be a large screen. - screenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE; - } else { - screenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL; - } - - // If this screen is wider than normal HVGA, or taller - // than FWVGA, then for old apps we want to run in size - // compatibility mode. - if (shortSize > 321 || longSize > 570) { - screenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED; - } - - // Is this a long screen? - if (((longSize*3)/5) >= (shortSize-1)) { - // Anything wider than WVGA (5:3) is considering to be long. - screenLayout |= Configuration.SCREENLAYOUT_LONG_YES; - } else { - screenLayout |= Configuration.SCREENLAYOUT_LONG_NO; - } - } - config.screenLayout = screenLayout; - // Determine whether a hard keyboard is available and enabled. boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS; if (hardKeyboardAvailable != mHardKeyboardAvailable) { @@ -6376,6 +6421,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int REMOVE_STARTING = 6; public static final int FINISHED_STARTING = 7; public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8; + public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9; public static final int WINDOW_FREEZE_TIMEOUT = 11; public static final int HOLD_SCREEN_CHANGED = 12; public static final int APP_TRANSITION_TIMEOUT = 13; @@ -6589,6 +6635,17 @@ public class WindowManagerService extends IWindowManager.Stub } } break; + case REPORT_APPLICATION_TOKEN_DRAWN: { + final AppWindowToken wtoken = (AppWindowToken)msg.obj; + + try { + if (DEBUG_VISIBILITY) Slog.v( + TAG, "Reporting drawn in " + wtoken); + wtoken.appToken.windowsDrawn(); + } catch (RemoteException ex) { + } + } break; + case REPORT_APPLICATION_TOKEN_WINDOWS: { final AppWindowToken wtoken = (AppWindowToken)msg.obj; diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index e9875a5..23ec2d9 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -596,11 +596,24 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } + // TODO: Fix and call finishExit() instead of cancelExitAnimationForNextAnimationLocked() + // for avoiding the code duplication. + void cancelExitAnimationForNextAnimationLocked() { + if (!mExiting) return; + if (mAnimation != null) { + mAnimation.cancel(); + mAnimation = null; + destroySurfaceLocked(); + } + mExiting = false; + } + Surface createSurfaceLocked() { if (mSurface == null) { mReportDestroySurface = false; mSurfacePendingDestroy = false; - Slog.i(WindowManagerService.TAG, "createSurface " + this + ": DRAW NOW PENDING"); + if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(WindowManagerService.TAG, + "createSurface " + this + ": DRAW NOW PENDING"); mDrawPending = true; mCommitDrawPending = false; mReadyToShow = false; @@ -1745,4 +1758,4 @@ final class WindowState implements WindowManagerPolicy.WindowState { } return mStringNameCache; } -}
\ No newline at end of file +} |
