diff options
Diffstat (limited to 'services/java')
48 files changed, 1957 insertions, 952 deletions
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 38f4554..8e341df 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -177,7 +177,7 @@ class AppWidgetService extends IAppWidgetService.Stub mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - onUserRemoved(intent.getIntExtra(Intent.EXTRA_USERID, -1)); + onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)); } }, userFilter); } diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java index 5250dfc..539e561 100644 --- a/services/java/com/android/server/AppWidgetServiceImpl.java +++ b/services/java/com/android/server/AppWidgetServiceImpl.java @@ -499,7 +499,7 @@ class AppWidgetServiceImpl { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED); intent.setComponent(p.info.provider); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId); - mContext.sendBroadcastToUser(intent, mUserId); + mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId)); if (p.instances.size() == 0) { // cancel the future updates cancelBroadcasts(p); @@ -507,7 +507,7 @@ class AppWidgetServiceImpl { // send the broacast saying that the provider is not in use any more intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED); intent.setComponent(p.info.provider); - mContext.sendBroadcastToUser(intent, mUserId); + mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId)); } } } @@ -880,7 +880,7 @@ class AppWidgetServiceImpl { intent.setComponent(p.info.provider); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options); - mContext.sendBroadcastToUser(intent, mUserId); + mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId)); } } @@ -1205,7 +1205,7 @@ class AppWidgetServiceImpl { void sendEnableIntentLocked(Provider p) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED); intent.setComponent(p.info.provider); - mContext.sendBroadcastToUser(intent, mUserId); + mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId)); } void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) { @@ -1213,7 +1213,7 @@ class AppWidgetServiceImpl { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); intent.setComponent(p.info.provider); - mContext.sendBroadcastToUser(intent, mUserId); + mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId)); } } diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java index 0a6f23c..6ae16a4 100644 --- a/services/java/com/android/server/BatteryService.java +++ b/services/java/com/android/server/BatteryService.java @@ -93,6 +93,7 @@ public class BatteryService extends Binder { private boolean mAcOnline; private boolean mUsbOnline; + private boolean mWirelessOnline; private int mBatteryStatus; private int mBatteryHealth; private boolean mBatteryPresent; @@ -150,7 +151,8 @@ public class BatteryService extends Binder { public final boolean isPowered() { // assume we are powered if battery state is unknown so the "stay on while plugged in" option will work. - return (mAcOnline || mUsbOnline || mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN); + return (mAcOnline || mUsbOnline || mWirelessOnline + || mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN); } public final boolean isPowered(int plugTypeSet) { @@ -169,6 +171,9 @@ public class BatteryService extends Binder { if (mUsbOnline) { plugTypeBit |= BatteryManager.BATTERY_PLUGGED_USB; } + if (mWirelessOnline) { + plugTypeBit |= BatteryManager.BATTERY_PLUGGED_WIRELESS; + } return (plugTypeSet & plugTypeBit) != 0; } @@ -243,6 +248,8 @@ public class BatteryService extends Binder { mPlugType = BatteryManager.BATTERY_PLUGGED_AC; } else if (mUsbOnline) { mPlugType = BatteryManager.BATTERY_PLUGGED_USB; + } else if (mWirelessOnline) { + mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS; } else { mPlugType = BATTERY_PLUGGED_NONE; } @@ -398,6 +405,7 @@ public class BatteryService extends Binder { " temperature: " + mBatteryTemperature + " technology: " + mBatteryTechnology + " AC powered:" + mAcOnline + " USB powered:" + mUsbOnline + + " Wireless powered:" + mWirelessOnline + " icon:" + icon + " invalid charger:" + mInvalidCharger); } @@ -503,6 +511,7 @@ public class BatteryService extends Binder { pw.println("Current Battery Service state:"); pw.println(" AC powered: " + mAcOnline); pw.println(" USB powered: " + mUsbOnline); + pw.println(" Wireless powered: " + mWirelessOnline); pw.println(" status: " + mBatteryStatus); pw.println(" health: " + mBatteryHealth); pw.println(" present: " + mBatteryPresent); @@ -523,6 +532,8 @@ public class BatteryService extends Binder { mAcOnline = Integer.parseInt(value) != 0; } else if ("usb".equals(key)) { mUsbOnline = Integer.parseInt(value) != 0; + } else if ("wireless".equals(key)) { + mWirelessOnline = Integer.parseInt(value) != 0; } else if ("status".equals(key)) { mBatteryStatus = Integer.parseInt(value); } else if ("level".equals(key)) { @@ -603,4 +614,3 @@ public class BatteryService extends Binder { } } } - diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java index baf33a9..0bf7aad 100644 --- a/services/java/com/android/server/ClipboardService.java +++ b/services/java/com/android/server/ClipboardService.java @@ -96,7 +96,7 @@ public class ClipboardService extends IClipboard.Stub { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_USER_REMOVED.equals(action)) { - removeClipboard(intent.getIntExtra(Intent.EXTRA_USERID, 0)); + removeClipboard(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); } } }, userFilter); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 375ba68..cb6ce4b 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2592,6 +2592,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // @see bug/4455071 handleConnectivityChange(info.getType(), false); break; + case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: + info = (NetworkInfo) msg.obj; + type = info.getType(); + updateNetworkSettings(mNetTrackers[type]); + break; } } } diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java index 8bdd7be..ef09b01 100644 --- a/services/java/com/android/server/DockObserver.java +++ b/services/java/com/android/server/DockObserver.java @@ -18,10 +18,6 @@ package com.android.server; import static android.provider.Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK; -import com.android.server.power.PowerManagerService; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -30,6 +26,7 @@ import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; @@ -47,7 +44,7 @@ import java.io.FileReader; /** * <p>DockObserver monitors for a docking station. */ -class DockObserver extends UEventObserver { +final class DockObserver extends UEventObserver { private static final String TAG = DockObserver.class.getSimpleName(); private static final boolean LOG = false; @@ -56,7 +53,9 @@ class DockObserver extends UEventObserver { private static final int DEFAULT_DOCK = 1; - private static final int MSG_DOCK_STATE = 0; + private static final int MSG_DOCK_STATE_CHANGED = 0; + + private final Object mLock = new Object(); private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; @@ -78,7 +77,7 @@ class DockObserver extends UEventObserver { Slog.v(TAG, "Dock UEVENT: " + event.toString()); } - synchronized (this) { + synchronized (mLock) { try { int newState = Integer.parseInt(event.get("SWITCH_STATE")); if (newState != mDockState) { @@ -96,7 +95,7 @@ class DockObserver extends UEventObserver { (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); pm.wakeUp(SystemClock.uptimeMillis()); } - update(); + updateLocked(); } } } catch (NumberFormatException e) { @@ -105,132 +104,142 @@ class DockObserver extends UEventObserver { } } - private final void init() { - char[] buffer = new char[1024]; - - try { - FileReader file = new FileReader(DOCK_STATE_PATH); - int len = file.read(buffer, 0, 1024); - file.close(); - mPreviousDockState = mDockState = Integer.valueOf((new String(buffer, 0, len)).trim()); - } catch (FileNotFoundException e) { - Slog.w(TAG, "This kernel does not have dock station support"); - } catch (Exception e) { - Slog.e(TAG, "" , e); + private void init() { + synchronized (mLock) { + try { + char[] buffer = new char[1024]; + FileReader file = new FileReader(DOCK_STATE_PATH); + try { + int len = file.read(buffer, 0, 1024); + mDockState = Integer.valueOf((new String(buffer, 0, len)).trim()); + mPreviousDockState = mDockState; + } finally { + file.close(); + } + } catch (FileNotFoundException e) { + Slog.w(TAG, "This kernel does not have dock station support"); + } catch (Exception e) { + Slog.e(TAG, "" , e); + } } } void systemReady() { - synchronized (this) { + synchronized (mLock) { // don't bother broadcasting undocked here if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) { - update(); + updateLocked(); } mSystemReady = true; } } - private final void update() { - mHandler.sendEmptyMessage(MSG_DOCK_STATE); + private void updateLocked() { + mHandler.sendEmptyMessage(MSG_DOCK_STATE_CHANGED); } - private static boolean isScreenSaverActivatedOnDock(Context context) { - return 0 != Settings.Secure.getInt( - context.getContentResolver(), SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_DOCK); - } + private void handleDockStateChange() { + synchronized (mLock) { + Slog.i(TAG, "Dock state changed: " + mDockState); - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_DOCK_STATE: - synchronized (this) { - Slog.i(TAG, "Dock state changed: " + mDockState); + final ContentResolver cr = mContext.getContentResolver(); - final ContentResolver cr = mContext.getContentResolver(); + if (Settings.Secure.getInt(cr, + Settings.Secure.DEVICE_PROVISIONED, 0) == 0) { + Slog.i(TAG, "Device not provisioned, skipping dock broadcast"); + return; + } - if (Settings.Secure.getInt(cr, - Settings.Secure.DEVICE_PROVISIONED, 0) == 0) { - Slog.i(TAG, "Device not provisioned, skipping dock broadcast"); - return; - } - // Pack up the values and broadcast them to everyone - Intent intent = new Intent(Intent.ACTION_DOCK_EVENT); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); - - // Check if this is Bluetooth Dock - // TODO(BT): Get Dock address. - String address = null; - if (address != null) - intent.putExtra(BluetoothDevice.EXTRA_DEVICE, - BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address)); - - // User feedback to confirm dock connection. Particularly - // useful for flaky contact pins... - if (Settings.System.getInt(cr, - Settings.System.DOCK_SOUNDS_ENABLED, 1) == 1) - { - String whichSound = null; - if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) { - if ((mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) || - (mPreviousDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) || - (mPreviousDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) { - whichSound = Settings.System.DESK_UNDOCK_SOUND; - } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) { - whichSound = Settings.System.CAR_UNDOCK_SOUND; - } - } else { - if ((mDockState == Intent.EXTRA_DOCK_STATE_DESK) || - (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) || - (mDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) { - whichSound = Settings.System.DESK_DOCK_SOUND; - } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) { - whichSound = Settings.System.CAR_DOCK_SOUND; - } - } + // Pack up the values and broadcast them to everyone + Intent intent = new Intent(Intent.ACTION_DOCK_EVENT); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); + + // Check if this is Bluetooth Dock + // TODO(BT): Get Dock address. + // String address = null; + // if (address != null) { + // intent.putExtra(BluetoothDevice.EXTRA_DEVICE, + // BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address)); + // } + + // User feedback to confirm dock connection. Particularly + // useful for flaky contact pins... + if (Settings.System.getInt(cr, + Settings.System.DOCK_SOUNDS_ENABLED, 1) == 1) { + String whichSound = null; + if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) { + if ((mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) || + (mPreviousDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) || + (mPreviousDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) { + whichSound = Settings.System.DESK_UNDOCK_SOUND; + } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) { + whichSound = Settings.System.CAR_UNDOCK_SOUND; + } + } else { + if ((mDockState == Intent.EXTRA_DOCK_STATE_DESK) || + (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) || + (mDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) { + whichSound = Settings.System.DESK_DOCK_SOUND; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) { + whichSound = Settings.System.CAR_DOCK_SOUND; + } + } - if (whichSound != null) { - final String soundPath = Settings.System.getString(cr, whichSound); - if (soundPath != null) { - final Uri soundUri = Uri.parse("file://" + soundPath); - if (soundUri != null) { - final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); - if (sfx != null) { - sfx.setStreamType(AudioManager.STREAM_SYSTEM); - sfx.play(); - } - } - } + if (whichSound != null) { + final String soundPath = Settings.System.getString(cr, whichSound); + if (soundPath != null) { + final Uri soundUri = Uri.parse("file://" + soundPath); + if (soundUri != null) { + final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); + if (sfx != null) { + sfx.setStreamType(AudioManager.STREAM_SYSTEM); + sfx.play(); } } + } + } + } - IDreamManager mgr = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams")); - if (mgr != null) { - // dreams feature enabled - boolean undocked = mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED; - if (undocked) { - try { - if (mgr.isDreaming()) { - mgr.awaken(); - } - } catch (RemoteException e) { - Slog.w(TAG, "Unable to awaken!", e); - } - } else { - if (isScreenSaverActivatedOnDock(mContext)) { - try { - mgr.dream(); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to dream!", e); - } - } - } - } else { - // dreams feature not enabled, send legacy intent - mContext.sendStickyBroadcast(intent); + IDreamManager mgr = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams")); + if (mgr != null) { + // dreams feature enabled + boolean undocked = mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED; + if (undocked) { + try { + if (mgr.isDreaming()) { + mgr.awaken(); } + } catch (RemoteException e) { + Slog.w(TAG, "Unable to awaken!", e); } + } else { + if (isScreenSaverActivatedOnDock(mContext)) { + try { + mgr.dream(); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to dream!", e); + } + } + } + } else { + // dreams feature not enabled, send legacy intent + mContext.sendStickyBroadcast(intent); + } + } + } + + private static boolean isScreenSaverActivatedOnDock(Context context) { + return Settings.Secure.getInt(context.getContentResolver(), + SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_DOCK) != 0; + } + + private final Handler mHandler = new Handler(Looper.myLooper(), null, true) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_DOCK_STATE_CHANGED: + handleDockStateChange(); break; } } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index e219e8d..23b2706 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -47,7 +47,6 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; -import android.os.Parcelable; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; @@ -64,6 +63,8 @@ import com.android.internal.location.ProviderRequest; import com.android.server.location.GeocoderProxy; import com.android.server.location.GeofenceManager; import com.android.server.location.GpsLocationProvider; +import com.android.server.location.LocationBlacklist; +import com.android.server.location.LocationFudger; import com.android.server.location.LocationProviderInterface; import com.android.server.location.LocationProviderProxy; import com.android.server.location.MockProvider; @@ -110,19 +111,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs private static final int MSG_LOCATION_CHANGED = 1; - // Accuracy in meters above which a location is considered coarse - private static final double COARSE_ACCURACY_M = 100.0; - private static final String EXTRA_COARSE_LOCATION = "coarseLocation"; - - private static final int APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR = 111000; - - /** - * Maximum latitude of 1 meter from the pole. - * This keeps cosine(MAX_LATITUDE) to a non-zero value; - */ - private static final double MAX_LATITUDE = - 90.0 - (1.0 / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR); - // Location Providers may sometimes deliver location updates // slightly faster that requested - provide grace period so // we don't unnecessarily filter events that are otherwise on @@ -137,6 +125,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs private final Object mLock = new Object(); // --- fields below are final after init() --- + private LocationFudger mLocationFudger; private GeofenceManager mGeofenceManager; private PowerManager.WakeLock mWakeLock; private PackageManager mPackageManager; @@ -144,8 +133,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs private IGpsStatusProvider mGpsStatusProvider; private INetInitiatedListener mNetInitiatedListener; private LocationWorkerHandler mLocationHandler; - // track the passive provider for some special cases - private PassiveProvider mPassiveProvider; + private PassiveProvider mPassiveProvider; // track passive provider for special cases + private LocationBlacklist mBlacklist; // --- fields below are protected by mWakeLock --- private int mPendingBroadcasts; @@ -220,7 +209,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs synchronized (mLock) { loadProvidersLocked(); } - mGeofenceManager = new GeofenceManager(mContext); + mBlacklist = new LocationBlacklist(mContext, mLocationHandler); + mBlacklist.init(); + mGeofenceManager = new GeofenceManager(mContext, mBlacklist); + mLocationFudger = new LocationFudger(); // Register for Network (Wifi or Mobile) updates IntentFilter filter = new IntentFilter(); @@ -907,7 +899,25 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs String perm = checkPermission(); if (ACCESS_COARSE_LOCATION.equals(perm)) { - request.applyCoarsePermissionRestrictions(); + switch (request.getQuality()) { + case LocationRequest.ACCURACY_FINE: + request.setQuality(LocationRequest.ACCURACY_BLOCK); + break; + case LocationRequest.POWER_HIGH: + request.setQuality(LocationRequest.POWER_LOW); + break; + } + // throttle + if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { + request.setInterval(LocationFudger.FASTEST_INTERVAL_MS); + } + if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { + request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); + } + } + // make getFastestInterval() the minimum of interval and fastest interval + if (request.getFastestInterval() > request.getInterval()) { + request.setFastestInterval(request.getInterval()); } return perm; } @@ -958,7 +968,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs final int uid = Binder.getCallingUid(); Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName); - // so wakelock calls will succeed (not totally sure this is still needed) + // providers may use public location API's, need to clear identity long identity = Binder.clearCallingIdentity(); try { synchronized (mLock) { @@ -1008,7 +1018,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs final int uid = Binder.getCallingUid(); Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName); - // so wakelock calls will succeed (not totally sure this is still needed) + // providers may use public location API's, need to clear identity long identity = Binder.clearCallingIdentity(); try { synchronized (mLock) { @@ -1056,10 +1066,17 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs } @Override - public Location getLastLocation(LocationRequest request) { + public Location getLastLocation(LocationRequest request, String packageName) { if (D) Log.d(TAG, "getLastLocation: " + request); if (request == null) request = DEFAULT_LOCATION_REQUEST; String perm = checkPermissionAndRequest(request); + checkPackageName(packageName); + + if (mBlacklist.isBlacklisted(packageName)) { + if (D) Log.d(TAG, "not returning last loc for blacklisted app: " + + packageName); + return null; + } synchronized (mLock) { // Figure out the provider. Either its explicitly request (deprecated API's), @@ -1075,7 +1092,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs if (ACCESS_FINE_LOCATION.equals(perm)) { return location; } else { - return getCoarseLocationExtra(location); + return mLocationFudger.getOrCreate(location); } } } @@ -1090,7 +1107,14 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent); - mGeofenceManager.addFence(request, geofence, intent, Binder.getCallingUid(), packageName); + // geo-fence manager uses the public location API, need to clear identity + int uid = Binder.getCallingUid(); + long identity = Binder.clearCallingIdentity(); + try { + mGeofenceManager.addFence(request, geofence, intent, uid, packageName); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override @@ -1101,7 +1125,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent); - mGeofenceManager.removeFence(geofence, intent); + // geo-fence manager uses the public location API, need to clear identity + long identity = Binder.clearCallingIdentity(); + try { + mGeofenceManager.removeFence(geofence, intent); + } finally { + Binder.restoreCallingIdentity(identity); + } } @@ -1283,6 +1313,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs } private void handleLocationChangedLocked(Location location, boolean passive) { + if (D) Log.d(TAG, "incoming location: " + location); + long now = SystemClock.elapsedRealtime(); String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); @@ -1291,11 +1323,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs LocationProviderInterface p = mProvidersByName.get(provider); if (p == null) return; - // Add the coarse location as an extra, if not already present - Location coarse = getCoarseLocationExtra(location); - if (coarse == null) { - coarse = addCoarseLocationExtra(location); - } + // Add the coarse location as an extra + Location coarse = mLocationFudger.getOrCreate(location); // Update last known locations Location lastLocation = mLastLocation.get(provider); @@ -1319,6 +1348,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs for (UpdateRecord r : records) { Receiver receiver = r.mReceiver; boolean receiverDead = false; + + if (mBlacklist.isBlacklisted(receiver.mPackageName)) { + if (D) Log.d(TAG, "skipping loc update for blacklisted app: " + + receiver.mPackageName); + continue; + } + if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) { location = lastLocation; // use fine location } else { @@ -1530,7 +1566,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs MockProvider provider = new MockProvider(name, this, properties); // remove the real provider if we are replacing GPS or network provider if (LocationManager.GPS_PROVIDER.equals(name) - || LocationManager.NETWORK_PROVIDER.equals(name)) { + || LocationManager.NETWORK_PROVIDER.equals(name) + || LocationManager.FUSED_PROVIDER.equals(name)) { LocationProviderInterface p = mProvidersByName.get(name); if (p != null) { removeProviderLocked(p); @@ -1660,106 +1697,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs } } - private static double wrapLatitude(double lat) { - if (lat > MAX_LATITUDE) lat = MAX_LATITUDE; - if (lat < -MAX_LATITUDE) lat = -MAX_LATITUDE; - return lat; - } - - private static double wrapLongitude(double lon) { - if (lon >= 180.0) lon -= 360.0; - if (lon < -180.0) lon += 360.0; - return lon; - } - - private static double distanceToDegreesLatitude(double distance) { - return distance / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR; - } - - /** - * Requires latitude since longitudinal distances change with distance from equator. - */ - private static double distanceToDegreesLongitude(double distance, double lat) { - return distance / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR / Math.cos(lat); - } - - /** - * Fudge a location into a coarse location. - * <p>Add a random offset, then quantize the result (snap-to-grid). - * Random offsets alone can be low-passed pretty easily. - * Snap-to-grid on its own is excellent unless you are sitting on a - * grid boundary and bouncing between quantizations. - * The combination is quite hard to reverse engineer. - * <p>The random offset used is smaller than the goal accuracy - * ({@link #COARSE_ACCURACY_M}), in order to give relatively stable - * results after quantization. - */ - private static Location createCoarse(Location fine) { - Location coarse = new Location(fine); - - coarse.removeBearing(); - coarse.removeSpeed(); - coarse.removeAltitude(); - - double lat = coarse.getLatitude(); - double lon = coarse.getLongitude(); - - // wrap - lat = wrapLatitude(lat); - lon = wrapLongitude(lon); - - if (coarse.getAccuracy() < COARSE_ACCURACY_M / 2) { - // apply a random offset - double fudgeDistance = COARSE_ACCURACY_M / 2.0 - coarse.getAccuracy(); - lat += (Math.random() - 0.5) * distanceToDegreesLatitude(fudgeDistance); - lon += (Math.random() - 0.5) * distanceToDegreesLongitude(fudgeDistance, lat); - } - - // wrap - lat = wrapLatitude(lat); - lon = wrapLongitude(lon); - - // quantize (snap-to-grid) - double latGranularity = distanceToDegreesLatitude(COARSE_ACCURACY_M); - double lonGranularity = distanceToDegreesLongitude(COARSE_ACCURACY_M, lat); - long latQuantized = Math.round(lat / latGranularity); - long lonQuantized = Math.round(lon / lonGranularity); - lat = latQuantized * latGranularity; - lon = lonQuantized * lonGranularity; - - // wrap again - lat = wrapLatitude(lat); - lon = wrapLongitude(lon); - - // apply - coarse.setLatitude(lat); - coarse.setLongitude(lon); - coarse.setAccuracy((float)COARSE_ACCURACY_M); - - return coarse; - } - - - private static Location getCoarseLocationExtra(Location location) { - Bundle extras = location.getExtras(); - if (extras == null) return null; - Parcelable parcel = extras.getParcelable(EXTRA_COARSE_LOCATION); - if (parcel == null) return null; - if (!(parcel instanceof Location)) return null; - Location coarse = (Location) parcel; - if (coarse.getAccuracy() < COARSE_ACCURACY_M) return null; - return coarse; - } - - private static Location addCoarseLocationExtra(Location location) { - Bundle extras = location.getExtras(); - if (extras == null) extras = new Bundle(); - Location coarse = createCoarse(location); - extras.putParcelable(EXTRA_COARSE_LOCATION, coarse); - location.setExtras(extras); - return coarse; - } - private void log(String log) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Slog.d(TAG, log); @@ -1810,8 +1747,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs for (String i : mDisabledProviders) { pw.println(" " + i); } - } + pw.append(" "); + mBlacklist.dump(pw); if (mMockProviders.size() > 0) { pw.println(" Mock Providers:"); for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { @@ -1819,6 +1757,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Obs } } + pw.append(" fudger: "); + mLocationFudger.dump(fd, pw, args); + if (args.length > 0 && "short".equals(args[0])) { return; } diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index a565d08..d6fed39 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -1272,7 +1272,7 @@ public class NotificationManagerService extends INotificationManager.Stub void checkCallerIsSystem() { int uid = Binder.getCallingUid(); - if (uid == Process.SYSTEM_UID || uid == 0) { + if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) { return; } throw new SecurityException("Disallowed call for uid " + uid); @@ -1280,7 +1280,7 @@ public class NotificationManagerService extends INotificationManager.Stub void checkCallerIsSystemOrSameApp(String pkg) { int uid = Binder.getCallingUid(); - if (uid == Process.SYSTEM_UID || uid == 0) { + if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) { return; } try { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index c471dd2..a117b06 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -155,13 +155,12 @@ class ServerThread extends Thread { power = new PowerManagerService(); ServiceManager.addService(Context.POWER_SERVICE, power); - Slog.i(TAG, "Display Manager"); - display = new DisplayManagerService(); - ServiceManager.addService(Context.DISPLAY_SERVICE, display, true); - Slog.i(TAG, "Activity Manager"); context = ActivityManagerService.main(factoryTest); - display.setContext(context); + + Slog.i(TAG, "Display Manager"); + display = new DisplayManagerService(context); + ServiceManager.addService(Context.DISPLAY_SERVICE, display, true); Slog.i(TAG, "Telephony Registry"); ServiceManager.addService("telephony.registry", new TelephonyRegistry(context)); diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index c5243a2..afd7d0e 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -45,6 +45,7 @@ import android.os.RemoteException; import android.os.FileObserver; import android.os.ParcelFileDescriptor; import android.os.RemoteCallbackList; +import android.os.SELinux; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; @@ -422,9 +423,9 @@ class WallpaperManagerService extends IWallpaperManager.Stub { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_USER_SWITCHED.equals(action)) { - switchUser(intent.getIntExtra(Intent.EXTRA_USERID, 0)); + switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); } else if (Intent.ACTION_USER_REMOVED.equals(action)) { - removeUser(intent.getIntExtra(Intent.EXTRA_USERID, 0)); + removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); } } }, userFilter); @@ -639,8 +640,12 @@ class WallpaperManagerService extends IWallpaperManager.Stub { FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1); } - ParcelFileDescriptor fd = ParcelFileDescriptor.open(new File(dir, WALLPAPER), + File file = new File(dir, WALLPAPER); + ParcelFileDescriptor fd = ParcelFileDescriptor.open(file, MODE_CREATE|MODE_READ_WRITE); + if (!SELinux.restorecon(file)) { + return null; + } wallpaper.name = name; return fd; } catch (FileNotFoundException e) { @@ -763,10 +768,6 @@ class WallpaperManagerService extends IWallpaperManager.Stub { WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper); intent.setComponent(componentName); int serviceUserId = wallpaper.userId; - // Because the image wallpaper is running in the system ui - if (componentName.equals(wallpaper.imageWallpaperComponent)) { - serviceUserId = 0; - } intent.putExtra(Intent.EXTRA_CLIENT_LABEL, com.android.internal.R.string.wallpaper_binding_label); intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java index 96ac493..56c0fdf 100644 --- a/services/java/com/android/server/WiredAccessoryObserver.java +++ b/services/java/com/android/server/WiredAccessoryObserver.java @@ -16,12 +16,12 @@ package com.android.server; -import android.app.ActivityManagerNative; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.PowerManager.WakeLock; @@ -39,7 +39,7 @@ import java.util.List; /** * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock. */ -class WiredAccessoryObserver extends UEventObserver { +final class WiredAccessoryObserver extends UEventObserver { private static final String TAG = WiredAccessoryObserver.class.getSimpleName(); private static final boolean LOG = true; private static final int BIT_HEADSET = (1 << 0); @@ -50,122 +50,32 @@ class WiredAccessoryObserver extends UEventObserver { private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC| BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL| BIT_HDMI_AUDIO); - private static final int HEADSETS_WITH_MIC = BIT_HEADSET; - private static class UEventInfo { - private final String mDevName; - private final int mState1Bits; - private final int mState2Bits; - - public UEventInfo(String devName, int state1Bits, int state2Bits) { - mDevName = devName; - mState1Bits = state1Bits; - mState2Bits = state2Bits; - } - - public String getDevName() { return mDevName; } - - public String getDevPath() { - return String.format("/devices/virtual/switch/%s", mDevName); - } - - public String getSwitchStatePath() { - return String.format("/sys/class/switch/%s/state", mDevName); - } - - public boolean checkSwitchExists() { - File f = new File(getSwitchStatePath()); - return ((null != f) && f.exists()); - } - - public int computeNewHeadsetState(int headsetState, int switchState) { - int preserveMask = ~(mState1Bits | mState2Bits); - int setBits = ((switchState == 1) ? mState1Bits : - ((switchState == 2) ? mState2Bits : 0)); - - return ((headsetState & preserveMask) | setBits); - } - } - - private static List<UEventInfo> makeObservedUEventList() { - List<UEventInfo> retVal = new ArrayList<UEventInfo>(); - UEventInfo uei; - - // Monitor h2w - uei = new UEventInfo("h2w", BIT_HEADSET, BIT_HEADSET_NO_MIC); - if (uei.checkSwitchExists()) { - retVal.add(uei); - } else { - Slog.w(TAG, "This kernel does not have wired headset support"); - } - - // Monitor USB - uei = new UEventInfo("usb_audio", BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL); - if (uei.checkSwitchExists()) { - retVal.add(uei); - } else { - Slog.w(TAG, "This kernel does not have usb audio support"); - } + private final Object mLock = new Object(); - // Monitor HDMI - // - // If the kernel has support for the "hdmi_audio" switch, use that. It will be signalled - // only when the HDMI driver has a video mode configured, and the downstream sink indicates - // support for audio in its EDID. - // - // If the kernel does not have an "hdmi_audio" switch, just fall back on the older "hdmi" - // switch instead. - uei = new UEventInfo("hdmi_audio", BIT_HDMI_AUDIO, 0); - if (uei.checkSwitchExists()) { - retVal.add(uei); - } else { - uei = new UEventInfo("hdmi", BIT_HDMI_AUDIO, 0); - if (uei.checkSwitchExists()) { - retVal.add(uei); - } else { - Slog.w(TAG, "This kernel does not have HDMI audio support"); - } - } - - return retVal; - } - - private static List<UEventInfo> uEventInfo = makeObservedUEventList(); + private final Context mContext; + private final WakeLock mWakeLock; // held while there is a pending route change + private final AudioManager mAudioManager; + private final List<UEventInfo> mUEventInfo; private int mHeadsetState; private int mPrevHeadsetState; private String mHeadsetName; - private final Context mContext; - private final WakeLock mWakeLock; // held while there is a pending route change - - private final AudioManager mAudioManager; - public WiredAccessoryObserver(Context context) { mContext = context; + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryObserver"); mWakeLock.setReferenceCounted(false); mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); + mUEventInfo = makeObservedUEventList(); + context.registerReceiver(new BootCompletedReceiver(), new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); } - private final class BootCompletedReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - // At any given time accessories could be inserted - // one on the board, one on the dock and one on HDMI: - // observe three UEVENTs - init(); // set initial status - for (int i = 0; i < uEventInfo.size(); ++i) { - UEventInfo uei = uEventInfo.get(i); - startObserving("DEVPATH="+uei.getDevPath()); - } - } - } - @Override public void onUEvent(UEventObserver.UEvent event) { if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString()); @@ -174,56 +84,64 @@ class WiredAccessoryObserver extends UEventObserver { String devPath = event.get("DEVPATH"); String name = event.get("SWITCH_NAME"); int state = Integer.parseInt(event.get("SWITCH_STATE")); - updateState(devPath, name, state); + synchronized (mLock) { + updateStateLocked(devPath, name, state); + } } catch (NumberFormatException e) { Slog.e(TAG, "Could not parse switch state from event " + event); } } - private synchronized final void updateState(String devPath, String name, int state) - { - for (int i = 0; i < uEventInfo.size(); ++i) { - UEventInfo uei = uEventInfo.get(i); - if (devPath.equals(uei.getDevPath())) { - update(name, uei.computeNewHeadsetState(mHeadsetState, state)); - return; + private void bootCompleted() { + synchronized (mLock) { + char[] buffer = new char[1024]; + mPrevHeadsetState = mHeadsetState; + + if (LOG) Slog.v(TAG, "init()"); + + for (int i = 0; i < mUEventInfo.size(); ++i) { + UEventInfo uei = mUEventInfo.get(i); + try { + int curState; + FileReader file = new FileReader(uei.getSwitchStatePath()); + int len = file.read(buffer, 0, 1024); + file.close(); + curState = Integer.valueOf((new String(buffer, 0, len)).trim()); + + if (curState > 0) { + updateStateLocked(uei.getDevPath(), uei.getDevName(), curState); + } + } catch (FileNotFoundException e) { + Slog.w(TAG, uei.getSwitchStatePath() + + " not found while attempting to determine initial switch state"); + } catch (Exception e) { + Slog.e(TAG, "" , e); + } } } - } - - private synchronized final void init() { - char[] buffer = new char[1024]; - mPrevHeadsetState = mHeadsetState; - - if (LOG) Slog.v(TAG, "init()"); - for (int i = 0; i < uEventInfo.size(); ++i) { - UEventInfo uei = uEventInfo.get(i); - try { - int curState; - FileReader file = new FileReader(uei.getSwitchStatePath()); - int len = file.read(buffer, 0, 1024); - file.close(); - curState = Integer.valueOf((new String(buffer, 0, len)).trim()); - - if (curState > 0) { - updateState(uei.getDevPath(), uei.getDevName(), curState); - } + // At any given time accessories could be inserted + // one on the board, one on the dock and one on HDMI: + // observe three UEVENTs + for (int i = 0; i < mUEventInfo.size(); ++i) { + UEventInfo uei = mUEventInfo.get(i); + startObserving("DEVPATH="+uei.getDevPath()); + } + } - } catch (FileNotFoundException e) { - Slog.w(TAG, uei.getSwitchStatePath() + - " not found while attempting to determine initial switch state"); - } catch (Exception e) { - Slog.e(TAG, "" , e); + private void updateStateLocked(String devPath, String name, int state) { + for (int i = 0; i < mUEventInfo.size(); ++i) { + UEventInfo uei = mUEventInfo.get(i); + if (devPath.equals(uei.getDevPath())) { + updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state)); + return; } } } - private synchronized final void update(String newName, int newState) { + private void updateLocked(String newName, int newState) { // Retain only relevant bits int headsetState = newState & SUPPORTED_HEADSETS; - int newOrOld = headsetState | mHeadsetState; - int delay = 0; int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG; int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL; int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC); @@ -254,28 +172,26 @@ class WiredAccessoryObserver extends UEventObserver { mHeadsetState = headsetState; mWakeLock.acquire(); - mHandler.sendMessage(mHandler.obtainMessage(0, - mHeadsetState, - mPrevHeadsetState, - mHeadsetName)); + + Message msg = mHandler.obtainMessage(0, mHeadsetState, mPrevHeadsetState, mHeadsetName); + mHandler.sendMessage(msg); } - private synchronized final void setDevicesState(int headsetState, - int prevHeadsetState, - String headsetName) { - int allHeadsets = SUPPORTED_HEADSETS; - for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) { - if ((curHeadset & allHeadsets) != 0) { - setDeviceState(curHeadset, headsetState, prevHeadsetState, headsetName); - allHeadsets &= ~curHeadset; + private void setDevicesState( + int headsetState, int prevHeadsetState, String headsetName) { + synchronized (mLock) { + int allHeadsets = SUPPORTED_HEADSETS; + for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) { + if ((curHeadset & allHeadsets) != 0) { + setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName); + allHeadsets &= ~curHeadset; + } } } } - private final void setDeviceState(int headset, - int headsetState, - int prevHeadsetState, - String headsetName) { + private void setDeviceStateLocked(int headset, + int headsetState, int prevHeadsetState, String headsetName) { if ((headsetState & headset) != (prevHeadsetState & headset)) { int device; int state; @@ -308,11 +224,96 @@ class WiredAccessoryObserver extends UEventObserver { } } - private final Handler mHandler = new Handler() { + private static List<UEventInfo> makeObservedUEventList() { + List<UEventInfo> retVal = new ArrayList<UEventInfo>(); + UEventInfo uei; + + // Monitor h2w + uei = new UEventInfo("h2w", BIT_HEADSET, BIT_HEADSET_NO_MIC); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have wired headset support"); + } + + // Monitor USB + uei = new UEventInfo("usb_audio", BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have usb audio support"); + } + + // Monitor HDMI + // + // If the kernel has support for the "hdmi_audio" switch, use that. It will be signalled + // only when the HDMI driver has a video mode configured, and the downstream sink indicates + // support for audio in its EDID. + // + // If the kernel does not have an "hdmi_audio" switch, just fall back on the older "hdmi" + // switch instead. + uei = new UEventInfo("hdmi_audio", BIT_HDMI_AUDIO, 0); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + uei = new UEventInfo("hdmi", BIT_HDMI_AUDIO, 0); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have HDMI audio support"); + } + } + + return retVal; + } + + private final Handler mHandler = new Handler(Looper.myLooper(), null, true) { @Override public void handleMessage(Message msg) { setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); mWakeLock.release(); } }; + + private static final class UEventInfo { + private final String mDevName; + private final int mState1Bits; + private final int mState2Bits; + + public UEventInfo(String devName, int state1Bits, int state2Bits) { + mDevName = devName; + mState1Bits = state1Bits; + mState2Bits = state2Bits; + } + + public String getDevName() { return mDevName; } + + public String getDevPath() { + return String.format("/devices/virtual/switch/%s", mDevName); + } + + public String getSwitchStatePath() { + return String.format("/sys/class/switch/%s/state", mDevName); + } + + public boolean checkSwitchExists() { + File f = new File(getSwitchStatePath()); + return ((null != f) && f.exists()); + } + + public int computeNewHeadsetState(int headsetState, int switchState) { + int preserveMask = ~(mState1Bits | mState2Bits); + int setBits = ((switchState == 1) ? mState1Bits : + ((switchState == 2) ? mState2Bits : 0)); + + return ((headsetState & preserveMask) | setBits); + } + } + + private final class BootCompletedReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + bootCompleted(); + } + } } diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index d8ccabb..e222936 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -1725,21 +1725,53 @@ public class ActiveServices { ArrayList<ActivityManager.RunningServiceInfo> res = new ArrayList<ActivityManager.RunningServiceInfo>(); - int userId = UserHandle.getUserId(Binder.getCallingUid()); - if (mServiceMap.getAllServices(userId).size() > 0) { - Iterator<ServiceRecord> it - = mServiceMap.getAllServices(userId).iterator(); - while (it.hasNext() && res.size() < maxNum) { - res.add(makeRunningServiceInfoLocked(it.next())); - } - } + final int uid = Binder.getCallingUid(); + final long ident = Binder.clearCallingIdentity(); + try { + if (ActivityManager.checkUidPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + uid) == PackageManager.PERMISSION_GRANTED) { + List<UserInfo> users = mAm.getUserManager().getUsers(); + for (int ui=0; ui<users.size() && res.size() < maxNum; ui++) { + final UserInfo user = users.get(ui); + if (mServiceMap.getAllServices(user.id).size() > 0) { + Iterator<ServiceRecord> it = mServiceMap.getAllServices( + user.id).iterator(); + while (it.hasNext() && res.size() < maxNum) { + res.add(makeRunningServiceInfoLocked(it.next())); + } + } + } + + for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) { + ServiceRecord r = mRestartingServices.get(i); + ActivityManager.RunningServiceInfo info = + makeRunningServiceInfoLocked(r); + info.restarting = r.nextRestartTime; + res.add(info); + } + } else { + int userId = UserHandle.getUserId(uid); + if (mServiceMap.getAllServices(userId).size() > 0) { + Iterator<ServiceRecord> it + = mServiceMap.getAllServices(userId).iterator(); + while (it.hasNext() && res.size() < maxNum) { + res.add(makeRunningServiceInfoLocked(it.next())); + } + } - for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) { - ServiceRecord r = mRestartingServices.get(i); - ActivityManager.RunningServiceInfo info = - makeRunningServiceInfoLocked(r); - info.restarting = r.nextRestartTime; - res.add(info); + for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) { + ServiceRecord r = mRestartingServices.get(i); + if (r.userId == userId) { + ActivityManager.RunningServiceInfo info = + makeRunningServiceInfoLocked(r); + info.restarting = r.nextRestartTime; + res.add(info); + } + } + } + } finally { + Binder.restoreCallingIdentity(ident); } return res; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 0eb9983..7f2b69f 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -27,7 +27,6 @@ import com.android.server.ProcessMap; import com.android.server.SystemServer; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; -import com.android.server.pm.UserManagerService; import com.android.server.wm.WindowManagerService; import dalvik.system.Zygote; @@ -52,7 +51,6 @@ import android.app.Instrumentation; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; -import android.app.Service; import android.app.backup.IBackupManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; @@ -145,7 +143,6 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -1980,10 +1977,20 @@ public final class ActivityManagerService extends ActivityManagerNative int uid = app.uid; int[] gids = null; + int mountExternal = Zygote.MOUNT_EXTERNAL_NONE; if (!app.isolated) { try { - gids = mContext.getPackageManager().getPackageGids( - app.info.packageName); + final PackageManager pm = mContext.getPackageManager(); + gids = pm.getPackageGids(app.info.packageName); + if (pm.checkPermission( + android.Manifest.permission.READ_EXTERNAL_STORAGE, app.info.packageName) + == PERMISSION_GRANTED) { + if (Environment.isExternalStorageEmulated()) { + mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER; + } else { + mountExternal = Zygote.MOUNT_EXTERNAL_SINGLEUSER; + } + } } catch (PackageManager.NameNotFoundException e) { Slog.w(TAG, "Unable to retrieve gids", e); } @@ -2025,7 +2032,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Start the process. It will either succeed and return a result containing // the PID of the new process, or else throw a RuntimeException. Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread", - app.processName, uid, uid, gids, debugFlags, + app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, null, null); BatteryStatsImpl bs = app.batteryStats.getBatteryStats(); @@ -2529,7 +2536,6 @@ public final class ActivityManagerService extends ActivityManagerNative // This is so super not safe, that only the system (or okay root) // can do it. - int userId = Binder.getOrigCallingUser(); final int callingUid = Binder.getCallingUid(); if (callingUid != 0 && callingUid != Process.myUid()) { throw new SecurityException( @@ -2538,7 +2544,7 @@ public final class ActivityManagerService extends ActivityManagerNative int ret = mMainStack.startActivityMayWait(null, uid, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, - null, null, null, null, options, userId); + null, null, null, null, options, UserHandle.getUserId(uid)); return ret; } @@ -8382,11 +8388,19 @@ public final class ActivityManagerService extends ActivityManagerNative // assume our apps are happy - lazy create the list List<ActivityManager.ProcessErrorStateInfo> errList = null; + final boolean allUsers = ActivityManager.checkUidPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + Binder.getCallingUid()) == PackageManager.PERMISSION_GRANTED; + int userId = UserHandle.getUserId(Binder.getCallingUid()); + synchronized (this) { // iterate across all processes for (int i=mLruProcesses.size()-1; i>=0; i--) { ProcessRecord app = mLruProcesses.get(i); + if (!allUsers && app.userId != userId) { + continue; + } if ((app.thread != null) && (app.crashing || app.notResponding)) { // This one's in trouble, so we'll generate a report for it // crashes are higher priority (in case there's a crash *and* an anr) @@ -8450,6 +8464,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (app.persistent) { outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT; } + if (app.hasActivities) { + outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES; + } outInfo.lastTrimLevel = app.trimMemoryLevel; int adj = app.curAdj; outInfo.importance = oomAdjToImportance(adj, outInfo); @@ -8460,10 +8477,17 @@ public final class ActivityManagerService extends ActivityManagerNative enforceNotIsolatedCaller("getRunningAppProcesses"); // Lazy instantiation of list List<ActivityManager.RunningAppProcessInfo> runList = null; + final boolean allUsers = ActivityManager.checkUidPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + Binder.getCallingUid()) == PackageManager.PERMISSION_GRANTED; + int userId = UserHandle.getUserId(Binder.getCallingUid()); synchronized (this) { // Iterate across all processes for (int i=mLruProcesses.size()-1; i>=0; i--) { ProcessRecord app = mLruProcesses.get(i); + if (!allUsers && app.userId != userId) { + continue; + } if ((app.thread != null) && (!app.crashing && !app.notResponding)) { // Generate process state info for running application ActivityManager.RunningAppProcessInfo currApp = @@ -13482,8 +13506,8 @@ public final class ActivityManagerService extends ActivityManagerNative // Inform of user switch Intent addedIntent = new Intent(Intent.ACTION_USER_SWITCHED); - addedIntent.putExtra(Intent.EXTRA_USERID, userId); - mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS); + addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_USERS); return true; } @@ -13499,7 +13523,7 @@ public final class ActivityManagerService extends ActivityManagerNative } private void onUserRemoved(Intent intent) { - int extraUserId = intent.getIntExtra(Intent.EXTRA_USERID, -1); + int extraUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); if (extraUserId < 1) return; // Kill all the processes for the user diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index b0d480c..c70650d 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -614,14 +614,14 @@ final class ActivityRecord { pendingOptions.getStartY()+pendingOptions.getStartHeight())); } break; - case ActivityOptions.ANIM_THUMBNAIL: - case ActivityOptions.ANIM_THUMBNAIL_DELAYED: - boolean delayed = (animationType == ActivityOptions.ANIM_THUMBNAIL_DELAYED); + case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP: + case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN: + boolean scaleUp = (animationType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP); service.mWindowManager.overridePendingAppTransitionThumb( pendingOptions.getThumbnail(), pendingOptions.getStartX(), pendingOptions.getStartY(), pendingOptions.getOnAnimationStartListener(), - delayed); + scaleUp); if (intent.getSourceBounds() == null) { intent.setSourceBounds(new Rect(pendingOptions.getStartX(), pendingOptions.getStartY(), diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 1e0827f..ccea41a 100755 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -3014,8 +3014,8 @@ final class ActivityStack { // Collect information about the target of the Intent. ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, profileFile, profileFd, userId); - if (aInfo != null && mService.isSingleton(aInfo.processName, aInfo.applicationInfo, - null, 0)) { + if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0 + && mService.isSingleton(aInfo.processName, aInfo.applicationInfo, null, 0)) { userId = 0; } aInfo = mService.getActivityInfoForUser(aInfo, userId); diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java index 0106114..5b3ff8d 100644 --- a/services/java/com/android/server/am/ConnectionRecord.java +++ b/services/java/com/android/server/am/ConnectionRecord.java @@ -18,6 +18,7 @@ package com.android.server.am; import android.app.IServiceConnection; import android.app.PendingIntent; +import android.content.Context; import java.io.PrintWriter; @@ -62,6 +63,33 @@ class ConnectionRecord { sb.append("ConnectionRecord{"); sb.append(Integer.toHexString(System.identityHashCode(this))); sb.append(' '); + if ((flags&Context.BIND_AUTO_CREATE) != 0) { + sb.append("CR "); + } + if ((flags&Context.BIND_DEBUG_UNBIND) != 0) { + sb.append("DBG "); + } + if ((flags&Context.BIND_NOT_FOREGROUND) != 0) { + sb.append("NOTFG "); + } + if ((flags&Context.BIND_ABOVE_CLIENT) != 0) { + sb.append("ABCLT "); + } + if ((flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) { + sb.append("OOM "); + } + if ((flags&Context.BIND_WAIVE_PRIORITY) != 0) { + sb.append("WPRI "); + } + if ((flags&Context.BIND_IMPORTANT) != 0) { + sb.append("IMP "); + } + if ((flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) { + sb.append("ACT "); + } + if ((flags&Context.BIND_NOT_VISIBLE) != 0) { + sb.append("NOTVIS "); + } if (serviceDead) { sb.append("DEAD "); } diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java index c94f714..0a92964 100644 --- a/services/java/com/android/server/am/IntentBindRecord.java +++ b/services/java/com/android/server/am/IntentBindRecord.java @@ -16,6 +16,7 @@ package com.android.server.am; +import android.content.Context; import android.content.Intent; import android.os.IBinder; @@ -78,6 +79,20 @@ class IntentBindRecord { intent = _intent; } + int collectFlags() { + int flags = 0; + if (apps.size() > 0) { + for (AppBindRecord app : apps.values()) { + if (app.connections.size() > 0) { + for (ConnectionRecord conn : app.connections) { + flags |= conn.flags; + } + } + } + } + return flags; + } + public String toString() { if (stringName != null) { return stringName; @@ -86,6 +101,9 @@ class IntentBindRecord { sb.append("IntentBindRecord{"); sb.append(Integer.toHexString(System.identityHashCode(this))); sb.append(' '); + if ((collectFlags()&Context.BIND_AUTO_CREATE) != 0) { + sb.append("CR "); + } sb.append(service.shortName); sb.append(':'); if (intent != null) { diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java index ab2e428..15fbb98 100644 --- a/services/java/com/android/server/am/ProviderMap.java +++ b/services/java/com/android/server/am/ProviderMap.java @@ -127,7 +127,12 @@ public class ProviderMap { Slog.i(TAG, "Removing from providersByName name=" + name + " user=" + (optionalUserId == -1 ? Binder.getOrigCallingUser() : optionalUserId)); - getProvidersByName(optionalUserId).remove(name); + HashMap<String, ContentProviderRecord> map = getProvidersByName(optionalUserId); + // map returned by getProvidersByName wouldn't be null + map.remove(name); + if (map.size() == 0) { + mProvidersByNamePerUser.remove(optionalUserId); + } } } @@ -141,7 +146,12 @@ public class ProviderMap { Slog.i(TAG, "Removing from providersByClass name=" + name + " user=" + (optionalUserId == -1 ? Binder.getOrigCallingUser() : optionalUserId)); - getProvidersByClass(optionalUserId).remove(name); + HashMap<ComponentName, ContentProviderRecord> map = getProvidersByClass(optionalUserId); + // map returned by getProvidersByClass wouldn't be null + map.remove(name); + if (map.size() == 0) { + mProvidersByClassPerUser.remove(optionalUserId); + } } } diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index 41386e4..5d60b9c 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -23,6 +23,7 @@ import android.app.INotificationManager; import android.app.Notification; import android.app.NotificationManager; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -260,6 +261,9 @@ class ServiceRecord extends Binder { IntentBindRecord b = it.next(); pw.print(prefix); pw.print("* IntentBindRecord{"); pw.print(Integer.toHexString(System.identityHashCode(b))); + if ((b.collectFlags()&Context.BIND_AUTO_CREATE) != 0) { + pw.append(" CREATE"); + } pw.println("}:"); b.dumpInService(pw, prefix + " "); } diff --git a/services/java/com/android/server/display/DisplayAdapter.java b/services/java/com/android/server/display/DisplayAdapter.java index b623906..f9fa7a8 100644 --- a/services/java/com/android/server/display/DisplayAdapter.java +++ b/services/java/com/android/server/display/DisplayAdapter.java @@ -16,38 +16,33 @@ package com.android.server.display; -import android.view.Display; - /** - * A display adapter makes a single display devices available to the system. + * A display adapter makes zero or more display devices available to the system + * and provides facilities for discovering when displays are connected or disconnected. * <p> * For now, all display adapters are registered in the system server but * in principle it could be done from other processes. * </p> */ public abstract class DisplayAdapter { - /** The current logical Display assignment for this adapter. Will change if other logical - * display is assigned to this adapter */ - private int mDisplayId = Display.NO_DISPLAY; - - /** Assign the displayId - * @hide */ - public void setDisplayId(int displayId) { - mDisplayId = displayId; - } - - /** Retrieve the displayId - * @hide */ - public int getDisplayId() { - return mDisplayId; - } - /** - * Gets the display adapter name. + * Gets the display adapter name for debugging purposes. + * * @return The display adapter name. */ public abstract String getName(); - // TODO: dynamically register display devices - public abstract DisplayDevice getDisplayDevice(); + /** + * Registers the display adapter with the display manager. + * The display adapter should register any built-in display devices now. + * Other display devices can be registered dynamically later. + * + * @param listener The listener for callbacks. + */ + public abstract void register(Listener listener); + + public interface Listener { + public void onDisplayDeviceAdded(DisplayDevice device); + public void onDisplayDeviceRemoved(DisplayDevice device); + } } diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/java/com/android/server/display/DisplayDevice.java index 6d723f2..57002ff 100644 --- a/services/java/com/android/server/display/DisplayDevice.java +++ b/services/java/com/android/server/display/DisplayDevice.java @@ -18,8 +18,20 @@ package com.android.server.display; /** * Represents a physical display device such as the built-in display - * or an external monitor. + * an external monitor, or a WiFi display. */ public abstract class DisplayDevice { + /** + * Gets the display adapter that makes the display device available. + * + * @return The display adapter. + */ + public abstract DisplayAdapter getAdapter(); + + /** + * Gets information about the display device. + * + * @param outInfo The object to populate with the information. + */ public abstract void getInfo(DisplayDeviceInfo outInfo); } diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/java/com/android/server/display/DisplayDeviceInfo.java index c60c2e9..9c0f964 100644 --- a/services/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/java/com/android/server/display/DisplayDeviceInfo.java @@ -21,6 +21,12 @@ package com.android.server.display; */ public final class DisplayDeviceInfo { /** + * Gets the name of the display device, which may be derived from + * EDID or other sources. The name may be displayed to the user. + */ + public String name; + + /** * The width of the display in its natural orientation, in pixels. * This value is not affected by display rotation. */ @@ -38,6 +44,7 @@ public final class DisplayDeviceInfo { public float yDpi; public void copyFrom(DisplayDeviceInfo other) { + name = other.name; width = other.width; height = other.height; refreshRate = other.refreshRate; @@ -46,9 +53,10 @@ public final class DisplayDeviceInfo { yDpi = other.yDpi; } + // For debugging purposes @Override public String toString() { - return width + " x " + height + ", " + refreshRate + " fps, " + return "\"" + name + "\": " + width + " x " + height + ", " + refreshRate + " fps, " + "density " + densityDpi + ", " + xDpi + " x " + yDpi + " dpi"; } } diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java index 468bf21..2ebad1d 100644 --- a/services/java/com/android/server/display/DisplayManagerService.java +++ b/services/java/com/android/server/display/DisplayManagerService.java @@ -19,11 +19,10 @@ package com.android.server.display; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; +import android.hardware.display.DisplayManager; import android.hardware.display.IDisplayManager; import android.os.Binder; import android.os.SystemProperties; -import android.util.Slog; -import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; @@ -47,41 +46,27 @@ public final class DisplayManagerService extends IDisplayManager.Stub { private final Object mLock = new Object(); - private Context mContext; + private final Context mContext; private final boolean mHeadless; - private int mDisplayIdSeq = Display.DEFAULT_DISPLAY; - - /** All registered DisplayAdapters. */ private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>(); + private final DisplayInfo mDefaultDisplayInfo = new DisplayInfo(); - /** All the DisplayAdapters showing the given displayId. */ - private final SparseArray<ArrayList<DisplayAdapter>> mLogicalToPhysicals = - new SparseArray<ArrayList<DisplayAdapter>>(); - - /** All the DisplayInfos in the system indexed by deviceId */ - private final SparseArray<DisplayInfo> mDisplayInfos = new SparseArray<DisplayInfo>(); - - private final ArrayList<DisplayCallback> mCallbacks = - new ArrayList<DisplayManagerService.DisplayCallback>(); - - public DisplayManagerService() { + public DisplayManagerService(Context context) { + mContext = context; mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1"); + registerDefaultDisplayAdapter(); } private void registerDefaultDisplayAdapter() { if (mHeadless) { - registerDisplayAdapter(new HeadlessDisplayAdapter()); + registerDisplayAdapter(new HeadlessDisplayAdapter(mContext)); } else { - registerDisplayAdapter(new SurfaceFlingerDisplayAdapter()); + registerDisplayAdapter(new SurfaceFlingerDisplayAdapter(mContext)); } } - public void setContext(Context context) { - mContext = context; - } - // FIXME: this isn't the right API for the long term public void getDefaultExternalDisplayDeviceInfo(DisplayDeviceInfo info) { // hardcoded assuming 720p touch screen plugged into HDMI and USB @@ -90,6 +75,11 @@ public final class DisplayManagerService extends IDisplayManager.Stub { info.height = 720; } + /** + * Returns true if the device is headless. + * + * @return True if the device is headless. + */ public boolean isHeadless() { return mHeadless; } @@ -101,12 +91,10 @@ public final class DisplayManagerService extends IDisplayManager.Stub { */ public void setDisplayInfo(int displayId, DisplayInfo info) { synchronized (mLock) { - DisplayInfo localInfo = mDisplayInfos.get(displayId); - if (localInfo == null) { - localInfo = new DisplayInfo(); - mDisplayInfos.put(displayId, localInfo); + if (displayId != Display.DEFAULT_DISPLAY) { + throw new UnsupportedOperationException(); } - localInfo.copyFrom(info); + mDefaultDisplayInfo.copyFrom(info); } } @@ -118,177 +106,32 @@ public final class DisplayManagerService extends IDisplayManager.Stub { @Override // Binder call public boolean getDisplayInfo(int displayId, DisplayInfo outInfo) { synchronized (mLock) { - DisplayInfo localInfo = mDisplayInfos.get(displayId); - if (localInfo == null) { + if (displayId != Display.DEFAULT_DISPLAY) { return false; } - outInfo.copyFrom(localInfo); + outInfo.copyFrom(mDefaultDisplayInfo); return true; } } - /** - * Inform the service of a new physical display. A new logical displayId is created and the new - * physical display is immediately bound to it. Use removeAdapterFromDisplay to disconnect it. - * - * @param adapter The wrapper for information associated with the physical display. - */ - public void registerDisplayAdapter(DisplayAdapter adapter) { - - int displayId; - DisplayCallback[] callbacks; - - synchronized (mLock) { - displayId = mDisplayIdSeq; - do { - // Find the next unused displayId. (Pretend like it might ever wrap around). - mDisplayIdSeq++; - if (mDisplayIdSeq < 0) { - mDisplayIdSeq = Display.DEFAULT_DISPLAY + 1; - } - } while (mDisplayInfos.get(mDisplayIdSeq) != null); - - adapter.setDisplayId(displayId); - - createDisplayInfoLocked(displayId, adapter); - - ArrayList<DisplayAdapter> list = new ArrayList<DisplayAdapter>(); - list.add(adapter); - mLogicalToPhysicals.put(displayId, list); - - mDisplayAdapters.add(adapter); - callbacks = mCallbacks.toArray(new DisplayCallback[mCallbacks.size()]); - } - - for (int i = callbacks.length - 1; i >= 0; i--) { - callbacks[i].displayAdded(displayId); - } - - // TODO: Notify SurfaceFlinger of new addition. - } - - /** - * Connect a logical display to a physical display. Will remove the physical display from any - * logical display it is currently attached to. - * - * @param displayId The logical display. Will be created if it does not already exist. - * @param adapter The physical display. - */ - public void addAdapterToDisplay(int displayId, DisplayAdapter adapter) { - if (adapter == null) { - // TODO: Or throw NPE? - Slog.e(TAG, "addDeviceToDisplay: Attempt to add null adapter"); - return; - } - - synchronized (mLock) { - if (!mDisplayAdapters.contains(adapter)) { - // TOOD: Handle unregistered adapter with exception or return value. - Slog.e(TAG, "addDeviceToDisplay: Attempt to add an unregistered adapter"); - return; - } - - DisplayInfo displayInfo = mDisplayInfos.get(displayId); - if (displayInfo == null) { - createDisplayInfoLocked(displayId, adapter); - } - - Integer oldDisplayId = adapter.getDisplayId(); - if (oldDisplayId != Display.NO_DISPLAY) { - if (oldDisplayId == displayId) { - // adapter already added to displayId. - return; - } - - removeAdapterLocked(adapter); - } - - ArrayList<DisplayAdapter> list = mLogicalToPhysicals.get(displayId); - if (list == null) { - list = new ArrayList<DisplayAdapter>(); - mLogicalToPhysicals.put(displayId, list); - } - list.add(adapter); - adapter.setDisplayId(displayId); - } - - // TODO: Notify SurfaceFlinger of new addition. - } - - /** - * Disconnect the physical display from whichever logical display it is attached to. - * @param adapter The physical display to detach. - */ - public void removeAdapterFromDisplay(DisplayAdapter adapter) { - if (adapter == null) { - // TODO: Or throw NPE? - return; - } - - synchronized (mLock) { - if (!mDisplayAdapters.contains(adapter)) { - // TOOD: Handle unregistered adapter with exception or return value. - Slog.e(TAG, "removeDeviceFromDisplay: Attempt to remove an unregistered adapter"); - return; + private void registerDisplayAdapter(DisplayAdapter adapter) { + mDisplayAdapters.add(adapter); + adapter.register(new DisplayAdapter.Listener() { + @Override + public void onDisplayDeviceAdded(DisplayDevice device) { + DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo(); + device.getInfo(deviceInfo); + copyDisplayInfoFromDeviceInfo(mDefaultDisplayInfo, deviceInfo); } - removeAdapterLocked(adapter); - } - - // TODO: Notify SurfaceFlinger of removal. - } - - public void registerDisplayCallback(final DisplayCallback callback) { - synchronized (mLock) { - if (!mCallbacks.contains(callback)) { - mCallbacks.add(callback); + @Override + public void onDisplayDeviceRemoved(DisplayDevice device) { } - } + }); } - public void unregisterDisplayCallback(final DisplayCallback callback) { - synchronized (mLock) { - mCallbacks.remove(callback); - } - } - - /** - * Create a new logical DisplayInfo and fill it in with information from the physical display. - * @param displayId The logical identifier. - * @param adapter The physical display for initial values. - */ - private void createDisplayInfoLocked(int displayId, DisplayAdapter adapter) { - DisplayInfo displayInfo = new DisplayInfo(); - DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo(); - adapter.getDisplayDevice().getInfo(deviceInfo); - copyDisplayInfoFromDeviceInfo(displayInfo, deviceInfo); - mDisplayInfos.put(displayId, displayInfo); - } - - /** - * Disconnect a physical display from its logical display. If there are no more physical - * displays attached to the logical display, delete the logical display. - * @param adapter The physical display to detach. - */ - void removeAdapterLocked(DisplayAdapter adapter) { - int displayId = adapter.getDisplayId(); - adapter.setDisplayId(Display.NO_DISPLAY); - - ArrayList<DisplayAdapter> list = mLogicalToPhysicals.get(displayId); - if (list != null) { - list.remove(adapter); - if (list.isEmpty()) { - mLogicalToPhysicals.remove(displayId); - // TODO: Keep count of Windows attached to logical display and don't delete if - // there are any outstanding. Also, what keeps the WindowManager from continuing - // to use the logical display? - mDisplayInfos.remove(displayId); - } - } - } - - private void copyDisplayInfoFromDeviceInfo(DisplayInfo displayInfo, - DisplayDeviceInfo deviceInfo) { + private void copyDisplayInfoFromDeviceInfo( + DisplayInfo displayInfo, DisplayDeviceInfo deviceInfo) { // Bootstrap the logical display using the physical display. displayInfo.appWidth = deviceInfo.width; displayInfo.appHeight = deviceInfo.height; @@ -319,19 +162,15 @@ public final class DisplayManagerService extends IDisplayManager.Stub { pw.println("Headless: " + mHeadless); - DisplayDeviceInfo info = new DisplayDeviceInfo(); - for (DisplayAdapter adapter : mDisplayAdapters) { - pw.println("Display for adapter " + adapter.getName() - + " assigned to Display " + adapter.getDisplayId()); - DisplayDevice device = adapter.getDisplayDevice(); - pw.print(" "); - device.getInfo(info); - pw.println(info); + synchronized (mLock) { + for (DisplayAdapter adapter : mDisplayAdapters) { + pw.println("Adapter: " + adapter.getName()); + } + + pw.println("Default display info: " + mDefaultDisplayInfo); } - } - public interface DisplayCallback { - public void displayAdded(int displayId); - public void displayRemoved(int displayId); + pw.println("Default display: " + + DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY)); } } diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java index 3eaf40f..17c2360 100644 --- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java +++ b/services/java/com/android/server/display/HeadlessDisplayAdapter.java @@ -16,15 +16,41 @@ package com.android.server.display; +import android.content.Context; import android.util.DisplayMetrics; /** * Provides a fake default display for headless systems. */ public final class HeadlessDisplayAdapter extends DisplayAdapter { - private final DisplayDevice mDefaultDisplay = new DisplayDevice() { + private final Context mContext; + private final HeadlessDisplayDevice mDefaultDisplayDevice; + + public HeadlessDisplayAdapter(Context context) { + mContext = context; + mDefaultDisplayDevice = new HeadlessDisplayDevice(); + } + + @Override + public String getName() { + return "HeadlessDisplayAdapter"; + } + + @Override + public void register(Listener listener) { + listener.onDisplayDeviceAdded(mDefaultDisplayDevice); + } + + private final class HeadlessDisplayDevice extends DisplayDevice { + @Override + public DisplayAdapter getAdapter() { + return HeadlessDisplayAdapter.this; + } + @Override public void getInfo(DisplayDeviceInfo outInfo) { + outInfo.name = mContext.getResources().getString( + com.android.internal.R.string.display_manager_built_in_display); outInfo.width = 640; outInfo.height = 480; outInfo.refreshRate = 60; @@ -32,15 +58,5 @@ public final class HeadlessDisplayAdapter extends DisplayAdapter { outInfo.xDpi = 160; outInfo.yDpi = 160; } - }; - - @Override - public String getName() { - return "HeadlessDisplayAdapter"; - } - - @Override - public DisplayDevice getDisplayDevice() { - return mDefaultDisplay; } } diff --git a/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java b/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java index 539f7c1..9531acb 100644 --- a/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java +++ b/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java @@ -16,18 +16,21 @@ package com.android.server.display; +import android.content.Context; + /** * A display adapter for the displays managed by Surface Flinger. */ public final class SurfaceFlingerDisplayAdapter extends DisplayAdapter { + private final Context mContext; + private final SurfaceFlingerDisplayDevice mDefaultDisplayDevice; + private static native void nativeGetDefaultDisplayDeviceInfo(DisplayDeviceInfo outInfo); - private final DisplayDevice mDefaultDisplay = new DisplayDevice() { - @Override - public void getInfo(DisplayDeviceInfo outInfo) { - nativeGetDefaultDisplayDeviceInfo(outInfo); - } - }; + public SurfaceFlingerDisplayAdapter(Context context) { + mContext = context; + mDefaultDisplayDevice = new SurfaceFlingerDisplayDevice(); + } @Override public String getName() { @@ -35,7 +38,21 @@ public final class SurfaceFlingerDisplayAdapter extends DisplayAdapter { } @Override - public DisplayDevice getDisplayDevice() { - return mDefaultDisplay; + public void register(Listener listener) { + listener.onDisplayDeviceAdded(mDefaultDisplayDevice); + } + + private final class SurfaceFlingerDisplayDevice extends DisplayDevice { + @Override + public DisplayAdapter getAdapter() { + return SurfaceFlingerDisplayAdapter.this; + } + + @Override + public void getInfo(DisplayDeviceInfo outInfo) { + outInfo.name = mContext.getResources().getString( + com.android.internal.R.string.display_manager_built_in_display); + nativeGetDefaultDisplayDeviceInfo(outInfo); + } } } diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java index 21100e2..0b8ff62 100644 --- a/services/java/com/android/server/input/InputManagerService.java +++ b/services/java/com/android/server/input/InputManagerService.java @@ -1218,8 +1218,12 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. } // Native callback. - private void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { - mCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); + private void notifySwitch(long whenNanos, int switchCode, int switchValue) { + switch (switchCode) { + case SW_LID: + mCallbacks.notifyLidSwitchChanged(whenNanos, switchValue == 0); + break; + } } // Native callback. diff --git a/services/java/com/android/server/location/GeofenceManager.java b/services/java/com/android/server/location/GeofenceManager.java index 338cd5d..26d9c15 100644 --- a/services/java/com/android/server/location/GeofenceManager.java +++ b/services/java/com/android/server/location/GeofenceManager.java @@ -34,9 +34,13 @@ import android.os.Bundle; import android.os.Looper; import android.os.PowerManager; import android.os.SystemClock; +import android.util.Log; + +import com.android.server.LocationManagerService; public class GeofenceManager implements LocationListener, PendingIntent.OnFinished { private static final String TAG = "GeofenceManager"; + private static final boolean D = LocationManagerService.D; /** * Assume a maximum land speed, as a heuristic to throttle location updates. @@ -49,6 +53,7 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish private final LocationManager mLocationManager; private final PowerManager.WakeLock mWakeLock; private final Looper mLooper; // looper thread to take location updates on + private final LocationBlacklist mBlacklist; private Object mLock = new Object(); @@ -56,12 +61,13 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish private Location mLastLocation; private List<GeofenceState> mFences = new LinkedList<GeofenceState>(); - public GeofenceManager(Context context) { + public GeofenceManager(Context context, LocationBlacklist blacklist) { mContext = context; mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mLooper = Looper.myLooper(); + mBlacklist = blacklist; LocationRequest request = new LocationRequest() .setQuality(LocationRequest.POWER_NONE) @@ -145,6 +151,12 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish removeExpiredFencesLocked(); for (GeofenceState state : mFences) { + if (mBlacklist.isBlacklisted(state.mPackageName)) { + if (D) Log.d(TAG, "skipping geofence processing for blacklisted app: " + + state.mPackageName); + continue; + } + int event = state.processLocation(location); if ((event & GeofenceState.FLAG_ENTER) != 0) { enterIntents.add(state.mIntent); diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java index 3cd767d..2d4fa2b 100755 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -496,6 +496,7 @@ public class GpsLocationProvider implements LocationProviderInterface { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ALARM_WAKEUP); intentFilter.addAction(ALARM_TIMEOUT); + intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiver(mBroadcastReciever, intentFilter); } @@ -845,6 +846,9 @@ public class GpsLocationProvider implements LocationProviderInterface { } } } + + // save current uids + mClientUids = uids; } @Override diff --git a/services/java/com/android/server/location/LocationBlacklist.java b/services/java/com/android/server/location/LocationBlacklist.java new file mode 100644 index 0000000..71fa9f9 --- /dev/null +++ b/services/java/com/android/server/location/LocationBlacklist.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.android.server.location; + +import android.content.Context; +import android.database.ContentObserver; +import android.os.Handler; +import android.provider.Settings; +import android.util.Log; +import android.util.Slog; + +import com.android.server.LocationManagerService; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Allows applications to be blacklisted from location updates at run-time. + * + * This is a silent blacklist. Applications can still call Location Manager + * API's, but they just won't receive any locations. + */ +public final class LocationBlacklist extends ContentObserver { + private static final String TAG = "LocationBlacklist"; + private static final boolean D = LocationManagerService.D; + private static final String BLACKLIST_CONFIG_NAME = "locationPackagePrefixBlacklist"; + private static final String WHITELIST_CONFIG_NAME = "locationPackagePrefixWhitelist"; + + private final Context mContext; + private final Object mLock = new Object(); + + // all fields below synchronized on mLock + private String[] mWhitelist = new String[0]; + private String[] mBlacklist = new String[0]; + + public LocationBlacklist(Context context, Handler handler) { + super(handler); + mContext = context; + } + + public void init() { + mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor( + BLACKLIST_CONFIG_NAME), false, this); +// mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor( +// WHITELIST_CONFIG_NAME), false, this); + reloadBlacklist(); + } + + private void reloadBlacklist() { + String blacklist[] = getStringArray(BLACKLIST_CONFIG_NAME); + String whitelist[] = getStringArray(WHITELIST_CONFIG_NAME); + synchronized (mLock) { + mWhitelist = whitelist; + Slog.i(TAG, "whitelist: " + Arrays.toString(mWhitelist)); + mBlacklist = blacklist; + Slog.i(TAG, "blacklist: " + Arrays.toString(mBlacklist)); + } + } + + /** + * Return true if in blacklist + * (package name matches blacklist, and does not match whitelist) + */ + public boolean isBlacklisted(String packageName) { + synchronized (mLock) { + for (String black : mBlacklist) { + if (packageName.startsWith(black)) { + if (inWhitelist(packageName)) { + continue; + } else { + if (D) Log.d(TAG, "dropping location (blacklisted): " + + packageName + " matches " + black); + return true; + } + } + } + } + return false; + } + + /** + * Return true if any of packages are in whitelist + */ + private boolean inWhitelist(String pkg) { + synchronized (mLock) { + for (String white : mWhitelist) { + if (pkg.startsWith(white)) return true; + } + } + return false; + } + + @Override + public void onChange(boolean selfChange) { + reloadBlacklist(); + } + + private String[] getStringArray(String key) { + String flatString = Settings.Secure.getString(mContext.getContentResolver(), key); + if (flatString == null) { + return new String[0]; + } + String[] splitStrings = flatString.split(","); + ArrayList<String> result = new ArrayList<String>(); + for (String pkg : splitStrings) { + pkg = pkg.trim(); + if (pkg.isEmpty()) { + continue; + } + result.add(pkg); + } + return result.toArray(new String[result.size()]); + } + + public void dump(PrintWriter pw) { + pw.println("mWhitelist=" + Arrays.toString(mWhitelist) + " mBlacklist=" + + Arrays.toString(mBlacklist)); + } +} diff --git a/services/java/com/android/server/location/LocationFudger.java b/services/java/com/android/server/location/LocationFudger.java new file mode 100644 index 0000000..57bc1c5 --- /dev/null +++ b/services/java/com/android/server/location/LocationFudger.java @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.security.SecureRandom; +import android.location.Location; +import android.os.Bundle; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.Log; + + +/** + * Contains the logic to obfuscate (fudge) locations for coarse applications. + * + * <p>The goal is just to prevent applications with only + * the coarse location permission from receiving a fine location. + */ +public class LocationFudger { + private static final boolean D = false; + private static final String TAG = "LocationFudge"; + + private static final String EXTRA_COARSE_LOCATION = "coarseLocation"; + + /** + * This is the main control: Best location accuracy allowed for coarse applications. + */ + private static final float ACCURACY_METERS = 200.0f; + + /** + * The distance between grids for snap-to-grid. See {@link #createCoarse}. + */ + private static final double GRID_SIZE_METERS = ACCURACY_METERS; + + /** + * Standard deviation of the (normally distributed) random offset applied + * to coarse locations. It does not need to be as large as + * {@link #COARSE_ACCURACY_METERS} because snap-to-grid is the primary obfuscation + * method. See further details in the implementation. + */ + private static final double STANDARD_DEVIATION_METERS = GRID_SIZE_METERS / 4.0; + + /** + * This is the fastest interval that applications can receive coarse + * locations. + */ + public static final long FASTEST_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes + + /** + * The duration until we change the random offset. + */ + private static final long CHANGE_INTERVAL_MS = 60 * 60 * 1000; // 1 hour + + /** + * The percentage that we change the random offset at every interval. + * + * <p>0.0 indicates the random offset doesn't change. 1.0 + * indicates the random offset is completely replaced every interval. + */ + private static final double CHANGE_PER_INTERVAL = 0.03; // 3% change + + // Pre-calculated weights used to move the random offset. + // + // The goal is to iterate on the previous offset, but keep + // the resulting standard deviation the same. The variance of + // two gaussian distributions summed together is equal to the + // sum of the variance of each distribution. So some quick + // algebra results in the following sqrt calculation to + // weigh in a new offset while keeping the final standard + // deviation unchanged. + private static final double NEW_WEIGHT = CHANGE_PER_INTERVAL; + private static final double PREVIOUS_WEIGHT = Math.sqrt(1 - NEW_WEIGHT * NEW_WEIGHT); + + /** + * This number actually varies because the earth is not round, but + * 111,000 meters is considered generally acceptable. + */ + private static final int APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR = 111000; + + /** + * Maximum latitude. + * + * <p>We pick a value 1 meter away from 90.0 degrees in order + * to keep cosine(MAX_LATITUDE) to a non-zero value, so that we avoid + * divide by zero fails. + */ + private static final double MAX_LATITUDE = 90.0 - + (1.0 / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR); + + private final Object mLock = new Object(); + private final SecureRandom mRandom = new SecureRandom(); + + // all fields below protected by mLock + private double mOffsetLatitudeMeters; + private double mOffsetLongitudeMeters; + private long mNextInterval; + + public LocationFudger() { + mOffsetLatitudeMeters = nextOffset(); + mOffsetLongitudeMeters = nextOffset(); + mNextInterval = SystemClock.elapsedRealtime() + CHANGE_INTERVAL_MS; + } + + /** + * Get the cached coarse location, or generate a new one and cache it. + */ + public Location getOrCreate(Location location) { + Bundle extras = location.getExtras(); + if (extras == null) { + return addCoarseLocationExtra(location); + } + Parcelable parcel = extras.getParcelable(EXTRA_COARSE_LOCATION); + if (parcel == null) { + return addCoarseLocationExtra(location); + } + if (!(parcel instanceof Location)) { + return addCoarseLocationExtra(location); + } + Location coarse = (Location) parcel; + if (coarse.getAccuracy() < ACCURACY_METERS) { + return addCoarseLocationExtra(location); + } + return coarse; + } + + private Location addCoarseLocationExtra(Location location) { + Bundle extras = location.getExtras(); + if (extras == null) extras = new Bundle(); + Location coarse = createCoarse(location); + extras.putParcelable(EXTRA_COARSE_LOCATION, coarse); + location.setExtras(extras); + return coarse; + } + + /** + * Create a coarse location. + * + * <p>Two techniques are used: random offsets and snap-to-grid. + * + * <p>First we add a random offset. This mitigates against detecting + * grid transitions. Without a random offset it is possible to detect + * a users position very accurately when they cross a grid boundary. + * The random offset changes very slowly over time, to mitigate against + * taking many location samples and averaging them out. + * + * <p>Second we snap-to-grid (quantize). This has the nice property of + * producing stable results, and mitigating against taking many samples + * to average out a random offset. + */ + private Location createCoarse(Location fine) { + Location coarse = new Location(fine); + + // clean all the optional information off the location, because + // this can leak detailed location information + coarse.removeBearing(); + coarse.removeSpeed(); + coarse.removeAltitude(); + coarse.setExtras(null); + + double lat = coarse.getLatitude(); + double lon = coarse.getLongitude(); + + // wrap + lat = wrapLatitude(lat); + lon = wrapLongitude(lon); + + // Step 1) apply a random offset + // + // The goal of the random offset is to prevent the application + // from determining that the device is on a grid boundary + // when it crosses from one grid to the next. + // + // We apply the offset even if the location already claims to be + // inaccurate, because it may be more accurate than claimed. + synchronized (mLock) { + updateRandomOffsetLocked(); + // perform lon first whilst lat is still within bounds + lon += metersToDegreesLongitude(mOffsetLongitudeMeters, lat); + lat += metersToDegreesLatitude(mOffsetLatitudeMeters); + if (D) Log.d(TAG, String.format("applied offset of %.0f, %.0f (meters)", + mOffsetLongitudeMeters, mOffsetLatitudeMeters)); + } + + // wrap + lat = wrapLatitude(lat); + lon = wrapLongitude(lon); + + // Step 2) Snap-to-grid (quantize) + // + // This is the primary means of obfuscation. It gives nice consistent + // results and is very effective at hiding the true location + // (as long as you are not sitting on a grid boundary, which + // step 1 mitigates). + // + // Note we quantize the latitude first, since the longitude + // quantization depends on the latitude value and so leaks information + // about the latitude + double latGranularity = metersToDegreesLatitude(GRID_SIZE_METERS); + lat = Math.round(lat / latGranularity) * latGranularity; + double lonGranularity = metersToDegreesLongitude(GRID_SIZE_METERS, lat); + lon = Math.round(lon / lonGranularity) * lonGranularity; + + // wrap again + lat = wrapLatitude(lat); + lon = wrapLongitude(lon); + + // apply + coarse.setLatitude(lat); + coarse.setLongitude(lon); + coarse.setAccuracy(Math.max(ACCURACY_METERS, coarse.getAccuracy())); + + if (D) Log.d(TAG, "fudged " + fine + " to " + coarse); + return coarse; + } + + /** + * Update the random offset over time. + * + * <p>If the random offset was new for every location + * fix then an application can more easily average location results + * over time, + * especially when the location is near a grid boundary. On the + * other hand if the random offset is constant then if an application + * found a way to reverse engineer the offset they would be able + * to detect location at grid boundaries very accurately. So + * we choose a random offset and then very slowly move it, to + * make both approaches very hard. + * + * <p>The random offset does not need to be large, because snap-to-grid + * is the primary obfuscation mechanism. It just needs to be large + * enough to stop information leakage as we cross grid boundaries. + */ + private void updateRandomOffsetLocked() { + long now = SystemClock.elapsedRealtime(); + if (now < mNextInterval) { + return; + } + + if (D) Log.d(TAG, String.format("old offset: %.0f, %.0f (meters)", + mOffsetLongitudeMeters, mOffsetLatitudeMeters)); + + // ok, need to update the random offset + mNextInterval = now + CHANGE_INTERVAL_MS; + + mOffsetLatitudeMeters *= PREVIOUS_WEIGHT; + mOffsetLatitudeMeters += NEW_WEIGHT * nextOffset(); + mOffsetLongitudeMeters *= PREVIOUS_WEIGHT; + mOffsetLongitudeMeters += NEW_WEIGHT * nextOffset(); + + if (D) Log.d(TAG, String.format("new offset: %.0f, %.0f (meters)", + mOffsetLongitudeMeters, mOffsetLatitudeMeters)); + } + + private double nextOffset() { + return mRandom.nextGaussian() * STANDARD_DEVIATION_METERS; + } + + private static double wrapLatitude(double lat) { + if (lat > MAX_LATITUDE) { + lat = MAX_LATITUDE; + } + if (lat < -MAX_LATITUDE) { + lat = -MAX_LATITUDE; + } + return lat; + } + + private static double wrapLongitude(double lon) { + lon %= 360.0; // wraps into range (-360.0, +360.0) + if (lon >= 180.0) { + lon -= 360.0; + } + if (lon < -180.0) { + lon += 360.0; + } + return lon; + } + + private static double metersToDegreesLatitude(double distance) { + return distance / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR; + } + + /** + * Requires latitude since longitudinal distances change with distance from equator. + */ + private static double metersToDegreesLongitude(double distance, double lat) { + return distance / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR / Math.cos(Math.toRadians(lat)); + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(String.format("offset: %.0f, %.0f (meters)", mOffsetLongitudeMeters, + mOffsetLatitudeMeters)); + } +} diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java index 48004bb..d4fe3fb 100644 --- a/services/java/com/android/server/pm/Installer.java +++ b/services/java/com/android/server/pm/Installer.java @@ -338,12 +338,14 @@ class Installer { return execute(builder.toString()); } - public int getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath, + public int getSizeInfo(String pkgName, int persona, String apkPath, String fwdLockApkPath, String asecPath, PackageStats pStats) { StringBuilder builder = new StringBuilder("getsize"); builder.append(' '); builder.append(pkgName); builder.append(' '); + builder.append(persona); + builder.append(' '); builder.append(apkPath); builder.append(' '); builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!"); diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 9e94333..a76f854 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -79,6 +79,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; import android.content.pm.ManifestDigest; +import android.content.pm.VerificationParams; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VerifierInfo; import android.net.Uri; @@ -97,6 +98,7 @@ import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; +import android.os.SELinux; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; @@ -145,6 +147,7 @@ import java.util.Set; import libcore.io.ErrnoException; import libcore.io.IoUtils; import libcore.io.Libcore; +import libcore.io.StructStat; /** * Keep track of all those .apks everywhere. @@ -304,8 +307,6 @@ public class PackageManagerService extends IPackageManager.Stub { File mScanningPath; int mLastScanError; - final int[] mOutPermissions = new int[3]; - // ---------------------------------------------------------------- // Keys are String (package name), values are Package. This also serves @@ -2422,6 +2423,9 @@ public class PackageManagerService extends IPackageManager.Stub { final int M = prefs.size(); for (int i=0; i<M; i++) { final PreferredActivity pa = prefs.get(i); + if (pa.mUserId != userId) { + continue; + } if (pa.mPref.mMatch != match) { continue; } @@ -3789,14 +3793,18 @@ public class PackageManagerService extends IPackageManager.Stub { boolean uidError = false; if (dataPath.exists()) { - // XXX should really do this check for each user. - mOutPermissions[1] = 0; - FileUtils.getPermissions(dataPath.getPath(), mOutPermissions); + int currentUid = 0; + try { + StructStat stat = Libcore.os.stat(dataPath.getPath()); + currentUid = stat.st_uid; + } catch (ErrnoException e) { + Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e); + } // If we have mismatched owners for the data path, we have a problem. - if (mOutPermissions[1] != pkg.applicationInfo.uid) { + if (currentUid != pkg.applicationInfo.uid) { boolean recovered = false; - if (mOutPermissions[1] == 0) { + if (currentUid == 0) { // The directory somehow became owned by root. Wow. // This is probably because the system was stopped while // installd was in the middle of messing with its libs @@ -3825,7 +3833,7 @@ public class PackageManagerService extends IPackageManager.Stub { ? "System package " : "Third party package "; String msg = prefix + pkg.packageName + " has changed from uid: " - + mOutPermissions[1] + " to " + + currentUid + " to " + pkg.applicationInfo.uid + "; old data erased"; reportSettingsProblem(Log.WARN, msg); recovered = true; @@ -3857,11 +3865,11 @@ public class PackageManagerService extends IPackageManager.Stub { if (!recovered) { pkg.applicationInfo.dataDir = "/mismatched_uid/settings_" + pkg.applicationInfo.uid + "/fs_" - + mOutPermissions[1]; + + currentUid; pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir; String msg = "Package " + pkg.packageName + " has mismatched uid: " - + mOutPermissions[1] + " on disk, " + + currentUid + " on disk, " + pkg.applicationInfo.uid + " in settings"; // writer synchronized (mPackages) { @@ -5344,7 +5352,17 @@ public class PackageManagerService extends IPackageManager.Stub { public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); + VerificationParams verificationParams = new VerificationParams(verificationURI, null, null, + manifestDigest); + installPackageWithVerificationAndEncryption(packageURI, observer, flags, + installerPackageName, verificationParams, encryptionParams); + } + + public void installPackageWithVerificationAndEncryption(Uri packageURI, + IPackageInstallObserver observer, int flags, String installerPackageName, + VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, + null); final int uid = Binder.getCallingUid(); @@ -5361,7 +5379,7 @@ public class PackageManagerService extends IPackageManager.Stub { final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName, - verificationURI, manifestDigest, encryptionParams); + verificationParams, encryptionParams); mHandler.sendMessage(msg); } @@ -5725,7 +5743,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override void handleStartCopy() throws RemoteException { synchronized (mInstallLock) { - mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats); + mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats); } final boolean mounted; @@ -5791,8 +5809,7 @@ public class PackageManagerService extends IPackageManager.Stub { private final Uri mPackageURI; final String installerPackageName; - final Uri verificationURI; - final ManifestDigest manifestDigest; + final VerificationParams verificationParams; private InstallArgs mArgs; private int mRet; private File mTempPackage; @@ -5800,17 +5817,23 @@ public class PackageManagerService extends IPackageManager.Stub { InstallParams(Uri packageURI, IPackageInstallObserver observer, int flags, - String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest, + String installerPackageName, VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { this.mPackageURI = packageURI; this.flags = flags; this.observer = observer; this.installerPackageName = installerPackageName; - this.verificationURI = verificationURI; - this.manifestDigest = manifestDigest; + this.verificationParams = verificationParams; this.encryptionParams = encryptionParams; } + public ManifestDigest getManifestDigest() { + if (verificationParams == null) { + return null; + } + return verificationParams.getManifestDigest(); + } + private int installLocationPolicy(PackageInfoLite pkgLite, int flags) { String packageName = pkgLite.packageName; int installLocation = pkgLite.installLocation; @@ -5999,9 +6022,19 @@ public class PackageManagerService extends IPackageManager.Stub { verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, flags); - if (verificationURI != null) { - verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI, - verificationURI); + if (verificationParams != null) { + if (verificationParams.getVerificationURI() != null) { + verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI, + verificationParams.getVerificationURI()); + } + if (verificationParams.getOriginatingURI() != null) { + verification.putExtra(Intent.EXTRA_ORIGINATING_URI, + verificationParams.getOriginatingURI()); + } + if (verificationParams.getReferrer() != null) { + verification.putExtra(Intent.EXTRA_REFERRER, + verificationParams.getReferrer()); + } } final PackageVerificationState verificationState = new PackageVerificationState( @@ -6337,7 +6370,7 @@ public class PackageManagerService extends IPackageManager.Stub { FileInstallArgs(InstallParams params) { super(params.getPackageUri(), params.observer, params.flags, - params.installerPackageName, params.manifestDigest); + params.installerPackageName, params.getManifestDigest()); } FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) { @@ -6484,6 +6517,10 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } + if (!SELinux.restorecon(newCodeFile)) { + return false; + } + return true; } } @@ -6620,7 +6657,7 @@ public class PackageManagerService extends IPackageManager.Stub { AsecInstallArgs(InstallParams params) { super(params.getPackageUri(), params.observer, params.flags, - params.installerPackageName, params.manifestDigest); + params.installerPackageName, params.getManifestDigest()); } AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath, @@ -7465,6 +7502,9 @@ public class PackageManagerService extends IPackageManager.Stub { FileUtils.setPermissions( tmpPackageFile.getCanonicalPath(), FileUtils.S_IRUSR|FileUtils.S_IWUSR, -1, -1); + if (!SELinux.restorecon(tmpPackageFile)) { + return null; + } } catch (IOException e) { Slog.e(TAG, "Trouble getting the canoncical path for a temp file."); return null; @@ -7634,7 +7674,7 @@ public class PackageManagerService extends IPackageManager.Stub { mSettings.updateSharedUserPermsLPw(deletedPs, mGlobalGids); } } - clearPackagePreferredActivitiesLPw(deletedPs.name); + clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL); } } // can downgrade to reader @@ -7996,12 +8036,12 @@ public class PackageManagerService extends IPackageManager.Stub { return true; } - public void getPackageSizeInfo(final String packageName, + public void getPackageSizeInfo(final String packageName, int userHandle, final IPackageStatsObserver observer) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.GET_PACKAGE_SIZE, null); - PackageStats stats = new PackageStats(packageName); + PackageStats stats = new PackageStats(packageName, userHandle); /* * Queue up an async operation since the package measurement may take a @@ -8012,7 +8052,8 @@ public class PackageManagerService extends IPackageManager.Stub { mHandler.sendMessage(msg); } - private boolean getPackageSizeInfoLI(String packageName, PackageStats pStats) { + private boolean getPackageSizeInfoLI(String packageName, int userHandle, + PackageStats pStats) { if (packageName == null) { Slog.w(TAG, "Attempt to get size of null packageName."); return false; @@ -8049,7 +8090,7 @@ public class PackageManagerService extends IPackageManager.Stub { publicSrcDir = applicationInfo.publicSourceDir; } } - int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir, + int res = mInstaller.getSizeInfo(packageName, userHandle, p.mPath, publicSrcDir, asecPath, pStats); if (res < 0) { return false; @@ -8101,26 +8142,28 @@ public class PackageManagerService extends IPackageManager.Stub { } public void addPreferredActivity(IntentFilter filter, int match, - ComponentName[] set, ComponentName activity) { + ComponentName[] set, ComponentName activity, int userId) { // writer + int callingUid = Binder.getCallingUid(); + checkValidCaller(callingUid, userId); synchronized (mPackages) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) != PackageManager.PERMISSION_GRANTED) { - if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid()) + if (getUidTargetSdkVersionLockedLPr(callingUid) < Build.VERSION_CODES.FROYO) { Slog.w(TAG, "Ignoring addPreferredActivity() from uid " - + Binder.getCallingUid()); + + callingUid); return; } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); } - - Slog.i(TAG, "Adding preferred activity " + activity + ":"); + + Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); mSettings.mPreferredActivities.addFilter( - new PreferredActivity(filter, match, set, activity)); + new PreferredActivity(filter, match, set, activity, userId)); scheduleWriteSettingsLocked(); } } @@ -8156,13 +8199,15 @@ public class PackageManagerService extends IPackageManager.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); } - + + final int callingUserId = UserHandle.getCallingUserId(); ArrayList<PreferredActivity> removed = null; Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator(); String action = filter.getAction(0); String category = filter.getCategory(0); while (it.hasNext()) { PreferredActivity pa = it.next(); + if (pa.mUserId != callingUserId) continue; if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) { if (removed == null) { removed = new ArrayList<PreferredActivity>(); @@ -8178,7 +8223,7 @@ public class PackageManagerService extends IPackageManager.Stub { mSettings.mPreferredActivities.removeFilter(pa); } } - addPreferredActivity(filter, match, set, activity); + addPreferredActivity(filter, match, set, activity, callingUserId); } } @@ -8202,17 +8247,21 @@ public class PackageManagerService extends IPackageManager.Stub { } } - if (clearPackagePreferredActivitiesLPw(packageName)) { + if (clearPackagePreferredActivitiesLPw(packageName, UserHandle.getCallingUserId())) { scheduleWriteSettingsLocked(); } } } - boolean clearPackagePreferredActivitiesLPw(String packageName) { + /** This method takes a specific user id as well as UserHandle.USER_ALL. */ + boolean clearPackagePreferredActivitiesLPw(String packageName, int userId) { ArrayList<PreferredActivity> removed = null; Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator(); while (it.hasNext()) { PreferredActivity pa = it.next(); + if (userId != UserHandle.USER_ALL && pa.mUserId != userId) { + continue; + } if (pa.mPref.mComponent.getPackageName().equals(packageName)) { if (removed == null) { removed = new ArrayList<PreferredActivity>(); @@ -8234,11 +8283,15 @@ public class PackageManagerService extends IPackageManager.Stub { List<ComponentName> outActivities, String packageName) { int num = 0; + final int userId = UserHandle.getCallingUserId(); // reader synchronized (mPackages) { final Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator(); while (it.hasNext()) { final PreferredActivity pa = it.next(); + if (pa.mUserId != userId) { + continue; + } if (packageName == null || pa.mPref.mComponent.getPackageName().equals(packageName)) { if (outFilters != null) { diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java index b100eb1..5539e84 100644 --- a/services/java/com/android/server/pm/PreferredActivity.java +++ b/services/java/com/android/server/pm/PreferredActivity.java @@ -33,22 +33,38 @@ class PreferredActivity extends IntentFilter implements PreferredComponent.Callb private static final String TAG = "PreferredActivity"; private static final boolean DEBUG_FILTERS = false; + static final String ATTR_USER_ID = "userId"; final PreferredComponent mPref; + final int mUserId; PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) { + this(filter, match, set, activity, 0); + } + + PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity, + int userId) { super(filter); + mUserId = userId; mPref = new PreferredComponent(this, match, set, activity); } PreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException { + String userIdString = parser.getAttributeValue(null, ATTR_USER_ID); + if (userIdString != null && userIdString.length() > 0) { + mUserId = Integer.parseInt(userIdString); + } else { + // Old format with no userId specified - assume primary user + mUserId = 0; + } mPref = new PreferredComponent(this, parser); } public void writeToXml(XmlSerializer serializer) throws IOException { + serializer.attribute(null, ATTR_USER_ID, Integer.toString(mUserId)); mPref.writeToXml(serializer); serializer.startTag(null, "filter"); - super.writeToXml(serializer); + super.writeToXml(serializer); serializer.endTag(null, "filter"); } diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java index 725d67d..c292bbc 100644 --- a/services/java/com/android/server/pm/UserManagerService.java +++ b/services/java/com/android/server/pm/UserManagerService.java @@ -22,6 +22,7 @@ import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; +import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -35,6 +36,7 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; +import android.util.AtomicFile; import android.util.Log; import android.util.Slog; import android.util.SparseArray; @@ -55,22 +57,17 @@ import org.xmlpull.v1.XmlSerializer; public class UserManagerService extends IUserManager.Stub { - private static final String TAG = "UserManagerService"; + private static final String LOG_TAG = "UserManagerService"; private static final String TAG_NAME = "name"; - private static final String ATTR_FLAGS = "flags"; - private static final String ATTR_ICON_PATH = "icon"; - private static final String ATTR_ID = "id"; - + private static final String ATTR_SERIAL_NO = "serialNumber"; + private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber"; private static final String TAG_USERS = "users"; - private static final String TAG_USER = "user"; - private static final String LOG_TAG = "UserManager"; - private static final String USER_INFO_DIR = "system" + File.separator + "users"; private static final String USER_LIST_FILENAME = "userlist.xml"; private static final String USER_PHOTO_FILENAME = "photo.png"; @@ -81,6 +78,7 @@ public class UserManagerService extends IUserManager.Stub { private final File mUserListFile; private int[] mUserIds; private boolean mGuestEnabled; + private int mNextSerialNumber; private Installer mInstaller; private File mBaseUserPath; @@ -125,7 +123,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public List<UserInfo> getUsers() { - enforceSystemOrRoot("Only the system can query users"); + checkManageUsersPermission("query users"); synchronized (mUsers) { ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); for (int i = 0; i < mUsers.size(); i++) { @@ -137,7 +135,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public UserInfo getUserInfo(int userId) { - enforceSystemOrRoot("Only the system can query user"); + checkManageUsersPermission("query user"); synchronized (mUsers) { UserInfo info = mUsers.get(userId); return info; @@ -152,7 +150,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public void setUserName(int userId, String name) { - enforceSystemOrRoot("Only the system can rename users"); + checkManageUsersPermission("rename users"); synchronized (mUsers) { UserInfo info = mUsers.get(userId); if (name != null && !name.equals(info.name)) { @@ -164,7 +162,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public ParcelFileDescriptor setUserIcon(int userId) { - enforceSystemOrRoot("Only the system can update users"); + checkManageUsersPermission("update users"); synchronized (mUsers) { UserInfo info = mUsers.get(userId); if (info == null) return null; @@ -178,7 +176,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public void setGuestEnabled(boolean enable) { - enforceSystemOrRoot("Only the system can enable guest users"); + checkManageUsersPermission("enable guest users"); synchronized (mUsers) { if (mGuestEnabled != enable) { mGuestEnabled = enable; @@ -209,7 +207,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public void wipeUser(int userHandle) { - enforceSystemOrRoot("Only the system can wipe users"); + checkManageUsersPermission("wipe user"); // TODO: } @@ -220,10 +218,13 @@ public class UserManagerService extends IUserManager.Stub { * @param message used as message if SecurityException is thrown * @throws SecurityException if the caller is not system or root */ - private static final void enforceSystemOrRoot(String message) { + private static final void checkManageUsersPermission(String message) { final int uid = Binder.getCallingUid(); - if (uid != Process.SYSTEM_UID && uid != 0) { - throw new SecurityException(message); + if (uid != Process.SYSTEM_UID && uid != 0 + && ActivityManager.checkComponentPermission( + android.Manifest.permission.MANAGE_USERS, + uid, -1, true) != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need MANAGE_USERS permission to: " + message); } } @@ -243,7 +244,7 @@ public class UserManagerService extends IUserManager.Stub { info.iconPath = file.getAbsolutePath(); return fd; } catch (FileNotFoundException e) { - Slog.w(TAG, "Error setting photo for user ", e); + Slog.w(LOG_TAG, "Error setting photo for user ", e); } return null; } @@ -270,8 +271,9 @@ public class UserManagerService extends IUserManager.Stub { return; } FileInputStream fis = null; + AtomicFile userListFile = new AtomicFile(mUserListFile); try { - fis = new FileInputStream(mUserListFile); + fis = userListFile.openRead(); XmlPullParser parser = Xml.newPullParser(); parser.setInput(fis, null); int type; @@ -286,15 +288,26 @@ public class UserManagerService extends IUserManager.Stub { return; } + mNextSerialNumber = -1; + if (parser.getName().equals(TAG_USERS)) { + String lastSerialNumber = parser.getAttributeValue(null, ATTR_NEXT_SERIAL_NO); + if (lastSerialNumber != null) { + mNextSerialNumber = Integer.parseInt(lastSerialNumber); + } + } + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) { String id = parser.getAttributeValue(null, ATTR_ID); UserInfo user = readUser(Integer.parseInt(id)); if (user != null) { mUsers.put(user.id, user); - } - if (user.isGuest()) { - mGuestEnabled = true; + if (user.isGuest()) { + mGuestEnabled = true; + } + if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) { + mNextSerialNumber = user.id + 1; + } } } } @@ -333,9 +346,9 @@ public class UserManagerService extends IUserManager.Stub { */ private void writeUserLocked(UserInfo userInfo) { FileOutputStream fos = null; + AtomicFile userFile = new AtomicFile(new File(mUsersDir, userInfo.id + ".xml")); try { - final File mUserFile = new File(mUsersDir, userInfo.id + ".xml"); - fos = new FileOutputStream(mUserFile); + fos = userFile.startWrite(); final BufferedOutputStream bos = new BufferedOutputStream(fos); // XmlSerializer serializer = XmlUtils.serializerInstance(); @@ -346,6 +359,7 @@ public class UserManagerService extends IUserManager.Stub { serializer.startTag(null, TAG_USER); serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id)); + serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber)); serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags)); if (userInfo.iconPath != null) { serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath); @@ -358,30 +372,26 @@ public class UserManagerService extends IUserManager.Stub { serializer.endTag(null, TAG_USER); serializer.endDocument(); - } catch (IOException ioe) { + userFile.finishWrite(fos); + } catch (Exception ioe) { Slog.e(LOG_TAG, "Error writing user info " + userInfo.id + "\n" + ioe); - } finally { - if (fos != null) { - try { - fos.close(); - } catch (IOException ioe) { - } - } + userFile.failWrite(fos); } } /* * Writes the user list file in this format: * - * <users> + * <users nextSerialNumber="3"> * <user id="0"></user> * <user id="2"></user> * </users> */ private void writeUserListLocked() { FileOutputStream fos = null; + AtomicFile userListFile = new AtomicFile(mUserListFile); try { - fos = new FileOutputStream(mUserListFile); + fos = userListFile.startWrite(); final BufferedOutputStream bos = new BufferedOutputStream(fos); // XmlSerializer serializer = XmlUtils.serializerInstance(); @@ -391,6 +401,7 @@ public class UserManagerService extends IUserManager.Stub { serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); serializer.startTag(null, TAG_USERS); + serializer.attribute(null, ATTR_NEXT_SERIAL_NO, Integer.toString(mNextSerialNumber)); for (int i = 0; i < mUsers.size(); i++) { UserInfo user = mUsers.valueAt(i); @@ -402,27 +413,24 @@ public class UserManagerService extends IUserManager.Stub { serializer.endTag(null, TAG_USERS); serializer.endDocument(); - } catch (IOException ioe) { + userListFile.finishWrite(fos); + } catch (Exception e) { + userListFile.failWrite(fos); Slog.e(LOG_TAG, "Error writing user list"); - } finally { - if (fos != null) { - try { - fos.close(); - } catch (IOException ioe) { - } - } } } private UserInfo readUser(int id) { int flags = 0; + int serialNumber = id; String name = null; String iconPath = null; FileInputStream fis = null; try { - File userFile = new File(mUsersDir, Integer.toString(id) + ".xml"); - fis = new FileInputStream(userFile); + AtomicFile userFile = + new AtomicFile(new File(mUsersDir, Integer.toString(id) + ".xml")); + fis = userFile.openRead(); XmlPullParser parser = Xml.newPullParser(); parser.setInput(fis, null); int type; @@ -442,6 +450,10 @@ public class UserManagerService extends IUserManager.Stub { Slog.e(LOG_TAG, "User id does not match the file name"); return null; } + String serialNumberValue = parser.getAttributeValue(null, ATTR_SERIAL_NO); + if (serialNumberValue != null) { + serialNumber = Integer.parseInt(serialNumberValue); + } String flagString = parser.getAttributeValue(null, ATTR_FLAGS); flags = Integer.parseInt(flagString); iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH); @@ -458,6 +470,7 @@ public class UserManagerService extends IUserManager.Stub { } UserInfo userInfo = new UserInfo(id, name, iconPath, flags); + userInfo.serialNumber = serialNumber; return userInfo; } catch (IOException ioe) { @@ -475,7 +488,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public UserInfo createUser(String name, int flags) { - enforceSystemOrRoot("Only the system can create users"); + checkManageUsersPermission("Only the system can create users"); int userId = getNextAvailableId(); UserInfo userInfo = new UserInfo(userId, name, null, flags); File userPath = new File(mBaseUserPath, Integer.toString(userId)); @@ -483,6 +496,7 @@ public class UserManagerService extends IUserManager.Stub { return null; } synchronized (mUsers) { + userInfo.serialNumber = mNextSerialNumber++; mUsers.put(userId, userInfo); writeUserListLocked(); writeUserLocked(userInfo); @@ -490,8 +504,10 @@ public class UserManagerService extends IUserManager.Stub { } if (userInfo != null) { Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED); - addedIntent.putExtra(Intent.EXTRA_USERID, userInfo.id); - mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS); + addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id); + mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_USERS); + mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_BOOT_COMPLETED), + new UserHandle(userInfo.id)); } return userInfo; } @@ -502,9 +518,34 @@ public class UserManagerService extends IUserManager.Stub { * @param id the user's id */ public boolean removeUser(int userHandle) { - enforceSystemOrRoot("Only the system can remove users"); + checkManageUsersPermission("Only the system can remove users"); + boolean result; + synchronized (mUsers) { + result = removeUserLocked(userHandle); + } + // Let other services shutdown any activity + Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED); + addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle); + mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_USERS); + return result; + } + + @Override + public int getUserSerialNumber(int userHandle) { + synchronized (mUsers) { + if (!exists(userHandle)) return -1; + return getUserInfo(userHandle).serialNumber; + } + } + + @Override + public int getUserHandle(int userSerialNumber) { synchronized (mUsers) { - return removeUserLocked(userHandle); + for (int userId : mUserIds) { + if (getUserInfo(userId).serialNumber == userSerialNumber) return userId; + } + // Not found + return -1; } } @@ -519,17 +560,12 @@ public class UserManagerService extends IUserManager.Stub { // Remove this user from the list mUsers.remove(userHandle); // Remove user file - File userFile = new File(mUsersDir, userHandle + ".xml"); + AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml")); userFile.delete(); // Update the user list writeUserListLocked(); updateUserIdsLocked(); - // Let other services shutdown any activity - Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED); - addedIntent.putExtra(Intent.EXTRA_USERID, userHandle); - mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS); - removePackageFolders(userHandle); return true; } diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java index b0c79fa..cf12b20 100644 --- a/services/java/com/android/server/power/DisplayPowerController.java +++ b/services/java/com/android/server/power/DisplayPowerController.java @@ -27,6 +27,7 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.SystemSensorManager; +import android.hardware.display.DisplayManager; import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; @@ -35,6 +36,7 @@ import android.os.SystemClock; import android.util.Slog; import android.util.Spline; import android.util.TimeUtils; +import android.view.Display; import java.io.PrintWriter; import java.io.StringWriter; @@ -70,6 +72,12 @@ final class DisplayPowerController { private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false; private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false; + // If true, uses the electron beam on animation. + // We might want to turn this off if we cannot get a guarantee that the screen + // actually turns on and starts showing new content after the call to set the + // screen state returns. Playing the animation can also be somewhat slow. + private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false; + private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 300; private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 600; @@ -92,15 +100,15 @@ final class DisplayPowerController { // Brightness animation ramp rate in brightness units per second. private static final int BRIGHTNESS_RAMP_RATE_FAST = 200; - private static final int BRIGHTNESS_RAMP_RATE_SLOW = 50; + private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40; // Filter time constant in milliseconds for computing a moving // average of light samples. Different constants are used // to calculate the average light level when adapting to brighter or // dimmer environments. // This parameter only controls the filtering of light samples. - private static final long BRIGHTENING_LIGHT_TIME_CONSTANT = 500; - private static final long DIMMING_LIGHT_TIME_CONSTANT = 2000; + private static final long BRIGHTENING_LIGHT_TIME_CONSTANT = 600; + private static final long DIMMING_LIGHT_TIME_CONSTANT = 4000; // Stability requirements in milliseconds for accepting a new brightness // level. This is used for debouncing the light sensor. Different constants @@ -422,7 +430,8 @@ final class DisplayPowerController { private void initialize() { final Executor executor = AsyncTask.THREAD_POOL_EXECUTOR; - mPowerState = new DisplayPowerState(new ElectronBeam(), + Display display = DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); + mPowerState = new DisplayPowerState(new ElectronBeam(display), new PhotonicModulator(executor, mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT), mSuspendBlocker)); @@ -470,11 +479,13 @@ final class DisplayPowerController { if (mPowerRequest == null) { mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked); mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked; + mPendingWaitForNegativeProximityLocked = false; mPendingRequestChangedLocked = false; mustInitialize = true; } else if (mPendingRequestChangedLocked) { mPowerRequest.copyFrom(mPendingRequestLocked); mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked; + mPendingWaitForNegativeProximityLocked = false; mPendingRequestChangedLocked = false; mDisplayReadyLocked = false; } @@ -487,24 +498,33 @@ final class DisplayPowerController { initialize(); } - // Clear a request to wait for negative proximity if needed. - if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_OFF - || mProximity == PROXIMITY_NEGATIVE - || mProximitySensor == null) { - mWaitingForNegativeProximity = false; - } - - // Turn on the proximity sensor if needed. + // Apply the proximity sensor. if (mProximitySensor != null) { - setProximitySensorEnabled(mPowerRequest.useProximitySensor - || mWaitingForNegativeProximity); - if (mProximitySensorEnabled && mProximity == PROXIMITY_POSITIVE) { - mScreenOffBecauseOfProximity = true; - setScreenOn(false); - } else if (mScreenOffBecauseOfProximity) { + if (mPowerRequest.useProximitySensor + && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) { + setProximitySensorEnabled(true); + if (!mScreenOffBecauseOfProximity + && mProximity == PROXIMITY_POSITIVE) { + mScreenOffBecauseOfProximity = true; + setScreenOn(false); + } + } else if (mWaitingForNegativeProximity + && mScreenOffBecauseOfProximity + && mProximity == PROXIMITY_POSITIVE + && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) { + setProximitySensorEnabled(true); + } else { + setProximitySensorEnabled(false); + mWaitingForNegativeProximity = false; + } + if (mScreenOffBecauseOfProximity + && mProximity != PROXIMITY_POSITIVE) { mScreenOffBecauseOfProximity = false; + setScreenOn(true); sendOnProximityNegative(); } + } else { + mWaitingForNegativeProximity = false; } // Turn on the light sensor if needed. @@ -550,14 +570,19 @@ final class DisplayPowerController { // on animation immediately then the results are pretty ugly. if (!mElectronBeamOffAnimator.isStarted()) { setScreenOn(true); - if (!mElectronBeamOnAnimator.isStarted()) { - if (mPowerState.getElectronBeamLevel() == 1.0f) { - mPowerState.dismissElectronBeam(); - } else if (mPowerState.prepareElectronBeam(true)) { - mElectronBeamOnAnimator.start(); - } else { - mElectronBeamOnAnimator.end(); + if (USE_ELECTRON_BEAM_ON_ANIMATION) { + if (!mElectronBeamOnAnimator.isStarted()) { + if (mPowerState.getElectronBeamLevel() == 1.0f) { + mPowerState.dismissElectronBeam(); + } else if (mPowerState.prepareElectronBeam(true)) { + mElectronBeamOnAnimator.start(); + } else { + mElectronBeamOnAnimator.end(); + } } + } else { + mPowerState.setElectronBeamLevel(1.0f); + mPowerState.dismissElectronBeam(); } } } else { diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java index f618725..64a0462 100644 --- a/services/java/com/android/server/power/DisplayPowerState.java +++ b/services/java/com/android/server/power/DisplayPowerState.java @@ -242,8 +242,9 @@ final class DisplayPowerState { mElectronBeam.draw(mElectronBeamLevel); } - if ((mDirty & (DIRTY_BRIGHTNESS | DIRTY_SCREEN_ON)) != 0) { - mScreenBrightnessModulator.setBrightness(mScreenOn ? mScreenBrightness : 0); + if ((mDirty & (DIRTY_BRIGHTNESS | DIRTY_SCREEN_ON | DIRTY_ELECTRON_BEAM)) != 0) { + mScreenBrightnessModulator.setBrightness(mScreenOn ? + (int)(mScreenBrightness * mElectronBeamLevel) : 0); } if ((mDirty & DIRTY_SCREEN_ON) != 0 && mScreenOn) { diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java index 5472148..2d24249 100644 --- a/services/java/com/android/server/power/ElectronBeam.java +++ b/services/java/com/android/server/power/ElectronBeam.java @@ -33,7 +33,6 @@ import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; import android.view.SurfaceSession; -import android.view.WindowManagerImpl; import java.io.PrintWriter; import java.nio.ByteBuffer; @@ -68,6 +67,7 @@ final class ElectronBeam { private boolean mPrepared; private boolean mWarmUp; + private final Display mDisplay; private final DisplayInfo mDisplayInfo = new DisplayInfo(); private int mDisplayLayerStack; // layer stack associated with primary display private int mDisplayRotation; @@ -90,7 +90,8 @@ final class ElectronBeam { private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8); private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8); - public ElectronBeam() { + public ElectronBeam(Display display) { + mDisplay = display; } /** @@ -109,9 +110,8 @@ final class ElectronBeam { mWarmUp = warmUp; // Get the display size and adjust it for rotation. - Display display = WindowManagerImpl.getDefault().getDefaultDisplay(); - display.getDisplayInfo(mDisplayInfo); - mDisplayLayerStack = display.getDisplayId(); + mDisplay.getDisplayInfo(mDisplayInfo); + mDisplayLayerStack = mDisplay.getLayerStack(); mDisplayRotation = mDisplayInfo.rotation; if (mDisplayRotation == Surface.ROTATION_90 || mDisplayRotation == Surface.ROTATION_270) { diff --git a/services/java/com/android/server/usb/UsbDebuggingManager.java b/services/java/com/android/server/usb/UsbDebuggingManager.java new file mode 100644 index 0000000..a3b45c7 --- /dev/null +++ b/services/java/com/android/server/usb/UsbDebuggingManager.java @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions an + * limitations under the License. + */ + +package com.android.server.usb; + +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Environment; +import android.os.FileUtils; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +import android.os.SystemClock; +import android.util.Slog; +import android.util.Base64; + +import java.lang.Thread; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.security.MessageDigest; +import java.util.Arrays; + +public class UsbDebuggingManager implements Runnable { + private static final String TAG = "UsbDebuggingManager"; + private static final boolean DEBUG = false; + + private final String ADBD_SOCKET = "adbd"; + private final String ADB_DIRECTORY = "misc/adb"; + private final String ADB_KEYS_FILE = "adb_keys"; + private final int BUFFER_SIZE = 4096; + + private final Context mContext; + private final Thread mThread; + private final Handler mHandler; + private final HandlerThread mHandlerThread; + private boolean mAdbEnabled = false; + private String mFingerprints; + private LocalSocket mSocket = null; + private OutputStream mOutputStream = null; + + public UsbDebuggingManager(Context context) { + mThread = new Thread(this); + mHandlerThread = new HandlerThread("UsbDebuggingHandler"); + mHandlerThread.start(); + mHandler = new UsbDebuggingHandler(mHandlerThread.getLooper()); + mContext = context; + } + + private void listenToSocket() throws IOException { + try { + byte[] buffer = new byte[BUFFER_SIZE]; + LocalSocketAddress address = new LocalSocketAddress(ADBD_SOCKET, + LocalSocketAddress.Namespace.RESERVED); + InputStream inputStream = null; + + mSocket = new LocalSocket(); + mSocket.connect(address); + + mOutputStream = mSocket.getOutputStream(); + inputStream = mSocket.getInputStream(); + + while (true) { + int count = inputStream.read(buffer); + if (count < 0) { + Slog.e(TAG, "got " + count + " reading"); + break; + } + + if (buffer[0] == 'P' && buffer[1] == 'K') { + String key = new String(Arrays.copyOfRange(buffer, 2, count)); + Slog.d(TAG, "Received public key: " + key); + Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_CONFIRM); + msg.obj = key; + mHandler.sendMessage(msg); + } + else { + Slog.e(TAG, "Wrong message: " + (new String(Arrays.copyOfRange(buffer, 0, 2)))); + break; + } + } + } catch (IOException ex) { + Slog.e(TAG, "Communication error: ", ex); + throw ex; + } finally { + closeSocket(); + } + } + + @Override + public void run() { + while (mAdbEnabled) { + try { + listenToSocket(); + } catch (Exception e) { + /* Don't loop too fast if adbd dies, before init restarts it */ + SystemClock.sleep(1000); + } + } + } + + private void closeSocket() { + try { + mOutputStream.close(); + } catch (IOException e) { + Slog.e(TAG, "Failed closing output stream: " + e); + } + + try { + mSocket.close(); + } catch (IOException ex) { + Slog.e(TAG, "Failed closing socket: " + ex); + } + } + + private void sendResponse(String msg) { + if (mOutputStream != null) { + try { + mOutputStream.write(msg.getBytes()); + } + catch (IOException ex) { + Slog.e(TAG, "Failed to write response:", ex); + } + } + } + + class UsbDebuggingHandler extends Handler { + private static final int MESSAGE_ADB_ENABLED = 1; + private static final int MESSAGE_ADB_DISABLED = 2; + private static final int MESSAGE_ADB_ALLOW = 3; + private static final int MESSAGE_ADB_DENY = 4; + private static final int MESSAGE_ADB_CONFIRM = 5; + + public UsbDebuggingHandler(Looper looper) { + super(looper); + } + + public void handleMessage(Message msg) { + switch (msg.what) { + case MESSAGE_ADB_ENABLED: + if (mAdbEnabled) + break; + + mAdbEnabled = true; + + mThread.start(); + + break; + + case MESSAGE_ADB_DISABLED: + if (!mAdbEnabled) + break; + + mAdbEnabled = false; + closeSocket(); + + try { + mThread.join(); + } catch (Exception ex) { + } + + mOutputStream = null; + mSocket = null; + + case MESSAGE_ADB_ALLOW: { + String key = (String)msg.obj; + String fingerprints = getFingerprints(key); + + if (!fingerprints.equals(mFingerprints)) { + Slog.e(TAG, "Fingerprints do not match. Got " + + fingerprints + ", expected " + mFingerprints); + break; + } + + if (msg.arg1 == 1) { + writeKey(key); + } + + sendResponse("OK"); + break; + } + + case MESSAGE_ADB_DENY: + sendResponse("NO"); + break; + + case MESSAGE_ADB_CONFIRM: { + String key = (String)msg.obj; + mFingerprints = getFingerprints(key); + showConfirmationDialog(key, mFingerprints); + break; + } + } + } + } + + private String getFingerprints(String key) { + String hex = "0123456789ABCDEF"; + StringBuilder sb = new StringBuilder(); + MessageDigest digester; + + try { + digester = MessageDigest.getInstance("MD5"); + } catch (Exception ex) { + Slog.e(TAG, "Error getting digester: " + ex); + return ""; + } + + byte[] base64_data = key.split("\\s+")[0].getBytes(); + byte[] digest = digester.digest(Base64.decode(base64_data, Base64.DEFAULT)); + + for (int i = 0; i < digest.length; i++) { + sb.append(hex.charAt((digest[i] >> 4) & 0xf)); + sb.append(hex.charAt(digest[i] & 0xf)); + if (i < digest.length - 1) + sb.append(":"); + } + return sb.toString(); + } + + private void showConfirmationDialog(String key, String fingerprints) { + Intent dialogIntent = new Intent(); + + dialogIntent.setClassName("com.android.systemui", + "com.android.systemui.usb.UsbDebuggingActivity"); + dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + dialogIntent.putExtra("key", key); + dialogIntent.putExtra("fingerprints", fingerprints); + try { + mContext.startActivity(dialogIntent); + } catch (ActivityNotFoundException e) { + Slog.e(TAG, "unable to start UsbDebuggingActivity"); + } + } + + private void writeKey(String key) { + File dataDir = Environment.getDataDirectory(); + File adbDir = new File(dataDir, ADB_DIRECTORY); + + if (!adbDir.exists()) { + Slog.e(TAG, "ADB data directory does not exist"); + return; + } + + try { + File keyFile = new File(adbDir, ADB_KEYS_FILE); + + if (!keyFile.exists()) { + keyFile.createNewFile(); + FileUtils.setPermissions(keyFile.toString(), + FileUtils.S_IRUSR | FileUtils.S_IWUSR | + FileUtils.S_IRGRP, -1, -1); + } + + FileOutputStream fo = new FileOutputStream(keyFile, true); + fo.write(key.getBytes()); + fo.write('\n'); + fo.close(); + } + catch (IOException ex) { + Slog.e(TAG, "Error writing key:" + ex); + } + } + + + public void setAdbEnabled(boolean enabled) { + mHandler.sendEmptyMessage(enabled ? UsbDebuggingHandler.MESSAGE_ADB_ENABLED + : UsbDebuggingHandler.MESSAGE_ADB_DISABLED); + } + + public void allowUsbDebugging(boolean alwaysAllow, String publicKey) { + Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_ALLOW); + msg.arg1 = alwaysAllow ? 1 : 0; + msg.obj = publicKey; + mHandler.sendMessage(msg); + } + + public void denyUsbDebugging() { + mHandler.sendEmptyMessage(UsbDebuggingHandler.MESSAGE_ADB_DENY); + } + + + public void dump(FileDescriptor fd, PrintWriter pw) { + pw.println(" USB Debugging State:"); + pw.println(" Connected to adbd: " + (mOutputStream != null)); + pw.println(" Last key received: " + mFingerprints); + pw.println(" User keys:"); + try { + pw.println(FileUtils.readTextFile(new File("/data/misc/adb/adb_keys"), 0, null)); + } catch (IOException e) { + pw.println("IOException: " + e); + } + pw.println(" System keys:"); + try { + pw.println(FileUtils.readTextFile(new File("/adb_keys"), 0, null)); + } catch (IOException e) { + pw.println("IOException: " + e); + } + } +} diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java index a115345..ddecf14 100644 --- a/services/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/java/com/android/server/usb/UsbDeviceManager.java @@ -114,6 +114,7 @@ public class UsbDeviceManager { private boolean mAudioSourceEnabled; private Map<String, List<Pair<String, String>>> mOemModeMap; private String[] mAccessoryStrings; + private UsbDebuggingManager mDebuggingManager; private class AdbSettingsObserver extends ContentObserver { public AdbSettingsObserver() { @@ -166,6 +167,10 @@ public class UsbDeviceManager { if (DEBUG) Slog.d(TAG, "accessory attached at boot"); startAccessoryMode(); } + + if ("1".equals(SystemProperties.get("ro.adb.secure"))) { + mDebuggingManager = new UsbDebuggingManager(context); + } } public void systemReady() { @@ -425,6 +430,9 @@ public class UsbDeviceManager { setEnabledFunctions(mDefaultFunctions, true); updateAdbNotification(); } + if (mDebuggingManager != null) { + mDebuggingManager.setAdbEnabled(mAdbEnabled); + } } private void setEnabledFunctions(String functions, boolean makeDefault) { @@ -601,6 +609,9 @@ public class UsbDeviceManager { if (mCurrentAccessory != null) { mSettingsManager.accessoryAttached(mCurrentAccessory); } + if (mDebuggingManager != null) { + mDebuggingManager.setAdbEnabled(mAdbEnabled); + } break; } } @@ -802,10 +813,25 @@ public class UsbDeviceManager { return usbFunctions; } + public void allowUsbDebugging(boolean alwaysAllow, String publicKey) { + if (mDebuggingManager != null) { + mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey); + } + } + + public void denyUsbDebugging() { + if (mDebuggingManager != null) { + mDebuggingManager.denyUsbDebugging(); + } + } + public void dump(FileDescriptor fd, PrintWriter pw) { if (mHandler != null) { mHandler.dump(fd, pw); } + if (mDebuggingManager != null) { + mDebuggingManager.dump(fd, pw); + } } private native String[] nativeGetAccessoryStrings(); diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java index 0205ef8..bebcd56 100644 --- a/services/java/com/android/server/usb/UsbService.java +++ b/services/java/com/android/server/usb/UsbService.java @@ -164,6 +164,16 @@ public class UsbService extends IUsbManager.Stub { } } + public void allowUsbDebugging(boolean alwaysAllow, String publicKey) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); + mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey); + } + + public void denyUsbDebugging() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); + mDeviceManager.denyUsbDebugging(); + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java index 691e2aa..c25f010 100644 --- a/services/java/com/android/server/wm/AppWindowAnimator.java +++ b/services/java/com/android/server/wm/AppWindowAnimator.java @@ -47,7 +47,7 @@ public class AppWindowAnimator { final Transformation thumbnailTransformation = new Transformation(); /** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */ - ArrayList<WindowStateAnimator> mAllAppWinAnimators; + ArrayList<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<WindowStateAnimator>(); static final Animation sDummyAnimation = new DummyAnimation(); diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java index 142c60d..7d85d89 100644 --- a/services/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java @@ -42,6 +42,7 @@ class ScreenRotationAnimation { static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200; final Context mContext; + final Display mDisplay; Surface mSurface; BlackFrame mCustomBlackFrame; BlackFrame mExitingBlackFrame; @@ -186,9 +187,10 @@ class ScreenRotationAnimation { pw.println(); } - public ScreenRotationAnimation(Context context, SurfaceSession session, + public ScreenRotationAnimation(Context context, Display display, SurfaceSession session, boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) { mContext = context; + mDisplay = display; // Screenshot does NOT include rotation! if (originalRotation == Surface.ROTATION_90 @@ -213,13 +215,13 @@ class ScreenRotationAnimation { try { try { if (WindowManagerService.DEBUG_SURFACE_TRACE) { - mSurface = new SurfaceTrace(session, 0, "FreezeSurface", Display.DEFAULT_DISPLAY, - mWidth, mHeight, - PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN); + mSurface = new SurfaceTrace(session, 0, "FreezeSurface", + mDisplay.getLayerStack(), mWidth, mHeight, + PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN); } else { - mSurface = new Surface(session, 0, "FreezeSurface", Display.DEFAULT_DISPLAY, - mWidth, mHeight, - PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN); + mSurface = new Surface(session, 0, "FreezeSurface", + mDisplay.getLayerStack(), mWidth, mHeight, + PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN); } if (!mSurface.isValid()) { // Screenshot failed, punt. diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/java/com/android/server/wm/StrictModeFlash.java index 4b072c3..775aa0f 100644 --- a/services/java/com/android/server/wm/StrictModeFlash.java +++ b/services/java/com/android/server/wm/StrictModeFlash.java @@ -22,8 +22,6 @@ import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; -import android.util.DisplayMetrics; -import android.util.Slog; import android.view.Display; import android.view.Surface; import android.view.SurfaceSession; @@ -39,7 +37,7 @@ class StrictModeFlash { public StrictModeFlash(Display display, SurfaceSession session) { try { - mSurface = new Surface(session, 0, "StrictModeFlash", Display.DEFAULT_DISPLAY, + mSurface = new Surface(session, 0, "StrictModeFlash", display.getLayerStack(), 1, 1, PixelFormat.TRANSLUCENT, 0); } catch (Surface.OutOfResourcesException e) { return; diff --git a/services/java/com/android/server/wm/Watermark.java b/services/java/com/android/server/wm/Watermark.java index 12076d8..5901cc8 100644 --- a/services/java/com/android/server/wm/Watermark.java +++ b/services/java/com/android/server/wm/Watermark.java @@ -35,6 +35,7 @@ import android.view.Surface.OutOfResourcesException; * Displays a watermark on top of the window manager's windows. */ class Watermark { + final Display mDisplay; final String[] mTokens; final String mText; final Paint mTextPaint; @@ -50,7 +51,7 @@ class Watermark { int mLastDH; boolean mDrawNeeded; - Watermark(DisplayMetrics dm, SurfaceSession session, String[] tokens) { + Watermark(Display display, DisplayMetrics dm, SurfaceSession session, String[] tokens) { if (false) { Log.i(WindowManagerService.TAG, "*********************** WATERMARK"); for (int i=0; i<tokens.length; i++) { @@ -58,6 +59,7 @@ class Watermark { } } + mDisplay = display; mTokens = tokens; StringBuilder builder = new StringBuilder(32); @@ -112,7 +114,7 @@ class Watermark { try { mSurface = new Surface(session, 0, - "WatermarkSurface", Display.DEFAULT_DISPLAY, + "WatermarkSurface", mDisplay.getLayerStack(), 1, 1, PixelFormat.TRANSLUCENT, 0); mSurface.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER*100); mSurface.setPosition(0, 0); diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java index 0dbe692..1defa49 100644 --- a/services/java/com/android/server/wm/WindowAnimator.java +++ b/services/java/com/android/server/wm/WindowAnimator.java @@ -190,8 +190,8 @@ public class WindowAnimator { for (int i = 0; i < N; i++) { final AppWindowAnimParams params = layoutToAnim.mAppWindowAnimParams.get(i); AppWindowAnimator appAnimator = params.mAppAnimator; - appAnimator.mAllAppWinAnimators = - new ArrayList<WindowStateAnimator>(params.mWinAnimators); + appAnimator.mAllAppWinAnimators.clear(); + appAnimator.mAllAppWinAnimators.addAll(params.mWinAnimators); mAppAnimators.add(appAnimator); } } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 27c298c..fd90082 100755 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -127,7 +127,7 @@ import android.view.SurfaceSession; import android.view.View; import android.view.ViewTreeObserver; import android.view.WindowManager; -import android.view.WindowManagerImpl; +import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicy; import android.view.WindowManager.LayoutParams; import android.view.WindowManagerPolicy.FakeWindow; @@ -318,15 +318,25 @@ public class WindowManagerService extends IWindowManager.Stub final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - mPolicy.enableKeyguard(true); - synchronized(mKeyguardTokenWatcher) { - // lazily evaluate this next time we're asked to disable keyguard - mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN; - mKeyguardDisabled = false; + final String action = intent.getAction(); + if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) { + mPolicy.enableKeyguard(true); + synchronized(mKeyguardTokenWatcher) { + // lazily evaluate this next time we're asked to disable keyguard + mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN; + mKeyguardDisabled = false; + } + } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { + final int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); + Slog.v(TAG, "Switching user from " + mCurrentUserId + " to " + newUserId); + mCurrentUserId = newUserId; } } }; + // Current user when multi-user is enabled. Don't show windows of non-current user. + int mCurrentUserId; + final Context mContext; final boolean mHaveInputMethods; @@ -512,7 +522,8 @@ public class WindowManagerService extends IWindowManager.Stub int mNextAppTransitionType = ActivityOptions.ANIM_NONE; String mNextAppTransitionPackage; Bitmap mNextAppTransitionThumbnail; - boolean mNextAppTransitionDelayed; + // Used for thumbnail transitions. True if we're scaling up, false if scaling down + boolean mNextAppTransitionScaleUp; IRemoteCallback mNextAppTransitionCallback; int mNextAppTransitionEnter; int mNextAppTransitionExit; @@ -907,6 +918,8 @@ public class WindowManagerService extends IWindowManager.Stub // Track changes to DevicePolicyManager state so we can enable/disable keyguard. IntentFilter filter = new IntentFilter(); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); + // Track user switching. + filter.addAction(Intent.ACTION_USER_SWITCHED); mContext.registerReceiver(mBroadcastReceiver, filter); mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK @@ -2140,7 +2153,7 @@ public class WindowManagerService extends IWindowManager.Stub WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, InputChannel outInputChannel) { int res = mPolicy.checkAddPermission(attrs); - if (res != WindowManagerImpl.ADD_OKAY) { + if (res != WindowManagerGlobal.ADD_OKAY) { return res; } @@ -2156,7 +2169,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mWindowMap.containsKey(client.asBinder())) { Slog.w(TAG, "Window " + client + " is already added"); - return WindowManagerImpl.ADD_DUPLICATE_ADD; + return WindowManagerGlobal.ADD_DUPLICATE_ADD; } if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) { @@ -2164,13 +2177,13 @@ public class WindowManagerService extends IWindowManager.Stub if (attachedWindow == null) { Slog.w(TAG, "Attempted to add window with token that is not a window: " + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN; + return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN; } if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) { Slog.w(TAG, "Attempted to add window with token that is a sub-window: " + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN; + return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN; } } @@ -2181,22 +2194,22 @@ public class WindowManagerService extends IWindowManager.Stub && attrs.type <= LAST_APPLICATION_WINDOW) { Slog.w(TAG, "Attempted to add application window with unknown token " + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_APP_TOKEN; + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } if (attrs.type == TYPE_INPUT_METHOD) { Slog.w(TAG, "Attempted to add input method window with unknown token " + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_APP_TOKEN; + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } if (attrs.type == TYPE_WALLPAPER) { Slog.w(TAG, "Attempted to add wallpaper window with unknown token " + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_APP_TOKEN; + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } if (attrs.type == TYPE_DREAM) { Slog.w(TAG, "Attempted to add Dream window with unknown token " + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_APP_TOKEN; + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } token = new WindowToken(this, attrs.token, -1, false); addToken = true; @@ -2206,35 +2219,35 @@ public class WindowManagerService extends IWindowManager.Stub if (atoken == null) { Slog.w(TAG, "Attempted to add window with non-application token " + token + ". Aborting."); - return WindowManagerImpl.ADD_NOT_APP_TOKEN; + return WindowManagerGlobal.ADD_NOT_APP_TOKEN; } else if (atoken.removed) { Slog.w(TAG, "Attempted to add window with exiting application token " + token + ". Aborting."); - return WindowManagerImpl.ADD_APP_EXITING; + return WindowManagerGlobal.ADD_APP_EXITING; } if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) { // No need for this guy! if (localLOGV) Slog.v( TAG, "**** NO NEED TO START: " + attrs.getTitle()); - return WindowManagerImpl.ADD_STARTING_NOT_NEEDED; + return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED; } } else if (attrs.type == TYPE_INPUT_METHOD) { if (token.windowType != TYPE_INPUT_METHOD) { Slog.w(TAG, "Attempted to add input method window with bad token " + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_APP_TOKEN; + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } else if (attrs.type == TYPE_WALLPAPER) { if (token.windowType != TYPE_WALLPAPER) { Slog.w(TAG, "Attempted to add wallpaper window with bad token " + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_APP_TOKEN; + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } else if (attrs.type == TYPE_DREAM) { if (token.windowType != TYPE_DREAM) { Slog.w(TAG, "Attempted to add Dream window with bad token " + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_APP_TOKEN; + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } @@ -2246,13 +2259,13 @@ public class WindowManagerService extends IWindowManager.Stub // continue. Slog.w(TAG, "Adding window client " + client.asBinder() + " that is dead, aborting."); - return WindowManagerImpl.ADD_APP_EXITING; + return WindowManagerGlobal.ADD_APP_EXITING; } mPolicy.adjustWindowParamsLw(win.mAttrs); res = mPolicy.prepareAddWindowLw(win, attrs); - if (res != WindowManagerImpl.ADD_OKAY) { + if (res != WindowManagerGlobal.ADD_OKAY) { return res; } @@ -2268,7 +2281,7 @@ public class WindowManagerService extends IWindowManager.Stub // From now on, no exceptions or errors allowed! - res = WindowManagerImpl.ADD_OKAY; + res = WindowManagerGlobal.ADD_OKAY; origId = Binder.clearCallingIdentity(); @@ -2312,10 +2325,10 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.getContentInsetHintLw(attrs, outContentInsets); if (mInTouchMode) { - res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE; + res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE; } if (win.mAppToken == null || !win.mAppToken.clientHidden) { - res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE; + res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE; } mInputMonitor.setUpdateInputWindowsNeededLw(); @@ -2747,7 +2760,7 @@ public class WindowManagerService extends IWindowManager.Stub } winAnimator.mSurfaceDestroyDeferred = - (flags&WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY) != 0; + (flags&WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY) != 0; int attrChanges = 0; int flagChanges = 0; @@ -2966,7 +2979,7 @@ public class WindowManagerService extends IWindowManager.Stub } mLayoutNeeded = true; - win.mGivenInsetsPending = (flags&WindowManagerImpl.RELAYOUT_INSETS_PENDING) != 0; + win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0; if (assignLayers) { assignLayersLocked(win.getWindowList()); } @@ -3009,10 +3022,10 @@ public class WindowManagerService extends IWindowManager.Stub Binder.restoreCallingIdentity(origId); - return (inTouchMode ? WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE : 0) - | (toBeDisplayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0) - | (surfaceChanged ? WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED : 0) - | (animating ? WindowManagerImpl.RELAYOUT_RES_ANIMATING : 0); + return (inTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0) + | (toBeDisplayed ? WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME : 0) + | (surfaceChanged ? WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED : 0) + | (animating ? WindowManagerGlobal.RELAYOUT_RES_ANIMATING : 0); } public void performDeferredDestroyWindow(Session session, IWindow client) { @@ -3224,7 +3237,7 @@ public class WindowManagerService extends IWindowManager.Stub } private Animation createThumbnailAnimationLocked(int transit, - boolean enter, boolean thumb, boolean delayed) { + boolean enter, boolean thumb, boolean scaleUp) { Animation a; final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; @@ -3234,7 +3247,6 @@ public class WindowManagerService extends IWindowManager.Stub // it is the standard duration for that. Otherwise we use the longer // task transition duration. int duration; - int delayDuration = delayed ? 270 : 0; switch (transit) { case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: @@ -3242,7 +3254,7 @@ public class WindowManagerService extends IWindowManager.Stub com.android.internal.R.integer.config_shortAnimTime); break; default: - duration = delayed ? 250 : 300; + duration = 250; break; } // TOOD(multidisplay): For now assume all app animation is on the main screen. @@ -3250,48 +3262,86 @@ public class WindowManagerService extends IWindowManager.Stub if (thumb) { // Animation for zooming thumbnail from its initial size to // filling the screen. - float scaleW = displayInfo.appWidth/thumbWidth; - float scaleH = displayInfo.appHeight/thumbHeight; - - Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, - computePivot(mNextAppTransitionStartX, 1/scaleW), - computePivot(mNextAppTransitionStartY, 1/scaleH)); - AnimationSet set = new AnimationSet(true); - Animation alpha = new AlphaAnimation(1, 0); - scale.setDuration(duration); - scale.setInterpolator( - new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR)); - set.addAnimation(scale); - alpha.setDuration(duration); - set.addAnimation(alpha); - set.setFillBefore(true); - if (delayDuration > 0) { - set.setStartOffset(delayDuration); + if (scaleUp) { + float scaleW = displayInfo.appWidth / thumbWidth; + float scaleH = displayInfo.appHeight / thumbHeight; + + Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, + computePivot(mNextAppTransitionStartX, 1 / scaleW), + computePivot(mNextAppTransitionStartY, 1 / scaleH)); + AnimationSet set = new AnimationSet(true); + Animation alpha = new AlphaAnimation(1, 0); + scale.setDuration(duration); + scale.setInterpolator( + new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR)); + set.addAnimation(scale); + alpha.setDuration(duration); + set.addAnimation(alpha); + set.setFillBefore(true); + a = set; + } else { + float scaleW = displayInfo.appWidth / thumbWidth; + float scaleH = displayInfo.appHeight / thumbHeight; + + Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1, + computePivot(mNextAppTransitionStartX, 1 / scaleW), + computePivot(mNextAppTransitionStartY, 1 / scaleH)); + AnimationSet set = new AnimationSet(true); + Animation alpha = new AlphaAnimation(1, 1); + scale.setDuration(duration); + scale.setInterpolator( + new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR)); + set.addAnimation(scale); + alpha.setDuration(duration); + set.addAnimation(alpha); + set.setFillBefore(true); + + a = set; } - a = set; } else if (enter) { // Entering app zooms out from the center of the thumbnail. - float scaleW = thumbWidth / displayInfo.appWidth; - float scaleH = thumbHeight / displayInfo.appHeight; - Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1, - computePivot(mNextAppTransitionStartX, scaleW), - computePivot(mNextAppTransitionStartY, scaleH)); - scale.setDuration(duration); - scale.setInterpolator( - new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR)); - scale.setFillBefore(true); - if (delayDuration > 0) { - scale.setStartOffset(delayDuration); + if (scaleUp) { + float scaleW = thumbWidth / displayInfo.appWidth; + float scaleH = thumbHeight / displayInfo.appHeight; + Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1, + computePivot(mNextAppTransitionStartX, scaleW), + computePivot(mNextAppTransitionStartY, scaleH)); + scale.setDuration(duration); + scale.setInterpolator( + new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR)); + scale.setFillBefore(true); + a = scale; + } else { + // noop animation + a = new AlphaAnimation(1, 1); + a.setDuration(duration); } - a = scale; } else { - if (delayed) { - a = new AlphaAnimation(1, 0); - a.setStartOffset(0); - a.setDuration(delayDuration - 120); - a.setBackgroundColor(0xFF000000); + // Exiting app + if (scaleUp) { + // noop animation + a = new AlphaAnimation(1, 1); + a.setDuration(duration); } else { - a = createExitAnimationLocked(transit, duration); + float scaleW = thumbWidth / displayInfo.appWidth; + float scaleH = thumbHeight / displayInfo.appHeight; + Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, + computePivot(mNextAppTransitionStartX, scaleW), + computePivot(mNextAppTransitionStartY, scaleH)); + scale.setDuration(duration); + scale.setInterpolator( + new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR)); + scale.setFillBefore(true); + AnimationSet set = new AnimationSet(true); + Animation alpha = new AlphaAnimation(1, 0); + set.addAnimation(scale); + alpha.setDuration(duration); + alpha.setInterpolator(new DecelerateInterpolator( + THUMBNAIL_ANIMATION_DECELERATE_FACTOR)); + set.addAnimation(alpha); + set.setFillBefore(true); + set.setZAdjustment(Animation.ZORDER_TOP); + a = set; } } a.setFillAfter(true); @@ -3326,14 +3376,14 @@ public class WindowManagerService extends IWindowManager.Stub "applyAnimation: wtoken=" + wtoken + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP" + " transit=" + transit + " Callers " + Debug.getCallers(3)); - } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL || - mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_DELAYED) { - boolean delayed = (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_DELAYED); - a = createThumbnailAnimationLocked(transit, enter, false, delayed); + } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP || + mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN) { + boolean scaleUp = (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP); + a = createThumbnailAnimationLocked(transit, enter, false, scaleUp); initialized = true; if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { - String animName = delayed ? "ANIM_THUMBNAIL_DELAYED" : "ANIM_THUMBNAIL"; + String animName = scaleUp ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN"; Slog.v(TAG, "applyAnimation: wtoken=" + wtoken + " anim=" + a + " nextAppTransition=" + animName + " transit=" + transit + " Callers " + Debug.getCallers(3)); @@ -4008,14 +4058,14 @@ public class WindowManagerService extends IWindowManager.Stub } public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, - int startY, IRemoteCallback startedCallback, boolean delayed) { + int startY, IRemoteCallback startedCallback, boolean scaleUp) { synchronized(mWindowMap) { if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { - mNextAppTransitionType = delayed - ? ActivityOptions.ANIM_THUMBNAIL_DELAYED : ActivityOptions.ANIM_THUMBNAIL; + mNextAppTransitionType = scaleUp + ? ActivityOptions.ANIM_THUMBNAIL_SCALE_UP : ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN; mNextAppTransitionPackage = null; mNextAppTransitionThumbnail = srcThumb; - mNextAppTransitionDelayed = delayed; + mNextAppTransitionScaleUp = scaleUp; mNextAppTransitionStartX = startX; mNextAppTransitionStartY = startY; scheduleAnimationCallback(mNextAppTransitionCallback); @@ -5219,14 +5269,14 @@ public class WindowManagerService extends IWindowManager.Stub // Called by window manager policy. Not exposed externally. @Override - public void shutdown() { - ShutdownThread.shutdown(mContext, true); + public void shutdown(boolean confirm) { + ShutdownThread.shutdown(mContext, confirm); } // Called by window manager policy. Not exposed externally. @Override - public void rebootSafeMode() { - ShutdownThread.rebootSafeMode(mContext, true); + public void rebootSafeMode(boolean confirm) { + ShutdownThread.rebootSafeMode(mContext, confirm); } public void setInputFilter(IInputFilter filter) { @@ -8329,15 +8379,23 @@ public class WindowManagerService extends IWindowManager.Stub NN = mOpeningApps.size(); for (i=0; i<NN; i++) { AppWindowToken wtoken = mOpeningApps.get(i); + final AppWindowAnimator appAnimator = wtoken.mAppAnimator; if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken); - wtoken.mAppAnimator.clearThumbnail(); + appAnimator.clearThumbnail(); wtoken.reportedVisible = false; wtoken.inPendingTransaction = false; - wtoken.mAppAnimator.animation = null; + appAnimator.animation = null; setTokenVisibilityLocked(wtoken, animLp, true, transit, false); wtoken.updateReportedVisibilityLocked(); wtoken.waitingToShow = false; - mAnimator.mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked(); + + appAnimator.mAllAppWinAnimators.clear(); + final int N = wtoken.allAppWindows.size(); + for (int j = 0; j < N; j++) { + appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator); + } + mAnimator.mAnimating |= appAnimator.showAllWindowsLocked(); + if (animLp != null) { int layer = -1; for (int j=0; j<wtoken.windows.size(); j++) { @@ -8392,7 +8450,7 @@ public class WindowManagerService extends IWindowManager.Stub drawSurface.release(); topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer; Animation anim = createThumbnailAnimationLocked( - transit, true, true, mNextAppTransitionDelayed); + transit, true, true, mNextAppTransitionScaleUp); topOpeningApp.mAppAnimator.thumbnailAnimation = anim; anim.restrictDuration(MAX_ANIMATION_DURATION); anim.scaleCurrentDuration(mTransitionAnimationScale); @@ -9591,7 +9649,7 @@ public class WindowManagerService extends IWindowManager.Stub // TODO(multidisplay): rotation on main screen only. DisplayInfo displayInfo = getDefaultDisplayContent().getDisplayInfo(); - mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext, + mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext, mDisplay, mFxSession, inTransaction, displayInfo.logicalWidth, displayInfo.logicalHeight, mDisplay.getRotation()); } @@ -9704,7 +9762,7 @@ public class WindowManagerService extends IWindowManager.Stub if (line != null) { String[] toks = line.split("%"); if (toks != null && toks.length > 0) { - mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks); + mWatermark = new Watermark(mDisplay, mRealDisplayMetrics, mFxSession, toks); } } } catch (FileNotFoundException e) { @@ -10163,15 +10221,15 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mNextAppTransitionStartHeight="); pw.println(mNextAppTransitionStartHeight); break; - case ActivityOptions.ANIM_THUMBNAIL: - case ActivityOptions.ANIM_THUMBNAIL_DELAYED: + case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP: + case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN: pw.print(" mNextAppTransitionThumbnail="); pw.print(mNextAppTransitionThumbnail); pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX); pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY); - pw.print(" mNextAppTransitionDelayed="); pw.println(mNextAppTransitionDelayed); + pw.print(" mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp); break; } if (mNextAppTransitionCallback != null) { diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 43ff398..a52e1d7 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -22,6 +22,9 @@ import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import com.android.server.input.InputWindowHandle; @@ -33,7 +36,9 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.os.IBinder; +import android.os.Process; import android.os.RemoteException; +import android.os.UserHandle; import android.util.Slog; import android.view.DisplayInfo; import android.view.Gravity; @@ -257,6 +262,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { DisplayContent mDisplayContent; + // UserId and appId of the owner. Don't display windows of non-current user. + final int mOwnerUid; + WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState attachedWindow, int seq, WindowManager.LayoutParams a, int viewVisibility, final DisplayContent displayContent) { @@ -264,6 +272,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mSession = s; mClient = c; mToken = token; + mOwnerUid = s.mUid; mAttrs.copyFrom(a); mViewVisibility = viewVisibility; mDisplayContent = displayContent; @@ -894,6 +903,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { } boolean showLw(boolean doAnimation, boolean requestAnim) { + if (isOtherUsersAppWindow()) { + Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display " + + this + ", type " + mAttrs.type + ", belonging to " + mOwnerUid); + return false; + } if (mPolicyVisibility && mPolicyVisibilityAfterAnim) { // Already showing. return false; @@ -970,6 +984,17 @@ final class WindowState implements WindowManagerPolicy.WindowState { return mClient.asBinder().isBinderAlive(); } + boolean isOtherUsersAppWindow() { + final int type = mAttrs.type; + if ((UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId) + && (mOwnerUid != Process.SYSTEM_UID) + && (type >= TYPE_BASE_APPLICATION) && (type <= LAST_APPLICATION_WINDOW) + && (type != TYPE_APPLICATION_STARTING)) { + return true; + } + return false; + } + private static void applyInsets(Region outRegion, Rect frame, Rect inset) { outRegion.set( frame.left + inset.left, frame.top + inset.top, diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java index d931426..69bad81 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -474,24 +474,14 @@ class WindowStateAnimator { private final Point mSize = new Point(); private final Rect mWindowCrop = new Rect(); private boolean mShown = false; - private int mDisplayId; - private String mName = "Not named"; + private int mLayerStack; + private String mName; public SurfaceTrace(SurfaceSession s, - int pid, int displayId, int w, int h, int format, int flags) throws - OutOfResourcesException { - super(s, pid, displayId, w, h, format, flags); - mSize.set(w, h); - mDisplayId = displayId; - Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by " - + Debug.getCallers(3)); - } - - public SurfaceTrace(SurfaceSession s, - int pid, String name, int displayId, int w, int h, int format, int flags) + int pid, String name, int layerStack, int w, int h, int format, int flags) throws OutOfResourcesException { - super(s, pid, name, displayId, w, h, format, flags); - mName = name; + super(s, pid, name, layerStack, w, h, format, flags); + mName = name != null ? name : "Not named"; mSize.set(w, h); Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by " + Debug.getCallers(3)); @@ -550,10 +540,10 @@ class WindowStateAnimator { } @Override - public void setDisplayId(int displayId) { - super.setDisplayId(displayId); - mDisplayId = displayId; - Slog.v(SURFACE_TAG, "setDisplayId: " + this + ". Called by " + Debug.getCallers(3)); + public void setLayerStack(int layerStack) { + super.setLayerStack(layerStack); + mLayerStack = layerStack; + Slog.v(SURFACE_TAG, "setLayerStack: " + this + ". Called by " + Debug.getCallers(3)); } @Override @@ -597,7 +587,7 @@ class WindowStateAnimator { @Override public String toString() { return "Surface " + Integer.toHexString(System.identityHashCode(this)) + " " - + mName + " (" + mDisplayId + "): shown=" + mShown + " layer=" + mLayer + + mName + " (" + mLayerStack + "): shown=" + mShown + " layer=" + mLayer + " alpha=" + mSurfaceTraceAlpha + " " + mPosition.x + "," + mPosition.y + " " + mSize.x + "x" + mSize.y + " crop=" + mWindowCrop.toShortString(); @@ -1300,6 +1290,11 @@ class WindowStateAnimator { // This must be called while inside a transaction. boolean performShowLocked() { + if (mWin.isOtherUsersAppWindow()) { + Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display " + + this + ", type " + mWin.mAttrs.type + ", belonging to " + mWin.mOwnerUid); + return false; + } if (DEBUG_VISIBILITY || (DEBUG_STARTING_WINDOW && mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING)) { RuntimeException e = null; |