diff options
Diffstat (limited to 'services/java')
18 files changed, 1088 insertions, 335 deletions
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 983329b..e3fff81 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -158,11 +158,13 @@ class BackupManagerService extends IBackupManager.Stub { case MSG_RUN_BACKUP: // snapshot the pending-backup set and work on that synchronized (mQueueLock) { - mBackupQueue = new ArrayList(); - for (BackupRequest b: mPendingBackups.values()) { - mBackupQueue.add(b); + if (mBackupQueue == null) { + mBackupQueue = new ArrayList(); + for (BackupRequest b: mPendingBackups.values()) { + mBackupQueue.add(b); + } + mPendingBackups = new HashMap<ComponentName,BackupRequest>(); } - mPendingBackups = new HashMap<ComponentName,BackupRequest>(); // !!! TODO: start a new backup-queue journal file too // WARNING: If we crash after this line, anything in mPendingBackups will // be lost. FIX THIS. @@ -190,9 +192,13 @@ class BackupManagerService extends IBackupManager.Stub { BackupRequest request; synchronized (mQueueLock) { int queueSize = mBackupQueue.size(); + Log.d(TAG, "mBackupQueue.size=" + queueSize); if (queueSize == 0) { mBackupQueue = null; - // TODO: Anything else to do here? + // if there are pending backups, start those after a short delay + if (mPendingBackups.size() > 0) { + mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, COLLECTION_INTERVAL); + } return; } request = mBackupQueue.get(0); @@ -267,7 +273,7 @@ class BackupManagerService extends IBackupManager.Stub { // !!! TODO: After successful transport, delete the now-stale data // and juggle the files so that next time the new state is passed - backupDataName.delete(); + //backupDataName.delete(); newStateName.renameTo(savedStateName); } catch (FileNotFoundException fnf) { @@ -284,6 +290,9 @@ class BackupManagerService extends IBackupManager.Stub { mBackupQueue.remove(0); } mContext.unbindService(mBackupHandler); + + // start the next one + startOneService(); } // Add the backup services in the given package to our set of known backup participants. diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java index caad7d0..596053d 100644 --- a/services/java/com/android/server/BatteryService.java +++ b/services/java/com/android/server/BatteryService.java @@ -271,6 +271,7 @@ class BatteryService extends Binder { * - is not plugged and battery level crosses the WARNING boundary (becomes < 15). */ final boolean sendBatteryLow = !plugged + && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN && mBatteryLevel < BATTERY_LEVEL_WARNING && (oldPlugged || mLastBatteryLevel >= BATTERY_LEVEL_WARNING); diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java index 7b8a2a4..9c1f942 100644 --- a/services/java/com/android/server/InputDevice.java +++ b/services/java/com/android/server/InputDevice.java @@ -63,7 +63,7 @@ public class InputDevice { yMoveScale = my != 0 ? (1.0f/my) : 1.0f; } - MotionEvent generateMotion(InputDevice device, long curTime, + MotionEvent generateMotion(InputDevice device, long curTime, long curTimeNano, boolean isAbs, Display display, int orientation, int metaState) { if (!changed) { @@ -167,7 +167,7 @@ public class InputDevice { if (!isAbs) { x = y = 0; } - return MotionEvent.obtain(downTime, curTime, action, + return MotionEvent.obtainNano(downTime, curTime, curTimeNano, action, scaledX, scaledY, scaledPressure, scaledSize, metaState, xPrecision, yPrecision, device.id, edgeFlags); } else { @@ -181,7 +181,7 @@ public class InputDevice { } return null; } - MotionEvent me = MotionEvent.obtain(downTime, curTime, + MotionEvent me = MotionEvent.obtainNano(downTime, curTime, curTimeNano, MotionEvent.ACTION_MOVE, scaledX, scaledY, scaledPressure, scaledSize, metaState, xPrecision, yPrecision, device.id, edgeFlags); diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java index 53e63c2..d8c8c90 100644 --- a/services/java/com/android/server/IntentResolver.java +++ b/services/java/com/android/server/IntentResolver.java @@ -180,8 +180,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> { return resultList; } - public List<R> queryIntent(ContentResolver resolver, Intent intent, - String resolvedType, boolean defaultOnly) { + public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly) { String scheme = intent.getScheme(); ArrayList<R> finalList = new ArrayList<R>(); diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java index 411cd6b..78cdf8b 100644 --- a/services/java/com/android/server/KeyInputQueue.java +++ b/services/java/com/android/server/KeyInputQueue.java @@ -18,8 +18,9 @@ package com.android.server; import android.content.Context; import android.content.res.Configuration; -import android.os.SystemClock; +import android.os.LatencyTimer; import android.os.PowerManager; +import android.os.SystemClock; import android.util.Log; import android.util.SparseArray; import android.view.Display; @@ -73,14 +74,17 @@ public abstract class KeyInputQueue { public static final int FILTER_REMOVE = 0; public static final int FILTER_KEEP = 1; public static final int FILTER_ABORT = -1; - + + private static final boolean MEASURE_LATENCY = false; + private LatencyTimer lt; + public interface FilterCallback { int filterEvent(QueuedEvent ev); } static class QueuedEvent { InputDevice inputDevice; - long when; + long whenNano; int flags; // From the raw event int classType; // One of the class constants in InputEvent Object event; @@ -88,7 +92,7 @@ public abstract class KeyInputQueue { void copyFrom(QueuedEvent that) { this.inputDevice = that.inputDevice; - this.when = that.when; + this.whenNano = that.whenNano; this.flags = that.flags; this.classType = that.classType; this.event = that.event; @@ -107,6 +111,10 @@ public abstract class KeyInputQueue { } KeyInputQueue(Context context) { + if (MEASURE_LATENCY) { + lt = new LatencyTimer(100, 1000); + } + PowerManager pm = (PowerManager)context.getSystemService( Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, @@ -241,7 +249,7 @@ public abstract class KeyInputQueue { if (configChanged) { synchronized (mFirst) { - addLocked(di, SystemClock.uptimeMillis(), 0, + addLocked(di, System.nanoTime(), 0, RawInputEvent.CLASS_CONFIGURATION_CHANGED, null); } @@ -256,6 +264,7 @@ public abstract class KeyInputQueue { // timebase as SystemClock.uptimeMillis(). //curTime = gotOne ? ev.when : SystemClock.uptimeMillis(); final long curTime = SystemClock.uptimeMillis(); + final long curTimeNano = System.nanoTime(); //Log.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis()); final int classes = di.classes; @@ -276,7 +285,7 @@ public abstract class KeyInputQueue { down = false; } int keycode = rotateKeyCodeLocked(ev.keycode); - addLocked(di, curTime, ev.flags, + addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, newKeyEvent(di, di.mDownTime, curTime, down, keycode, 0, scancode, @@ -330,7 +339,7 @@ public abstract class KeyInputQueue { } MotionEvent me; - me = di.mAbs.generateMotion(di, curTime, true, + me = di.mAbs.generateMotion(di, curTime, curTimeNano, true, mDisplay, mOrientation, mGlobalMetaState); if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x + " y=" + di.mAbs.y + " ev=" + me); @@ -338,15 +347,15 @@ public abstract class KeyInputQueue { if (WindowManagerPolicy.WATCH_POINTER) { Log.i(TAG, "Enqueueing: " + me); } - addLocked(di, curTime, ev.flags, + addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_TOUCHSCREEN, me); } - me = di.mRel.generateMotion(di, curTime, false, + me = di.mRel.generateMotion(di, curTime, curTimeNano, false, mDisplay, mOrientation, mGlobalMetaState); if (false) Log.v(TAG, "Relative: x=" + di.mRel.x + " y=" + di.mRel.y + " ev=" + me); if (me != null) { - addLocked(di, curTime, ev.flags, + addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_TRACKBALL, me); } } @@ -530,7 +539,7 @@ public abstract class KeyInputQueue { } } - private QueuedEvent obtainLocked(InputDevice device, long when, + private QueuedEvent obtainLocked(InputDevice device, long whenNano, int flags, int classType, Object event) { QueuedEvent ev; if (mCacheCount == 0) { @@ -542,7 +551,7 @@ public abstract class KeyInputQueue { mCacheCount--; } ev.inputDevice = device; - ev.when = when; + ev.whenNano = whenNano; ev.flags = flags; ev.classType = classType; ev.event = event; @@ -561,13 +570,13 @@ public abstract class KeyInputQueue { } } - private void addLocked(InputDevice device, long when, int flags, + private void addLocked(InputDevice device, long whenNano, int flags, int classType, Object event) { boolean poke = mFirst.next == mLast; - QueuedEvent ev = obtainLocked(device, when, flags, classType, event); + QueuedEvent ev = obtainLocked(device, whenNano, flags, classType, event); QueuedEvent p = mLast.prev; - while (p != mFirst && ev.when < p.when) { + while (p != mFirst && ev.whenNano < p.whenNano) { p = p.prev; } @@ -578,8 +587,15 @@ public abstract class KeyInputQueue { ev.inQueue = true; if (poke) { + long time; + if (MEASURE_LATENCY) { + time = System.nanoTime(); + } mFirst.notify(); mWakeLock.acquire(); + if (MEASURE_LATENCY) { + lt.sample("1 addLocked-queued event ", System.nanoTime() - time); + } } } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 05888e0..147a085 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -46,7 +46,6 @@ import android.location.Address; import android.location.IGeocodeProvider; import android.location.IGpsStatusListener; import android.location.IGpsStatusProvider; -import android.location.ILocationCollector; import android.location.ILocationListener; import android.location.ILocationManager; import android.location.ILocationProvider; @@ -107,8 +106,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS; private static final String INSTALL_LOCATION_PROVIDER = android.Manifest.permission.INSTALL_LOCATION_PROVIDER; - private static final String INSTALL_LOCATION_COLLECTOR = - android.Manifest.permission.INSTALL_LOCATION_COLLECTOR; // Set of providers that are explicitly enabled private final Set<String> mEnabledProviders = new HashSet<String>(); @@ -171,9 +168,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run private HashMap<String,Location> mLastKnownLocation = new HashMap<String,Location>(); - // Location collector - private ILocationCollector mCollector; - private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; // for Settings change notification @@ -630,16 +624,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } } - public void installLocationCollector(ILocationCollector collector) { - if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_COLLECTOR) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires INSTALL_LOCATION_COLLECTOR permission"); - } - - // FIXME - only support one collector - mCollector = collector; - } - public void installGeocodeProvider(IGeocodeProvider provider) { if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) != PackageManager.PERMISSION_GRANTED) { @@ -1619,23 +1603,19 @@ public class LocationManagerService extends ILocationManager.Stub implements Run synchronized (mLock) { Location location = (Location) msg.obj; + String provider = location.getProvider(); - if (mCollector != null && - LocationManager.GPS_PROVIDER.equals(location.getProvider())) { - try { - mCollector.updateLocation(location); - } catch (RemoteException e) { - Log.w(TAG, "mCollector.updateLocation failed"); - mCollector = null; + // notify other providers of the new location + for (int i = mProviders.size() - 1; i >= 0; i--) { + LocationProviderProxy proxy = mProviders.get(i); + if (!provider.equals(proxy.getName())) { + proxy.updateLocation(location); } } - String provider = location.getProvider(); - if (!isAllowedBySettingsLocked(provider)) { - return; + if (isAllowedBySettingsLocked(provider)) { + handleLocationChangedLocked(location); } - - handleLocationChangedLocked(location); } } } catch (Exception e) { @@ -1935,7 +1915,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run synchronized (mLock) { pw.println("Current Location Manager state:"); pw.println(" sProvidersLoaded=" + sProvidersLoaded); - pw.println(" mCollector=" + mCollector); pw.println(" Listeners:"); int N = mReceivers.size(); for (int i=0; i<N; i++) { diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 5194aea..1cfe002 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -1270,8 +1270,7 @@ class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); List<PreferredActivity> prefs = - mSettings.mPreferredActivities.queryIntent(null, - intent, resolvedType, + mSettings.mPreferredActivities.queryIntent(intent, resolvedType, (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0); if (prefs != null && prefs.size() > 0) { // First figure out how good the original match set is. @@ -1348,7 +1347,7 @@ class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { return (List<ResolveInfo>)mActivities. - queryIntent(null, intent, resolvedType, flags); + queryIntent(intent, resolvedType, flags); } } @@ -1517,7 +1516,7 @@ class PackageManagerService extends IPackageManager.Stub { String resolvedType, int flags) { synchronized (mPackages) { return (List<ResolveInfo>)mReceivers. - queryIntent(null, intent, resolvedType, flags); + queryIntent(intent, resolvedType, flags); } } @@ -1550,8 +1549,7 @@ class PackageManagerService extends IPackageManager.Stub { } synchronized (mPackages) { - return (List<ResolveInfo>)mServices. - queryIntent(null, intent, resolvedType, flags); + return (List<ResolveInfo>)mServices.queryIntent(intent, resolvedType, flags); } } @@ -2831,6 +2829,21 @@ class PackageManagerService extends IPackageManager.Stub { // we can't add any new permissions to it. if (!gp.loadedPermissions.contains(perm)) { allowed = false; + // Except... if this is a permission that was added + // to the platform (note: need to only do this when + // updating the platform). + final int NP = PackageParser.NEW_PERMISSIONS.length; + for (int ip=0; ip<NP; ip++) { + final PackageParser.NewPermissionInfo npi + = PackageParser.NEW_PERMISSIONS[ip]; + if (npi.name.equals(perm) + && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) { + allowed = true; + Log.i(TAG, "Auto-granting WRITE_SDCARD to old pkg " + + pkg.packageName); + break; + } + } } } if (allowed) { @@ -2869,17 +2882,14 @@ class PackageManagerService extends IPackageManager.Stub { private final class ActivityIntentResolver extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { - public List queryIntent(ContentResolver resolver, Intent intent, - String resolvedType, boolean defaultOnly) { + public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) { mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; - return super.queryIntent(resolver, intent, resolvedType, defaultOnly); + return super.queryIntent(intent, resolvedType, defaultOnly); } - public List queryIntent(ContentResolver resolver, Intent intent, - String resolvedType, int flags) { + public List queryIntent(Intent intent, String resolvedType, int flags) { mFlags = flags; - return super.queryIntent( - resolver, intent, resolvedType, + return super.queryIntent(intent, resolvedType, (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0); } @@ -2893,8 +2903,13 @@ class PackageManagerService extends IPackageManager.Stub { int N = packageActivities.size(); ArrayList<ArrayList<PackageParser.ActivityIntentInfo>> listCut = new ArrayList<ArrayList<PackageParser.ActivityIntentInfo>>(N); + + ArrayList<PackageParser.ActivityIntentInfo> intentFilters; for (int i = 0; i < N; ++i) { - listCut.add(packageActivities.get(i).intents); + intentFilters = packageActivities.get(i).intents; + if (intentFilters != null && intentFilters.size() > 0) { + listCut.add(intentFilters); + } } return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut); } @@ -3013,17 +3028,14 @@ class PackageManagerService extends IPackageManager.Stub { private final class ServiceIntentResolver extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> { - public List queryIntent(ContentResolver resolver, Intent intent, - String resolvedType, boolean defaultOnly) { + public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) { mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; - return super.queryIntent(resolver, intent, resolvedType, defaultOnly); + return super.queryIntent(intent, resolvedType, defaultOnly); } - public List queryIntent(ContentResolver resolver, Intent intent, - String resolvedType, int flags) { + public List queryIntent(Intent intent, String resolvedType, int flags) { mFlags = flags; - return super.queryIntent( - resolver, intent, resolvedType, + return super.queryIntent(intent, resolvedType, (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0); } @@ -3589,7 +3601,9 @@ class PackageManagerService extends IPackageManager.Stub { } else { // Re installation failed. Restore old information // Remove new pkg information - removePackageLI(newPackage, true); + if (newPackage != null) { + removePackageLI(newPackage, true); + } // Add back the old system package scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath, oldPkgSetting.resourcePath, diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java index fa54421..88f47fd 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/java/com/android/server/TelephonyRegistry.java @@ -26,6 +26,7 @@ import android.os.RemoteException; import android.telephony.CellLocation; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; @@ -39,48 +40,64 @@ import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.DefaultPhoneNotifier; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneStateIntentReceiver; import com.android.internal.telephony.TelephonyIntents; import com.android.server.am.BatteryStatsService; - /** - * Since phone process can be restarted, this class provides a centralized - * place that applications can register and be called back from. + * Since phone process can be restarted, this class provides a centralized place + * that applications can register and be called back from. */ class TelephonyRegistry extends ITelephonyRegistry.Stub { private static final String TAG = "TelephonyRegistry"; private static class Record { String pkgForDebug; + IBinder binder; + IPhoneStateListener callback; + int events; } private final Context mContext; + private final ArrayList<Record> mRecords = new ArrayList(); + private final IBatteryStats mBatteryStats; private int mCallState = TelephonyManager.CALL_STATE_IDLE; + private String mCallIncomingNumber = ""; + private ServiceState mServiceState = new ServiceState(); - private int mSignalStrength = -1; + + private SignalStrength mSignalStrength = new SignalStrength(); + private boolean mMessageWaiting = false; + private boolean mCallForwarding = false; + private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; + private int mDataConnectionState = TelephonyManager.DATA_CONNECTED; + private boolean mDataConnectionPossible = false; + private String mDataConnectionReason = ""; + private String mDataConnectionApn = ""; + private String mDataConnectionInterfaceName = ""; + private Bundle mCellLocation = new Bundle(); - // we keep a copy of all of the sate so we can send it out when folks register for it + // we keep a copy of all of the state so we can send it out when folks + // register for it // - // In these calls we call with the lock held. This is safe becasuse remote - // calls go through a oneway interface and local calls going through a handler before - // they get to app code. + // In these calls we call with the lock held. This is safe becasuse remote + // calls go through a oneway interface and local calls going through a + // handler before they get to app code. TelephonyRegistry(Context context) { CellLocation.getEmpty().fillInNotifierBundle(mCellLocation); @@ -90,13 +107,18 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow) { - //Log.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)); + // Log.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" + + // Integer.toHexString(events)); if (events != 0) { // check permissions if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.ACCESS_COARSE_LOCATION, null); - + // ACCESS_FINE_LOCATION implies ACCESS_COARSE_LOCATION + if (mContext.checkCallingPermission( + android.Manifest.permission.ACCESS_FINE_LOCATION) + != PackageManager.PERMISSION_GRANTED) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.ACCESS_COARSE_LOCATION, null); + } } synchronized (mRecords) { @@ -105,7 +127,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { find_and_add: { IBinder b = callback.asBinder(); final int N = mRecords.size(); - for (int i=0; i<N; i++) { + for (int i = 0; i < N; i++) { r = mRecords.get(i); if (b == r.binder) { break find_and_add; @@ -125,7 +147,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { try { - r.callback.onSignalStrengthChanged(mSignalStrength); + int gsmSignalStrength = mSignalStrength.getGsmSignalStrength(); + r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 + : gsmSignalStrength)); } catch (RemoteException ex) { remove(r.binder); } @@ -168,6 +192,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { remove(r.binder); } } + if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { + try { + r.callback.onSignalStrengthsChanged(mSignalStrength); + } catch (RemoteException ex) { + remove(r.binder); + } + } } } } else { @@ -177,8 +208,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private void remove(IBinder binder) { synchronized (mRecords) { - final int N = mRecords.size(); - for (int i=0; i<N; i++) { + final int recordCount = mRecords.size(); + for (int i = 0; i < recordCount; i++) { if (mRecords.get(i).binder == binder) { mRecords.remove(i); return; @@ -194,8 +225,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { synchronized (mRecords) { mCallState = state; mCallIncomingNumber = incomingNumber; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { + for (int i = mRecords.size() - 1; i >= 0; i--) { Record r = mRecords.get(i); if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) { try { @@ -212,11 +242,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { public void notifyServiceState(ServiceState state) { if (!checkPhoneStatePermission("notifyServiceState()")) { return; - } + } synchronized (mRecords) { mServiceState = state; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { + for (int i = mRecords.size() - 1; i >= 0; i--) { Record r = mRecords.get(i); if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) { sendServiceState(r, state); @@ -226,35 +255,38 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { broadcastServiceStateChanged(state); } - public void notifySignalStrength(int signalStrengthASU) { + public void notifySignalStrength(SignalStrength signalStrength) { if (!checkPhoneStatePermission("notifySignalStrength()")) { return; - } + } synchronized (mRecords) { - mSignalStrength = signalStrengthASU; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { + mSignalStrength = signalStrength; + for (int i = mRecords.size() - 1; i >= 0; i--) { Record r = mRecords.get(i); + if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { + sendSignalStrength(r, signalStrength); + } if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { try { - r.callback.onSignalStrengthChanged(signalStrengthASU); + int gsmSignalStrength = signalStrength.getGsmSignalStrength(); + r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 + : gsmSignalStrength)); } catch (RemoteException ex) { remove(r.binder); } } } } - broadcastSignalStrengthChanged(signalStrengthASU); + broadcastSignalStrengthChanged(signalStrength); } public void notifyMessageWaitingChanged(boolean mwi) { if (!checkPhoneStatePermission("notifyMessageWaitingChanged()")) { return; - } + } synchronized (mRecords) { mMessageWaiting = mwi; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { + for (int i = mRecords.size() - 1; i >= 0; i--) { Record r = mRecords.get(i); if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) { try { @@ -270,11 +302,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { public void notifyCallForwardingChanged(boolean cfi) { if (!checkPhoneStatePermission("notifyCallForwardingChanged()")) { return; - } + } synchronized (mRecords) { mCallForwarding = cfi; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { + for (int i = mRecords.size() - 1; i >= 0; i--) { Record r = mRecords.get(i); if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) { try { @@ -290,11 +321,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { public void notifyDataActivity(int state) { if (!checkPhoneStatePermission("notifyDataActivity()")) { return; - } + } synchronized (mRecords) { mDataActivity = state; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { + for (int i = mRecords.size() - 1; i >= 0; i--) { Record r = mRecords.get(i); if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) { try { @@ -307,19 +337,18 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - public void notifyDataConnection(int state, boolean isDataConnectivityPissible, - String reason, String apn, String interfaceName) { + public void notifyDataConnection(int state, boolean isDataConnectivityPossible, String reason, + String apn, String interfaceName) { if (!checkPhoneStatePermission("notifyDataConnection()")) { return; - } + } synchronized (mRecords) { mDataConnectionState = state; - mDataConnectionPossible = isDataConnectivityPissible; + mDataConnectionPossible = isDataConnectivityPossible; mDataConnectionReason = reason; mDataConnectionApn = apn; mDataConnectionInterfaceName = interfaceName; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { + for (int i = mRecords.size() - 1; i >= 0; i--) { Record r = mRecords.get(i); if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { try { @@ -330,17 +359,17 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } } - broadcastDataConnectionStateChanged(state, isDataConnectivityPissible, - reason, apn, interfaceName); + broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn, + interfaceName); } public void notifyDataConnectionFailed(String reason) { if (!checkPhoneStatePermission("notifyDataConnectionFailed()")) { return; - } + } /* * This is commented out because there is on onDataConnectionFailed callback - * on PhoneStateListener. There should be. + * on PhoneStateListener. There should be synchronized (mRecords) { mDataConnectionFailedReason = reason; final int N = mRecords.size(); @@ -358,11 +387,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { public void notifyCellLocation(Bundle cellLocation) { if (!checkPhoneStatePermission("notifyCellLocation()")) { return; - } + } synchronized (mRecords) { mCellLocation = cellLocation; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { + for (int i = mRecords.size() - 1; i >= 0; i--) { Record r = mRecords.get(i); if ((r.events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) { sendCellLocation(r, cellLocation); @@ -371,12 +399,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - // - // the new callback broadcasting - // - // copy the service state object so they can't mess it up in the local calls - // - public void sendServiceState(Record r, ServiceState state) { + /** + * Copy the service state object so they can't mess it up in the local calls + */ + private void sendServiceState(Record r, ServiceState state) { try { r.callback.onServiceStateChanged(new ServiceState(state)); } catch (RemoteException ex) { @@ -384,7 +410,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - public void sendCellLocation(Record r, Bundle cellLocation) { + private void sendCellLocation(Record r, Bundle cellLocation) { try { r.callback.onCellLocationChanged(new Bundle(cellLocation)); } catch (RemoteException ex) { @@ -392,18 +418,24 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + private void sendSignalStrength(Record r, SignalStrength signalStrength) { + try { + r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength)); + } catch (RemoteException ex) { + remove(r.binder); + } + } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump telephony.registry from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); return; } synchronized (mRecords) { - final int N = mRecords.size(); + final int recordCount = mRecords.size(); pw.println("last known state:"); pw.println(" mCallState=" + mCallState); pw.println(" mCallIncomingNumber=" + mCallIncomingNumber); @@ -418,15 +450,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println(" mDataConnectionApn=" + mDataConnectionApn); pw.println(" mDataConnectionInterfaceName=" + mDataConnectionInterfaceName); pw.println(" mCellLocation=" + mCellLocation); - pw.println("registrations: count=" + N); - for (int i=0; i<N; i++) { + pw.println("registrations: count=" + recordCount); + for (int i = 0; i < recordCount; i++) { Record r = mRecords.get(i); pw.println(" " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events)); } } } - // // the legacy intent broadcasting // @@ -439,17 +470,20 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mContext.sendStickyBroadcast(intent); } - private void broadcastSignalStrengthChanged(int asu) { + private void broadcastSignalStrengthChanged(SignalStrength signalStrength) { long ident = Binder.clearCallingIdentity(); try { - mBatteryStats.notePhoneSignalStrength(asu); + mBatteryStats.notePhoneSignalStrength(signalStrength); } catch (RemoteException e) { + /* The remote entity disappeared, we can safely ignore the exception. */ } finally { Binder.restoreCallingIdentity(ident); } - + Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED); - intent.putExtra(PhoneStateIntentReceiver.INTENT_KEY_ASU, asu); + Bundle data = new Bundle(); + signalStrength.fillInNotifierBundle(data); + intent.putExtras(data); mContext.sendStickyBroadcast(intent); } @@ -462,13 +496,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mBatteryStats.notePhoneOn(); } } catch (RemoteException e) { + /* The remote entity disappeared, we can safely ignore the exception. */ } finally { Binder.restoreCallingIdentity(ident); } - + Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED); - intent.putExtra(Phone.STATE_KEY, - DefaultPhoneNotifier.convertCallState(state).toString()); + intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertCallState(state).toString()); if (!TextUtils.isEmpty(incomingNumber)) { intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber); } @@ -498,15 +532,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { intent.putExtra(Phone.FAILURE_REASON_KEY, reason); mContext.sendStickyBroadcast(intent); } - + private boolean checkPhoneStatePermission(String method) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { return true; } String msg = "Modify Phone State Permission Denial: " + method + " from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid(); + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid(); Log.w(TAG, msg); return false; } diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 348f0a1..5fa8701 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -96,8 +96,8 @@ public class WifiService extends IWifiManager.Stub { private int mScanLocksAcquired; private int mScanLocksReleased; - private final List<WifiMulticaster> mMulticasters = - new ArrayList<WifiMulticaster>(); + private final List<Multicaster> mMulticasters = + new ArrayList<Multicaster>(); private int mMulticastEnabled; private int mMulticastDisabled; @@ -1449,10 +1449,12 @@ public class WifiService extends IWifiManager.Stub { Settings.System.getInt(mContext.getContentResolver(), Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0); if (action.equals(Intent.ACTION_SCREEN_ON)) { + Log.d(TAG, "ACTION_SCREEN_ON"); mAlarmManager.cancel(mIdleIntent); mDeviceIdle = false; mScreenOff = false; } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { + Log.d(TAG, "ACTION_SCREEN_OFF"); mScreenOff = true; /* * Set a timer to put Wi-Fi to sleep, but only if the screen is off @@ -1461,12 +1463,20 @@ public class WifiService extends IWifiManager.Stub { * or plugged in to AC). */ if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) { - long triggerTime = System.currentTimeMillis() + idleMillis; - mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); + if (!mWifiStateTracker.hasIpAddress()) { + // do not keep Wifi awake when screen is off if Wifi is not fully active + mDeviceIdle = true; + updateWifiState(); + } else { + long triggerTime = System.currentTimeMillis() + idleMillis; + Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms"); + mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); + } } /* we can return now -- there's nothing to do until we get the idle intent back */ return; } else if (action.equals(ACTION_DEVICE_IDLE)) { + Log.d(TAG, "got ACTION_DEVICE_IDLE"); mDeviceIdle = true; } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { /* @@ -1477,9 +1487,11 @@ public class WifiService extends IWifiManager.Stub { * the already-set timer. */ int pluggedType = intent.getIntExtra("plugged", 0); + Log.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType); if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) && !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) { long triggerTime = System.currentTimeMillis() + idleMillis; + Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms"); mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); mPluggedType = pluggedType; return; @@ -1732,7 +1744,7 @@ public class WifiService extends IWifiManager.Stub { } } - private class WifiLock extends WifiDeathRecipient { + private class WifiLock extends DeathRecipient { WifiLock(int lockMode, String tag, IBinder binder) { super(lockMode, tag, binder); } @@ -1875,13 +1887,13 @@ public class WifiService extends IWifiManager.Stub { return hadLock; } - private abstract class WifiDeathRecipient + private abstract class DeathRecipient implements IBinder.DeathRecipient { String mTag; int mMode; IBinder mBinder; - WifiDeathRecipient(int mode, String tag, IBinder binder) { + DeathRecipient(int mode, String tag, IBinder binder) { super(); mTag = tag; mMode = mode; @@ -1894,13 +1906,13 @@ public class WifiService extends IWifiManager.Stub { } } - private class WifiMulticaster extends WifiDeathRecipient { - WifiMulticaster(String tag, IBinder binder) { + private class Multicaster extends DeathRecipient { + Multicaster(String tag, IBinder binder) { super(Binder.getCallingUid(), tag, binder); } public void binderDied() { - Log.e(TAG, "WifiMulticaster binderDied"); + Log.e(TAG, "Multicaster binderDied"); synchronized (mMulticasters) { int i = mMulticasters.indexOf(this); if (i != -1) { @@ -1910,7 +1922,7 @@ public class WifiService extends IWifiManager.Stub { } public String toString() { - return "WifiMulticaster{" + mTag + " binder=" + mBinder + "}"; + return "Multicaster{" + mTag + " binder=" + mBinder + "}"; } public int getUid() { @@ -1918,12 +1930,12 @@ public class WifiService extends IWifiManager.Stub { } } - public void enableWifiMulticast(IBinder binder, String tag) { + public void enableMulticast(IBinder binder, String tag) { enforceChangePermission(); synchronized (mMulticasters) { mMulticastEnabled++; - mMulticasters.add(new WifiMulticaster(tag, binder)); + mMulticasters.add(new Multicaster(tag, binder)); // Note that we could call stopPacketFiltering only when // our new size == 1 (first call), but this function won't // be called often and by making the stopPacket call each @@ -1941,7 +1953,7 @@ public class WifiService extends IWifiManager.Stub { } } - public void disableWifiMulticast() { + public void disableMulticast() { enforceChangePermission(); int uid = Binder.getCallingUid(); @@ -1949,7 +1961,7 @@ public class WifiService extends IWifiManager.Stub { mMulticastDisabled++; int size = mMulticasters.size(); for (int i = size - 1; i >= 0; i--) { - WifiMulticaster m = mMulticasters.get(i); + Multicaster m = mMulticasters.get(i); if ((m != null) && (m.getUid() == uid)) { removeMulticasterLocked(i, uid); } @@ -1973,7 +1985,7 @@ public class WifiService extends IWifiManager.Stub { } } - public boolean isWifiMulticastEnabled() { + public boolean isMulticastEnabled() { enforceAccessPermission(); synchronized (mMulticasters) { diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 3fa5baf..4561e1a 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -63,6 +63,7 @@ import android.os.Binder; import android.os.Debug; import android.os.Handler; import android.os.IBinder; +import android.os.LatencyTimer; import android.os.LocalPowerManager; import android.os.Looper; import android.os.Message; @@ -133,7 +134,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo static final boolean DEBUG_STARTING_WINDOW = false; static final boolean DEBUG_REORDER = false; static final boolean SHOW_TRANSACTIONS = false; - + static final boolean MEASURE_LATENCY = false; + static private LatencyTimer lt; + static final boolean PROFILE_ORIENTATION = false; static final boolean BLUR = true; static final boolean localLOGV = DEBUG; @@ -495,6 +498,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo private WindowManagerService(Context context, PowerManagerService pm, boolean haveInputMethods) { + if (MEASURE_LATENCY) { + lt = new LatencyTimer(100, 1000); + } + mContext = context; mHaveInputMethods = haveInputMethods; mLimitedAlphaCompositing = context.getResources().getBoolean( @@ -1300,7 +1307,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo mKeyWaiter.handleNewWindowLocked(mCurrentFocus); } } - if (localLOGV) Log.v( TAG, "New client " + client.asBinder() + ": window=" + win); @@ -3715,7 +3721,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo private final void wakeupIfNeeded(WindowState targetWin, int eventType) { long curTime = SystemClock.uptimeMillis(); - if (eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) { + if (eventType == TOUCH_EVENT || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) { if (mLastTouchEventType == eventType && (curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) { return; @@ -3775,9 +3781,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG, "dispatchPointer " + ev); + if (MEASURE_LATENCY) { + lt.sample("3 Wait for last dispatch ", System.nanoTime() - qev.whenNano); + } + Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev, ev, true, false); + if (MEASURE_LATENCY) { + lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano); + } + int action = ev.getAction(); if (action == MotionEvent.ACTION_UP) { @@ -3814,6 +3828,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo WindowState target = (WindowState)targetObj; final long eventTime = ev.getEventTime(); + final long eventTimeNano = ev.getEventTimeNano(); //Log.i(TAG, "Sending " + ev + " to " + target); @@ -3832,6 +3847,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } + if (MEASURE_LATENCY) { + lt.sample("4 in dispatchPointer ", System.nanoTime() - eventTimeNano); + } + if ((target.mAttrs.flags & WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) { //target wants to ignore fat touch events @@ -3914,6 +3933,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } + if (MEASURE_LATENCY) { + lt.sample("5 in dispatchPointer ", System.nanoTime() - eventTimeNano); + } + synchronized(mWindowMap) { if (qev != null && action == MotionEvent.ACTION_MOVE) { mKeyWaiter.bindTargetWindowLocked(target, @@ -3951,7 +3974,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) { Log.v(TAG, "Delivering pointer " + qev + " to " + target); } + + if (MEASURE_LATENCY) { + lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano); + } + target.mClient.dispatchPointer(ev, eventTime); + + if (MEASURE_LATENCY) { + lt.sample("7 after svr->client ipc ", System.nanoTime() - eventTimeNano); + } return true; } catch (android.os.RemoteException e) { Log.i(TAG, "WINDOW DIED during motion dispatch: " + target); @@ -5072,7 +5104,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } } - }; + } public boolean detectSafeMode() { mSafeMode = mPolicy.detectSafeMode(); @@ -5137,9 +5169,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (DEBUG_INPUT && ev != null) Log.v( TAG, "Event: type=" + ev.classType + " data=" + ev.event); + if (MEASURE_LATENCY) { + lt.sample("2 got event ", System.nanoTime() - ev.whenNano); + } + try { if (ev != null) { - curTime = ev.when; + curTime = SystemClock.uptimeMillis(); int eventType; if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) { eventType = eventType((MotionEvent)ev.event); @@ -5150,17 +5186,29 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo eventType = LocalPowerManager.OTHER_EVENT; } try { - long now = SystemClock.uptimeMillis(); - - if ((now - mLastBatteryStatsCallTime) + if ((curTime - mLastBatteryStatsCallTime) >= MIN_TIME_BETWEEN_USERACTIVITIES) { - mLastBatteryStatsCallTime = now; + mLastBatteryStatsCallTime = curTime; mBatteryStats.noteInputEvent(); } } catch (RemoteException e) { // Ignore } - mPowerManager.userActivity(curTime, false, eventType, false); + + if (eventType != TOUCH_EVENT + && eventType != LONG_TOUCH_EVENT + && eventType != CHEEK_EVENT) { + mPowerManager.userActivity(curTime, false, + eventType, false); + } else if (mLastTouchEventType != eventType + || (curTime - mLastUserActivityCallTime) + >= MIN_TIME_BETWEEN_USERACTIVITIES) { + mLastUserActivityCallTime = curTime; + mLastTouchEventType = eventType; + mPowerManager.userActivity(curTime, false, + eventType, false); + } + switch (ev.classType) { case RawInputEvent.CLASS_KEYBOARD: KeyEvent ke = (KeyEvent)ev.event; @@ -7732,7 +7780,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo int i; // FIRST LOOP: Perform a layout, if needed. - performLayoutLockedInner(); if (mFxSession == null) { @@ -7752,7 +7799,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } // SECOND LOOP: Execute animations and update visibility of windows. - boolean orientationChangeComplete = true; Session holdScreen = null; float screenBrightness = -1; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 9471eff..f2959e3 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -30,6 +30,7 @@ import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.AlertDialog; +import android.app.ApplicationErrorReport; import android.app.Dialog; import android.app.IActivityWatcher; import android.app.IApplicationThread; @@ -41,6 +42,7 @@ import android.app.IThumbnailReceiver; import android.app.Instrumentation; import android.app.PendingIntent; import android.app.ResultInfo; +import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -78,10 +80,14 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Checkin; import android.provider.Settings; +import android.server.data.CrashData; +import android.server.data.StackTraceElementData; +import android.server.data.ThrowableData; import android.text.TextUtils; import android.util.Config; import android.util.EventLog; import android.util.Log; +import android.util.LogPrinter; import android.util.PrintWriterPrinter; import android.util.SparseArray; import android.view.Gravity; @@ -92,10 +98,13 @@ import android.view.WindowManagerPolicy; import dalvik.system.Zygote; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.PrintWriter; import java.lang.IllegalStateException; import java.lang.ref.WeakReference; @@ -191,6 +200,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Maximum number of recent tasks that we can remember. static final int MAX_RECENT_TASKS = 20; + // Amount of time after a call to stopAppSwitches() during which we will + // prevent further untrusted switches from happening. + static final long APP_SWITCH_DELAY_TIME = 5*1000; + // How long until we reset a task when the user returns to it. Currently // 30 minutes. static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30; @@ -328,6 +341,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen final ArrayList mHistory = new ArrayList(); /** + * Description of a request to start a new activity, which has been held + * due to app switches being disabled. + */ + class PendingActivityLaunch { + HistoryRecord r; + HistoryRecord sourceRecord; + Uri[] grantedUriPermissions; + int grantedMode; + boolean onlyIfNeeded; + } + + final ArrayList<PendingActivityLaunch> mPendingActivityLaunches + = new ArrayList<PendingActivityLaunch>(); + + /** * List of all active broadcasts that are to be executed immediately * (without waiting for another broadcast to finish). Currently this only * contains broadcasts to registered receivers, to avoid spinning up @@ -705,6 +733,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen int mFactoryTest; /** + * The time at which we will allow normal application switches again, + * after a call to {@link #stopAppSwitches()}. + */ + long mAppSwitchesAllowedTime; + + /** + * This is set to true after the first switch after mAppSwitchesAllowedTime + * is set; any switches after that will clear the time. + */ + boolean mDidAppSwitch; + + /** * Set while we are wanting to sleep, to prevent any * activities from being started/resumed. */ @@ -852,6 +892,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen static final int SERVICE_ERROR_MSG = 18; static final int RESUME_TOP_ACTIVITY_MSG = 19; static final int PROC_START_TIMEOUT_MSG = 20; + static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21; AlertDialog mUidAlert; @@ -910,6 +951,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen d.show(); proc.anrDialog = d; } + + ensureScreenEnabled(); } break; case SHOW_FACTORY_ERROR_MSG: { Dialog d = new FactoryErrorDialog( @@ -1041,6 +1084,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen processStartTimedOutLocked(app); } } + case DO_PENDING_ACTIVITY_LAUNCHES_MSG: { + synchronized (ActivityManagerService.this) { + doPendingActivityLaunchesLocked(true); + } + } } } }; @@ -1495,6 +1543,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return null; } + private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) { + int i = mHistory.size()-1; + while (i >= 0) { + HistoryRecord r = (HistoryRecord)mHistory.get(i); + if (!r.finishing && !r.delayedResume && r != notTop) { + return r; + } + i--; + } + return null; + } + /** * This is a simplified version of topRunningActivityLocked that provides a number of * optional skip-over modes. It is intended for use with the ActivityWatcher hook only. @@ -2245,6 +2305,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return true; } + next.delayedResume = false; + // If the top activity is the resumed one, nothing to do. if (mResumedActivity == next && next.state == ActivityState.RESUMED) { // Make sure we have executed any pending transitions, since there @@ -2471,7 +2533,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return true; } - private final void startActivityLocked(HistoryRecord r, boolean newTask) { + private final void startActivityLocked(HistoryRecord r, boolean newTask, + boolean doResume) { final int NH = mHistory.size(); int addPos = -1; @@ -2558,7 +2621,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if ((r.intent.getFlags() &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { resetTaskIfNeededLocked(r, r); - doShow = topRunningActivityLocked(null) == r; + doShow = topRunningNonDelayedActivityLocked(null) == r; } } if (SHOW_APP_STARTING_ICON && doShow) { @@ -2588,13 +2651,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mWindowManager.validateAppTokens(mHistory); } - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } } /** * Perform clear operation as requested by - * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: assuming the top task on the - * stack is the one that the new activity is being launched in, look for + * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the + * stack to the given task, then look for * an instance of that activity in the stack and, if found, finish all * activities on top of it and return the instance. * @@ -2602,9 +2667,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen * @return Returns the old activity that should be continue to be used, * or null if none was found. */ - private final HistoryRecord performClearTopTaskLocked(int taskId, + private final HistoryRecord performClearTaskLocked(int taskId, HistoryRecord newR, boolean doClear) { int i = mHistory.size(); + + // First find the requested task. + while (i > 0) { + i--; + HistoryRecord r = (HistoryRecord)mHistory.get(i); + if (r.task.taskId == taskId) { + i++; + break; + } + } + + // Now clear it. while (i > 0) { i--; HistoryRecord r = (HistoryRecord)mHistory.get(i); @@ -2840,15 +2917,75 @@ public final class ActivityManagerService extends ActivityManagerNative implemen intent, resolvedType, aInfo, mConfiguration, resultRecord, resultWho, requestCode, componentSpecified); - HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) - != 0 ? r : null; - + if (mResumedActivity == null + || mResumedActivity.info.applicationInfo.uid != callingUid) { + if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) { + PendingActivityLaunch pal = new PendingActivityLaunch(); + pal.r = r; + pal.sourceRecord = sourceRecord; + pal.grantedUriPermissions = grantedUriPermissions; + pal.grantedMode = grantedMode; + pal.onlyIfNeeded = onlyIfNeeded; + mPendingActivityLaunches.add(pal); + return START_SWITCHES_CANCELED; + } + } + + if (mDidAppSwitch) { + // This is the second allowed switch since we stopped switches, + // so now just generally allow switches. Use case: user presses + // home (switches disabled, switch to home, mDidAppSwitch now true); + // user taps a home icon (coming from home so allowed, we hit here + // and now allow anyone to switch again). + mAppSwitchesAllowedTime = 0; + } else { + mDidAppSwitch = true; + } + + doPendingActivityLaunchesLocked(false); + + return startActivityUncheckedLocked(r, sourceRecord, + grantedUriPermissions, grantedMode, onlyIfNeeded, true); + } + + private final void doPendingActivityLaunchesLocked(boolean doResume) { + final int N = mPendingActivityLaunches.size(); + if (N <= 0) { + return; + } + for (int i=0; i<N; i++) { + PendingActivityLaunch pal = mPendingActivityLaunches.get(i); + startActivityUncheckedLocked(pal.r, pal.sourceRecord, + pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded, + doResume && i == (N-1)); + } + mPendingActivityLaunches.clear(); + } + + private final int startActivityUncheckedLocked(HistoryRecord r, + HistoryRecord sourceRecord, Uri[] grantedUriPermissions, + int grantedMode, boolean onlyIfNeeded, boolean doResume) { + final Intent intent = r.intent; + final int callingUid = r.launchedFromUid; + + int launchFlags = intent.getFlags(); + // We'll invoke onUserLeaving before onPause only if the launching // activity did not explicitly state that this is an automated launch. mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0; if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving); + // If the caller has asked not to resume at this point, we make note + // of this in the record so that we can skip it when trying to find + // the top running activity. + if (!doResume) { + r.delayedResume = true; + } + + HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) + != 0 ? r : null; + // If the onlyIfNeeded flag is set, then we can do this if the activity // being launched is the same as the one making the call... or, as // a special case, if we do not know the caller then we count the @@ -2856,7 +2993,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (onlyIfNeeded) { HistoryRecord checkedCaller = sourceRecord; if (checkedCaller == null) { - checkedCaller = topRunningActivityLocked(notTop); + checkedCaller = topRunningNonDelayedActivityLocked(notTop); } if (!checkedCaller.realActivity.equals(r.realActivity)) { // Caller is not the same as launcher, so always needed. @@ -2894,7 +3031,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } - if (resultRecord != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { // For whatever reason this activity is being launched into a new // task... yet the caller has requested a result back. Well, that // is pretty messed up, so instead immediately send back a cancel @@ -2902,10 +3039,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // dependency on its originator. Log.w(TAG, "Activity is launching as a new task, so cancelling activity result."); sendActivityResultLocked(-1, - resultRecord, resultWho, requestCode, + r.resultTo, r.resultWho, r.requestCode, Activity.RESULT_CANCELED, null); r.resultTo = null; - resultRecord = null; } boolean addingToTask = false; @@ -2916,7 +3052,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // If bring to front is requested, and no result is requested, and // we can find a task that was started with this same // component, then instead of launching bring that one to the front. - if (resultRecord == null) { + if (r.resultTo == null) { // See if there is a task to bring to the front. If this is // a SINGLE_INSTANCE activity, there can be one and only one // instance of it in the history, and it is always in its own @@ -2938,7 +3074,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // to have the same behavior as if a new instance was // being started, which means not bringing it to the front // if the caller is not itself in the front. - HistoryRecord curTop = topRunningActivityLocked(notTop); + HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop); if (curTop.task != taskTop.task) { r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); boolean callerAtFront = sourceRecord == null @@ -2959,7 +3095,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // the client said not to do anything if that // is the case, so this is it! And for paranoia, make // sure we have correctly resumed the top activity. - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } return START_RETURN_INTENT_TO_CALLER; } if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0 @@ -2969,7 +3107,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // from the task up to the one being started. In most // cases this means we are resetting the task to its // initial state. - HistoryRecord top = performClearTopTaskLocked( + HistoryRecord top = performClearTaskLocked( taskTop.task.taskId, r, true); if (top != null) { if (top.frontOfTask) { @@ -3035,7 +3173,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // We didn't do anything... but it was needed (a.k.a., client // don't use that intent!) And for paranoia, make // sure we have correctly resumed the top activity. - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } return START_TASK_TO_FRONT; } } @@ -3052,8 +3192,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // If the activity being launched is the same as the one currently // at the top, then we need to check if it should only be launched // once. - HistoryRecord top = topRunningActivityLocked(notTop); - if (top != null && resultRecord == null) { + HistoryRecord top = topRunningNonDelayedActivityLocked(notTop); + if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity)) { if (top.app != null && top.app.thread != null) { if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 @@ -3062,7 +3202,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen logStartActivity(LOG_AM_NEW_INTENT, top, top.task); // For paranoia, make sure we have correctly // resumed the top activity. - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } if (onlyIfNeeded) { // We don't need to start a new activity, and // the client said not to do anything if that @@ -3077,9 +3219,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } else { - if (resultRecord != null) { + if (r.resultTo != null) { sendActivityResultLocked(-1, - resultRecord, resultWho, requestCode, + r.resultTo, r.resultWho, r.requestCode, Activity.RESULT_CANCELED, null); } return START_CLASS_NOT_FOUND; @@ -3088,7 +3230,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen boolean newTask = false; // Should this be considered a new task? - if (resultRecord == null && !addingToTask + if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { // todo: should do better management of integers. mCurTask++; @@ -3108,14 +3250,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // In this case, we are adding the activity to an existing // task, but the caller has asked to clear that task if the // activity is already running. - HistoryRecord top = performClearTopTaskLocked( + HistoryRecord top = performClearTaskLocked( sourceRecord.task.taskId, r, true); if (top != null) { logStartActivity(LOG_AM_NEW_INTENT, r, top.task); deliverNewIntentLocked(top, r.intent); // For paranoia, make sure we have correctly // resumed the top activity. - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } return START_DELIVERED_TO_TOP; } } else if (!addingToTask && @@ -3128,7 +3272,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen HistoryRecord top = moveActivityToFrontLocked(where); logStartActivity(LOG_AM_NEW_INTENT, r, top.task); deliverNewIntentLocked(top, r.intent); - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } return START_DELIVERED_TO_TOP; } } @@ -3157,7 +3303,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId); } logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task); - startActivityLocked(r, newTask); + startActivityLocked(r, newTask, doResume); return START_SUCCESS; } @@ -4911,6 +5057,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + final void ensureScreenEnabled() { + boolean enableScreen; + synchronized (this) { + enableScreen = !mBooted; + mBooted = true; + } + + if (enableScreen) { + EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN, + SystemClock.uptimeMillis()); + enableScreenAfterBoot(); + } + } + public final void activityPaused(IBinder token, Bundle icicle) { // Refuse possible leaked file descriptors if (icicle != null && icicle.hasFileDescriptors()) { @@ -6251,6 +6411,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen "moveTaskToFront()"); synchronized(this) { + if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(), + Binder.getCallingUid(), "Task to front")) { + return; + } final long origId = Binder.clearCallingIdentity(); try { int N = mRecentTasks.size(); @@ -6335,6 +6499,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen "moveTaskToBack()"); synchronized(this) { + if (mResumedActivity != null && mResumedActivity.task.taskId == task) { + if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(), + Binder.getCallingUid(), "Task to back")) { + return; + } + } final long origId = Binder.clearCallingIdentity(); moveTaskToBackLocked(task); Binder.restoreCallingIdentity(origId); @@ -6438,6 +6608,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen "moveTaskBackwards()"); synchronized(this) { + if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(), + Binder.getCallingUid(), "Task backwards")) { + return; + } final long origId = Binder.clearCallingIdentity(); moveTaskBackwardsLocked(task); Binder.restoreCallingIdentity(origId); @@ -7179,6 +7353,55 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + public void stopAppSwitches() { + if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires permission " + + android.Manifest.permission.STOP_APP_SWITCHES); + } + + synchronized(this) { + mAppSwitchesAllowedTime = SystemClock.uptimeMillis() + + APP_SWITCH_DELAY_TIME; + mDidAppSwitch = false; + mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG); + Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG); + mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME); + } + } + + public void resumeAppSwitches() { + if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires permission " + + android.Manifest.permission.STOP_APP_SWITCHES); + } + + synchronized(this) { + // Note that we don't execute any pending app switches... we will + // let those wait until either the timeout, or the next start + // activity request. + mAppSwitchesAllowedTime = 0; + } + } + + boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid, + String name) { + if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) { + return true; + } + + final int perm = checkComponentPermission( + android.Manifest.permission.STOP_APP_SWITCHES, callingPid, + callingUid, -1); + if (perm == PackageManager.PERMISSION_GRANTED) { + return true; + } + + Log.w(TAG, name + " request from " + callingUid + " stopped"); + return false; + } + public void setDebugApp(String packageName, boolean waitForDebugger, boolean persistent) { enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP, @@ -7595,6 +7818,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return handleAppCrashLocked(app); } + private ComponentName getErrorReportReceiver(ProcessRecord app) { + IPackageManager pm = ActivityThread.getPackageManager(); + try { + // was an installer package name specified when this app was + // installed? + String installerPackageName = pm.getInstallerPackageName(app.info.packageName); + if (installerPackageName == null) { + return null; + } + + // is there an Activity in this package that handles ACTION_APP_ERROR? + Intent intent = new Intent(Intent.ACTION_APP_ERROR); + ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName); + if (info == null || info.activityInfo == null) { + return null; + } + + return new ComponentName(installerPackageName, info.activityInfo.name); + } catch (RemoteException e) { + // will return null and no error report will be delivered + } + return null; + } + void makeAppNotRespondingLocked(ProcessRecord app, String tag, String shortMsg, String longMsg, byte[] crashData) { app.notResponding = true; @@ -7713,6 +7960,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } void startAppProblemLocked(ProcessRecord app) { + app.errorReportReceiver = getErrorReportReceiver(app); skipCurrentReceiverLocked(app); } @@ -7745,7 +7993,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen public int handleApplicationError(IBinder app, int flags, String tag, String shortMsg, String longMsg, byte[] crashData) { AppErrorResult result = new AppErrorResult(); - ProcessRecord r = null; synchronized (this) { if (app != null) { @@ -7834,16 +8081,96 @@ public final class ActivityManagerService extends ActivityManagerNative implemen int res = result.get(); + Intent appErrorIntent = null; synchronized (this) { if (r != null) { mProcessCrashTimes.put(r.info.processName, r.info.uid, SystemClock.uptimeMillis()); } + if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) { + appErrorIntent = createAppErrorIntentLocked(r); + res = AppErrorDialog.FORCE_QUIT; + } + } + + if (appErrorIntent != null) { + try { + mContext.startActivity(appErrorIntent); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "bug report receiver dissappeared", e); + } } return res; } + Intent createAppErrorIntentLocked(ProcessRecord r) { + ApplicationErrorReport report = createAppErrorReportLocked(r); + if (report == null) { + return null; + } + Intent result = new Intent(Intent.ACTION_APP_ERROR); + result.setComponent(r.errorReportReceiver); + result.putExtra(Intent.EXTRA_BUG_REPORT, report); + result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return result; + } + + ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) { + if (r.errorReportReceiver == null) { + return null; + } + + if (!r.crashing && !r.notResponding) { + return null; + } + + try { + ApplicationErrorReport report = new ApplicationErrorReport(); + report.packageName = r.info.packageName; + report.installerPackageName = r.errorReportReceiver.getPackageName(); + report.processName = r.processName; + + if (r.crashing) { + report.type = ApplicationErrorReport.TYPE_CRASH; + report.crashInfo = new ApplicationErrorReport.CrashInfo(); + + ByteArrayInputStream byteStream = new ByteArrayInputStream( + r.crashingReport.crashData); + DataInputStream dataStream = new DataInputStream(byteStream); + CrashData crashData = new CrashData(dataStream); + ThrowableData throwData = crashData.getThrowableData(); + + report.time = crashData.getTime(); + report.crashInfo.stackTrace = throwData.toString(); + + // extract the source of the exception, useful for report + // clustering + while (throwData.getCause() != null) { + throwData = throwData.getCause(); + } + StackTraceElementData trace = throwData.getStackTrace()[0]; + report.crashInfo.exceptionClassName = throwData.getType(); + report.crashInfo.throwFileName = trace.getFileName(); + report.crashInfo.throwClassName = trace.getClassName(); + report.crashInfo.throwMethodName = trace.getMethodName(); + } else if (r.notResponding) { + report.type = ApplicationErrorReport.TYPE_ANR; + report.anrInfo = new ApplicationErrorReport.AnrInfo(); + + report.anrInfo.activity = r.notRespondingReport.tag; + report.anrInfo.cause = r.notRespondingReport.shortMsg; + report.anrInfo.info = r.notRespondingReport.longMsg; + } + + return report; + } catch (IOException e) { + // we don't send it + } + + return null; + } + public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() { // assume our apps are happy - lazy create the list List<ActivityManager.ProcessErrorStateInfo> errList = null; @@ -10176,8 +10503,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - final ContentResolver resolver = mContext.getContentResolver(); - // Figure out who all will receive this broadcast. List receivers = null; List<BroadcastFilter> registeredReceivers = null; @@ -10200,8 +10525,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ActivityThread.getPackageManager().queryIntentReceivers( intent, resolvedType, STOCK_PM_FLAGS); } - registeredReceivers = mReceiverResolver.queryIntent(resolver, - intent, resolvedType, false); + registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false); } } catch (RemoteException ex) { // pm is in same process, this will never happen. diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java index 3fcfad0..33894d6 100644 --- a/services/java/com/android/server/am/AppErrorDialog.java +++ b/services/java/com/android/server/am/AppErrorDialog.java @@ -19,17 +19,22 @@ package com.android.server.am; import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; import android.content.Context; +import android.content.DialogInterface; import android.content.res.Resources; import android.os.Handler; import android.os.Message; +import android.util.Log; class AppErrorDialog extends BaseErrorDialog { + private final static String TAG = "AppErrorDialog"; + private final AppErrorResult mResult; private final ProcessRecord mProc; // Event 'what' codes static final int FORCE_QUIT = 0; static final int DEBUG = 1; + static final int FORCE_QUIT_AND_REPORT = 2; // 5-minute timeout, then we automatically dismiss the crash dialog static final long DISMISS_TIMEOUT = 1000 * 60 * 5; @@ -58,12 +63,22 @@ class AppErrorDialog extends BaseErrorDialog { setCancelable(false); - setButton(res.getText(com.android.internal.R.string.force_close), - mHandler.obtainMessage(FORCE_QUIT)); + setButton(DialogInterface.BUTTON_POSITIVE, + res.getText(com.android.internal.R.string.force_close), + mHandler.obtainMessage(FORCE_QUIT)); + if ((flags&1) != 0) { - setButton(res.getText(com.android.internal.R.string.debug), + setButton(DialogInterface.BUTTON_NEUTRAL, + res.getText(com.android.internal.R.string.debug), mHandler.obtainMessage(DEBUG)); } + + if (app.errorReportReceiver != null) { + setButton(DialogInterface.BUTTON_NEGATIVE, + res.getText(com.android.internal.R.string.report), + mHandler.obtainMessage(FORCE_QUIT_AND_REPORT)); + } + setTitle(res.getText(com.android.internal.R.string.aerr_title)); getWindow().addFlags(FLAG_SYSTEM_ERROR); getWindow().setTitle("Application Error: " + app.info.processName); diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java index 7390ed0..03c2a04 100644 --- a/services/java/com/android/server/am/AppNotRespondingDialog.java +++ b/services/java/com/android/server/am/AppNotRespondingDialog.java @@ -18,7 +18,10 @@ package com.android.server.am; import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; +import android.content.ActivityNotFoundException; import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; import android.content.res.Resources; import android.os.Handler; import android.os.Message; @@ -26,6 +29,13 @@ import android.os.Process; import android.util.Log; class AppNotRespondingDialog extends BaseErrorDialog { + private static final String TAG = "AppNotRespondingDialog"; + + // Event 'what' codes + static final int FORCE_CLOSE = 1; + static final int WAIT = 2; + static final int WAIT_AND_REPORT = 3; + private final ActivityManagerService mService; private final ProcessRecord mProc; @@ -67,10 +77,19 @@ class AppNotRespondingDialog extends BaseErrorDialog { ? res.getString(resid, name1.toString(), name2.toString()) : res.getString(resid, name1.toString())); - setButton(res.getText(com.android.internal.R.string.force_close), - mHandler.obtainMessage(1)); - setButton2(res.getText(com.android.internal.R.string.wait), - mHandler.obtainMessage(2)); + setButton(DialogInterface.BUTTON_POSITIVE, + res.getText(com.android.internal.R.string.force_close), + mHandler.obtainMessage(FORCE_CLOSE)); + setButton(DialogInterface.BUTTON_NEUTRAL, + res.getText(com.android.internal.R.string.wait), + mHandler.obtainMessage(WAIT)); + + if (app.errorReportReceiver != null) { + setButton(DialogInterface.BUTTON_NEGATIVE, + res.getText(com.android.internal.R.string.report), + mHandler.obtainMessage(WAIT_AND_REPORT)); + } + setTitle(res.getText(com.android.internal.R.string.anr_title)); getWindow().addFlags(FLAG_SYSTEM_ERROR); getWindow().setTitle("Application Not Responding: " + app.info.processName); @@ -81,16 +100,23 @@ class AppNotRespondingDialog extends BaseErrorDialog { private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { + Intent appErrorIntent = null; switch (msg.what) { - case 1: + case FORCE_CLOSE: // Kill the application. mService.killAppAtUsersRequest(mProc, AppNotRespondingDialog.this, true); break; - case 2: + case WAIT_AND_REPORT: + case WAIT: // Continue waiting for the application. synchronized (mService) { ProcessRecord app = mProc; + + if (msg.what == WAIT_AND_REPORT) { + appErrorIntent = mService.createAppErrorIntentLocked(app); + } + app.notResponding = false; app.notRespondingReport = null; if (app.anrDialog == AppNotRespondingDialog.this) { @@ -99,6 +125,14 @@ class AppNotRespondingDialog extends BaseErrorDialog { } break; } + + if (appErrorIntent != null) { + try { + getContext().startActivity(appErrorIntent); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "bug report receiver dissappeared", e); + } + } } }; } diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java index 0387be5..a695eba 100644 --- a/services/java/com/android/server/am/BatteryStatsService.java +++ b/services/java/com/android/server/am/BatteryStatsService.java @@ -25,6 +25,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Process; import android.os.ServiceManager; +import android.telephony.SignalStrength; import android.util.Log; import java.io.FileDescriptor; @@ -177,10 +178,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub { } } - public void notePhoneSignalStrength(int asu) { + public void notePhoneSignalStrength(SignalStrength signalStrength) { enforceCallingPermission(); synchronized (mStats) { - mStats.notePhoneSignalStrengthLocked(asu); + mStats.notePhoneSignalStrengthLocked(signalStrength); } } diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java index 1488791..1789687 100644 --- a/services/java/com/android/server/am/HistoryRecord.java +++ b/services/java/com/android/server/am/HistoryRecord.java @@ -85,6 +85,7 @@ class HistoryRecord extends IApplicationToken.Stub { boolean launchFailed; // set if a launched failed, to abort on 2nd try boolean haveState; // have we gotten the last activity state? boolean stopped; // is activity pause finished? + boolean delayedResume; // not yet resumed because of stopped app switches? boolean finishing; // activity in pending finish list? boolean configDestroy; // need to destroy due to config change? int configChangeFlags; // which config values have changed @@ -146,6 +147,7 @@ class HistoryRecord extends IApplicationToken.Stub { pw.print(" icicle="); pw.println(icicle); pw.print(prefix); pw.print("state="); pw.print(state); pw.print(" stopped="); pw.print(stopped); + pw.print(" delayedResume="); pw.print(delayedResume); pw.print(" finishing="); pw.println(finishing); pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused); pw.print(" inHistory="); pw.print(inHistory); @@ -191,6 +193,7 @@ class HistoryRecord extends IApplicationToken.Stub { launchFailed = false; haveState = false; stopped = false; + delayedResume = false; finishing = false; configDestroy = false; keysPaused = false; diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 68aebc3..419dadf 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -107,6 +107,10 @@ class ProcessRecord implements Watchdog.PssRequestor { ActivityManager.ProcessErrorStateInfo crashingReport; ActivityManager.ProcessErrorStateInfo notRespondingReport; + // Who will be notified of the error. This is usually an activity in the + // app that installed the package. + ComponentName errorReportReceiver; + void dump(PrintWriter pw, String prefix) { if (info.className != null) { pw.print(prefix); pw.print("class="); pw.println(info.className); @@ -157,7 +161,14 @@ class ProcessRecord implements Watchdog.PssRequestor { pw.print(" "); pw.print(crashDialog); pw.print(" notResponding="); pw.print(notResponding); pw.print(" " ); pw.print(anrDialog); - pw.print(" bad="); pw.println(bad); + pw.print(" bad="); pw.print(bad); + + // crashing or notResponding is always set before errorReportReceiver + if (errorReportReceiver != null) { + pw.print(" errorReportReceiver="); + pw.print(errorReportReceiver.flattenToShortString()); + } + pw.println(); } if (activities.size() > 0) { pw.print(prefix); pw.print("activities="); pw.println(activities); diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java index b17ba82..76c05d9 100644 --- a/services/java/com/android/server/status/StatusBarPolicy.java +++ b/services/java/com/android/server/status/StatusBarPolicy.java @@ -41,6 +41,7 @@ import android.os.RemoteException; import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.telephony.TelephonyManager; import android.text.format.DateFormat; import android.util.Log; @@ -57,6 +58,7 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.location.GpsLocationProvider; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.cdma.EriInfo; import com.android.internal.telephony.cdma.TtyIntent; import com.android.server.am.BatteryStatsService; @@ -106,45 +108,140 @@ public class StatusBarPolicy { // phone private TelephonyManager mPhone; private IBinder mPhoneIcon; + private IBinder mPhoneEvdoIcon; //***** Signal strength icons private IconData mPhoneData; + private IconData mPhoneEvdoData; //GSM/UMTS private static final int[] sSignalImages = new int[] { - com.android.internal.R.drawable.stat_sys_signal_0, - com.android.internal.R.drawable.stat_sys_signal_1, - com.android.internal.R.drawable.stat_sys_signal_2, - com.android.internal.R.drawable.stat_sys_signal_3, - com.android.internal.R.drawable.stat_sys_signal_4 - }; + com.android.internal.R.drawable.stat_sys_signal_0, + com.android.internal.R.drawable.stat_sys_signal_1, + com.android.internal.R.drawable.stat_sys_signal_2, + com.android.internal.R.drawable.stat_sys_signal_3, + com.android.internal.R.drawable.stat_sys_signal_4 + }; private static final int[] sSignalImages_r = new int[] { - com.android.internal.R.drawable.stat_sys_r_signal_0, - com.android.internal.R.drawable.stat_sys_r_signal_1, - com.android.internal.R.drawable.stat_sys_r_signal_2, - com.android.internal.R.drawable.stat_sys_r_signal_3, - com.android.internal.R.drawable.stat_sys_r_signal_4 - }; + com.android.internal.R.drawable.stat_sys_r_signal_0, + com.android.internal.R.drawable.stat_sys_r_signal_1, + com.android.internal.R.drawable.stat_sys_r_signal_2, + com.android.internal.R.drawable.stat_sys_r_signal_3, + com.android.internal.R.drawable.stat_sys_r_signal_4 + }; //CDMA private static final int[] sSignalImages_cdma = new int[] { - com.android.internal.R.drawable.stat_sys_signal_0_cdma, - com.android.internal.R.drawable.stat_sys_signal_1_cdma, - com.android.internal.R.drawable.stat_sys_signal_2_cdma, - com.android.internal.R.drawable.stat_sys_signal_3_cdma, - com.android.internal.R.drawable.stat_sys_signal_4_cdma + com.android.internal.R.drawable.stat_sys_signal_cdma_0, + com.android.internal.R.drawable.stat_sys_signal_cdma_1, + com.android.internal.R.drawable.stat_sys_signal_cdma_2, + com.android.internal.R.drawable.stat_sys_signal_cdma_3, + com.android.internal.R.drawable.stat_sys_signal_cdma_4 }; - private static final int[] sSignalImages_r_cdma = new int[] { - com.android.internal.R.drawable.stat_sys_r_signal_0_cdma, - com.android.internal.R.drawable.stat_sys_r_signal_1_cdma, - com.android.internal.R.drawable.stat_sys_r_signal_2_cdma, - com.android.internal.R.drawable.stat_sys_r_signal_3_cdma, - com.android.internal.R.drawable.stat_sys_r_signal_4_cdma + private static final int[] sRoamingIndicatorImages_cdma = new int[] { + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator + // 1 is Standard Roaming Indicator OFF + // TODO T: image never used, remove and put 0 instead? + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + + // 2 is Standard Roaming Indicator FLASHING + // TODO T: image never used, remove and put 0 instead? + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + + // 3-12 Standard ERI + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //3 + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + + // 13-63 Reserved for Standard ERI + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //13 + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + + // 64-127 Reserved for Non Standard (Operator Specific) ERI + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //64 + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0, + com.android.internal.R.drawable.stat_sys_roaming_cdma_0 //83 + + // 128-255 Reserved }; - private static final int[] sSignalImages_ra_cdma = new int[] { - com.android.internal.R.drawable.stat_sys_ra_signal_0_cdma, - com.android.internal.R.drawable.stat_sys_ra_signal_1_cdma, - com.android.internal.R.drawable.stat_sys_ra_signal_2_cdma, - com.android.internal.R.drawable.stat_sys_ra_signal_3_cdma, - com.android.internal.R.drawable.stat_sys_ra_signal_4_cdma + // EVDO + private static final int[] sSignalImages_evdo = new int[] { + com.android.internal.R.drawable.stat_sys_signal_evdo_0, + com.android.internal.R.drawable.stat_sys_signal_evdo_1, + com.android.internal.R.drawable.stat_sys_signal_evdo_2, + com.android.internal.R.drawable.stat_sys_signal_evdo_3, + com.android.internal.R.drawable.stat_sys_signal_evdo_4 }; //***** Data connection icons @@ -174,12 +271,14 @@ public class StatusBarPolicy { com.android.internal.R.drawable.stat_sys_data_in_evdo, com.android.internal.R.drawable.stat_sys_data_out_evdo, com.android.internal.R.drawable.stat_sys_data_inandout_evdo, + com.android.internal.R.drawable.stat_sys_data_dormant_evdo, }; private static final int[] sDataNetType_1xrtt = new int[] { com.android.internal.R.drawable.stat_sys_data_connected_1xrtt, com.android.internal.R.drawable.stat_sys_data_in_1xrtt, com.android.internal.R.drawable.stat_sys_data_out_1xrtt, com.android.internal.R.drawable.stat_sys_data_inandout_1xrtt, + com.android.internal.R.drawable.stat_sys_data_dormant_1xrtt, }; // Assume it's all good unless we hear otherwise. We don't always seem @@ -189,7 +288,7 @@ public class StatusBarPolicy { int mDataState = TelephonyManager.DATA_DISCONNECTED; int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; ServiceState mServiceState; - int mSignalAsu = -1; + SignalStrength mSignalStrength; // data connection private IBinder mDataIcon; @@ -244,6 +343,10 @@ public class StatusBarPolicy { private IBinder mTTYModeIcon; private IconData mTTYModeEnableIconData; + // Cdma Roaming Indicator, ERI + private IBinder mCdmaRoamingIndicatorIcon; + private IconData mCdmaRoamingIndicatorIconData; + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -304,6 +407,7 @@ public class StatusBarPolicy { private StatusBarPolicy(Context context, StatusBarService service) { mContext = context; mService = service; + mSignalStrength = new SignalStrength(); mBatteryStats = BatteryStatsService.getService(); // clock @@ -319,14 +423,21 @@ public class StatusBarPolicy { // phone_signal mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); - mPhoneData = IconData.makeIcon("phone_signal", + mPhoneData = IconData.makeIcon("phone_signal", null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0); mPhoneIcon = service.addIcon(mPhoneData, null); + + // phone_evdo_signal + mPhoneEvdoData = IconData.makeIcon("phone_evdo_signal", + null, com.android.internal.R.drawable.stat_sys_signal_evdo_0, 0, 0); + mPhoneEvdoIcon = service.addIcon(mPhoneEvdoData, null); + service.setIconVisibility(mPhoneEvdoIcon, false); + // register for phone state notifications. ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE)) .listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE - | PhoneStateListener.LISTEN_SIGNAL_STRENGTH + | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS | PhoneStateListener.LISTEN_CALL_STATE | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE | PhoneStateListener.LISTEN_DATA_ACTIVITY); @@ -349,6 +460,12 @@ public class StatusBarPolicy { mTTYModeIcon = service.addIcon(mTTYModeEnableIconData, null); service.setIconVisibility(mTTYModeIcon, false); + // Cdma Roaming Indicator, ERI + mCdmaRoamingIndicatorIconData = IconData.makeIcon("cdma_eri", + null, com.android.internal.R.drawable.stat_sys_roaming_cdma_0, 0, 0); + mCdmaRoamingIndicatorIcon = service.addIcon(mCdmaRoamingIndicatorIconData, null); + service.setIconVisibility(mCdmaRoamingIndicatorIcon, false); + // bluetooth status mBluetoothData = IconData.makeIcon("bluetooth", null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0); @@ -645,8 +762,8 @@ public class StatusBarPolicy { private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { @Override - public void onSignalStrengthChanged(int asu) { - mSignalAsu = asu; + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + mSignalStrength = signalStrength; updateSignalStrength(); } @@ -654,6 +771,7 @@ public class StatusBarPolicy { public void onServiceStateChanged(ServiceState state) { mServiceState = state; updateSignalStrength(); + updateCdmaRoamingIcon(); updateDataIcon(); } @@ -675,7 +793,6 @@ public class StatusBarPolicy { updateDataIcon(); } }; - private final void updateSimState(Intent intent) { String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE); @@ -702,25 +819,51 @@ public class StatusBarPolicy { updateDataIcon(); } - private final void updateSignalStrength() { - int asu = mSignalAsu; - ServiceState ss = mServiceState; + // TODO(Teleca): I've add isCdma() to reduce some code duplication and simplify. + // Please validate the correctness of these changes + private boolean isCdma() { + // Is this equivalent, if so it seems simpler? +// return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA)); + + if (mServiceState != null) { + switch(mServiceState.getRadioTechnology()) { + case ServiceState.RADIO_TECHNOLOGY_1xRTT: + case ServiceState.RADIO_TECHNOLOGY_EVDO_0: + case ServiceState.RADIO_TECHNOLOGY_EVDO_A: + case ServiceState.RADIO_TECHNOLOGY_IS95A: + case ServiceState.RADIO_TECHNOLOGY_IS95B: + return true; + default: + return false; + } + } else { + return false; + } + } - boolean hasService = true; - - if (ss != null) { - int state = ss.getState(); - switch (state) { + // TODO(Teleca): I've add hasService() to reduce some code duplication and simplify. + // Please validate the correctness of these changes. + private boolean hasService() { + if (mServiceState != null) { + switch (mServiceState.getState()) { case ServiceState.STATE_OUT_OF_SERVICE: case ServiceState.STATE_POWER_OFF: - hasService = false; - break; + return false; + default: + return true; } } else { - hasService = false; + return false; } + } - if (!hasService) { + private final void updateSignalStrength() { + int iconLevel = -1; + int evdoIconLevel = -1; + int[] iconList; + int[] evdoIconList; + + if (!hasService()) { //Log.d(TAG, "updateSignalStrength: no service"); if (Settings.System.getInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) == 1) { @@ -729,48 +872,92 @@ public class StatusBarPolicy { mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null; } mService.updateIcon(mPhoneIcon, mPhoneData, null); + mService.setIconVisibility(mPhoneEvdoIcon,false); return; } - // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5 - // asu = 0 (-113dB or less) is very weak - // signal, its better to show 0 bars to the user in such cases. - // asu = 99 is a special case, where the signal strength is unknown. - if (asu <= 0 || asu == 99) asu = 0; - else if (asu >= 16) asu = 4; - else if (asu >= 8) asu = 3; - else if (asu >= 4) asu = 2; - else asu = 1; - - int[] iconList; - if (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { - switch(ss.getExtendedCdmaRoaming()) { - case ServiceState.REGISTRATION_STATE_ROAMING: - iconList = this.sSignalImages_r_cdma; - break; - case ServiceState.REGISTRATION_STATE_ROAMING_AFFILIATE: - iconList = this.sSignalImages_ra_cdma; - break; - default: - iconList = this.sSignalImages_cdma; - break; + if (!isCdma()) { + int asu = mSignalStrength.getGsmSignalStrength(); + + // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5 + // asu = 0 (-113dB or less) is very weak + // signal, its better to show 0 bars to the user in such cases. + // asu = 99 is a special case, where the signal strength is unknown. + if (asu <= 0 || asu == 99) iconLevel = 0; + else if (asu >= 16) iconLevel = 4; + else if (asu >= 8) iconLevel = 3; + else if (asu >= 4) iconLevel = 2; + else iconLevel = 1; + + if (mPhone.isNetworkRoaming()) { + iconList = sSignalImages_r; + } else { + iconList = sSignalImages; } - } else if (mPhone.isNetworkRoaming()) { - iconList = sSignalImages_r; } else { - iconList = sSignalImages; + iconList = this.sSignalImages_cdma; + + int cdmaDbm = mSignalStrength.getCdmaDbm(); + int cdmaEcio = mSignalStrength.getCdmaEcio(); + int levelDbm = 0; + int levelEcio = 0; + + if (cdmaDbm >= -75) levelDbm = 4; + else if (cdmaDbm >= -85) levelDbm = 3; + else if (cdmaDbm >= -95) levelDbm = 2; + else if (cdmaDbm >= -100) levelDbm = 1; + else levelDbm = 0; + + // Ec/Io are in dB*10 + if (cdmaEcio >= -90) levelEcio = 4; + else if (cdmaEcio >= -110) levelEcio = 3; + else if (cdmaEcio >= -130) levelEcio = 2; + else if (cdmaEcio >= -150) levelEcio = 1; + else levelEcio = 0; + + iconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio; } - mPhoneData.iconId = iconList[asu]; + if ((mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_0) + || (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) { + // Use Evdo icon + evdoIconList = this.sSignalImages_evdo; + + int evdoEcio = mSignalStrength.getEvdoEcio(); + int evdoSnr = mSignalStrength.getEvdoSnr(); + int levelEvdoEcio = 0; + int levelEvdoSnr = 0; + + // Ec/Io are in dB*10 + if (evdoEcio >= -650) levelEvdoEcio = 4; + else if (evdoEcio >= -750) levelEvdoEcio = 3; + else if (evdoEcio >= -900) levelEvdoEcio = 2; + else if (evdoEcio >= -1050) levelEvdoEcio = 1; + else levelEvdoEcio = 0; + + if (evdoSnr > 7) levelEvdoSnr = 4; + else if (evdoSnr > 5) levelEvdoSnr = 3; + else if (evdoSnr > 3) levelEvdoSnr = 2; + else if (evdoSnr > 1) levelEvdoSnr = 1; + else levelEvdoSnr = 0; + + evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr; + + mPhoneEvdoData.iconId = evdoIconList[evdoIconLevel]; + mService.updateIcon(mPhoneEvdoIcon, mPhoneEvdoData, null); + mService.setIconVisibility(mPhoneEvdoIcon,true); + } else { + mService.setIconVisibility(mPhoneEvdoIcon,false); + } + + mPhoneData.iconId = iconList[iconLevel]; mService.updateIcon(mPhoneIcon, mPhoneData, null); } private final void updateDataNetType() { int net = mPhone.getNetworkType(); - ServiceState ss = this.mServiceState; switch (net) { - case TelephonyManager.NETWORK_TYPE_EDGE: mDataIconList = sDataNetType_e; break; @@ -798,32 +985,51 @@ public class StatusBarPolicy { int iconId; boolean visible = true; - if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) { - int data = mDataState; - - int[] list = mDataIconList; - - ServiceState ss = mServiceState; - - boolean hasService = false; - - if (ss != null) { - hasService = (ss.getState() == ServiceState.STATE_IN_SERVICE); + if (!isCdma()) { + // GSM case, we have to check also the sim state + if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) { + if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { + switch (mDataActivity) { + case TelephonyManager.DATA_ACTIVITY_IN: + iconId = mDataIconList[1]; + break; + case TelephonyManager.DATA_ACTIVITY_OUT: + iconId = mDataIconList[2]; + break; + case TelephonyManager.DATA_ACTIVITY_INOUT: + iconId = mDataIconList[3]; + break; + default: + iconId = mDataIconList[0]; + break; + } + mDataData.iconId = iconId; + mService.updateIcon(mDataIcon, mDataData, null); + } else { + visible = false; + } + } else { + mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim; + mService.updateIcon(mDataIcon, mDataData, null); } - - if (hasService && data == TelephonyManager.DATA_CONNECTED) { + } else { + // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT + if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { switch (mDataActivity) { case TelephonyManager.DATA_ACTIVITY_IN: - iconId = list[1]; + iconId = mDataIconList[1]; break; case TelephonyManager.DATA_ACTIVITY_OUT: - iconId = list[2]; + iconId = mDataIconList[2]; break; case TelephonyManager.DATA_ACTIVITY_INOUT: - iconId = list[3]; + iconId = mDataIconList[3]; + break; + case TelephonyManager.DATA_ACTIVITY_DORMANT: + iconId = mDataIconList[4]; break; default: - iconId = list[0]; + iconId = mDataIconList[0]; break; } mDataData.iconId = iconId; @@ -831,10 +1037,8 @@ public class StatusBarPolicy { } else { visible = false; } - } else { - mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim; - mService.updateIcon(mDataIcon, mDataData, null); } + long ident = Binder.clearCallingIdentity(); try { mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible); @@ -842,6 +1046,7 @@ public class StatusBarPolicy { } finally { Binder.restoreCallingIdentity(ident); } + if (mDataIconVisible != visible) { mService.setIconVisibility(mDataIcon, visible); mDataIconVisible = visible; @@ -852,7 +1057,7 @@ public class StatusBarPolicy { AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); final int ringerMode = audioManager.getRingerMode(); final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT || - ringerMode == AudioManager.RINGER_MODE_VIBRATE; + ringerMode == AudioManager.RINGER_MODE_VIBRATE; final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER) ? com.android.internal.R.drawable.stat_sys_ringer_vibrate : com.android.internal.R.drawable.stat_sys_ringer_silent; @@ -884,7 +1089,7 @@ public class StatusBarPolicy { } else { return; } - + if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED || mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING) { @@ -899,15 +1104,15 @@ public class StatusBarPolicy { private final void updateWifi(Intent intent) { final String action = intent.getAction(); if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - + final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; - + if (!enabled) { // If disabled, hide the icon. (We show icon when connected.) mService.setIconVisibility(mWifiIcon, false); } - + } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) { final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false); @@ -916,9 +1121,9 @@ public class StatusBarPolicy { } } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - final NetworkInfo networkInfo = (NetworkInfo) + final NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - + int iconId; if (networkInfo != null && networkInfo.isConnected()) { mIsWifiConnected = true; @@ -965,18 +1170,18 @@ public class StatusBarPolicy { if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) { // GPS is getting fixes mService.updateIcon(mGpsIcon, mGpsFixIconData, null); - mService.setIconVisibility(mGpsIcon, true); + mService.setIconVisibility(mGpsIcon, true); } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) { // GPS is off - mService.setIconVisibility(mGpsIcon, false); + mService.setIconVisibility(mGpsIcon, false); } else { // GPS is on, but not receiving fixes mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null); - mService.setIconVisibility(mGpsIcon, true); + mService.setIconVisibility(mGpsIcon, true); } } - private final void updateTTY(Intent intent) { + private final void updateTTY(Intent intent) { final String action = intent.getAction(); final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false); @@ -986,14 +1191,59 @@ public class StatusBarPolicy { // TTY is on Log.i(TAG, "updateTTY: set TTY on"); mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null); - mService.setIconVisibility(mTTYModeIcon, true); + mService.setIconVisibility(mTTYModeIcon, true); } else { // TTY is off Log.i(TAG, "updateTTY: set TTY off"); - mService.setIconVisibility(mTTYModeIcon, false); + mService.setIconVisibility(mTTYModeIcon, false); + } + } + + private final void updateCdmaRoamingIcon() { + if (!hasService()) { + mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false); + } + + if (!isCdma()) { + mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false); + } + + int[] iconList = sRoamingIndicatorImages_cdma; + int iconIndex = mPhone.getCdmaEriIconIndex(); + int iconMode = mPhone.getCdmaEriIconMode(); + + if (iconIndex == -1) { + Log.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update"); + return; + } + + if (iconMode == -1) { + Log.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update"); + return; + } + + if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) { + Log.d(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon"); + mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false); + return; + } + + switch (iconMode) { + case EriInfo.ROAMING_ICON_MODE_NORMAL: + mCdmaRoamingIndicatorIconData.iconId = iconList[iconIndex]; + mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null); + mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true); + break; + case EriInfo.ROAMING_ICON_MODE_FLASH: + mCdmaRoamingIndicatorIconData.iconId = com.android.internal.R.drawable.stat_sys_roaming_cdma_flash; + mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null); + break; + } + mService.updateIcon(mPhoneIcon, mPhoneData, null); } + private class StatusBarHandler extends Handler { @Override public void handleMessage(Message msg) { @@ -1007,6 +1257,3 @@ public class StatusBarPolicy { } } } - - - diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java index 5336e27..48cbace 100644 --- a/services/java/com/android/server/status/StatusBarService.java +++ b/services/java/com/android/server/status/StatusBarService.java @@ -19,6 +19,7 @@ package com.android.server.status; import com.android.internal.R; import com.android.internal.util.CharSequences; +import android.app.ActivityManagerNative; import android.app.Dialog; import android.app.IStatusBar; import android.app.PendingIntent; @@ -1254,6 +1255,14 @@ public class StatusBarService extends IStatusBar.Stub public void onClick(View v) { try { + // The intent we are sending is for the application, which + // won't have permission to immediately start an activity after + // the user switches to home. We know it is safe to do at this + // point, so make sure new activity switches are now allowed. + ActivityManagerNative.getDefault().resumeAppSwitches(); + } catch (RemoteException e) { + } + try { mIntent.send(); mNotificationCallbacks.onNotificationClick(mPkg, mId); } catch (PendingIntent.CanceledException e) { |