summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/ConnectivityService.java94
-rw-r--r--services/java/com/android/server/EventLogTags.logtags5
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java25
-rw-r--r--services/java/com/android/server/LocationManagerService.java66
-rw-r--r--services/java/com/android/server/NotificationManagerService.java368
-rw-r--r--services/java/com/android/server/StatusBarManagerService.java2
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityInputFilter.java59
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityManagerService.java318
-rw-r--r--services/java/com/android/server/accessibility/EventStreamTransformation.java2
-rw-r--r--services/java/com/android/server/accounts/AccountManagerService.java9
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java54
-rw-r--r--services/java/com/android/server/am/ActivityStack.java10
-rw-r--r--services/java/com/android/server/am/NativeCrashListener.java2
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java62
-rw-r--r--services/java/com/android/server/content/ContentService.java2
-rw-r--r--services/java/com/android/server/content/SyncManager.java38
-rw-r--r--services/java/com/android/server/firewall/AndFilter.java7
-rw-r--r--services/java/com/android/server/firewall/CategoryFilter.java2
-rw-r--r--services/java/com/android/server/firewall/Filter.java11
-rw-r--r--services/java/com/android/server/firewall/IntentFirewall.java116
-rw-r--r--services/java/com/android/server/firewall/NotFilter.java7
-rw-r--r--services/java/com/android/server/firewall/OrFilter.java7
-rw-r--r--services/java/com/android/server/firewall/PortFilter.java3
-rw-r--r--services/java/com/android/server/firewall/SenderFilter.java12
-rw-r--r--services/java/com/android/server/firewall/SenderPermissionFilter.java3
-rw-r--r--services/java/com/android/server/firewall/StringFilter.java57
-rw-r--r--services/java/com/android/server/location/GeofenceProxy.java154
-rw-r--r--services/java/com/android/server/location/GpsLocationProvider.java111
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java141
-rw-r--r--services/java/com/android/server/pm/UserManagerService.java11
-rw-r--r--services/java/com/android/server/power/PowerManagerService.java2
-rw-r--r--services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java12
-rw-r--r--services/java/com/android/server/updates/IntentFirewallInstallReceiver.java27
-rw-r--r--services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java113
-rw-r--r--services/java/com/android/server/wifi/WifiService.java2
-rw-r--r--services/java/com/android/server/wm/AppWindowAnimator.java10
-rw-r--r--services/java/com/android/server/wm/WindowAnimator.java1
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java83
-rw-r--r--services/java/com/android/server/wm/WindowState.java12
-rw-r--r--services/java/com/android/server/wm/WindowStateAnimator.java17
40 files changed, 1664 insertions, 373 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 9e06db8..01625dd 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -321,12 +321,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// track the current default http proxy - tell the world if we get a new one (real change)
private ProxyProperties mDefaultProxy = null;
- private Object mDefaultProxyLock = new Object();
+ private Object mProxyLock = new Object();
private boolean mDefaultProxyDisabled = false;
// track the global proxy.
private ProxyProperties mGlobalProxy = null;
- private final Object mGlobalProxyLock = new Object();
private SettingsObserver mSettingsObserver;
@@ -1471,8 +1470,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
loge("Error modifying route - no interface name");
return false;
}
-
- if (r.isHostRoute() == false) {
+ if (r.hasGateway()) {
RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), r.getGateway());
if (bestRoute != null) {
if (bestRoute.getGateway().equals(r.getGateway())) {
@@ -2348,28 +2346,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
- for (RouteInfo r : routeDiff.added) {
- if (isLinkDefault || ! r.isDefaultRoute()) {
- addRoute(newLp, r, TO_DEFAULT_TABLE);
- } else {
- // add to a secondary route table
- addRoute(newLp, r, TO_SECONDARY_TABLE);
-
- // many radios add a default route even when we don't want one.
- // remove the default route unless somebody else has asked for it
- String ifaceName = newLp.getInterfaceName();
- if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
- if (VDBG) log("Removing " + r + " for interface " + ifaceName);
- try {
- mNetd.removeRoute(ifaceName, r);
- } catch (Exception e) {
- // never crash - catch them all
- if (DBG) loge("Exception trying to remove a route: " + e);
- }
- }
- }
- }
-
if (!isLinkDefault) {
// handle DNS routes
if (routesChanged) {
@@ -2394,6 +2370,29 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
}
+
+ for (RouteInfo r : routeDiff.added) {
+ if (isLinkDefault || ! r.isDefaultRoute()) {
+ addRoute(newLp, r, TO_DEFAULT_TABLE);
+ } else {
+ // add to a secondary route table
+ addRoute(newLp, r, TO_SECONDARY_TABLE);
+
+ // many radios add a default route even when we don't want one.
+ // remove the default route unless somebody else has asked for it
+ String ifaceName = newLp.getInterfaceName();
+ if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
+ if (VDBG) log("Removing " + r + " for interface " + ifaceName);
+ try {
+ mNetd.removeRoute(ifaceName, r);
+ } catch (Exception e) {
+ // never crash - catch them all
+ if (DBG) loge("Exception trying to remove a route: " + e);
+ }
+ }
+ }
+ }
+
return routesChanged;
}
@@ -3039,14 +3038,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// so this API change wouldn't have a benifit. It also breaks the passing
// of proxy info to all the JVMs.
// enforceAccessPermission();
- synchronized (mDefaultProxyLock) {
- return mDefaultProxyDisabled ? null : mDefaultProxy;
+ synchronized (mProxyLock) {
+ if (mGlobalProxy != null) return mGlobalProxy;
+ return (mDefaultProxyDisabled ? null : mDefaultProxy);
}
}
public void setGlobalProxy(ProxyProperties proxyProperties) {
- enforceChangePermission();
- synchronized (mGlobalProxyLock) {
+ enforceConnectivityInternalPermission();
+ synchronized (mProxyLock) {
if (proxyProperties == mGlobalProxy) return;
if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
@@ -3063,16 +3063,21 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mGlobalProxy = null;
}
ContentResolver res = mContext.getContentResolver();
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
- Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
- exclList);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
+ Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
+ Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
+ exclList);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
if (mGlobalProxy == null) {
proxyProperties = mDefaultProxy;
}
- //sendProxyBroadcast(proxyProperties);
+ sendProxyBroadcast(proxyProperties);
}
private void loadGlobalProxy() {
@@ -3083,7 +3088,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
if (!TextUtils.isEmpty(host)) {
ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
- synchronized (mGlobalProxyLock) {
+ synchronized (mProxyLock) {
mGlobalProxy = proxyProperties;
}
}
@@ -3094,7 +3099,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// so this API change wouldn't have a benifit. It also breaks the passing
// of proxy info to all the JVMs.
// enforceAccessPermission();
- synchronized (mGlobalProxyLock) {
+ synchronized (mProxyLock) {
return mGlobalProxy;
}
}
@@ -3103,11 +3108,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (proxy != null && TextUtils.isEmpty(proxy.getHost())) {
proxy = null;
}
- synchronized (mDefaultProxyLock) {
+ synchronized (mProxyLock) {
if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
- if (mDefaultProxy == proxy) return;
+ if (mDefaultProxy == proxy) return; // catches repeated nulls
mDefaultProxy = proxy;
+ if (mGlobalProxy != null) return;
if (!mDefaultProxyDisabled) {
sendProxyBroadcast(proxy);
}
@@ -3350,10 +3356,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mDnsOverridden = true;
}
- // Temporarily disable the default proxy.
- synchronized (mDefaultProxyLock) {
+ // Temporarily disable the default proxy (not global).
+ synchronized (mProxyLock) {
mDefaultProxyDisabled = true;
- if (mDefaultProxy != null) {
+ if (mGlobalProxy == null && mDefaultProxy != null) {
sendProxyBroadcast(null);
}
}
@@ -3368,9 +3374,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mHandler.sendEmptyMessage(EVENT_RESTORE_DNS);
}
}
- synchronized (mDefaultProxyLock) {
+ synchronized (mProxyLock) {
mDefaultProxyDisabled = false;
- if (mDefaultProxy != null) {
+ if (mGlobalProxy == null && mDefaultProxy != null) {
sendProxyBroadcast(mDefaultProxy);
}
}
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 8bc2da2..59577ad 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -157,3 +157,8 @@ option java_package com.android.server
# ConfigUpdateInstallReceiver.java
# ---------------------------
51300 config_install_failed (dir|3)
+
+# ---------------------------
+# IntentFirewall.java
+# ---------------------------
+51400 ifw_intent_matched (Intent Type|1|5),(Component Name|3),(Caller Uid|1|5),(Caller Pkg Count|1|1),(Caller Pkgs|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 3b541ec..a28c387 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1070,7 +1070,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
showCurrentInputLocked(getAppShowFlags(), null);
}
- return new InputBindResult(session.session, session.channel, mCurId, mCurSeq);
+ return new InputBindResult(session.session,
+ session.channel != null ? session.channel.dup() : null, mCurId, mCurSeq);
}
InputBindResult startInputLocked(IInputMethodClient client,
@@ -2357,13 +2358,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return true;
case MSG_CREATE_SESSION: {
args = (SomeArgs)msg.obj;
+ IInputMethod method = (IInputMethod)args.arg1;
InputChannel channel = (InputChannel)args.arg2;
try {
- ((IInputMethod)args.arg1).createSession(channel,
- (IInputSessionCallback)args.arg3);
+ method.createSession(channel, (IInputSessionCallback)args.arg3);
} catch (RemoteException e) {
} finally {
- if (channel != null) {
+ // Dispose the channel if the input method is not local to this process
+ // because the remote proxy will get its own copy when unparceled.
+ if (channel != null && Binder.isProxy(method)) {
channel.dispose();
}
}
@@ -2404,16 +2407,24 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// There is nothing interesting about the last client dying.
}
return true;
- case MSG_BIND_METHOD:
+ case MSG_BIND_METHOD: {
args = (SomeArgs)msg.obj;
+ IInputMethodClient client = (IInputMethodClient)args.arg1;
+ InputBindResult res = (InputBindResult)args.arg2;
try {
- ((IInputMethodClient)args.arg1).onBindMethod(
- (InputBindResult)args.arg2);
+ client.onBindMethod(res);
} catch (RemoteException e) {
Slog.w(TAG, "Client died receiving input method " + args.arg2);
+ } finally {
+ // Dispose the channel if the input method is not local to this process
+ // because the remote proxy will get its own copy when unparceled.
+ if (res.channel != null && Binder.isProxy(client)) {
+ res.channel.dispose();
+ }
}
args.recycle();
return true;
+ }
case MSG_SET_ACTIVE:
try {
((ClientState)msg.obj).client.setActive(msg.arg1 != 0);
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index bcb7cb7..b47e8a0 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -54,19 +54,17 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
-
-import com.android.internal.app.IAppOpsService;
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.server.location.GeocoderProxy;
+import com.android.server.location.GeofenceProxy;
import com.android.server.location.GeofenceManager;
import com.android.server.location.GpsLocationProvider;
import com.android.server.location.LocationBlacklist;
@@ -118,6 +116,8 @@ public class LocationManagerService extends ILocationManager.Stub {
private static final int MSG_LOCATION_CHANGED = 1;
+ private static final long NANOS_PER_MILLI = 1000000L;
+
// 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
@@ -181,6 +181,11 @@ public class LocationManagerService extends ILocationManager.Stub {
// mapping from provider name to last known location
private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
+ // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
+ // locations stored here are not fudged for coarse permissions.
+ private final HashMap<String, Location> mLastLocationCoarseInterval =
+ new HashMap<String, Location>();
+
// all providers that operate over proxy, for authorizing incoming location
private final ArrayList<LocationProviderProxy> mProxyProviders =
new ArrayList<LocationProviderProxy>();
@@ -338,11 +343,11 @@ public class LocationManagerService extends ILocationManager.Stub {
addProviderLocked(passiveProvider);
mEnabledProviders.add(passiveProvider.getName());
mPassiveProvider = passiveProvider;
+ // Create a gps location provider
+ GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
+ mLocationHandler.getLooper());
if (GpsLocationProvider.isSupported()) {
- // Create a gps location provider
- GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
- mLocationHandler.getLooper());
mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
addProviderLocked(gpsProvider);
@@ -406,6 +411,14 @@ public class LocationManagerService extends ILocationManager.Stub {
if (mGeocodeProvider == null) {
Slog.e(TAG, "no geocoder provider found");
}
+
+ // bind to geofence provider
+ GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, providerPackageNames,
+ mLocationHandler, gpsProvider.getGpsGeofenceProxy());
+ if (provider == null) {
+ Slog.e(TAG, "no geofence provider found");
+ }
+
}
/**
@@ -417,6 +430,7 @@ public class LocationManagerService extends ILocationManager.Stub {
mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
synchronized (mLock) {
mLastLocation.clear();
+ mLastLocationCoarseInterval.clear();
for (LocationProviderInterface p : mProviders) {
updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
}
@@ -1401,7 +1415,14 @@ public class LocationManagerService extends ILocationManager.Stub {
if (!isAllowedByUserSettingsLocked(name, uid)) return null;
- Location location = mLastLocation.get(name);
+ Location location;
+ if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
+ // Make sure that an app with coarse permissions can't get frequent location
+ // updates by calling LocationManager.getLastKnownLocation repeatedly.
+ location = mLastLocationCoarseInterval.get(name);
+ } else {
+ location = mLastLocation.get(name);
+ }
if (location == null) {
return null;
}
@@ -1667,7 +1688,8 @@ public class LocationManagerService extends ILocationManager.Stub {
// Check whether sufficient time has passed
long minTime = record.mRequest.getFastestInterval();
- long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
+ long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
+ / NANOS_PER_MILLI;
if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
return false;
}
@@ -1720,13 +1742,30 @@ public class LocationManagerService extends ILocationManager.Stub {
}
lastLocation.set(location);
+ // Update last known coarse interval location if enough time has passed.
+ Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
+ if (lastLocationCoarseInterval == null) {
+ lastLocationCoarseInterval = new Location(location);
+ mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
+ }
+ long timeDiffNanos = location.getElapsedRealtimeNanos()
+ - lastLocationCoarseInterval.getElapsedRealtimeNanos();
+ if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
+ lastLocationCoarseInterval.set(location);
+ }
+ // Don't ever return a coarse location that is more recent than the allowed update
+ // interval (i.e. don't allow an app to keep registering and unregistering for
+ // location updates to overcome the minimum interval).
+ noGPSLocation =
+ lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
+
// Skip if there are no UpdateRecords for this provider.
ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
if (records == null || records.size() == 0) return;
// Fetch coarse location
Location coarseLocation = null;
- if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
+ if (noGPSLocation != null) {
coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
}
@@ -2015,6 +2054,7 @@ public class LocationManagerService extends ILocationManager.Stub {
addProviderLocked(provider);
mMockProviders.put(name, provider);
mLastLocation.put(name, null);
+ mLastLocationCoarseInterval.put(name, null);
updateProvidersLocked();
}
Binder.restoreCallingIdentity(identity);
@@ -2037,6 +2077,7 @@ public class LocationManagerService extends ILocationManager.Stub {
addProviderLocked(realProvider);
}
mLastLocation.put(provider, null);
+ mLastLocationCoarseInterval.put(provider, null);
updateProvidersLocked();
Binder.restoreCallingIdentity(identity);
}
@@ -2168,6 +2209,13 @@ public class LocationManagerService extends ILocationManager.Stub {
pw.println(" " + provider + ": " + location);
}
+ pw.println(" Last Known Locations Coarse Intervals:");
+ for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
+ String provider = entry.getKey();
+ Location location = entry.getValue();
+ pw.println(" " + provider + ": " + location);
+ }
+
mGeofenceManager.dump(pw);
if (mEnabledProviders.size() > 0) {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 44d730c..cfb892f 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -26,16 +26,17 @@ import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.INotificationManager;
-import android.app.INotificationListener;
import android.app.ITransientNotification;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -57,6 +58,9 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
+import android.service.notification.INotificationListener;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.AtomicFile;
@@ -68,8 +72,6 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
-import com.android.internal.statusbar.StatusBarNotification;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -121,6 +123,8 @@ public class NotificationManagerService extends INotificationManager.Stub
private static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
private static final boolean ENABLE_BLOCKED_TOASTS = true;
+ private static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
+
final Context mContext;
final IActivityManager mAm;
final UserManager mUserManager;
@@ -163,8 +167,18 @@ public class NotificationManagerService extends INotificationManager.Stub
private final AppOpsManager mAppOps;
- private ArrayList<NotificationListenerInfo> mListeners = new ArrayList<NotificationListenerInfo>();
- private ArrayList<String> mEnabledListenersForCurrentUser = new ArrayList<String>();
+ // contains connections to all connected listeners, including app services
+ // and system listeners
+ private ArrayList<NotificationListenerInfo> mListeners
+ = new ArrayList<NotificationListenerInfo>();
+ // things that will be put into mListeners as soon as they're ready
+ private ArrayList<String> mServicesBinding = new ArrayList<String>();
+ // lists the component names of all enabled (and therefore connected) listener
+ // app services for the current user only
+ private HashSet<ComponentName> mEnabledListenersForCurrentUser
+ = new HashSet<ComponentName>();
+ // Just the packages from mEnabledListenersForCurrentUser
+ private HashSet<String> mEnabledListenerPackageNames = new HashSet<String>();
// Notification control database. For now just contains disabled packages.
private AtomicFile mPolicyFile;
@@ -181,27 +195,42 @@ public class NotificationManagerService extends INotificationManager.Stub
private class NotificationListenerInfo implements DeathRecipient {
INotificationListener listener;
- String pkg;
+ ComponentName component;
int userid;
boolean isSystem;
+ ServiceConnection connection;
- public NotificationListenerInfo(INotificationListener listener, String pkg, int userid,
- boolean isSystem) {
+ public NotificationListenerInfo(INotificationListener listener, ComponentName component,
+ int userid, boolean isSystem) {
this.listener = listener;
- this.pkg = pkg;
+ this.component = component;
this.userid = userid;
this.isSystem = isSystem;
+ this.connection = null;
+ }
+
+ public NotificationListenerInfo(INotificationListener listener, ComponentName component,
+ int userid, ServiceConnection connection) {
+ this.listener = listener;
+ this.component = component;
+ this.userid = userid;
+ this.isSystem = false;
+ this.connection = connection;
}
boolean enabledAndUserMatches(StatusBarNotification sbn) {
final int nid = sbn.getUserId();
- if (!(isSystem || isEnabledForUser(nid))) return false;
+ if (!isEnabledForCurrentUser()) {
+ return false;
+ }
if (this.userid == UserHandle.USER_ALL) return true;
return (nid == UserHandle.USER_ALL || nid == this.userid);
}
public void notifyPostedIfUserMatch(StatusBarNotification sbn) {
- if (!enabledAndUserMatches(sbn)) return;
+ if (!enabledAndUserMatches(sbn)) {
+ return;
+ }
try {
listener.onNotificationPosted(sbn);
} catch (RemoteException ex) {
@@ -220,15 +249,17 @@ public class NotificationManagerService extends INotificationManager.Stub
@Override
public void binderDied() {
- unregisterListener(this.listener, this.userid);
+ if (connection == null) {
+ // This is not a service; it won't be recreated. We can give up this connection.
+ unregisterListener(this.listener, this.userid);
+ }
}
/** convenience method for looking in mEnabledListenersForCurrentUser */
- public boolean isEnabledForUser(int userid) {
- for (int i=0; i<mEnabledListenersForCurrentUser.size(); i++) {
- if (this.pkg.equals(mEnabledListenersForCurrentUser.get(i))) return true;
- }
- return false;
+ public boolean isEnabledForCurrentUser() {
+ if (this.isSystem) return true;
+ if (this.connection == null) return false;
+ return mEnabledListenersForCurrentUser.contains(this.component);
}
}
@@ -434,6 +465,12 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ /**
+ * System-only API for getting a list of current (i.e. not cleared) notifications.
+ *
+ * Requires ACCESS_NOTIFICATIONS which is signature|system.
+ */
+ @Override
public StatusBarNotification[] getActiveNotifications(String callingPkg) {
// enforce() will ensure the calling uid has the correct permission
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
@@ -456,6 +493,12 @@ public class NotificationManagerService extends INotificationManager.Stub
return tmp;
}
+ /**
+ * System-only API for getting a list of recent (cleared, no longer shown) notifications.
+ *
+ * Requires ACCESS_NOTIFICATIONS which is signature|system.
+ */
+ @Override
public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
// enforce() will ensure the calling uid has the correct permission
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
@@ -474,27 +517,76 @@ public class NotificationManagerService extends INotificationManager.Stub
return tmp;
}
- boolean packageCanTapNotificationsForUser(final int uid, final String pkg) {
- // Make sure the package and uid match, and that the package is allowed access
- return (AppOpsManager.MODE_ALLOWED
- == mAppOps.checkOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, pkg));
+ /**
+ * Called whenever packages change, the user switches, or ENABLED_NOTIFICATION_LISTENERS
+ * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
+ */
+ void rebindListenerServices() {
+ String flat = Settings.Secure.getString(
+ mContext.getContentResolver(),
+ Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
+ NotificationListenerInfo[] toRemove = new NotificationListenerInfo[mListeners.size()];
+ final ArrayList<ComponentName> toAdd;
+ final int currentUser = ActivityManager.getCurrentUser();
+
+ synchronized (mNotificationList) {
+ // unbind and remove all existing listeners
+ toRemove = mListeners.toArray(toRemove);
+
+ toAdd = new ArrayList<ComponentName>();
+ final HashSet<ComponentName> newEnabled = new HashSet<ComponentName>();
+ final HashSet<String> newPackages = new HashSet<String>();
+
+ // decode the list of components
+ if (flat != null) {
+ String[] components = flat.split(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR);
+ for (int i=0; i<components.length; i++) {
+ final ComponentName component
+ = ComponentName.unflattenFromString(components[i]);
+ if (component != null) {
+ newEnabled.add(component);
+ toAdd.add(component);
+ newPackages.add(component.getPackageName());
+ }
+ }
+
+ mEnabledListenersForCurrentUser = newEnabled;
+ mEnabledListenerPackageNames = newPackages;
+ }
+ }
+
+ for (NotificationListenerInfo info : toRemove) {
+ final ComponentName component = info.component;
+ final int oldUser = info.userid;
+ Slog.v(TAG, "disabling notification listener for user " + oldUser + ": " + component);
+ unregisterListenerService(component, info.userid);
+ }
+
+ final int N = toAdd.size();
+ for (int i=0; i<N; i++) {
+ final ComponentName component = toAdd.get(i);
+ Slog.v(TAG, "enabling notification listener for user " + currentUser + ": "
+ + component);
+ registerListenerService(component, currentUser);
+ }
}
+ /**
+ * Register a listener binder directly with the notification manager.
+ *
+ * Only works with system callers. Apps should extend
+ * {@link android.service.notification.NotificationListenerService}.
+ */
@Override
public void registerListener(final INotificationListener listener,
- final String pkg, final int userid) {
- // ensure system or allowed pkg
- int uid = Binder.getCallingUid();
- boolean isSystem = (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0);
- if (!(isSystem || packageCanTapNotificationsForUser(uid, pkg))) {
- throw new SecurityException("Package " + pkg
- + " may not listen for notifications");
- }
+ final ComponentName component, final int userid) {
+ checkCallerIsSystem();
synchronized (mNotificationList) {
try {
NotificationListenerInfo info
- = new NotificationListenerInfo(listener, pkg, userid, isSystem);
+ = new NotificationListenerInfo(listener, component, userid, true);
listener.asBinder().linkToDeath(info, 0);
mListeners.add(info);
} catch (RemoteException e) {
@@ -503,6 +595,90 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ /**
+ * Version of registerListener that takes the name of a
+ * {@link android.service.notification.NotificationListenerService} to bind to.
+ *
+ * This is the mechanism by which third parties may subscribe to notifications.
+ */
+ private void registerListenerService(final ComponentName name, final int userid) {
+ checkCallerIsSystem();
+
+ if (DBG) Slog.v(TAG, "registerListenerService: " + name + " u=" + userid);
+
+ synchronized (mNotificationList) {
+ final String servicesBindingTag = name.toString() + "/" + userid;
+ if (mServicesBinding.contains(servicesBindingTag)) {
+ // stop registering this thing already! we're working on it
+ return;
+ }
+ mServicesBinding.add(servicesBindingTag);
+
+ final int N = mListeners.size();
+ for (int i=N-1; i>=0; i--) {
+ final NotificationListenerInfo info = mListeners.get(i);
+ if (name.equals(info.component)
+ && info.userid == userid) {
+ // cut old connections
+ if (DBG) Slog.v(TAG, " disconnecting old listener: " + info.listener);
+ mListeners.remove(i);
+ if (info.connection != null) {
+ mContext.unbindService(info.connection);
+ }
+ }
+ }
+
+ Intent intent = new Intent(NotificationListenerService.SERVICE_INTERFACE);
+ intent.setComponent(name);
+
+ intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
+ com.android.internal.R.string.notification_listener_binding_label);
+ intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
+ mContext, 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0));
+
+ try {
+ if (DBG) Slog.v(TAG, "binding: " + intent);
+ if (!mContext.bindServiceAsUser(intent,
+ new ServiceConnection() {
+ INotificationListener mListener;
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mNotificationList) {
+ mServicesBinding.remove(servicesBindingTag);
+ try {
+ mListener = INotificationListener.Stub.asInterface(service);
+ NotificationListenerInfo info = new NotificationListenerInfo(
+ mListener, name, userid, this);
+ service.linkToDeath(info, 0);
+ mListeners.add(info);
+ } catch (RemoteException e) {
+ // already dead
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Slog.v(TAG, "notification listener connection lost: " + name);
+ }
+ },
+ Context.BIND_AUTO_CREATE,
+ new UserHandle(userid)))
+ {
+ mServicesBinding.remove(servicesBindingTag);
+ Slog.w(TAG, "Unable to bind listener service: " + intent);
+ return;
+ }
+ } catch (SecurityException ex) {
+ Slog.e(TAG, "Unable to bind listener service: " + intent, ex);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Remove a listener binder directly
+ */
@Override
public void unregisterListener(INotificationListener listener, int userid) {
// no need to check permissions; if your listener binder is in the list,
@@ -513,12 +689,39 @@ public class NotificationManagerService extends INotificationManager.Stub
for (int i=N-1; i>=0; i--) {
final NotificationListenerInfo info = mListeners.get(i);
if (info.listener == listener && info.userid == userid) {
- mListeners.remove(listener);
+ mListeners.remove(i);
+ if (info.connection != null) {
+ mContext.unbindService(info.connection);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove a listener service for the given user by ComponentName
+ */
+ private void unregisterListenerService(ComponentName name, int userid) {
+ checkCallerIsSystem();
+
+ synchronized (mNotificationList) {
+ final int N = mListeners.size();
+ for (int i=N-1; i>=0; i--) {
+ final NotificationListenerInfo info = mListeners.get(i);
+ if (name.equals(info.component)
+ && info.userid == userid) {
+ mListeners.remove(i);
+ if (info.connection != null) {
+ mContext.unbindService(info.connection);
+ }
}
}
}
}
+ /**
+ * asynchronously notify all listeners about a new notification
+ */
private void notifyPostedLocked(NotificationRecord n) {
final StatusBarNotification sbn = n.sbn;
for (final NotificationListenerInfo info : mListeners) {
@@ -530,6 +733,9 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ /**
+ * asynchronously notify all listeners about a removed notification
+ */
private void notifyRemovedLocked(NotificationRecord n) {
final StatusBarNotification sbn = n.sbn;
for (final NotificationListenerInfo info : mListeners) {
@@ -541,6 +747,57 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ // -- APIs to support listeners clicking/clearing notifications --
+
+ private NotificationListenerInfo checkListenerToken(INotificationListener listener) {
+ final IBinder token = listener.asBinder();
+ final int N = mListeners.size();
+ for (int i=0; i<N; i++) {
+ final NotificationListenerInfo info = mListeners.get(i);
+ if (info.listener.asBinder() == token) return info;
+ }
+ throw new SecurityException("Disallowed call from unknown listener: " + listener);
+ }
+
+ /**
+ * Allow an INotificationListener to simulate a "clear all" operation.
+ *
+ * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
+ public void clearAllNotificationsFromListener(INotificationListener token) {
+ NotificationListenerInfo info = checkListenerToken(token);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ cancelAll(info.userid);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
+ *
+ * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
+ public void clearNotificationFromListener(INotificationListener token, String pkg, String tag, int id) {
+ NotificationListenerInfo info = checkListenerToken(token);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ cancelNotification(pkg, tag, id, 0,
+ Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+ true,
+ info.userid);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ // -- end of listener APIs --
+
public static final class NotificationRecord
{
final StatusBarNotification sbn;
@@ -759,12 +1016,23 @@ public class NotificationManagerService extends INotificationManager.Stub
}
pkgList = new String[]{pkgName};
}
+
+ boolean anyListenersInvolved = false;
if (pkgList != null && (pkgList.length > 0)) {
for (String pkgName : pkgList) {
cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart,
UserHandle.USER_ALL);
+ if (mEnabledListenerPackageNames.contains(pkgName)) {
+ anyListenersInvolved = true;
+ }
}
}
+
+ if (anyListenersInvolved) {
+ // make sure we're still bound to any of our
+ // listeners who may have just upgraded
+ rebindListenerServices();
+ }
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
// Keep track of screen on/off state, but do not turn off the notification light
// until user passes through the lock screen or views the notification.
@@ -795,7 +1063,7 @@ public class NotificationManagerService extends INotificationManager.Stub
= Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
private final Uri ENABLED_NOTIFICATION_LISTENERS_URI
- = Settings.System.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+ = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
SettingsObserver(Handler handler) {
super(handler);
@@ -804,9 +1072,9 @@ public class NotificationManagerService extends INotificationManager.Stub
void observe() {
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
- false, this);
+ false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI,
- false, this);
+ false, this, UserHandle.USER_ALL);
update(null);
}
@@ -825,19 +1093,7 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
if (uri == null || ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri)) {
- String pkglist = Settings.Secure.getString(
- mContext.getContentResolver(),
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
- mEnabledListenersForCurrentUser.clear();
- if (pkglist != null) {
- String[] pkgs = pkglist.split(";");
- for (int i=0; i<pkgs.length; i++) {
- final String pkg = pkgs[i];
- if (pkg != null && ! "".equals(pkg)) {
- mEnabledListenersForCurrentUser.add(pkgs[i]);
- }
- }
- }
+ rebindListenerServices();
}
}
}
@@ -956,6 +1212,9 @@ public class NotificationManagerService extends INotificationManager.Stub
// no beeping until we're basically done booting
mSystemReady = true;
+
+ // make sure our listener services are properly bound
+ rebindListenerServices();
}
// Toasts
@@ -1781,16 +2040,17 @@ public class NotificationManagerService extends INotificationManager.Stub
pw.println("Current Notification Manager state:");
- pw.print(" Enabled listeners: [");
- for (String pkg : mEnabledListenersForCurrentUser) {
- pw.print(" " + pkg);
+ pw.println(" Listeners (" + mEnabledListenersForCurrentUser.size()
+ + ") enabled for current user:");
+ for (ComponentName cmpt : mEnabledListenersForCurrentUser) {
+ pw.println(" " + cmpt);
}
- pw.println(" ]");
- pw.println(" Live listeners:");
+ pw.println(" Live listeners (" + mListeners.size() + "):");
for (NotificationListenerInfo info : mListeners) {
- pw.println(" " + info.pkg + " (user " + info.userid + "): " + info.listener
- + (info.isSystem?" SYSTEM":""));
+ pw.println(" " + info.component
+ + " (user " + info.userid + "): " + info.listener
+ + (info.isSystem?" SYSTEM":""));
}
int N;
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 1fe98af..c21d8c6 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.app.StatusBarManager;
+import android.service.notification.StatusBarNotification;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -33,7 +34,6 @@ import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.statusbar.StatusBarNotification;
import com.android.server.wm.WindowManagerService;
import java.io.FileDescriptor;
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 179db12..0d8a571 100644
--- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -25,6 +25,7 @@ import android.view.Display;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.InputFilter;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManagerPolicy;
import android.view.accessibility.AccessibilityEvent;
@@ -80,7 +81,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
private final Choreographer mChoreographer;
- private int mCurrentDeviceId;
+ private int mCurrentTouchDeviceId;
private boolean mInstalled;
@@ -98,6 +99,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
private boolean mHoverEventSequenceStarted;
+ private boolean mKeyEventSequenceStarted;
+
AccessibilityInputFilter(Context context, AccessibilityManagerService service) {
super(context.getMainLooper());
mContext = context;
@@ -133,11 +136,21 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
Slog.d(TAG, "Received event: " + event + ", policyFlags=0x"
+ Integer.toHexString(policyFlags));
}
- if (mEventHandler == null) {
+ if (event instanceof MotionEvent
+ && event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
+ MotionEvent motionEvent = (MotionEvent) event;
+ onMotionEvent(motionEvent, policyFlags);
+ } else if (event instanceof KeyEvent
+ && event.isFromSource(InputDevice.SOURCE_KEYBOARD)) {
+ KeyEvent keyEvent = (KeyEvent) event;
+ onKeyEvent(keyEvent, policyFlags);
+ } else {
super.onInputEvent(event, policyFlags);
- return;
}
- if (event.getSource() != InputDevice.SOURCE_TOUCHSCREEN) {
+ }
+
+ private void onMotionEvent(MotionEvent event, int policyFlags) {
+ if (mEventHandler == null) {
super.onInputEvent(event, policyFlags);
return;
}
@@ -149,26 +162,25 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
return;
}
final int deviceId = event.getDeviceId();
- if (mCurrentDeviceId != deviceId) {
+ if (mCurrentTouchDeviceId != deviceId) {
+ mCurrentTouchDeviceId = deviceId;
mMotionEventSequenceStarted = false;
mHoverEventSequenceStarted = false;
mEventHandler.clear();
- mCurrentDeviceId = deviceId;
}
- if (mCurrentDeviceId < 0) {
+ if (mCurrentTouchDeviceId < 0) {
super.onInputEvent(event, policyFlags);
return;
}
// We do not handle scroll events.
- MotionEvent motionEvent = (MotionEvent) event;
- if (motionEvent.getActionMasked() == MotionEvent.ACTION_SCROLL) {
+ if (event.getActionMasked() == MotionEvent.ACTION_SCROLL) {
super.onInputEvent(event, policyFlags);
return;
}
// Wait for a down touch event to start processing.
- if (motionEvent.isTouchEvent()) {
+ if (event.isTouchEvent()) {
if (!mMotionEventSequenceStarted) {
- if (motionEvent.getActionMasked() != MotionEvent.ACTION_DOWN) {
+ if (event.getActionMasked() != MotionEvent.ACTION_DOWN) {
return;
}
mMotionEventSequenceStarted = true;
@@ -176,7 +188,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
} else {
// Wait for an enter hover event to start processing.
if (!mHoverEventSequenceStarted) {
- if (motionEvent.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER) {
+ if (event.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER) {
return;
}
mHoverEventSequenceStarted = true;
@@ -185,6 +197,22 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
batchMotionEvent((MotionEvent) event, policyFlags);
}
+ private void onKeyEvent(KeyEvent event, int policyFlags) {
+ if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
+ mKeyEventSequenceStarted = false;
+ super.onInputEvent(event, policyFlags);
+ return;
+ }
+ // Wait for a down key event to start processing.
+ if (!mKeyEventSequenceStarted) {
+ if (event.getAction() != KeyEvent.ACTION_DOWN) {
+ return;
+ }
+ mKeyEventSequenceStarted = true;
+ }
+ mAms.notifyKeyEvent(event, policyFlags);
+ }
+
private void scheduleProcessBatchedEvents() {
mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
mProcessBatchedEventsRunnable, null);
@@ -286,6 +314,13 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
}
+ void reset() {
+ setEnabledFeatures(0);
+ mKeyEventSequenceStarted = false;
+ mMotionEventSequenceStarted = false;
+ mHoverEventSequenceStarted = false;
+ }
+
private void enableFeatures() {
mMotionEventSequenceStarted = false;
mHoverEventSequenceStarted = false;
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 527e891..128a49f 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -61,16 +61,20 @@ import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
+import android.util.Pools.Pool;
+import android.util.Pools.SimplePool;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.IWindow;
import android.view.IWindowManager;
import android.view.InputDevice;
+import android.view.InputEventConsistencyVerifier;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MagnificationSpec;
import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityManager;
@@ -132,6 +136,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private static final int OWN_PROCESS_ID = android.os.Process.myPid();
+ private static final int MAX_POOL_SIZE = 10;
+
private static int sIdCounter = 0;
private static int sNextWindowId;
@@ -140,6 +146,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private final Object mLock = new Object();
+ private final Pool<PendingEvent> mPendingEventPool =
+ new SimplePool<PendingEvent>(MAX_POOL_SIZE);
+
private final SimpleStringSplitter mStringColonSplitter =
new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
@@ -633,6 +642,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
+ boolean notifyKeyEvent(KeyEvent event, int policyFlags) {
+ synchronized (mLock) {
+ KeyEvent localClone = KeyEvent.obtain(event);
+ boolean handled = notifyKeyEventLocked(localClone, policyFlags, false);
+ if (!handled) {
+ handled = notifyKeyEventLocked(localClone, policyFlags, true);
+ }
+ return handled;
+ }
+ }
+
/**
* Gets the bounds of the accessibility focus in the active window.
*
@@ -798,6 +818,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return false;
}
+ private boolean notifyKeyEventLocked(KeyEvent event, int policyFlags, boolean isDefault) {
+ // TODO: Now we are giving the key events to the last enabled
+ // service that can handle them which is the last one
+ // in our list since we write the last enabled as the
+ // last record in the enabled services setting. Ideally,
+ // the user should make the call which service handles
+ // key events. However, only one service should handle
+ // key events to avoid user frustration when different
+ // behavior is observed from different combinations of
+ // enabled accessibility services.
+ UserState state = getCurrentUserStateLocked();
+ for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+ Service service = state.mBoundServices.get(i);
+ if (service.mIsDefault == isDefault) {
+ service.notifyKeyEvent(event, policyFlags);
+ return true;
+ }
+ }
+ return false;
+ }
+
private void notifyClearAccessibilityNodeInfoCacheLocked() {
UserState state = getCurrentUserStateLocked();
for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
@@ -1119,8 +1160,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
boolean setInputFilter = false;
AccessibilityInputFilter inputFilter = null;
synchronized (mLock) {
- if ((userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled)
- || userState.mIsDisplayMagnificationEnabled) {
+ if (userState.mIsAccessibilityEnabled) {
if (!mHasInputFilter) {
mHasInputFilter = true;
if (mInputFilter == null) {
@@ -1141,7 +1181,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
} else {
if (mHasInputFilter) {
mHasInputFilter = false;
- mInputFilter.setEnabledFeatures(0);
+ mInputFilter.reset();
inputFilter = null;
setInputFilter = true;
}
@@ -1446,6 +1486,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 5;
public static final int MSG_UPDATE_INPUT_FILTER = 6;
public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7;
+ public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
public MainHandler(Looper looper) {
super(looper);
@@ -1464,6 +1505,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
event.recycle();
} break;
+ case MSG_SEND_KEY_EVENT_TO_INPUT_FILTER: {
+ KeyEvent event = (KeyEvent) msg.obj;
+ final int policyFlags = msg.arg1;
+ synchronized (mLock) {
+ if (mHasInputFilter && mInputFilter != null) {
+ mInputFilter.sendInputEvent(event, policyFlags);
+ }
+ }
+ event.recycle();
+ } break;
case MSG_SEND_STATE_TO_CLIENTS: {
final int clientState = msg.arg1;
final int userId = msg.arg2;
@@ -1536,6 +1587,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
+ private PendingEvent obtainPendingEventLocked(KeyEvent event, int policyFlags, int sequence) {
+ PendingEvent pendingEvent = mPendingEventPool.acquire();
+ if (pendingEvent == null) {
+ pendingEvent = new PendingEvent();
+ }
+ pendingEvent.event = event;
+ pendingEvent.policyFlags = policyFlags;
+ pendingEvent.sequence = sequence;
+ return pendingEvent;
+ }
+
+ private void recyclePendingEventLocked(PendingEvent pendingEvent) {
+ pendingEvent.clear();
+ mPendingEventPool.release(pendingEvent);
+ }
+
/**
* This class represents an accessibility service. It stores all per service
* data required for the service management, provides API for starting/stopping the
@@ -1545,12 +1612,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
* connection for the service.
*/
class Service extends IAccessibilityServiceConnection.Stub
- implements ServiceConnection, DeathRecipient {
-
- // We pick the MSBs to avoid collision since accessibility event types are
- // used as message types allowing us to remove messages per event type.
- private static final int MSG_ON_GESTURE = 0x80000000;
- private static final int MSG_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE = 0x40000000;
+ implements ServiceConnection, DeathRecipient {;
final int mUserId;
@@ -1594,29 +1656,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
final SparseArray<AccessibilityEvent> mPendingEvents =
new SparseArray<AccessibilityEvent>();
- /**
- * Handler for delayed event dispatch.
- */
- public Handler mHandler = new Handler(mMainHandler.getLooper()) {
+ final KeyEventDispatcher mKeyEventDispatcher = new KeyEventDispatcher();
+
+ // Handler only for dispatching accessibility events since we use event
+ // types as message types allowing us to remove messages per event type.
+ public Handler mEventDispatchHandler = new Handler(mMainHandler.getLooper()) {
@Override
public void handleMessage(Message message) {
- final int type = message.what;
- switch (type) {
- case MSG_ON_GESTURE: {
- final int gestureId = message.arg1;
- notifyGestureInternal(gestureId);
- } break;
- case MSG_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE: {
- notifyClearAccessibilityNodeInfoCacheInternal();
- } break;
- default: {
- final int eventType = type;
- notifyAccessibilityEventInternal(eventType);
- } break;
- }
+ final int eventType = message.what;
+ notifyAccessibilityEventInternal(eventType);
}
};
+ // Handler for scheduling method invocations on the main thread.
+ public InvocationHandler mInvocationHandler = new InvocationHandler(
+ mMainHandler.getLooper());
+
public Service(int userId, ComponentName componentName,
AccessibilityServiceInfo accessibilityServiceInfo) {
mUserId = userId;
@@ -1703,6 +1758,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return false;
}
UserState userState = getUserStateLocked(mUserId);
+ mKeyEventDispatcher.flush();
if (!mIsAutomation) {
mContext.unbindService(this);
} else {
@@ -1718,6 +1774,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
@Override
+ public void setOnKeyEventResult(boolean handled, int sequence) {
+ mKeyEventDispatcher.setOnKeyEventResult(handled, sequence);
+ }
+
+ @Override
public AccessibilityServiceInfo getServiceInfo() {
synchronized (mLock) {
return mAccessibilityServiceInfo;
@@ -1756,11 +1817,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
addServiceLocked(this, userState);
if (userState.mBindingServices.contains(mComponentName)) {
userState.mBindingServices.remove(mComponentName);
- onUserStateChangedLocked(userState);
try {
- mServiceInterface.setConnection(this, mId);
+ mServiceInterface.setConnection(this, mId);
+ onUserStateChangedLocked(userState);
} catch (RemoteException re) {
- Slog.w(LOG_TAG, "Error while setting connection for service: " + service, re);
+ Slog.w(LOG_TAG, "Error while setting connection for service: "
+ + service, re);
+ binderDied();
}
} else {
binderDied();
@@ -2109,6 +2172,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
public void binderDied() {
synchronized (mLock) {
+ mKeyEventDispatcher.flush();
UserState userState = getUserStateLocked(mUserId);
// The death recipient is unregistered in removeServiceLocked
removeServiceLocked(this, userState);
@@ -2141,12 +2205,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
final int what = eventType;
if (oldEvent != null) {
- mHandler.removeMessages(what);
+ mEventDispatchHandler.removeMessages(what);
oldEvent.recycle();
}
- Message message = mHandler.obtainMessage(what);
- mHandler.sendMessageDelayed(message, mNotificationTimeout);
+ Message message = mEventDispatchHandler.obtainMessage(what);
+ mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout);
}
}
@@ -2211,11 +2275,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
public void notifyGesture(int gestureId) {
- mHandler.obtainMessage(MSG_ON_GESTURE, gestureId, 0).sendToTarget();
+ mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE,
+ gestureId, 0).sendToTarget();
+ }
+
+ public void notifyKeyEvent(KeyEvent event, int policyFlags) {
+ mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_KEY_EVENT,
+ policyFlags, 0, event).sendToTarget();
}
public void notifyClearAccessibilityNodeInfoCache() {
- mHandler.sendEmptyMessage(MSG_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE);
+ mInvocationHandler.sendEmptyMessage(
+ InvocationHandler.MSG_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE);
}
private void notifyGestureInternal(int gestureId) {
@@ -2230,6 +2301,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
+ private void notifyKeyEventInternal(KeyEvent event, int policyFlags) {
+ mKeyEventDispatcher.notifyKeyEvent(event, policyFlags);
+ }
+
private void notifyClearAccessibilityNodeInfoCacheInternal() {
IAccessibilityServiceClient listener = mServiceInterface;
if (listener != null) {
@@ -2339,6 +2414,179 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
return null;
}
+
+ private final class InvocationHandler extends Handler {
+
+ public static final int MSG_ON_GESTURE = 1;
+ public static final int MSG_ON_KEY_EVENT = 2;
+ public static final int MSG_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE = 3;
+ public static final int MSG_ON_KEY_EVENT_TIMEOUT = 4;
+
+ public InvocationHandler(Looper looper) {
+ super(looper, null, true);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ final int type = message.what;
+ switch (type) {
+ case MSG_ON_GESTURE: {
+ final int gestureId = message.arg1;
+ notifyGestureInternal(gestureId);
+ } break;
+ case MSG_ON_KEY_EVENT: {
+ KeyEvent event = (KeyEvent) message.obj;
+ final int policyFlags = message.arg1;
+ notifyKeyEventInternal(event, policyFlags);
+ } break;
+ case MSG_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE: {
+ notifyClearAccessibilityNodeInfoCacheInternal();
+ } break;
+ case MSG_ON_KEY_EVENT_TIMEOUT: {
+ PendingEvent eventState = (PendingEvent) message.obj;
+ setOnKeyEventResult(false, eventState.sequence);
+ } break;
+ default: {
+ throw new IllegalArgumentException("Unknown message: " + type);
+ }
+ }
+ }
+ }
+
+ private final class KeyEventDispatcher {
+
+ private static final long ON_KEY_EVENT_TIMEOUT_MILLIS = 500;
+
+ private PendingEvent mPendingEvents;
+
+ private final InputEventConsistencyVerifier mSentEventsVerifier =
+ InputEventConsistencyVerifier.isInstrumentationEnabled()
+ ? new InputEventConsistencyVerifier(
+ this, 0, KeyEventDispatcher.class.getSimpleName()) : null;
+
+ public void notifyKeyEvent(KeyEvent event, int policyFlags) {
+ final PendingEvent pendingEvent;
+
+ synchronized (mLock) {
+ pendingEvent = addPendingEventLocked(event, policyFlags);
+ }
+
+ Message message = mInvocationHandler.obtainMessage(
+ InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT, pendingEvent);
+ mInvocationHandler.sendMessageDelayed(message, ON_KEY_EVENT_TIMEOUT_MILLIS);
+
+ try {
+ // Accessibility services are exclusively not in the system
+ // process, therefore no need to clone the motion event to
+ // prevent tampering. It will be cloned in the IPC call.
+ mServiceInterface.onKeyEvent(pendingEvent.event, pendingEvent.sequence);
+ } catch (RemoteException re) {
+ setOnKeyEventResult(false, pendingEvent.sequence);
+ }
+ }
+
+ public void setOnKeyEventResult(boolean handled, int sequence) {
+ synchronized (mLock) {
+ PendingEvent pendingEvent = removePendingEventLocked(sequence);
+ if (pendingEvent != null) {
+ mInvocationHandler.removeMessages(
+ InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT,
+ pendingEvent);
+ pendingEvent.handled = handled;
+ finishPendingEventLocked(pendingEvent);
+ }
+ }
+ }
+
+ public void flush() {
+ synchronized (mLock) {
+ cancelAllPendingEventsLocked();
+ if (mSentEventsVerifier != null) {
+ mSentEventsVerifier.reset();
+ }
+ }
+ }
+
+ private PendingEvent addPendingEventLocked(KeyEvent event, int policyFlags) {
+ final int sequence = event.getSequenceNumber();
+ PendingEvent pendingEvent = obtainPendingEventLocked(event, policyFlags, sequence);
+ pendingEvent.next = mPendingEvents;
+ mPendingEvents = pendingEvent;
+ return pendingEvent;
+ }
+
+ private PendingEvent removePendingEventLocked(int sequence) {
+ PendingEvent previous = null;
+ PendingEvent current = mPendingEvents;
+
+ while (current != null) {
+ if (current.sequence == sequence) {
+ if (previous != null) {
+ previous.next = current.next;
+ } else {
+ mPendingEvents = current.next;
+ }
+ current.next = null;
+ return current;
+ }
+ previous = current;
+ current = current.next;
+ }
+ return null;
+ }
+
+ private void finishPendingEventLocked(PendingEvent pendingEvent) {
+ if (!pendingEvent.handled) {
+ sendKeyEventToInputFilter(pendingEvent.event, pendingEvent.policyFlags);
+ }
+ // Nullify the event since we do not want it to be
+ // recycled yet. It will be sent to the input filter.
+ pendingEvent.event = null;
+ recyclePendingEventLocked(pendingEvent);
+ }
+
+ private void sendKeyEventToInputFilter(KeyEvent event, int policyFlags) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Injecting event: " + event);
+ }
+ if (mSentEventsVerifier != null) {
+ mSentEventsVerifier.onKeyEvent(event, 0);
+ }
+ policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER;
+ mMainHandler.obtainMessage(MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER,
+ policyFlags, 0, event).sendToTarget();
+ }
+
+ private void cancelAllPendingEventsLocked() {
+ while (mPendingEvents != null) {
+ PendingEvent pendingEvent = removePendingEventLocked(mPendingEvents.sequence);
+ pendingEvent.handled = false;
+ mInvocationHandler.removeMessages(InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT,
+ pendingEvent);
+ finishPendingEventLocked(pendingEvent);
+ }
+ }
+ }
+ }
+
+ private static final class PendingEvent {
+ PendingEvent next;
+
+ KeyEvent event;
+ int policyFlags;
+ int sequence;
+ boolean handled;
+
+ public void clear() {
+ if (event != null) {
+ event.recycle();
+ event = null;
+ }
+ next = null;
+ policyFlags = 0;
+ sequence = 0;
+ handled = false;
+ }
}
final class SecurityPolicy {
diff --git a/services/java/com/android/server/accessibility/EventStreamTransformation.java b/services/java/com/android/server/accessibility/EventStreamTransformation.java
index 3289a15..8c93e7b 100644
--- a/services/java/com/android/server/accessibility/EventStreamTransformation.java
+++ b/services/java/com/android/server/accessibility/EventStreamTransformation.java
@@ -57,7 +57,7 @@ import android.view.accessibility.AccessibilityEvent;
interface EventStreamTransformation {
/**
- * Receives motion event. Passed are the event transformed by previous
+ * Receives a motion event. Passed are the event transformed by previous
* transformations and the raw event to which no transformations have
* been applied.
*
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index 14d808f..fd7cd78 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -22,6 +22,7 @@ import android.accounts.AccountAndUser;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorDescription;
+import android.accounts.CantAddAccountActivity;
import android.accounts.GrantCredentialsPermissionActivity;
import android.accounts.IAccountAuthenticator;
import android.accounts.IAccountAuthenticatorResponse;
@@ -1456,6 +1457,14 @@ public class AccountManagerService
"User is not allowed to add an account!");
} catch (RemoteException re) {
}
+ Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
+ cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ long identityToken = clearCallingIdentity();
+ try {
+ mContext.startActivityAsUser(cantAddAccount, UserHandle.CURRENT);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
return;
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7710f13..bc1df85 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -936,6 +936,12 @@ public final class ActivityManagerService extends ActivityManagerNative
CompatModeDialog mCompatModeDialog;
long mLastMemUsageReportTime = 0;
+ /**
+ * Flag whether the current user is a "monkey", i.e. whether
+ * the UI is driven by a UI automation tool.
+ */
+ private boolean mUserIsMonkey;
+
final Handler mHandler = new Handler() {
//public Handler() {
// if (localLOGV) Slog.v(TAG, "Handler started!");
@@ -3858,6 +3864,9 @@ public final class ActivityManagerService extends ActivityManagerNative
if (app.userId != userId) {
continue;
}
+ if (appId >= 0 && UserHandle.getAppId(app.uid) != appId) {
+ continue;
+ }
// Package has been specified, we want to hit all processes
// that match it. We need to qualify this by the processes
// that are running under the specified app and user ID.
@@ -4574,7 +4583,7 @@ public final class ActivityManagerService extends ActivityManagerNative
public String getCallingPackage(IBinder token) {
synchronized (this) {
ActivityRecord r = getCallingRecordLocked(token);
- return r != null && r.app != null ? r.info.packageName : null;
+ return r != null ? r.info.packageName : null;
}
}
@@ -7431,11 +7440,27 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ public void setUserIsMonkey(boolean userIsMonkey) {
+ synchronized (this) {
+ synchronized (mPidsSelfLocked) {
+ final int callingPid = Binder.getCallingPid();
+ ProcessRecord precessRecord = mPidsSelfLocked.get(callingPid);
+ if (precessRecord == null) {
+ throw new SecurityException("Unknown process: " + callingPid);
+ }
+ if (precessRecord.instrumentationUiAutomationConnection == null) {
+ throw new SecurityException("Only an instrumentation process "
+ + "with a UiAutomation can call setUserIsMonkey");
+ }
+ }
+ mUserIsMonkey = userIsMonkey;
+ }
+ }
+
public boolean isUserAMonkey() {
- // For now the fact that there is a controller implies
- // we have a monkey.
synchronized (this) {
- return mController != null;
+ // If there is a controller also implies the user is a monkey.
+ return (mUserIsMonkey || mController != null);
}
}
@@ -7733,6 +7758,18 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
+ public void killUid(int uid, String reason) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("killUid only available to the system");
+ }
+ synchronized (this) {
+ killPackageProcessesLocked(null, UserHandle.getAppId(uid), UserHandle.getUserId(uid),
+ ProcessList.FOREGROUND_APP_ADJ-1, false, true, true, false,
+ reason != null ? reason : "kill uid");
+ }
+ }
+
+ @Override
public boolean killProcessesBelowForeground(String reason) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("killProcessesBelowForeground() only available to system");
@@ -8350,13 +8387,13 @@ public final class ActivityManagerService extends ActivityManagerNative
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
- handleApplicationCrashInner(r, processName, crashInfo);
+ handleApplicationCrashInner("crash", r, processName, crashInfo);
}
/* Native crash reporting uses this inner version because it needs to be somewhat
* decoupled from the AM-managed cleanup lifecycle
*/
- void handleApplicationCrashInner(ProcessRecord r, String processName,
+ void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
UserHandle.getUserId(Binder.getCallingUid()), processName,
@@ -8366,7 +8403,7 @@ public final class ActivityManagerService extends ActivityManagerNative
crashInfo.throwFileName,
crashInfo.throwLineNumber);
- addErrorToDropBox("crash", r, processName, null, null, null, null, null, crashInfo);
+ addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
crashApplication(r, crashInfo);
}
@@ -12420,6 +12457,9 @@ public final class ActivityManagerService extends ActivityManagerNative
} catch (RemoteException re) {
/* ignore */
}
+ // Only a UiAutomation can set this flag and now that
+ // it is finished we make sure it is reset to its default.
+ mUserIsMonkey = false;
}
app.instrumentationWatcher = null;
app.instrumentationUiAutomationConnection = null;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 3d7da7b..0f1700d 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -47,6 +47,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -2594,8 +2595,7 @@ final class ActivityStack {
}
boolean abort = !mService.mIntentFirewall.checkStartActivity(intent,
- callerApp==null?null:callerApp.info, callingPackage, callingUid, callingPid,
- resolvedType, aInfo);
+ callerApp==null?null:callerApp.info, callingUid, callingPid, resolvedType, aInfo);
if (mMainStack) {
if (mService.mController != null) {
@@ -4601,11 +4601,13 @@ final class ActivityStack {
private final void logStartActivity(int tag, ActivityRecord r,
TaskRecord task) {
+ final Uri data = r.intent.getData();
+ final String strData = data != null ? data.toSafeString() : null;
+
EventLog.writeEvent(tag,
r.userId, System.identityHashCode(r), task.taskId,
r.shortComponentName, r.intent.getAction(),
- r.intent.getType(), r.intent.getDataString(),
- r.intent.getFlags());
+ r.intent.getType(), strData, r.intent.getFlags());
}
/**
diff --git a/services/java/com/android/server/am/NativeCrashListener.java b/services/java/com/android/server/am/NativeCrashListener.java
index e83433f..0688c50 100644
--- a/services/java/com/android/server/am/NativeCrashListener.java
+++ b/services/java/com/android/server/am/NativeCrashListener.java
@@ -82,7 +82,7 @@ class NativeCrashListener extends Thread {
ci.stackTrace = mCrashReport;
if (DEBUG) Slog.v(TAG, "Calling handleApplicationCrash()");
- mAm.handleApplicationCrashInner(mApp, mApp.processName, ci);
+ mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);
if (DEBUG) Slog.v(TAG, "<-- handleApplicationCrash() returned");
} catch (Exception e) {
Slog.e(TAG, "Unable to report native crash", e);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 8ff1c7d..fccaab5 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -376,37 +376,37 @@ class ServiceRecord extends Binder {
// icon, but this used to be able to slip through, so for
// those dirty apps give it the app's icon.
foregroundNoti.icon = appInfo.icon;
- if (foregroundNoti.contentView == null) {
- // In this case the app may not have specified a
- // content view... so we'll give them something to show.
- CharSequence appName = appInfo.loadLabel(
- ams.mContext.getPackageManager());
- if (appName == null) {
- appName = appInfo.packageName;
- }
- Context ctx = null;
- try {
- ctx = ams.mContext.createPackageContext(
- appInfo.packageName, 0);
- Intent runningIntent = new Intent(
- Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
- runningIntent.setData(Uri.fromParts("package",
- appInfo.packageName, null));
- PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0,
- runningIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- foregroundNoti.setLatestEventInfo(ctx,
- ams.mContext.getString(
- com.android.internal.R.string
- .app_running_notification_title,
- appName),
- ams.mContext.getString(
- com.android.internal.R.string
- .app_running_notification_text,
- appName),
- pi);
- } catch (PackageManager.NameNotFoundException e) {
- foregroundNoti.icon = 0;
- }
+
+ // Do not allow apps to present a sneaky invisible content view either.
+ foregroundNoti.contentView = null;
+ foregroundNoti.bigContentView = null;
+ CharSequence appName = appInfo.loadLabel(
+ ams.mContext.getPackageManager());
+ if (appName == null) {
+ appName = appInfo.packageName;
+ }
+ Context ctx = null;
+ try {
+ ctx = ams.mContext.createPackageContext(
+ appInfo.packageName, 0);
+ Intent runningIntent = new Intent(
+ Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ runningIntent.setData(Uri.fromParts("package",
+ appInfo.packageName, null));
+ PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0,
+ runningIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ foregroundNoti.setLatestEventInfo(ctx,
+ ams.mContext.getString(
+ com.android.internal.R.string
+ .app_running_notification_title,
+ appName),
+ ams.mContext.getString(
+ com.android.internal.R.string
+ .app_running_notification_text,
+ appName),
+ pi);
+ } catch (PackageManager.NameNotFoundException e) {
+ foregroundNoti.icon = 0;
}
}
if (foregroundNoti.icon == 0) {
diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
index 68cf5fc..f82cf01 100644
--- a/services/java/com/android/server/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -459,7 +459,7 @@ public final class ContentService extends IContentService.Stub {
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- return syncManager.getSyncStorageEngine().getIsSyncable(
+ return syncManager.getIsSyncable(
account, userId, providerName);
}
} finally {
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
index b3f9bf1..1c883ec 100644
--- a/services/java/com/android/server/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -21,6 +21,7 @@ import android.accounts.AccountAndUser;
import android.accounts.AccountManager;
import android.app.ActivityManager;
import android.app.AlarmManager;
+import android.app.AppGlobals;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -41,6 +42,7 @@ import android.content.SyncInfo;
import android.content.SyncResult;
import android.content.SyncStatusInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.RegisteredServicesCache;
@@ -491,6 +493,36 @@ public class SyncManager {
return mSyncStorageEngine;
}
+ public int getIsSyncable(Account account, int userId, String providerName) {
+ int isSyncable = mSyncStorageEngine.getIsSyncable(account, userId, providerName);
+ UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
+
+ // If it's not a restricted user, return isSyncable
+ if (userInfo == null || !userInfo.isRestricted()) return isSyncable;
+
+ // Else check if the sync adapter has opted-in or not
+ RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
+ mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(providerName, account.type), userId);
+ if (syncAdapterInfo == null) return isSyncable;
+
+ PackageInfo pInfo = null;
+ try {
+ pInfo = AppGlobals.getPackageManager().getPackageInfo(
+ syncAdapterInfo.componentName.getPackageName(), 0, userId);
+ if (pInfo == null) return isSyncable;
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ return isSyncable;
+ }
+ if (pInfo.restrictedAccountType != null
+ && pInfo.restrictedAccountType.equals(account.type)) {
+ return isSyncable;
+ } else {
+ return 0;
+ }
+ }
+
private void ensureAlarmService() {
if (mAlarmService == null) {
mAlarmService = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
@@ -608,7 +640,7 @@ public class SyncManager {
}
for (String authority : syncableAuthorities) {
- int isSyncable = mSyncStorageEngine.getIsSyncable(account.account, account.userId,
+ int isSyncable = getIsSyncable(account.account, account.userId,
authority);
if (isSyncable == 0) {
continue;
@@ -1930,7 +1962,7 @@ public class SyncManager {
continue;
}
- if (mSyncStorageEngine.getIsSyncable(info.account, info.userId, info.authority)
+ if (getIsSyncable(info.account, info.userId, info.authority)
== 0) {
continue;
}
@@ -2069,7 +2101,7 @@ public class SyncManager {
}
// drop this sync request if it isn't syncable
- int syncableState = mSyncStorageEngine.getIsSyncable(
+ int syncableState = getIsSyncable(
op.account, op.userId, op.authority);
if (syncableState == 0) {
operationIterator.remove();
diff --git a/services/java/com/android/server/firewall/AndFilter.java b/services/java/com/android/server/firewall/AndFilter.java
index cabf00b..e4276d0 100644
--- a/services/java/com/android/server/firewall/AndFilter.java
+++ b/services/java/com/android/server/firewall/AndFilter.java
@@ -26,11 +26,10 @@ import java.io.IOException;
class AndFilter extends FilterList {
@Override
public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
- String callerPackage, int callerUid, int callerPid, String resolvedType,
- ApplicationInfo resolvedApp) {
+ int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
for (int i=0; i<children.size(); i++) {
- if (!children.get(i).matches(ifw, intent, callerApp, callerPackage, callerUid,
- callerPid, resolvedType, resolvedApp)) {
+ if (!children.get(i).matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
+ resolvedApp)) {
return false;
}
}
diff --git a/services/java/com/android/server/firewall/CategoryFilter.java b/services/java/com/android/server/firewall/CategoryFilter.java
index d5e9fe8..4938cb8 100644
--- a/services/java/com/android/server/firewall/CategoryFilter.java
+++ b/services/java/com/android/server/firewall/CategoryFilter.java
@@ -34,7 +34,7 @@ class CategoryFilter implements Filter {
}
@Override
- public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp, String callerPackage,
+ public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
Set<String> categories = intent.getCategories();
if (categories == null) {
diff --git a/services/java/com/android/server/firewall/Filter.java b/services/java/com/android/server/firewall/Filter.java
index 7639466..0e783e8 100644
--- a/services/java/com/android/server/firewall/Filter.java
+++ b/services/java/com/android/server/firewall/Filter.java
@@ -26,17 +26,14 @@ interface Filter {
* @param ifw The IntentFirewall instance
* @param intent The intent being started/bound/broadcast
* @param callerApp An ApplicationInfo of an application in the caller's process. This may not
- * be the specific app that is actually sending the intent. This also may be
- * null, if the caller is the system process, or an unrecognized process (e.g.
- * am start)
- * @param callerPackage The package name of the component sending the intent. This value is
-* provided by the caller and might be forged/faked.
+ * be the specific app that is actually sending the intent. This also may be
+ * null, if the caller is the system process, or an unrecognized process (e.g.
+ * am start)
* @param callerUid
* @param callerPid
* @param resolvedType The resolved mime type of the intent
* @param resolvedApp The application that contains the resolved component that the intent is
*/
boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
- String callerPackage, int callerUid, int callerPid, String resolvedType,
- ApplicationInfo resolvedApp);
+ int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp);
}
diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/java/com/android/server/firewall/IntentFirewall.java
index ebbbd86..08e6b45 100644
--- a/services/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/java/com/android/server/firewall/IntentFirewall.java
@@ -16,18 +16,21 @@
package com.android.server.firewall;
+import android.app.AppGlobals;
+import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.os.Environment;
-import android.os.ServiceManager;
+import android.os.RemoteException;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
+import com.android.server.EventLogTags;
import com.android.server.IntentResolver;
-import com.android.server.pm.PackageManagerService;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -42,13 +45,22 @@ import java.util.List;
public class IntentFirewall {
private static final String TAG = "IntentFirewall";
- private static final String RULES_FILENAME = "ifw.xml";
+ // e.g. /data/system/ifw/ifw.xml or /data/secure/system/ifw/ifw.xml
+ private static final File RULES_FILE =
+ new File(Environment.getSystemSecureDirectory(), "ifw/ifw.xml");
+
+ private static final int LOG_PACKAGES_MAX_LENGTH = 150;
+ private static final int LOG_PACKAGES_SUFFICIENT_LENGTH = 125;
private static final String TAG_RULES = "rules";
private static final String TAG_ACTIVITY = "activity";
private static final String TAG_SERVICE = "service";
private static final String TAG_BROADCAST = "broadcast";
+ private static final int TYPE_ACTIVITY = 0;
+ private static final int TYPE_SERVICE = 1;
+ private static final int TYPE_BROADCAST = 2;
+
private static final HashMap<String, FilterFactory> factoryMap;
private final AMSInterface mAms;
@@ -74,7 +86,6 @@ public class IntentFirewall {
StringFilter.HOST,
StringFilter.MIME_TYPE,
StringFilter.PATH,
- StringFilter.SENDER_PACKAGE,
StringFilter.SSP,
CategoryFilter.FACTORY,
@@ -93,22 +104,19 @@ public class IntentFirewall {
public IntentFirewall(AMSInterface ams) {
mAms = ams;
- File dataSystemDir = new File(Environment.getDataDirectory(), "system");
- File rulesFile = new File(dataSystemDir, RULES_FILENAME);
- readRules(rulesFile);
+ readRules(getRulesFile());
}
- public boolean checkStartActivity(Intent intent, ApplicationInfo callerApp,
- String callerPackage, int callerUid, int callerPid, String resolvedType,
- ActivityInfo resolvedActivity) {
+ public boolean checkStartActivity(Intent intent, ApplicationInfo callerApp, int callerUid,
+ int callerPid, String resolvedType, ActivityInfo resolvedActivity) {
List<Rule> matchingRules = mActivityResolver.queryIntent(intent, resolvedType, false, 0);
boolean log = false;
boolean block = false;
for (int i=0; i< matchingRules.size(); i++) {
Rule rule = matchingRules.get(i);
- if (rule.matches(this, intent, callerApp, callerPackage, callerUid, callerPid,
- resolvedType, resolvedActivity.applicationInfo)) {
+ if (rule.matches(this, intent, callerApp, callerUid, callerPid, resolvedType,
+ resolvedActivity.applicationInfo)) {
block |= rule.getBlock();
log |= rule.getLog();
@@ -121,12 +129,85 @@ public class IntentFirewall {
}
if (log) {
- // TODO: log info about intent to event log
+ logIntent(TYPE_ACTIVITY, intent, callerUid, resolvedType);
}
return !block;
}
+ private static void logIntent(int intentType, Intent intent, int callerUid,
+ String resolvedType) {
+ // The component shouldn't be null, but let's double check just to be safe
+ ComponentName cn = intent.getComponent();
+ String shortComponent = null;
+ if (cn != null) {
+ shortComponent = cn.flattenToShortString();
+ }
+
+ String callerPackages = null;
+ int callerPackageCount = 0;
+ IPackageManager pm = AppGlobals.getPackageManager();
+ if (pm != null) {
+ try {
+ String[] callerPackagesArray = pm.getPackagesForUid(callerUid);
+ if (callerPackagesArray != null) {
+ callerPackageCount = callerPackagesArray.length;
+ callerPackages = joinPackages(callerPackagesArray);
+ }
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Remote exception while retrieving packages", ex);
+ }
+ }
+
+ EventLogTags.writeIfwIntentMatched(intentType, shortComponent, callerUid,
+ callerPackageCount, callerPackages, intent.getAction(), resolvedType,
+ intent.getDataString(), intent.getFlags());
+ }
+
+ /**
+ * Joins a list of package names such that the resulting string is no more than
+ * LOG_PACKAGES_MAX_LENGTH.
+ *
+ * Only full package names will be added to the result, unless every package is longer than the
+ * limit, in which case one of the packages will be truncated and added. In this case, an
+ * additional '-' character will be added to the end of the string, to denote the truncation.
+ *
+ * If it encounters a package that won't fit in the remaining space, it will continue on to the
+ * next package, unless the total length of the built string so far is greater than
+ * LOG_PACKAGES_SUFFICIENT_LENGTH, in which case it will stop and return what it has.
+ */
+ private static String joinPackages(String[] packages) {
+ boolean first = true;
+ StringBuilder sb = new StringBuilder();
+ for (int i=0; i<packages.length; i++) {
+ String pkg = packages[i];
+
+ // + 1 length for the comma. This logic technically isn't correct for the first entry,
+ // but it's not critical.
+ if (sb.length() + pkg.length() + 1 < LOG_PACKAGES_MAX_LENGTH) {
+ if (!first) {
+ sb.append(',');
+ } else {
+ first = false;
+ }
+ sb.append(pkg);
+ } else if (sb.length() >= LOG_PACKAGES_SUFFICIENT_LENGTH) {
+ return sb.toString();
+ }
+ }
+ if (sb.length() == 0 && packages.length > 0) {
+ String pkg = packages[0];
+ // truncating from the end - the last part of the package name is more likely to be
+ // interesting/unique
+ return pkg.substring(pkg.length() - LOG_PACKAGES_MAX_LENGTH + 1) + '-';
+ }
+ return null;
+ }
+
+ public static File getRulesFile() {
+ return RULES_FILE;
+ }
+
private void readRules(File rulesFile) {
FileInputStream fis;
try {
@@ -309,7 +390,12 @@ public class IntentFirewall {
}
boolean signaturesMatch(int uid1, int uid2) {
- PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
- return pm.checkUidSignatures(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
+ try {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ return pm.checkUidSignatures(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Remote exception while checking signatures", ex);
+ return false;
+ }
}
}
diff --git a/services/java/com/android/server/firewall/NotFilter.java b/services/java/com/android/server/firewall/NotFilter.java
index 2ff108a..f0fc337 100644
--- a/services/java/com/android/server/firewall/NotFilter.java
+++ b/services/java/com/android/server/firewall/NotFilter.java
@@ -33,10 +33,9 @@ class NotFilter implements Filter {
@Override
public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
- String callerPackage, int callerUid, int callerPid, String resolvedType,
- ApplicationInfo resolvedApp) {
- return !mChild.matches(ifw, intent, callerApp, callerPackage, callerUid, callerPid,
- resolvedType, resolvedApp);
+ int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+ return !mChild.matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
+ resolvedApp);
}
public static final FilterFactory FACTORY = new FilterFactory("not") {
diff --git a/services/java/com/android/server/firewall/OrFilter.java b/services/java/com/android/server/firewall/OrFilter.java
index 1ed1c85..72db31e 100644
--- a/services/java/com/android/server/firewall/OrFilter.java
+++ b/services/java/com/android/server/firewall/OrFilter.java
@@ -26,11 +26,10 @@ import java.io.IOException;
class OrFilter extends FilterList {
@Override
public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
- String callerPackage, int callerUid, int callerPid, String resolvedType,
- ApplicationInfo resolvedApp) {
+ int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
for (int i=0; i<children.size(); i++) {
- if (children.get(i).matches(ifw, intent, callerApp, callerPackage, callerUid, callerPid,
- resolvedType, resolvedApp)) {
+ if (children.get(i).matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
+ resolvedApp)) {
return true;
}
}
diff --git a/services/java/com/android/server/firewall/PortFilter.java b/services/java/com/android/server/firewall/PortFilter.java
index 2b2a198..fe7e085 100644
--- a/services/java/com/android/server/firewall/PortFilter.java
+++ b/services/java/com/android/server/firewall/PortFilter.java
@@ -42,8 +42,7 @@ class PortFilter implements Filter {
@Override
public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
- String callerPackage, int callerUid, int callerPid, String resolvedType,
- ApplicationInfo resolvedApp) {
+ int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
int port = -1;
Uri uri = intent.getData();
if (uri != null) {
diff --git a/services/java/com/android/server/firewall/SenderFilter.java b/services/java/com/android/server/firewall/SenderFilter.java
index 0b790bd..58bdd73 100644
--- a/services/java/com/android/server/firewall/SenderFilter.java
+++ b/services/java/com/android/server/firewall/SenderFilter.java
@@ -68,8 +68,7 @@ class SenderFilter {
private static final Filter SIGNATURE = new Filter() {
@Override
public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
- String callerPackage, int callerUid, int callerPid, String resolvedType,
- ApplicationInfo resolvedApp) {
+ int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
if (callerApp == null) {
return false;
}
@@ -80,8 +79,7 @@ class SenderFilter {
private static final Filter SYSTEM = new Filter() {
@Override
public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
- String callerPackage, int callerUid, int callerPid, String resolvedType,
- ApplicationInfo resolvedApp) {
+ int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
if (callerApp == null) {
// if callerApp is null, the caller is the system process
return false;
@@ -93,8 +91,7 @@ class SenderFilter {
private static final Filter SYSTEM_OR_SIGNATURE = new Filter() {
@Override
public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
- String callerPackage, int callerUid, int callerPid, String resolvedType,
- ApplicationInfo resolvedApp) {
+ int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
return isSystemApp(callerApp, callerUid, callerPid) ||
ifw.signaturesMatch(callerUid, resolvedApp.uid);
}
@@ -103,8 +100,7 @@ class SenderFilter {
private static final Filter USER_ID = new Filter() {
@Override
public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
- String callerPackage, int callerUid, int callerPid, String resolvedType,
- ApplicationInfo resolvedApp) {
+ int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
// This checks whether the caller is either the system process, or has the same user id
// I.e. the same app, or an app that uses the same shared user id.
// This is the same set of applications that would be able to access the component if
diff --git a/services/java/com/android/server/firewall/SenderPermissionFilter.java b/services/java/com/android/server/firewall/SenderPermissionFilter.java
index 02d8b15..310da20 100644
--- a/services/java/com/android/server/firewall/SenderPermissionFilter.java
+++ b/services/java/com/android/server/firewall/SenderPermissionFilter.java
@@ -34,8 +34,7 @@ class SenderPermissionFilter implements Filter {
@Override
public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
- String callerPackage, int callerUid, int callerPid, String resolvedType,
- ApplicationInfo resolvedApp) {
+ int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
// We assume the component is exported here. If the component is not exported, then
// ActivityManager would only resolve to this component for callers from the same uid.
// In this case, it doesn't matter whether the component is exported or not.
diff --git a/services/java/com/android/server/firewall/StringFilter.java b/services/java/com/android/server/firewall/StringFilter.java
index de5a69f..ed5d3f3 100644
--- a/services/java/com/android/server/firewall/StringFilter.java
+++ b/services/java/com/android/server/firewall/StringFilter.java
@@ -119,10 +119,9 @@ abstract class StringFilter implements Filter {
protected abstract boolean matchesValue(String value);
@Override
- public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp, String callerPackage,
+ public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
- String value = mValueProvider.getValue(intent, callerApp, callerPackage, resolvedType,
- resolvedApp);
+ String value = mValueProvider.getValue(intent, callerApp, resolvedType, resolvedApp);
return matchesValue(value);
}
@@ -137,7 +136,7 @@ abstract class StringFilter implements Filter {
}
public abstract String getValue(Intent intent, ApplicationInfo callerApp,
- String callerPackage, String resolvedType, ApplicationInfo resolvedApp);
+ String resolvedType, ApplicationInfo resolvedApp);
}
private static class EqualsFilter extends StringFilter {
@@ -231,8 +230,8 @@ abstract class StringFilter implements Filter {
public static final ValueProvider COMPONENT = new ValueProvider("component") {
@Override
- public String getValue(Intent intent, ApplicationInfo callerApp, String callerPackage,
- String resolvedType, ApplicationInfo resolvedApp) {
+ public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+ ApplicationInfo resolvedApp) {
ComponentName cn = intent.getComponent();
if (cn != null) {
return cn.flattenToString();
@@ -243,8 +242,8 @@ abstract class StringFilter implements Filter {
public static final ValueProvider COMPONENT_NAME = new ValueProvider("component-name") {
@Override
- public String getValue(Intent intent, ApplicationInfo callerApp, String callerPackage,
- String resolvedType, ApplicationInfo resolvedApp) {
+ public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+ ApplicationInfo resolvedApp) {
ComponentName cn = intent.getComponent();
if (cn != null) {
return cn.getClassName();
@@ -255,8 +254,8 @@ abstract class StringFilter implements Filter {
public static final ValueProvider COMPONENT_PACKAGE = new ValueProvider("component-package") {
@Override
- public String getValue(Intent intent, ApplicationInfo callerApp, String callerPackage,
- String resolvedType, ApplicationInfo resolvedApp) {
+ public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+ ApplicationInfo resolvedApp) {
ComponentName cn = intent.getComponent();
if (cn != null) {
return cn.getPackageName();
@@ -265,28 +264,18 @@ abstract class StringFilter implements Filter {
}
};
- public static final ValueProvider SENDER_PACKAGE = new ValueProvider("sender-package") {
- @Override
- public String getValue(Intent intent, ApplicationInfo callerApp, String callerPackage,
- String resolvedType, ApplicationInfo resolvedApp) {
- // TODO: We can't trust this value, so maybe should check all packages in the caller process?
- return callerPackage;
- }
- };
-
-
public static final FilterFactory ACTION = new ValueProvider("action") {
@Override
- public String getValue(Intent intent, ApplicationInfo callerApp, String callerPackage,
- String resolvedType, ApplicationInfo resolvedApp) {
+ public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+ ApplicationInfo resolvedApp) {
return intent.getAction();
}
};
public static final ValueProvider DATA = new ValueProvider("data") {
@Override
- public String getValue(Intent intent, ApplicationInfo callerApp, String callerPackage,
- String resolvedType, ApplicationInfo resolvedApp) {
+ public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+ ApplicationInfo resolvedApp) {
Uri data = intent.getData();
if (data != null) {
return data.toString();
@@ -297,16 +286,16 @@ abstract class StringFilter implements Filter {
public static final ValueProvider MIME_TYPE = new ValueProvider("mime-type") {
@Override
- public String getValue(Intent intent, ApplicationInfo callerApp, String callerPackage,
- String resolvedType, ApplicationInfo resolvedApp) {
+ public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+ ApplicationInfo resolvedApp) {
return resolvedType;
}
};
public static final ValueProvider SCHEME = new ValueProvider("scheme") {
@Override
- public String getValue(Intent intent, ApplicationInfo callerApp, String callerPackage,
- String resolvedType, ApplicationInfo resolvedApp) {
+ public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+ ApplicationInfo resolvedApp) {
Uri data = intent.getData();
if (data != null) {
return data.getScheme();
@@ -317,8 +306,8 @@ abstract class StringFilter implements Filter {
public static final ValueProvider SSP = new ValueProvider("scheme-specific-part") {
@Override
- public String getValue(Intent intent, ApplicationInfo callerApp, String callerPackage,
- String resolvedType, ApplicationInfo resolvedApp) {
+ public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+ ApplicationInfo resolvedApp) {
Uri data = intent.getData();
if (data != null) {
return data.getSchemeSpecificPart();
@@ -329,8 +318,8 @@ abstract class StringFilter implements Filter {
public static final ValueProvider HOST = new ValueProvider("host") {
@Override
- public String getValue(Intent intent, ApplicationInfo callerApp, String callerPackage,
- String resolvedType, ApplicationInfo resolvedApp) {
+ public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+ ApplicationInfo resolvedApp) {
Uri data = intent.getData();
if (data != null) {
return data.getHost();
@@ -341,8 +330,8 @@ abstract class StringFilter implements Filter {
public static final ValueProvider PATH = new ValueProvider("path") {
@Override
- public String getValue(Intent intent, ApplicationInfo callerApp, String callerPackage,
- String resolvedType, ApplicationInfo resolvedApp) {
+ public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+ ApplicationInfo resolvedApp) {
Uri data = intent.getData();
if (data != null) {
return data.getPath();
diff --git a/services/java/com/android/server/location/GeofenceProxy.java b/services/java/com/android/server/location/GeofenceProxy.java
new file mode 100644
index 0000000..36e9fcc
--- /dev/null
+++ b/services/java/com/android/server/location/GeofenceProxy.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2013 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.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.hardware.location.GeofenceHardwareService;
+import android.hardware.location.IGeofenceHardware;
+import android.location.IGeofenceProvider;
+import android.location.IGpsGeofenceHardware;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import com.android.server.ServiceWatcher;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+public final class GeofenceProxy {
+ private static final String TAG = "GeofenceProxy";
+ private static final String SERVICE_ACTION =
+ "com.android.location.service.GeofenceProvider";
+ private ServiceWatcher mServiceWatcher;
+ private Context mContext;
+ private IGeofenceHardware mGeofenceHardware;
+ private IGpsGeofenceHardware mGpsGeofenceHardware;
+
+ private static final int GEOFENCE_PROVIDER_CONNECTED = 1;
+ private static final int GEOFENCE_HARDWARE_CONNECTED = 2;
+ private static final int GEOFENCE_HARDWARE_DISCONNECTED = 3;
+ private static final int GEOFENCE_GPS_HARDWARE_CONNECTED = 4;
+ private static final int GEOFENCE_GPS_HARDWARE_DISCONNECTED = 5;
+
+ private Runnable mRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mHandler.sendEmptyMessage(GEOFENCE_PROVIDER_CONNECTED);
+ }
+ };
+
+ public static GeofenceProxy createAndBind(Context context,
+ List<String> initialPackageNames, Handler handler, IGpsGeofenceHardware gpsGeofence) {
+ GeofenceProxy proxy = new GeofenceProxy(context, initialPackageNames, handler, gpsGeofence);
+ if (proxy.bindGeofenceProvider()) {
+ return proxy;
+ } else {
+ return null;
+ }
+ }
+
+ private GeofenceProxy(Context context, List<String> initialPackageName, Handler handler,
+ IGpsGeofenceHardware gpsGeofence) {
+ mContext = context;
+ mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, initialPackageName,
+ mRunnable, handler);
+ mGpsGeofenceHardware = gpsGeofence;
+ bindHardwareGeofence();
+ }
+
+ private boolean bindGeofenceProvider() {
+ return mServiceWatcher.start();
+ }
+
+ private IGeofenceProvider getGeofenceProviderService() {
+ return IGeofenceProvider.Stub.asInterface(mServiceWatcher.getBinder());
+ }
+
+ private void bindHardwareGeofence() {
+ mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
+ mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.OWNER);
+ }
+
+ private ServiceConnection mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mGeofenceHardware = IGeofenceHardware.Stub.asInterface(service);
+ mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_CONNECTED);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mGeofenceHardware = null;
+ mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_DISCONNECTED);
+ }
+ };
+
+ private void setGeofenceHardwareInProvider() {
+ try {
+ getGeofenceProviderService().setGeofenceHardware(mGeofenceHardware);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote Exception: setGeofenceHardwareInProvider: " + e);
+ }
+ }
+
+ private void setGpsGeofence() {
+ try {
+ mGeofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error while connecting to GeofenceHardwareService");
+ }
+ }
+
+
+ // This needs to be reworked, when more services get added,
+ // Might need a state machine or add a framework utility class,
+ private Handler mHandler = new Handler() {
+ private boolean mGeofenceHardwareConnected = false;
+ private boolean mGeofenceProviderConnected = false;
+
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case GEOFENCE_PROVIDER_CONNECTED:
+ mGeofenceProviderConnected = true;
+ if (mGeofenceHardwareConnected) {
+ setGeofenceHardwareInProvider();
+ }
+ break;
+ case GEOFENCE_HARDWARE_CONNECTED:
+ setGpsGeofence();
+ mGeofenceHardwareConnected = true;
+ if (mGeofenceProviderConnected) {
+ setGeofenceHardwareInProvider();
+ }
+ break;
+ case GEOFENCE_HARDWARE_DISCONNECTED:
+ mGeofenceHardwareConnected = false;
+ setGeofenceHardwareInProvider();
+ break;
+ }
+ }
+ };
+}
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 3552b6a..1ebff67 100644
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -24,7 +24,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
+import android.hardware.location.GeofenceHardwareImpl;
+import android.hardware.location.IGeofenceHardware;
import android.location.Criteria;
+import android.location.IGpsGeofenceHardware;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
import android.location.ILocationManager;
@@ -314,6 +317,8 @@ public class GpsLocationProvider implements LocationProviderInterface {
// only modified on handler thread
private WorkSource mClientSource = new WorkSource();
+ private GeofenceHardwareImpl mGeofenceHardwareImpl;
+
private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
@Override
public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
@@ -367,6 +372,10 @@ public class GpsLocationProvider implements LocationProviderInterface {
return mGpsStatusProvider;
}
+ public IGpsGeofenceHardware getGpsGeofenceProxy() {
+ return mGpsGeofenceBinder;
+ }
+
private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -918,6 +927,31 @@ public class GpsLocationProvider implements LocationProviderInterface {
return result;
}
+ private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
+ public boolean isHardwareGeofenceSupported() {
+ return native_is_geofence_supported();
+ }
+
+ public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
+ double longitude, double radius, int lastTransition, int monitorTransitions,
+ int notificationResponsiveness, int unknownTimer) {
+ return native_add_geofence(geofenceId, latitude, longitude, radius,
+ lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
+ }
+
+ public boolean removeHardwareGeofence(int geofenceId) {
+ return native_remove_geofence(geofenceId);
+ }
+
+ public boolean pauseHardwareGeofence(int geofenceId) {
+ return native_pause_geofence(geofenceId);
+ }
+
+ public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
+ return native_resume_geofence(geofenceId, monitorTransition);
+ }
+ };
+
private boolean deleteAidingData(Bundle extras) {
int flags;
@@ -1017,6 +1051,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
return ((mEngineCapabilities & capability) != 0);
}
+
/**
* called from native code to update our position.
*/
@@ -1320,6 +1355,73 @@ public class GpsLocationProvider implements LocationProviderInterface {
sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
}
+ /**
+ * Called from native to report GPS Geofence transition
+ * All geofence callbacks are called on the same thread
+ */
+ private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
+ double longitude, double altitude, float speed, float bearing, float accuracy,
+ long timestamp, int transition, long transitionTimestamp) {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ mGeofenceHardwareImpl.reportGpsGeofenceTransition(geofenceId, flags, latitude, longitude,
+ altitude, speed, bearing, accuracy, timestamp, transition, transitionTimestamp);
+ }
+
+ /**
+ * called from native code to report GPS status change.
+ */
+ private void reportGeofenceStatus(int status, int flags, double latitude,
+ double longitude, double altitude, float speed, float bearing, float accuracy,
+ long timestamp) {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ mGeofenceHardwareImpl.reportGpsGeofenceStatus(status, flags, latitude, longitude, altitude,
+ speed, bearing, accuracy, timestamp);
+ }
+
+ /**
+ * called from native code - Geofence Add callback
+ */
+ private void reportGeofenceAddStatus(int geofenceId, int status) {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ mGeofenceHardwareImpl.reportGpsGeofenceAddStatus(geofenceId, status);
+ }
+
+ /**
+ * called from native code - Geofence Remove callback
+ */
+ private void reportGeofenceRemoveStatus(int geofenceId, int status) {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ mGeofenceHardwareImpl.reportGpsGeofenceRemoveStatus(geofenceId, status);
+ }
+
+ /**
+ * called from native code - Geofence Pause callback
+ */
+ private void reportGeofencePauseStatus(int geofenceId, int status) {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ mGeofenceHardwareImpl.reportGpsGeofencePauseStatus(geofenceId, status);
+ }
+
+ /**
+ * called from native code - Geofence Resume callback
+ */
+ private void reportGeofenceResumeStatus(int geofenceId, int status) {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ mGeofenceHardwareImpl.reportGpsGeofenceResumeStatus(geofenceId, status);
+ }
+
//=============================================================
// NI Client support
//=============================================================
@@ -1650,4 +1752,13 @@ public class GpsLocationProvider implements LocationProviderInterface {
private native void native_update_network_state(boolean connected, int type,
boolean roaming, boolean available, String extraInfo, String defaultAPN);
+
+ // Hardware Geofence support.
+ private static native boolean native_is_geofence_supported();
+ private static native boolean native_add_geofence(int geofenceId, double latitude,
+ double longitude, double radius, int lastTransition,int monitorTransitions,
+ int notificationResponsivenes, int unknownTimer);
+ private static native boolean native_remove_geofence(int geofenceId);
+ private static native boolean native_resume_geofence(int geofenceId, int transitions);
+ private static native boolean native_pause_geofence(int geofenceId);
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index ca7bba2..1b8ee82 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -2308,6 +2308,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
public void revokePermission(String packageName, String permissionName) {
+ int changedAppId = -1;
+
synchronized (mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
@@ -2335,6 +2337,30 @@ public class PackageManagerService extends IPackageManager.Stub {
gp.gids = removeInts(gp.gids, bp.gids);
}
mSettings.writeLPr();
+ changedAppId = ps.appId;
+ }
+ }
+
+ if (changedAppId >= 0) {
+ // We changed the perm on someone, kill its processes.
+ IActivityManager am = ActivityManagerNative.getDefault();
+ if (am != null) {
+ final int callingUserId = UserHandle.getCallingUserId();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ //XXX we should only revoke for the calling user's app permissions,
+ // but for now we impact all users.
+ //am.killUid(UserHandle.getUid(callingUserId, changedAppId),
+ // "revoke " + permissionName);
+ int[] users = sUserManager.getUserIds();
+ for (int user : users) {
+ am.killUid(UserHandle.getUid(user, changedAppId),
+ "revoke " + permissionName);
+ }
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
}
@@ -8223,6 +8249,24 @@ public class PackageManagerService extends IPackageManager.Stub {
updatePermissionsLPw(newPackage.packageName, newPackage,
UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
? UPDATE_PERMISSIONS_ALL : 0));
+ // For system-bundled packages, we assume that installing an upgraded version
+ // of the package implies that the user actually wants to run that new code,
+ // so we enable the package.
+ if (isSystemApp(newPackage)) {
+ // NB: implicit assumption that system package upgrades apply to all users
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
+ }
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (ps != null) {
+ if (res.origUsers != null) {
+ for (int userHandle : res.origUsers) {
+ ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
+ userHandle, installerPackageName);
+ }
+ }
+ }
+ }
res.name = pkgName;
res.uid = newPackage.applicationInfo.uid;
res.pkg = newPackage;
@@ -8647,16 +8691,10 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.writeLPr();
}
}
- // A user ID was deleted here. Go through all users and remove it from
- // KeyStore.
- final int appId = outInfo.removedAppId;
- if (appId != -1) {
- final KeyStore keyStore = KeyStore.getInstance();
- if (keyStore != null) {
- for (final int userId : sUserManager.getUserIds()) {
- keyStore.clearUid(UserHandle.getUid(userId, appId));
- }
- }
+ if (outInfo != null) {
+ // A user ID was deleted here. Go through all users and remove it
+ // from KeyStore.
+ removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);
}
}
@@ -8816,6 +8854,7 @@ public class PackageManagerService extends IPackageManager.Stub {
outInfo.removedUsers = new int[] {removeUser};
}
mInstaller.clearUserData(packageName, removeUser);
+ removeKeystoreDataIfNeeded(removeUser, appId);
schedulePackageCleaning(packageName, removeUser, false);
return true;
}
@@ -8968,29 +9007,34 @@ public class PackageManagerService extends IPackageManager.Stub {
}
PackageParser.Package p;
boolean dataOnly = false;
+ final int appId;
synchronized (mPackages) {
p = mPackages.get(packageName);
- if(p == null) {
+ if (p == null) {
dataOnly = true;
PackageSetting ps = mSettings.mPackages.get(packageName);
- if((ps == null) || (ps.pkg == null)) {
- Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ if ((ps == null) || (ps.pkg == null)) {
+ Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
return false;
}
p = ps.pkg;
}
- }
-
- if (!dataOnly) {
- //need to check this only for fully installed applications
- if (p == null) {
- Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
- return false;
+ if (!dataOnly) {
+ // need to check this only for fully installed applications
+ if (p == null) {
+ Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
+ return false;
+ }
+ final ApplicationInfo applicationInfo = p.applicationInfo;
+ if (applicationInfo == null) {
+ Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
+ return false;
+ }
}
- final ApplicationInfo applicationInfo = p.applicationInfo;
- if (applicationInfo == null) {
- Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
- return false;
+ if (p != null && p.applicationInfo != null) {
+ appId = p.applicationInfo.uid;
+ } else {
+ appId = -1;
}
}
int retCode = mInstaller.clearUserData(packageName, userId);
@@ -8999,9 +9043,33 @@ public class PackageManagerService extends IPackageManager.Stub {
+ packageName);
return false;
}
+ removeKeystoreDataIfNeeded(userId, appId);
return true;
}
+ /**
+ * Remove entries from the keystore daemon. Will only remove it if the
+ * {@code appId} is valid.
+ */
+ private static void removeKeystoreDataIfNeeded(int userId, int appId) {
+ if (appId < 0) {
+ return;
+ }
+
+ final KeyStore keyStore = KeyStore.getInstance();
+ if (keyStore != null) {
+ if (userId == UserHandle.USER_ALL) {
+ for (final int individual : sUserManager.getUserIds()) {
+ keyStore.clearUid(UserHandle.getUid(individual, appId));
+ }
+ } else {
+ keyStore.clearUid(UserHandle.getUid(userId, appId));
+ }
+ } else {
+ Slog.w(TAG, "Could not contact keystore to clear entries for app id " + appId);
+ }
+ }
+
public void deleteApplicationCacheFiles(final String packageName,
final IPackageDataObserver observer) {
mContext.enforceCallingOrSelfPermission(
@@ -10655,19 +10723,18 @@ public class PackageManagerService extends IPackageManager.Stub {
|| mSettings.mReadExternalStorageEnforced != enforced) {
mSettings.mReadExternalStorageEnforced = enforced;
mSettings.writeLPr();
-
- // kill any non-foreground processes so we restart them and
- // grant/revoke the GID.
- final IActivityManager am = ActivityManagerNative.getDefault();
- if (am != null) {
- final long token = Binder.clearCallingIdentity();
- try {
- am.killProcessesBelowForeground("setPermissionEnforcement");
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
+ }
+ }
+ // kill any non-foreground processes so we restart them and
+ // grant/revoke the GID.
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ if (am != null) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ am.killProcessesBelowForeground("setPermissionEnforcement");
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
} else {
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index aa1b2ff..df90a56 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -622,6 +622,8 @@ public class UserManagerService extends IUserManager.Stub {
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_BLUETOOTH);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_REMOVE_USER);
serializer.endTag(null, TAG_RESTRICTIONS);
}
serializer.endTag(null, TAG_USER);
@@ -742,6 +744,8 @@ public class UserManagerService extends IUserManager.Stub {
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_BLUETOOTH);
readBoolean(parser, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_REMOVE_USER);
}
}
}
@@ -963,7 +967,7 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public List<RestrictionEntry> getApplicationRestrictions(String packageName, int userId) {
if (UserHandle.getCallingUserId() != userId
- || Binder.getCallingUid() != getUidForPackage(packageName)) {
+ || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
checkManageUsersPermission("Only system can get restrictions for other users/apps");
}
synchronized (mPackagesLock) {
@@ -976,7 +980,7 @@ public class UserManagerService extends IUserManager.Stub {
public void setApplicationRestrictions(String packageName, List<RestrictionEntry> entries,
int userId) {
if (UserHandle.getCallingUserId() != userId
- || Binder.getCallingUid() != getUidForPackage(packageName)) {
+ || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
checkManageUsersPermission("Only system can set restrictions for other users/apps");
}
synchronized (mPackagesLock) {
@@ -986,11 +990,14 @@ public class UserManagerService extends IUserManager.Stub {
}
private int getUidForPackage(String packageName) {
+ long ident = Binder.clearCallingIdentity();
try {
return mContext.getPackageManager().getApplicationInfo(packageName,
PackageManager.GET_UNINSTALLED_PACKAGES).uid;
} catch (NameNotFoundException nnfe) {
return -1;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 2652739..1203e02 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -432,7 +432,7 @@ public final class PowerManagerService extends IPowerManager.Stub
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
- SensorManager sensorManager = new SystemSensorManager(mHandler.getLooper());
+ SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
// The notifier runs on the system server's main looper so as not to interfere
// with the animations and other critical functions of the power manager.
diff --git a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
index d603cfa..9601e9a 100644
--- a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
+++ b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
@@ -56,9 +56,9 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
private static final String UPDATE_CERTIFICATE_KEY = "config_update_certificate";
- private final File updateDir;
- private final File updateContent;
- private final File updateVersion;
+ protected final File updateDir;
+ protected final File updateContent;
+ protected final File updateVersion;
public ConfigUpdateInstallReceiver(String updateDir, String updateContentPath,
String updateMetadataPath, String updateVersionPath) {
@@ -222,12 +222,10 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
return signer.verify(Base64.decode(signature.getBytes(), Base64.DEFAULT));
}
- private void writeUpdate(File dir, File file, byte[] content) throws IOException {
+ protected void writeUpdate(File dir, File file, byte[] content) throws IOException {
FileOutputStream out = null;
File tmp = null;
try {
- // create the temporary file
- tmp = File.createTempFile("journal", "", dir);
// create the parents for the destination file
File parent = file.getParentFile();
parent.mkdirs();
@@ -235,6 +233,8 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
if (!parent.exists()) {
throw new IOException("Failed to create directory " + parent.getCanonicalPath());
}
+ // create the temporary file
+ tmp = File.createTempFile("journal", "", dir);
// mark tmp -rw-r--r--
tmp.setReadable(true, false);
// write to it
diff --git a/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java b/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
new file mode 100644
index 0000000..9185903
--- /dev/null
+++ b/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2013 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.updates;
+
+import com.android.server.firewall.IntentFirewall;
+
+public class IntentFirewallInstallReceiver extends ConfigUpdateInstallReceiver {
+
+ public IntentFirewallInstallReceiver() {
+ super(IntentFirewall.getRulesFile().getParent(), IntentFirewall.getRulesFile().getName(),
+ "metadata/", "version");
+ }
+}
diff --git a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
index 748849e..e8337f6 100644
--- a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
+++ b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
@@ -18,28 +18,127 @@ package com.android.server.updates;
import android.content.Context;
import android.content.Intent;
+import android.os.FileUtils;
import android.os.SELinux;
+import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Base64;
import android.util.Slog;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import libcore.io.ErrnoException;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
public class SELinuxPolicyInstallReceiver extends ConfigUpdateInstallReceiver {
+ private static final String TAG = "SELinuxPolicyInstallReceiver";
+
+ private static final String sepolicyPath = "sepolicy";
+ private static final String fileContextsPath = "file_contexts";
+ private static final String propertyContextsPath = "property_contexts";
+ private static final String seappContextsPath = "seapp_contexts";
+
public SELinuxPolicyInstallReceiver() {
- super("/data/security/", "sepolicy", "metadata/", "version");
+ super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version");
}
- @Override
- protected void install(byte[] encodedContent, int version) throws IOException {
- super.install(Base64.decode(encodedContent, Base64.DEFAULT), version);
+ private void backupContexts(File contexts) {
+ new File(contexts, seappContextsPath).renameTo(
+ new File(contexts, seappContextsPath + "_backup"));
+
+ new File(contexts, propertyContextsPath).renameTo(
+ new File(contexts, propertyContextsPath + "_backup"));
+
+ new File(contexts, fileContextsPath).renameTo(
+ new File(contexts, fileContextsPath + "_backup"));
+
+ new File(contexts, sepolicyPath).renameTo(
+ new File(contexts, sepolicyPath + "_backup"));
+ }
+
+ private void copyUpdate(File contexts) {
+ new File(updateDir, seappContextsPath).renameTo(new File(contexts, seappContextsPath));
+ new File(updateDir, propertyContextsPath).renameTo(new File(contexts, propertyContextsPath));
+ new File(updateDir, fileContextsPath).renameTo(new File(contexts, fileContextsPath));
+ new File(updateDir, sepolicyPath).renameTo(new File(contexts, sepolicyPath));
+ }
+
+ private int readInt(BufferedInputStream reader) throws IOException {
+ int value = 0;
+ for (int i=0; i < 4; i++) {
+ value = (value << 8) | reader.read();
+ }
+ return value;
+ }
+
+ private int[] readChunkLengths(BufferedInputStream bundle) throws IOException {
+ int[] chunks = new int[4];
+ chunks[0] = readInt(bundle);
+ chunks[1] = readInt(bundle);
+ chunks[2] = readInt(bundle);
+ chunks[3] = readInt(bundle);
+ return chunks;
+ }
+
+ private void installFile(File destination, BufferedInputStream stream, int length)
+ throws IOException {
+ byte[] chunk = new byte[length];
+ stream.read(chunk, 0, length);
+ writeUpdate(updateDir, destination, Base64.decode(chunk, Base64.DEFAULT));
+ }
+
+ private void unpackBundle() throws IOException {
+ BufferedInputStream stream = new BufferedInputStream(new FileInputStream(updateContent));
+ int[] chunkLengths = readChunkLengths(stream);
+ installFile(new File(updateDir, seappContextsPath), stream, chunkLengths[0]);
+ installFile(new File(updateDir, propertyContextsPath), stream, chunkLengths[1]);
+ installFile(new File(updateDir, fileContextsPath), stream, chunkLengths[2]);
+ installFile(new File(updateDir, sepolicyPath), stream, chunkLengths[3]);
+ }
+
+ private void applyUpdate() throws IOException, ErrnoException {
+ Slog.i(TAG, "Applying SELinux policy");
+ File contexts = new File(updateDir.getParentFile(), "contexts");
+ File current = new File(updateDir.getParentFile(), "current");
+ File update = new File(updateDir.getParentFile(), "update");
+ File tmp = new File(updateDir.getParentFile(), "tmp");
+ if (current.exists()) {
+ Libcore.os.symlink(updateDir.getPath(), update.getPath());
+ Libcore.os.rename(update.getPath(), current.getPath());
+ } else {
+ Libcore.os.symlink(updateDir.getPath(), current.getPath());
+ }
+ contexts.mkdirs();
+ backupContexts(contexts);
+ copyUpdate(contexts);
+ Libcore.os.symlink(contexts.getPath(), tmp.getPath());
+ Libcore.os.rename(tmp.getPath(), current.getPath());
+ SystemProperties.set("selinux.reload_policy", "1");
+ }
+
+ private void setEnforcingMode(Context context) {
+ boolean mode = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.SELINUX_STATUS, 0) == 1;
+ SELinux.setSELinuxEnforce(mode);
}
@Override
protected void postInstall(Context context, Intent intent) {
- boolean mode = Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.SELINUX_STATUS, 0) == 1;
- SELinux.setSELinuxEnforce(mode);
+ try {
+ unpackBundle();
+ applyUpdate();
+ setEnforcingMode(context);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "SELinux policy update malformed: ", e);
+ } catch (IOException e) {
+ Slog.e(TAG, "Could not update selinux policy: ", e);
+ } catch (ErrnoException e) {
+ Slog.e(TAG, "Could not update selinux policy: ", e);
+ }
}
}
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index f8d5d2e..4d23e5c 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -734,7 +734,7 @@ public final class WifiService extends IWifiManager.Stub {
if (gateway instanceof Inet4Address) {
info.gateway = NetworkUtils.inetAddressToInt((Inet4Address)gateway);
}
- } else if (r.isHostRoute()) {
+ } else if (r.hasGateway() == false) {
LinkAddress dest = r.getDestination();
if (dest.getAddress() instanceof Inet4Address) {
info.netmask = NetworkUtils.prefixLengthToNetmaskInt(
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index 297324b..6293dc6 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -4,6 +4,7 @@ package com.android.server.wm;
import android.graphics.Matrix;
import android.util.Slog;
+import android.util.TimeUtils;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -30,6 +31,11 @@ public class AppWindowAnimator {
// Protect with mAnimator.
boolean freezingScreen;
+ /**
+ * How long we last kept the screen frozen.
+ */
+ int lastFreezeDuration;
+
// Offset to the window of all layers in the token, for use by
// AppWindowToken animations.
int animLayerAdjustment;
@@ -287,6 +293,10 @@ public class AppWindowAnimator {
pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen);
pw.print(" allDrawn="); pw.print(allDrawn);
pw.print(" animLayerAdjustment="); pw.println(animLayerAdjustment);
+ if (lastFreezeDuration != 0) {
+ pw.print(prefix); pw.print("lastFreezeDuration=");
+ TimeUtils.formatDuration(lastFreezeDuration, pw); pw.println();
+ }
if (animating || animation != null) {
pw.print(prefix); pw.print("animating="); pw.println(animating);
pw.print(prefix); pw.print("animation="); pw.println(animation);
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 3964782..054a075 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -70,6 +70,7 @@ public class WindowAnimator {
int mAboveUniverseLayer = 0;
int mBulkUpdateParams = 0;
+ Object mLastWindowFreezeSource;
SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
new SparseArray<WindowAnimator.DisplayContentsAnimator>();
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index cbc42eb..1d1fda5 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -43,6 +43,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import android.app.AppOpsManager;
+import android.util.TimeUtils;
import android.view.IWindowId;
import com.android.internal.app.IBatteryStats;
import com.android.internal.policy.PolicyManager;
@@ -464,6 +465,9 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mTraversalScheduled = false;
boolean mDisplayFrozen = false;
+ long mDisplayFreezeTime = 0;
+ int mLastDisplayFreezeDuration = 0;
+ Object mLastFinishedFreezeSource = null;
boolean mWaitingForConfig = false;
boolean mWindowsFreezingScreen = false;
boolean mClientFreezingScreen = false;
@@ -582,6 +586,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mWallpaperForceHidingChanged = false;
boolean mWallpaperMayChange = false;
boolean mOrientationChangeComplete = true;
+ Object mLastWindowFreezeSource = null;
private Session mHoldScreen = null;
private boolean mObscured = false;
boolean mDimming = false;
@@ -3590,7 +3595,10 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
mCurConfiguration = new Configuration(config);
- mWaitingForConfig = false;
+ if (mWaitingForConfig) {
+ mWaitingForConfig = false;
+ mLastFinishedFreezeSource = "new-config";
+ }
performLayoutAndPlaceSurfacesLocked();
}
}
@@ -4209,6 +4217,7 @@ public class WindowManagerService extends IWindowManager.Stub
w.mOrientationChanging = true;
mInnerFields.mOrientationChangeComplete = false;
}
+ w.mLastFreezeDuration = 0;
unfrozeWindows = true;
w.mDisplayContent.layoutNeeded = true;
}
@@ -4216,7 +4225,10 @@ public class WindowManagerService extends IWindowManager.Stub
if (force || unfrozeWindows) {
if (DEBUG_ORIENTATION) Slog.v(TAG, "No longer freezing: " + wtoken);
wtoken.mAppAnimator.freezingScreen = false;
+ wtoken.mAppAnimator.lastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+ - mDisplayFreezeTime);
mAppsFreezingScreen--;
+ mLastFinishedFreezeSource = wtoken;
}
if (unfreezeSurfaceNow) {
if (unfrozeWindows) {
@@ -4242,6 +4254,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (!wtoken.hiddenRequested) {
if (!wtoken.mAppAnimator.freezingScreen) {
wtoken.mAppAnimator.freezingScreen = true;
+ wtoken.mAppAnimator.lastFreezeDuration = 0;
mAppsFreezingScreen++;
if (mAppsFreezingScreen == 1) {
startFreezingDisplayLocked(false, 0, 0);
@@ -4750,6 +4763,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
if (mClientFreezingScreen) {
mClientFreezingScreen = false;
+ mLastFinishedFreezeSource = "client";
final long origId = Binder.clearCallingIdentity();
try {
stopFreezingDisplayLocked();
@@ -5365,6 +5379,9 @@ public class WindowManagerService extends IWindowManager.Stub
if (maxLayer < winAnim.mSurfaceLayer) {
maxLayer = winAnim.mSurfaceLayer;
}
+ if (minLayer > winAnim.mSurfaceLayer) {
+ minLayer = winAnim.mSurfaceLayer;
+ }
// Don't include wallpaper in bounds calculation
if (!ws.mIsWallpaper) {
@@ -5377,17 +5394,14 @@ public class WindowManagerService extends IWindowManager.Stub
frame.union(left, top, right, bottom);
}
- if (ws.mAppToken != null && ws.mAppToken.token == appToken) {
- if (minLayer > ws.mWinAnimator.mSurfaceLayer) {
- minLayer = ws.mWinAnimator.mSurfaceLayer;
- }
- if (ws.isDisplayedLw()) {
- screenshotReady = true;
- }
- if (fullscreen) {
- // No point in continuing down through windows.
- break;
- }
+ if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
+ ws.isDisplayedLw()) {
+ screenshotReady = true;
+ }
+
+ if (fullscreen) {
+ // No point in continuing down through windows.
+ break;
}
}
@@ -5461,14 +5475,12 @@ public class WindowManagerService extends IWindowManager.Stub
rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer);
}
} while (!screenshotReady && retryCount <= MAX_SCREENSHOT_RETRIES);
- if (DEBUG_SCREENSHOT && retryCount > MAX_SCREENSHOT_RETRIES) {
- Slog.i(TAG, "Screenshot max retries " + retryCount + " of " + appToken + " appWin="
- + (appWin == null ? "null" : (appWin + " drawState="
- + appWin.mWinAnimator.mDrawState)));
- }
+ if (retryCount > MAX_SCREENSHOT_RETRIES) Slog.i(TAG, "Screenshot max retries " +
+ retryCount + " of " + appToken + " appWin=" + (appWin == null ?
+ "null" : (appWin + " drawState=" + appWin.mWinAnimator.mDrawState)));
if (rawss == null) {
- Slog.w(TAG, "Failure taking screenshot for (" + dw + "x" + dh
+ Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh
+ ") to layer " + maxLayer);
return null;
}
@@ -5481,7 +5493,7 @@ public class WindowManagerService extends IWindowManager.Stub
canvas.drawBitmap(rawss, matrix, null);
canvas.setBitmap(null);
- if (DEBUG_SCREENSHOT) {
+ if (true || DEBUG_SCREENSHOT) {
// TEST IF IT's ALL BLACK
int[] buffer = new int[bm.getWidth() * bm.getHeight()];
bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
@@ -5494,7 +5506,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (allBlack) {
Slog.i(TAG, "Screenshot " + appWin + " was all black! mSurfaceLayer=" +
- (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null"));
+ (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null") +
+ " minLayer=" + minLayer + " maxLayer=" + maxLayer);
}
}
@@ -5743,6 +5756,7 @@ public class WindowManagerService extends IWindowManager.Stub
w.mOrientationChanging = true;
mInnerFields.mOrientationChangeComplete = false;
}
+ w.mLastFreezeDuration = 0;
}
for (int i=mRotationWatchers.size()-1; i>=0; i--) {
@@ -6241,6 +6255,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (config == null && mWaitingForConfig) {
// Nothing changed but we are waiting for something... stop that!
mWaitingForConfig = false;
+ mLastFinishedFreezeSource = "new-config";
performLayoutAndPlaceSurfacesLocked();
}
return config;
@@ -7037,6 +7052,8 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState w = windows.get(i);
if (w.mOrientationChanging) {
w.mOrientationChanging = false;
+ w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+ - mDisplayFreezeTime);
Slog.w(TAG, "Force clearing orientation change: " + w);
}
}
@@ -7113,6 +7130,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mWindowMap) {
if (mClientFreezingScreen) {
mClientFreezingScreen = false;
+ mLastFinishedFreezeSource = "client-timeout";
stopFreezingDisplayLocked();
}
}
@@ -8030,6 +8048,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_ORIENTATION) Slog.v(TAG,
"Changing surface while display frozen: " + w);
w.mOrientationChanging = true;
+ w.mLastFreezeDuration = 0;
mInnerFields.mOrientationChangeComplete = false;
if (!mWindowsFreezingScreen) {
mWindowsFreezingScreen = true;
@@ -8418,6 +8437,8 @@ public class WindowManagerService extends IWindowManager.Stub
"Orientation not waiting for draw in "
+ w + ", surface " + winAnimator.mSurfaceControl);
w.mOrientationChanging = false;
+ w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+ - mDisplayFreezeTime);
}
}
}
@@ -8931,6 +8952,8 @@ public class WindowManagerService extends IWindowManager.Stub
winAnimator.mSurfaceResized = false;
} catch (RemoteException e) {
win.mOrientationChanging = false;
+ win.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+ - mDisplayFreezeTime);
}
mResizingWindows.remove(i);
}
@@ -8941,6 +8964,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mInnerFields.mOrientationChangeComplete) {
if (mWindowsFreezingScreen) {
mWindowsFreezingScreen = false;
+ mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
}
stopFreezingDisplayLocked();
@@ -9227,6 +9251,7 @@ public class WindowManagerService extends IWindowManager.Stub
mInnerFields.mOrientationChangeComplete = false;
} else {
mInnerFields.mOrientationChangeComplete = true;
+ mInnerFields.mLastWindowFreezeSource = mAnimator.mLastWindowFreezeSource;
if (mWindowsFreezingScreen) {
doRequest = true;
}
@@ -9499,6 +9524,8 @@ public class WindowManagerService extends IWindowManager.Stub
mScreenFrozenLock.acquire();
mDisplayFrozen = true;
+ mDisplayFreezeTime = SystemClock.elapsedRealtime();
+ mLastFinishedFreezeSource = null;
mInputMonitor.freezeInputDispatchingLw();
@@ -9553,6 +9580,15 @@ public class WindowManagerService extends IWindowManager.Stub
}
mDisplayFrozen = false;
+ mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Screen frozen for ");
+ TimeUtils.formatDuration(mLastDisplayFreezeDuration, sb);
+ if (mLastFinishedFreezeSource != null) {
+ sb.append(" due to ");
+ sb.append(mLastFinishedFreezeSource);
+ }
+ Slog.i(TAG, sb.toString());
mH.removeMessages(H.APP_FREEZE_TIMEOUT);
mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
if (PROFILE_ORIENTATION) {
@@ -10077,6 +10113,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
pw.print(" mInTouchMode="); pw.print(mInTouchMode);
pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
+ pw.print(" mLastDisplayFreezeDuration=");
+ TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw);
+ if ( mLastFinishedFreezeSource != null) {
+ pw.print(" due to ");
+ pw.print(mLastFinishedFreezeSource);
+ }
+ pw.println();
if (dumpAll) {
pw.print(" mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 506fcec..788d514 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
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_KEYGUARD;
@@ -26,6 +27,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import android.app.AppOpsManager;
import android.os.RemoteCallbackList;
+import android.util.TimeUtils;
import android.view.IWindowFocusObserver;
import android.view.IWindowId;
import com.android.server.input.InputWindowHandle;
@@ -266,6 +268,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
*/
boolean mOrientationChanging;
+ /**
+ * How long we last kept the screen frozen.
+ */
+ int mLastFreezeDuration;
+
/** Is this window now (or just being) removed? */
boolean mRemoved;
@@ -917,6 +924,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return mContentChanged && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
&& (mFrame.top != mLastFrame.top
|| mFrame.left != mLastFrame.left)
+ && (mAttrs.privateFlags&PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
&& (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove());
}
@@ -1387,6 +1395,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
pw.print(" mAppFreezing="); pw.print(mAppFreezing);
pw.print(" mTurnOnScreen="); pw.println(mTurnOnScreen);
}
+ if (mLastFreezeDuration != 0) {
+ pw.print(prefix); pw.print("mLastFreezeDuration=");
+ TimeUtils.formatDuration(mLastFreezeDuration, pw); pw.println();
+ }
if (mHScale != 1 || mVScale != 1) {
pw.print(prefix); pw.print("mHScale="); pw.print(mHScale);
pw.print(" mVScale="); pw.println(mVScale);
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 3a9f7cb..c07174b 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -505,20 +505,20 @@ class WindowStateAnimator {
public void setAlpha(float alpha) {
super.setAlpha(alpha);
if (alpha != mSurfaceTraceAlpha) {
+ mSurfaceTraceAlpha = alpha;
Slog.v(SURFACE_TAG, "setAlpha: " + this + ". Called by "
+ Debug.getCallers(3));
}
- mSurfaceTraceAlpha = alpha;
}
@Override
public void setLayer(int zorder) {
super.setLayer(zorder);
if (zorder != mLayer) {
+ mLayer = zorder;
Slog.v(SURFACE_TAG, "setLayer: " + this + ". Called by "
+ Debug.getCallers(3));
}
- mLayer = zorder;
sSurfaces.remove(this);
int i;
@@ -535,20 +535,20 @@ class WindowStateAnimator {
public void setPosition(float x, float y) {
super.setPosition(x, y);
if (x != mPosition.x || y != mPosition.y) {
+ mPosition.set(x, y);
Slog.v(SURFACE_TAG, "setPosition: " + this + ". Called by "
+ Debug.getCallers(3));
}
- mPosition.set(x, y);
}
@Override
public void setSize(int w, int h) {
super.setSize(w, h);
if (w != mSize.x || h != mSize.y) {
+ mSize.set(w, h);
Slog.v(SURFACE_TAG, "setSize: " + this + ". Called by "
+ Debug.getCallers(3));
}
- mSize.set(w, h);
}
@Override
@@ -556,10 +556,10 @@ class WindowStateAnimator {
super.setWindowCrop(crop);
if (crop != null) {
if (!crop.equals(mWindowCrop)) {
+ mWindowCrop.set(crop);
Slog.v(SURFACE_TAG, "setWindowCrop: " + this + ". Called by "
+ Debug.getCallers(3));
}
- mWindowCrop.set(crop);
}
}
@@ -567,28 +567,28 @@ class WindowStateAnimator {
public void setLayerStack(int layerStack) {
super.setLayerStack(layerStack);
if (layerStack != mLayerStack) {
+ mLayerStack = layerStack;
Slog.v(SURFACE_TAG, "setLayerStack: " + this + ". Called by " + Debug.getCallers(3));
}
- mLayerStack = layerStack;
}
@Override
public void hide() {
super.hide();
if (mShown) {
+ mShown = false;
Slog.v(SURFACE_TAG, "hide: " + this + ". Called by "
+ Debug.getCallers(3));
}
- mShown = false;
}
@Override
public void show() {
super.show();
if (!mShown) {
+ mShown = true;
Slog.v(SURFACE_TAG, "show: " + this + ". Called by "
+ Debug.getCallers(3));
}
- mShown = true;
}
@Override
@@ -1307,6 +1307,7 @@ class WindowStateAnimator {
if (w.mOrientationChanging) {
if (!w.isDrawnLw()) {
mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
+ mAnimator.mLastWindowFreezeSource = w;
if (DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation continue waiting for draw in " + w);
} else {