diff options
Diffstat (limited to 'services/java/com/android')
17 files changed, 988 insertions, 499 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 851cb33..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; @@ -171,6 +178,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int ENABLED = 1; private static final int DISABLED = 0; + private static final boolean ADD = true; + private static final boolean REMOVE = false; + + private static final boolean TO_DEFAULT_TABLE = true; + private static final boolean TO_SECONDARY_TABLE = false; + // Share the event space with NetworkStateTracker (which can't see this // internal class but sends us events). If you change these, change // NetworkStateTracker.java too. @@ -485,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); @@ -495,13 +514,15 @@ 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); INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b); - mTethering = new Tethering(mContext, nmService, statsService, mHandler.getLooper()); + mTethering = new Tethering(mContext, nmService, statsService, this, mHandler.getLooper()); mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 || mTethering.getTetherableWifiRegexs().length != 0 || mTethering.getTetherableBluetoothRegexs().length != 0) && @@ -525,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 @@ -1146,23 +1241,24 @@ public class ConnectivityService extends IConnectivityManager.Stub { return false; } - private boolean addRoute(LinkProperties p, RouteInfo r) { - return modifyRoute(p.getInterfaceName(), p, r, 0, true); + private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) { + return modifyRoute(p.getInterfaceName(), p, r, 0, ADD, toDefaultTable); } - private boolean removeRoute(LinkProperties p, RouteInfo r) { - return modifyRoute(p.getInterfaceName(), p, r, 0, false); + private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) { + return modifyRoute(p.getInterfaceName(), p, r, 0, REMOVE, toDefaultTable); } private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) { - return modifyRouteToAddress(lp, addr, true); + return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE); } private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) { - return modifyRouteToAddress(lp, addr, false); + return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE); } - private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd) { + private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd, + boolean toDefaultTable) { RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), addr); if (bestRoute == null) { bestRoute = RouteInfo.makeHostRoute(addr); @@ -1176,15 +1272,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway()); } } - return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd); + return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd, toDefaultTable); } private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount, - boolean doAdd) { + boolean doAdd, boolean toDefaultTable) { if ((ifaceName == null) || (lp == null) || (r == null)) return false; if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) { - loge("Error adding route - too much recursion"); + loge("Error modifying route - too much recursion"); return false; } @@ -1199,14 +1295,18 @@ public class ConnectivityService extends IConnectivityManager.Stub { // route to it's gateway bestRoute = RouteInfo.makeHostRoute(r.getGateway(), bestRoute.getGateway()); } - modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd); + modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd, toDefaultTable); } } if (doAdd) { if (VDBG) log("Adding " + r + " for interface " + ifaceName); - mAddedRoutes.add(r); try { - mNetd.addRoute(ifaceName, r); + if (toDefaultTable) { + mAddedRoutes.add(r); // only track default table - only one apps can effect + mNetd.addRoute(ifaceName, r); + } else { + mNetd.addSecondaryRoute(ifaceName, r); + } } catch (Exception e) { // never crash - catch them all if (VDBG) loge("Exception trying to add a route: " + e); @@ -1215,18 +1315,29 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { // if we remove this one and there are no more like it, then refcount==0 and // we can remove it from the table - mAddedRoutes.remove(r); - if (mAddedRoutes.contains(r) == false) { + if (toDefaultTable) { + mAddedRoutes.remove(r); + if (mAddedRoutes.contains(r) == false) { + if (VDBG) log("Removing " + r + " for interface " + ifaceName); + try { + mNetd.removeRoute(ifaceName, r); + } catch (Exception e) { + // never crash - catch them all + if (VDBG) loge("Exception trying to remove a route: " + e); + return false; + } + } else { + if (VDBG) log("not removing " + r + " as it's still in use"); + } + } else { if (VDBG) log("Removing " + r + " for interface " + ifaceName); try { - mNetd.removeRoute(ifaceName, r); + mNetd.removeSecondaryRoute(ifaceName, r); } catch (Exception e) { // never crash - catch them all if (VDBG) loge("Exception trying to remove a route: " + e); return false; } - } else { - if (VDBG) log("not removing " + r + " as it's still in use"); } } return true; @@ -1486,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 @@ -1862,14 +1974,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (RouteInfo r : routeDiff.removed) { if (isLinkDefault || ! r.isDefaultRoute()) { - removeRoute(curLp, r); + removeRoute(curLp, r, TO_DEFAULT_TABLE); + } + if (isLinkDefault == false) { + // remove from a secondary route table + removeRoute(curLp, r, TO_SECONDARY_TABLE); } } for (RouteInfo r : routeDiff.added) { if (isLinkDefault || ! r.isDefaultRoute()) { - addRoute(newLp, r); + addRoute(newLp, r, TO_DEFAULT_TABLE); } else { + // add to a secondary route table + addRoute(newLp, r, TO_SECONDARY_TABLE); + // many radios add a default route even when we don't want one. // remove the default route unless somebody else has asked for it String ifaceName = newLp.getInterfaceName(); @@ -2450,12 +2569,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0); - // Short term disabling of Tethering if DUN is required. - // TODO - fix multi-connection tethering using policy-base routing - int[] upstreamConnTypes = mTethering.getUpstreamIfaceTypes(); - for (int i : upstreamConnTypes) { - if (i == ConnectivityManager.TYPE_MOBILE_DUN) return false; - } return tetherEnabledInSettings && mTetheringConfigValid; } 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/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index 4e4fe4a..da960ae 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -59,7 +59,11 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Inet4Address; import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.net.SocketException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.NoSuchElementException; import java.util.StringTokenizer; @@ -77,6 +81,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub private static final int ADD = 1; private static final int REMOVE = 2; + private static final String DEFAULT = "default"; + private static final String SECONDARY = "secondary"; + /** * Name representing {@link #setGlobalAlert(long)} limit when delivered to * {@link INetworkManagementEventObserver#limitReached(String, String)}. @@ -505,15 +512,25 @@ public class NetworkManagementService extends INetworkManagementService.Stub public void addRoute(String interfaceName, RouteInfo route) { mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG); - modifyRoute(interfaceName, ADD, route); + modifyRoute(interfaceName, ADD, route, DEFAULT); } public void removeRoute(String interfaceName, RouteInfo route) { mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG); - modifyRoute(interfaceName, REMOVE, route); + modifyRoute(interfaceName, REMOVE, route, DEFAULT); } - private void modifyRoute(String interfaceName, int action, RouteInfo route) { + public void addSecondaryRoute(String interfaceName, RouteInfo route) { + mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG); + modifyRoute(interfaceName, ADD, route, SECONDARY); + } + + public void removeSecondaryRoute(String interfaceName, RouteInfo route) { + mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG); + modifyRoute(interfaceName, REMOVE, route, SECONDARY); + } + + private void modifyRoute(String interfaceName, int action, RouteInfo route, String type) { ArrayList<String> rsp; StringBuilder cmd; @@ -521,12 +538,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub switch (action) { case ADD: { - cmd = new StringBuilder("interface route add " + interfaceName); + cmd = new StringBuilder("interface route add " + interfaceName + " " + type); break; } case REMOVE: { - cmd = new StringBuilder("interface route remove " + interfaceName); + cmd = new StringBuilder("interface route remove " + interfaceName + " " + type); break; } default: @@ -833,14 +850,33 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } + private void modifyNat(String cmd, String internalInterface, String externalInterface) + throws SocketException { + cmd = String.format("nat %s %s %s", cmd, internalInterface, externalInterface); + + NetworkInterface internalNetworkInterface = + NetworkInterface.getByName(internalInterface); + Collection<InterfaceAddress>interfaceAddresses = + internalNetworkInterface.getInterfaceAddresses(); + cmd += " " + interfaceAddresses.size(); + for (InterfaceAddress ia : interfaceAddresses) { + InetAddress addr = NetworkUtils.getNetworkPart(ia.getAddress(), + ia.getNetworkPrefixLength()); + cmd = cmd + " " + addr.getHostAddress() + "/" + ia.getNetworkPrefixLength(); + } + + mConnector.doCommand(cmd); + } + public void enableNat(String internalInterface, String externalInterface) throws IllegalStateException { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); + if (DBG) Log.d(TAG, "enableNat(" + internalInterface + ", " + externalInterface + ")"); try { - mConnector.doCommand( - String.format("nat enable %s %s", internalInterface, externalInterface)); - } catch (NativeDaemonConnectorException e) { + modifyNat("enable", internalInterface, externalInterface); + } catch (Exception e) { + Log.e(TAG, "enableNat got Exception " + e.toString()); throw new IllegalStateException( "Unable to communicate to native daemon for enabling NAT interface"); } @@ -850,10 +886,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub throws IllegalStateException { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); + if (DBG) Log.d(TAG, "disableNat(" + internalInterface + ", " + externalInterface + ")"); try { - mConnector.doCommand( - String.format("nat disable %s %s", internalInterface, externalInterface)); - } catch (NativeDaemonConnectorException e) { + modifyNat("disable", internalInterface, externalInterface); + } catch (Exception e) { + Log.e(TAG, "disableNat got Exception " + e.toString()); throw new IllegalStateException( "Unable to communicate to native daemon for disabling NAT interface"); } @@ -1099,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 e97ee7a..5788a31 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 @@ -3048,7 +3051,7 @@ public class PowerManagerService extends IPowerManager.Stub handleLightSensorValue(value); } 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 b042da6..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; } } 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/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 0c42926..cd63090 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -120,6 +120,7 @@ import android.view.WindowManagerPolicy; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; @@ -128,8 +129,10 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; +import java.io.StringWriter; import java.lang.IllegalStateException; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -857,9 +860,11 @@ public final class ActivityManagerService extends ActivityManagerNative static final int SHOW_COMPAT_MODE_DIALOG_MSG = 30; static final int DISPATCH_FOREGROUND_ACTIVITIES_CHANGED = 31; static final int DISPATCH_PROCESS_DIED = 32; + static final int REPORT_MEM_USAGE = 33; AlertDialog mUidAlert; CompatModeDialog mCompatModeDialog; + long mLastMemUsageReportTime = 0; final Handler mHandler = new Handler() { //public Handler() { @@ -1199,6 +1204,71 @@ public final class ActivityManagerService extends ActivityManagerNative dispatchProcessDied(pid, uid); break; } + case REPORT_MEM_USAGE: { + boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); + if (!isDebuggable) { + return; + } + synchronized (ActivityManagerService.this) { + long now = SystemClock.uptimeMillis(); + if (now < (mLastMemUsageReportTime+10000)) { + // Don't report more than every 10 seconds to somewhat + // avoid spamming. + return; + } + mLastMemUsageReportTime = now; + } + 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", }); + final InputStreamReader converter = new InputStreamReader( + proc.getInputStream()); + BufferedReader in = new BufferedReader(converter); + String line; + while (true) { + line = in.readLine(); + if (line == null) { + break; + } + if (line.length() > 0) { + 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); + 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) { + mLastMemUsageReportTime = now; + } + } + } + }; + thread.start(); + break; + } } } }; @@ -1339,7 +1409,7 @@ public final class ActivityManagerService extends ActivityManagerNative return; } - mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args); + mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null); } } @@ -1599,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); } } @@ -2276,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); @@ -2359,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)) { @@ -2379,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); } } @@ -2445,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"); @@ -2547,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) { @@ -2635,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(); @@ -2768,6 +2839,7 @@ public final class ActivityManagerService extends ActivityManagerNative addProcessToGcListLocked(rec); } } + mHandler.sendEmptyMessage(REPORT_MEM_USAGE); scheduleAppGcsLocked(); } } @@ -3136,7 +3208,49 @@ public final class ActivityManagerService extends ActivityManagerNative return; } killPackageProcessesLocked(packageName, pkgUid, - ProcessList.SERVICE_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); @@ -3308,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 @@ -3343,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; } @@ -3374,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++) { @@ -3462,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); @@ -3481,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) { @@ -5059,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); } } @@ -5433,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; } @@ -5454,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--; @@ -6790,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"); } } @@ -6986,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; } @@ -6998,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 @@ -8517,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(); @@ -8934,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); @@ -9242,8 +9357,10 @@ public final class ActivityManagerService extends ActivityManagerNative } final void dumpApplicationMemoryUsage(FileDescriptor fd, - PrintWriter pw, String prefix, String[] args) { + PrintWriter pw, String prefix, String[] args, boolean brief, + PrintWriter categoryPw) { boolean dumpAll = false; + boolean oomOnly = false; int opti = 0; while (opti < args.length) { @@ -9254,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; @@ -9382,15 +9502,20 @@ public final class ActivityManagerService extends ActivityManagerNative } } - pw.println(); - pw.println("Total PSS by process:"); - dumpMemItems(pw, " ", procMems, true); - pw.println(); + if (!brief && !oomOnly) { + pw.println(); + pw.println("Total PSS by process:"); + dumpMemItems(pw, " ", procMems, true); + pw.println(); + } pw.println("Total PSS by OOM adjustment:"); dumpMemItems(pw, " ", oomMems, false); - 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"); } diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 00e6cb2..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,14 +579,14 @@ 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); } } @@ -687,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 8435eaa..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); } @@ -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) @@ -1399,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); @@ -1414,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, @@ -1433,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; @@ -1457,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; } @@ -1496,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, @@ -1511,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(); @@ -1528,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, @@ -1549,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; } @@ -1567,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, @@ -1610,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; } @@ -1677,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 @@ -1705,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) { @@ -1725,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. @@ -1826,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; } @@ -1849,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++; } @@ -1985,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; @@ -2081,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"); @@ -3007,7 +3016,7 @@ final class ActivityStack { return res; } - resultTo = outActivity[0]; + resultTo = outActivity[0] != null ? outActivity[0].appToken : null; } } } finally { @@ -3065,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); @@ -3080,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) { @@ -3098,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); } @@ -3145,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) { @@ -3186,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) { @@ -3413,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); @@ -3440,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; } @@ -3570,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(); @@ -3653,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 @@ -3712,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); @@ -3781,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. @@ -3803,7 +3814,7 @@ final class ActivityStack { } mHistory.remove(pos); mHistory.add(top, r); - moved.add(0, r); + moved.add(0, r.appToken); top--; } pos--; @@ -3826,7 +3837,7 @@ final class ActivityStack { mService.mWindowManager.moveAppTokensToTop(moved); if (VALIDATE_TOKENS) { - mService.mWindowManager.validateAppTokens(mHistory); + validateAppTokensLocked(); } finishTaskMoveLocked(task); @@ -3873,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); @@ -3898,7 +3909,7 @@ final class ActivityStack { } mHistory.remove(pos); mHistory.add(bottom, r); - moved.add(r); + moved.add(r.appToken); bottom++; } pos++; @@ -3918,7 +3929,7 @@ final class ActivityStack { } mService.mWindowManager.moveAppTokensToBottom(moved); if (VALIDATE_TOKENS) { - mService.mWindowManager.validateAppTokens(mHistory); + validateAppTokensLocked(); } finishTaskMoveLocked(task); @@ -4148,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. } @@ -4178,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/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index 7bd29d9..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; @@ -81,6 +81,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private String[] mTetherableBluetoothRegexs; private Collection<Integer> mUpstreamIfaceTypes; + // used to synchronize public access to members + private Object mPublicSync; + private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE); private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI); private static final Integer DUN_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_DUN); @@ -91,6 +94,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private final INetworkManagementService mNMService; private final INetworkStatsService mStatsService; + private final IConnectivityManager mConnService; private Looper mLooper; private HandlerThread mThread; @@ -127,12 +131,15 @@ public class Tethering extends INetworkManagementEventObserver.Stub { // when RNDIS is enabled public Tethering(Context context, INetworkManagementService nmService, - INetworkStatsService statsService, Looper looper) { + INetworkStatsService statsService, IConnectivityManager connService, Looper looper) { mContext = context; mNMService = nmService; mStatsService = statsService; + mConnService = connService; mLooper = looper; + mPublicSync = new Object(); + mIfaces = new HashMap<String, TetherInterfaceSM>(); // make our own thread so we don't anr the system @@ -170,18 +177,25 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } void updateConfiguration() { - mTetherableUsbRegexs = mContext.getResources().getStringArray( + String[] tetherableUsbRegexs = mContext.getResources().getStringArray( com.android.internal.R.array.config_tether_usb_regexs); - mTetherableWifiRegexs = mContext.getResources().getStringArray( + String[] tetherableWifiRegexs = mContext.getResources().getStringArray( com.android.internal.R.array.config_tether_wifi_regexs); - mTetherableBluetoothRegexs = mContext.getResources().getStringArray( + String[] tetherableBluetoothRegexs = mContext.getResources().getStringArray( com.android.internal.R.array.config_tether_bluetooth_regexs); int ifaceTypes[] = mContext.getResources().getIntArray( com.android.internal.R.array.config_tether_upstream_types); - mUpstreamIfaceTypes = new ArrayList(); + Collection<Integer> upstreamIfaceTypes = new ArrayList(); for (int i : ifaceTypes) { - mUpstreamIfaceTypes.add(new Integer(i)); + upstreamIfaceTypes.add(new Integer(i)); + } + + synchronized (mPublicSync) { + mTetherableUsbRegexs = tetherableUsbRegexs; + mTetherableWifiRegexs = tetherableWifiRegexs; + mTetherableBluetoothRegexs = tetherableBluetoothRegexs; + mUpstreamIfaceTypes = upstreamIfaceTypes; } // check if the upstream type list needs to be modified due to secure-settings @@ -192,17 +206,17 @@ public class Tethering extends INetworkManagementEventObserver.Stub { if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up); boolean found = false; boolean usb = false; - if (isWifi(iface)) { - found = true; - } else if (isUsb(iface)) { - found = true; - usb = true; - } else if (isBluetooth(iface)) { - found = true; - } - if (found == false) return; + synchronized (mPublicSync) { + if (isWifi(iface)) { + found = true; + } else if (isUsb(iface)) { + found = true; + usb = true; + } else if (isBluetooth(iface)) { + found = true; + } + if (found == false) return; - synchronized (mIfaces) { TetherInterfaceSM sm = mIfaces.get(iface); if (up) { if (sm == null) { @@ -214,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); @@ -229,46 +243,52 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } private boolean isUsb(String iface) { - for (String regex : mTetherableUsbRegexs) { - if (iface.matches(regex)) return true; + synchronized (mPublicSync) { + for (String regex : mTetherableUsbRegexs) { + if (iface.matches(regex)) return true; + } + return false; } - return false; } public boolean isWifi(String iface) { - for (String regex : mTetherableWifiRegexs) { - if (iface.matches(regex)) return true; + synchronized (mPublicSync) { + for (String regex : mTetherableWifiRegexs) { + if (iface.matches(regex)) return true; + } + return false; } - return false; } public boolean isBluetooth(String iface) { - for (String regex : mTetherableBluetoothRegexs) { - if (iface.matches(regex)) return true; + synchronized (mPublicSync) { + for (String regex : mTetherableBluetoothRegexs) { + if (iface.matches(regex)) return true; + } + return false; } - return false; } public void interfaceAdded(String iface) { if (VDBG) Log.d(TAG, "interfaceAdded " + iface); boolean found = false; boolean usb = false; - if (isWifi(iface)) { - found = true; - } - if (isUsb(iface)) { - found = true; - usb = true; - } - if (isBluetooth(iface)) { - found = true; - } - if (found == false) { - if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring"); - return; - } + synchronized (mPublicSync) { + if (isWifi(iface)) { + found = true; + } + if (isUsb(iface)) { + found = true; + usb = true; + } + if (isBluetooth(iface)) { + found = true; + } + if (found == false) { + if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring"); + return; + } - synchronized (mIfaces) { TetherInterfaceSM sm = mIfaces.get(iface); if (sm != null) { if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring"); @@ -278,12 +298,11 @@ public class Tethering extends INetworkManagementEventObserver.Stub { mIfaces.put(iface, sm); sm.start(); } - if (VDBG) Log.d(TAG, "interfaceAdded :" + iface); } public void interfaceRemoved(String iface) { if (VDBG) Log.d(TAG, "interfaceRemoved " + iface); - synchronized (mIfaces) { + synchronized (mPublicSync) { TetherInterfaceSM sm = mIfaces.get(iface); if (sm == null) { if (VDBG) { @@ -301,7 +320,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { public int tether(String iface) { if (DBG) Log.d(TAG, "Tethering " + iface); TetherInterfaceSM sm = null; - synchronized (mIfaces) { + synchronized (mPublicSync) { sm = mIfaces.get(iface); } if (sm == null) { @@ -319,7 +338,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { public int untether(String iface) { if (DBG) Log.d(TAG, "Untethering " + iface); TetherInterfaceSM sm = null; - synchronized (mIfaces) { + synchronized (mPublicSync) { sm = mIfaces.get(iface); } if (sm == null) { @@ -336,21 +355,22 @@ public class Tethering extends INetworkManagementEventObserver.Stub { public int getLastTetherError(String iface) { TetherInterfaceSM sm = null; - synchronized (mIfaces) { + synchronized (mPublicSync) { sm = mIfaces.get(iface); + if (sm == null) { + Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface + + ", ignoring"); + return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE; + } + return sm.getLastError(); } - if (sm == null) { - Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface + ", ignoring"); - return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE; - } - return sm.getLastError(); } + // TODO - move all private methods used only by the state machine into the state machine + // to clarify what needs synchronized protection. private void sendTetherStateChangedBroadcast() { - IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); - IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b); try { - if (!cm.isTetheringSupported()) return; + if (!mConnService.isTetheringSupported()) return; } catch (RemoteException e) { return; } @@ -363,7 +383,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { boolean usbTethered = false; boolean bluetoothTethered = false; - synchronized (mIfaces) { + synchronized (mPublicSync) { Set ifaces = mIfaces.keySet(); for (Object iface : ifaces) { TetherInterfaceSM sm = mIfaces.get(iface); @@ -394,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()); } @@ -469,7 +489,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { public void onReceive(Context content, Intent intent) { String action = intent.getAction(); if (action.equals(UsbManager.ACTION_USB_STATE)) { - synchronized (Tethering.this) { + synchronized (Tethering.this.mPublicSync) { boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false); mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false); // start tethering if we have a request pending @@ -545,6 +565,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { return true; } + // TODO - return copies so people can't tamper public String[] getTetherableUsbRegexs() { return mTetherableUsbRegexs; } @@ -561,7 +582,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")"); UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE); - synchronized (this) { + synchronized (mPublicSync) { if (enable) { if (mRndisEnabled) { tetherUsb(true); @@ -581,11 +602,14 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } public int[] getUpstreamIfaceTypes() { - updateConfiguration(); - int values[] = new int[mUpstreamIfaceTypes.size()]; - Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator(); - for (int i=0; i < mUpstreamIfaceTypes.size(); i++) { - values[i] = iterator.next(); + int values[]; + synchronized (mPublicSync) { + updateConfiguration(); + values = new int[mUpstreamIfaceTypes.size()]; + Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator(); + for (int i=0; i < mUpstreamIfaceTypes.size(); i++) { + values[i] = iterator.next(); + } } return values; } @@ -593,43 +617,46 @@ public class Tethering extends INetworkManagementEventObserver.Stub { public void checkDunRequired() { int secureSetting = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.TETHER_DUN_REQUIRED, 2); - // 2 = not set, 0 = DUN not required, 1 = DUN required - if (secureSetting != 2) { - int requiredApn = (secureSetting == 1 ? - ConnectivityManager.TYPE_MOBILE_DUN : - ConnectivityManager.TYPE_MOBILE_HIPRI); - if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) { - while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) { - mUpstreamIfaceTypes.remove(MOBILE_TYPE); - } - while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) { - mUpstreamIfaceTypes.remove(HIPRI_TYPE); - } - if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) { - mUpstreamIfaceTypes.add(DUN_TYPE); + synchronized (mPublicSync) { + // 2 = not set, 0 = DUN not required, 1 = DUN required + if (secureSetting != 2) { + int requiredApn = (secureSetting == 1 ? + ConnectivityManager.TYPE_MOBILE_DUN : + ConnectivityManager.TYPE_MOBILE_HIPRI); + if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) { + while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) { + mUpstreamIfaceTypes.remove(MOBILE_TYPE); + } + while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) { + mUpstreamIfaceTypes.remove(HIPRI_TYPE); + } + if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) { + mUpstreamIfaceTypes.add(DUN_TYPE); + } + } else { + while (mUpstreamIfaceTypes.contains(DUN_TYPE)) { + mUpstreamIfaceTypes.remove(DUN_TYPE); + } + if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) { + mUpstreamIfaceTypes.add(MOBILE_TYPE); + } + if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) { + mUpstreamIfaceTypes.add(HIPRI_TYPE); + } } + } + if (mUpstreamIfaceTypes.contains(DUN_TYPE)) { + mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_DUN; } else { - while (mUpstreamIfaceTypes.contains(DUN_TYPE)) { - mUpstreamIfaceTypes.remove(DUN_TYPE); - } - if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) { - mUpstreamIfaceTypes.add(MOBILE_TYPE); - } - if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) { - mUpstreamIfaceTypes.add(HIPRI_TYPE); - } + mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_HIPRI; } } - if (mUpstreamIfaceTypes.contains(DUN_TYPE)) { - mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_DUN; - } else { - mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_HIPRI; - } } + // TODO review API - maybe return ArrayList<String> here and below? public String[] getTetheredIfaces() { ArrayList<String> list = new ArrayList<String>(); - synchronized (mIfaces) { + synchronized (mPublicSync) { Set keys = mIfaces.keySet(); for (Object key : keys) { TetherInterfaceSM sm = mIfaces.get(key); @@ -647,7 +674,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { public String[] getTetheredIfacePairs() { final ArrayList<String> list = Lists.newArrayList(); - synchronized (mIfaces) { + synchronized (mPublicSync) { for (TetherInterfaceSM sm : mIfaces.values()) { if (sm.isTethered()) { list.add(sm.mMyUpstreamIfaceName); @@ -660,7 +687,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { public String[] getTetherableIfaces() { ArrayList<String> list = new ArrayList<String>(); - synchronized (mIfaces) { + synchronized (mPublicSync) { Set keys = mIfaces.keySet(); for (Object key : keys) { TetherInterfaceSM sm = mIfaces.get(key); @@ -678,7 +705,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { public String[] getErroredIfaces() { ArrayList<String> list = new ArrayList<String>(); - synchronized (mIfaces) { + synchronized (mPublicSync) { Set keys = mIfaces.keySet(); for (Object key : keys) { TetherInterfaceSM sm = mIfaces.get(key); @@ -777,43 +804,54 @@ public class Tethering extends INetworkManagementEventObserver.Stub { return res; } - public synchronized int getLastError() { - return mLastError; + public int getLastError() { + synchronized (Tethering.this.mPublicSync) { + return mLastError; + } } - private synchronized void setLastError(int error) { - mLastError = error; + private void setLastError(int error) { + synchronized (Tethering.this.mPublicSync) { + mLastError = error; - if (isErrored()) { - if (mUsb) { - // note everything's been unwound by this point so nothing to do on - // further error.. - Tethering.this.configureUsbIface(false); + if (isErrored()) { + if (mUsb) { + // note everything's been unwound by this point so nothing to do on + // further error.. + Tethering.this.configureUsbIface(false); + } } } } - // synchronized between this getter and the following setter - public synchronized boolean isAvailable() { - return mAvailable; + public boolean isAvailable() { + synchronized (Tethering.this.mPublicSync) { + return mAvailable; + } } - private synchronized void setAvailable(boolean available) { - mAvailable = available; + private void setAvailable(boolean available) { + synchronized (Tethering.this.mPublicSync) { + mAvailable = available; + } } - // synchronized between this getter and the following setter - public synchronized boolean isTethered() { - return mTethered; + public boolean isTethered() { + synchronized (Tethering.this.mPublicSync) { + return mTethered; + } } - private synchronized void setTethered(boolean tethered) { - mTethered = tethered; + private void setTethered(boolean tethered) { + synchronized (Tethering.this.mPublicSync) { + mTethered = tethered; + } } - // synchronized between this getter and the following setter - public synchronized boolean isErrored() { - return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR); + public boolean isErrored() { + synchronized (Tethering.this.mPublicSync) { + return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR); + } } class InitialState extends State { @@ -826,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: @@ -867,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? @@ -910,6 +948,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { try { mNMService.tetherInterface(mIfaceName); } catch (Exception e) { + Log.e(TAG, "Error Tethering: " + e.toString()); setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR); transitionTo(mInitialState); @@ -921,7 +960,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { sendTetherStateChangedBroadcast(); } - void cleanupUpstream() { + private void cleanupUpstream() { if (mMyUpstreamIfaceName != null) { // note that we don't care about errors here. // sometimes interfaces are gone before we get @@ -945,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) { @@ -987,6 +1026,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { try { mNMService.enableNat(mIfaceName, newUpstreamIfaceName); } catch (Exception e) { + Log.e(TAG, "Exception enabling Nat: " + e.toString()); try { mNMService.untetherInterface(mIfaceName); } catch (Exception ee) {} @@ -1020,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)) { @@ -1150,13 +1190,11 @@ public class Tethering extends INetworkManagementEventObserver.Stub { boolean retValue = true; if (apnType == ConnectivityManager.TYPE_NONE) return false; if (apnType != mMobileApnReserved) turnOffUpstreamMobileConnection(); - IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); - IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b); int result = Phone.APN_REQUEST_FAILED; String enableString = enableString(apnType); if (enableString == null) return false; try { - result = cm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + result = mConnService.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, enableString, new Binder()); } catch (Exception e) { } @@ -1178,10 +1216,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } protected boolean turnOffUpstreamMobileConnection() { if (mMobileApnReserved != ConnectivityManager.TYPE_NONE) { - IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); - IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b); try { - cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + mConnService.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, enableString(mMobileApnReserved)); } catch (Exception e) { return false; @@ -1234,32 +1270,32 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } protected void chooseUpstreamType(boolean tryCell) { - IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); - IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b); int upType = ConnectivityManager.TYPE_NONE; String iface = null; updateConfiguration(); - if (VDBG) { - Log.d(TAG, "chooseUpstreamType has upstream iface types:"); - for (Integer netType : mUpstreamIfaceTypes) { - Log.d(TAG, " " + netType); + synchronized (mPublicSync) { + if (VDBG) { + Log.d(TAG, "chooseUpstreamType has upstream iface types:"); + for (Integer netType : mUpstreamIfaceTypes) { + Log.d(TAG, " " + netType); + } } - } - for (Integer netType : mUpstreamIfaceTypes) { - NetworkInfo info = null; - try { - info = cm.getNetworkInfo(netType.intValue()); - } catch (RemoteException e) { } - if ((info != null) && info.isConnected()) { - upType = netType.intValue(); - break; + for (Integer netType : mUpstreamIfaceTypes) { + NetworkInfo info = null; + try { + info = mConnService.getNetworkInfo(netType.intValue()); + } catch (RemoteException e) { } + if ((info != null) && info.isConnected()) { + upType = netType.intValue(); + break; + } } } - if (VDBG) { + if (DBG) { Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn =" + mPreferredUpstreamMobileApn + ", got type=" + upType); } @@ -1283,7 +1319,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } else { LinkProperties linkProperties = null; try { - linkProperties = cm.getLinkProperties(upType); + linkProperties = mConnService.getLinkProperties(upType); } catch (RemoteException e) { } if (linkProperties != null) iface = linkProperties.getInterfaceName(); } @@ -1291,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; @@ -1307,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: @@ -1349,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: @@ -1483,14 +1519,14 @@ public class Tethering extends INetworkManagementEventObserver.Stub { return; } - pw.println("mUpstreamIfaceTypes: "); - for (Integer netType : mUpstreamIfaceTypes) { - pw.println(" " + netType); - } + synchronized (mPublicSync) { + pw.println("mUpstreamIfaceTypes: "); + for (Integer netType : mUpstreamIfaceTypes) { + pw.println(" " + netType); + } - pw.println(); - pw.println("Tether state:"); - synchronized (mIfaces) { + pw.println(); + pw.println("Tether state:"); for (Object o : mIfaces.values()) { pw.println(" "+o.toString()); } diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index 289ea1f..2a1b1db 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -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 } } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 494c655..6365525 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -152,10 +152,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String TAG_NETSTATS_ERROR = "netstats_error"; - private static final String DEV = "dev"; - private static final String XT = "xt"; - private static final String UID = "uid"; - private final Context mContext; private final INetworkManagementService mNetworkManager; private final IAlarmManager mAlarmManager; @@ -278,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); @@ -311,9 +310,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { registerPollAlarmLocked(); registerGlobalAlert(); - // bootstrap initial stats to prevent double-counting later - bootstrapStats(); - mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE); } @@ -810,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); @@ -837,9 +831,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // persist when enough network data has occurred final long persistNetworkDevDelta = computeStatsDelta( - mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, DEV).getTotalBytes(); + mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, "devp").getTotalBytes(); final long persistNetworkXtDelta = computeStatsDelta( - mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, XT).getTotalBytes(); + mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, "xtp").getTotalBytes(); final boolean networkOverThreshold = persistNetworkDevDelta > threshold || persistNetworkXtDelta > threshold; if (persistForce || (persistNetwork && networkOverThreshold)) { @@ -851,7 +845,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // persist when enough uid data has occurred final long persistUidDelta = computeStatsDelta( - mLastPersistUidSnapshot, uidSnapshot, true, UID).getTotalBytes(); + mLastPersistUidSnapshot, uidSnapshot, true, "uidp").getTotalBytes(); if (persistForce || (persistUid && persistUidDelta > threshold)) { writeUidStatsLocked(); mLastPersistUidSnapshot = uidSnapshot; @@ -880,7 +874,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HashSet<String> unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta( - mLastPollNetworkDevSnapshot, networkDevSnapshot, false, DEV); + mLastPollNetworkDevSnapshot, networkDevSnapshot, false, "dev"); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -910,7 +904,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HashSet<String> unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta( - mLastPollNetworkXtSnapshot, networkXtSnapshot, false, XT); + mLastPollNetworkXtSnapshot, networkXtSnapshot, false, "xt"); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -940,9 +934,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ensureUidStatsLoadedLocked(); final NetworkStats delta = computeStatsDelta( - mLastPollUidSnapshot, uidSnapshot, false, UID); + mLastPollUidSnapshot, uidSnapshot, false, "uid"); final NetworkStats operationsDelta = computeStatsDelta( - mLastPollOperationsSnapshot, mOperations, false, UID); + mLastPollOperationsSnapshot, mOperations, false, "uidop"); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -971,8 +965,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } mLastPollUidSnapshot = uidSnapshot; - mLastPollOperationsSnapshot = mOperations; - mOperations = new NetworkStats(0L, 10); + mLastPollOperationsSnapshot = mOperations.clone(); } /** @@ -1510,20 +1503,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStats before, NetworkStats current, boolean collectStale, String type) { if (before != null) { try { - return current.subtract(before); + 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 + 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()); - // return empty delta to avoid recording broken stats - return new NetworkStats(0L, 10); + 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. @@ -1535,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/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/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 2cd3062..50321b3 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -3070,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) { @@ -5809,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 @@ -5826,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, @@ -5924,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) { @@ -8682,7 +8717,8 @@ public class WindowManagerService extends IWindowManager.Stub if (needRelayout) { requestAnimationLocked(0); } else if (animating) { - requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis()); + final int refreshTimeUs = (int)(1000 / mDisplay.getRefreshRate()); + requestAnimationLocked(currentTime + refreshTimeUs - SystemClock.uptimeMillis()); } // Finally update all input windows now that the window changes have stabilized. |