summaryrefslogtreecommitdiff
path: root/com/android/server/appwidget/AppWidgetServiceImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'com/android/server/appwidget/AppWidgetServiceImpl.java')
-rw-r--r--com/android/server/appwidget/AppWidgetServiceImpl.java221
1 files changed, 65 insertions, 156 deletions
diff --git a/com/android/server/appwidget/AppWidgetServiceImpl.java b/com/android/server/appwidget/AppWidgetServiceImpl.java
index a6aaaa67..76e77825 100644
--- a/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -21,9 +21,12 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManagerInternal;
@@ -71,7 +74,6 @@ import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.StorageManager;
import android.service.appwidget.AppWidgetServiceDumpProto;
import android.service.appwidget.WidgetProto;
import android.text.TextUtils;
@@ -100,7 +102,6 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.widget.IRemoteViewsAdapterConnection;
import com.android.internal.widget.IRemoteViewsFactory;
import com.android.server.LocalServices;
import com.android.server.WidgetBackupProvider;
@@ -159,7 +160,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// Bump if the stored widgets need to be upgraded.
private static final int CURRENT_VERSION = 1;
- private static final AtomicLong REQUEST_COUNTER = new AtomicLong();
+ // Every widget update request is associated which an increasing sequence number. This is
+ // used to verify which request has successfully been received by the host.
+ private static final AtomicLong UPDATE_COUNTER = new AtomicLong();
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -190,10 +193,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
};
- // Manages active connections to RemoteViewsServices.
- private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection>
- mBoundRemoteViewsServices = new HashMap<>();
-
// Manages persistent references to RemoteViewsServices from different App Widgets.
private final HashMap<Pair<Integer, FilterComparison>, HashSet<Integer>>
mRemoteViewsServicesAppWidgets = new HashMap<>();
@@ -814,9 +813,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
Host host = lookupOrAddHostLocked(id);
host.callbacks = callbacks;
+ long updateSequenceNo = UPDATE_COUNTER.incrementAndGet();
int N = appWidgetIds.length;
ArrayList<PendingHostUpdate> outUpdates = new ArrayList<>(N);
-
LongSparseArray<PendingHostUpdate> updatesMap = new LongSparseArray<>();
for (int i = 0; i < N; i++) {
if (host.getPendingUpdatesForId(appWidgetIds[i], updatesMap)) {
@@ -828,6 +827,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
}
+ // Reset the update counter once all the updates have been calculated
+ host.lastWidgetUpdateSequenceNo = updateSequenceNo;
return new ParceledListSlice<>(outUpdates);
}
}
@@ -1206,17 +1207,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
@Override
- public void bindRemoteViewsService(String callingPackage, int appWidgetId,
- Intent intent, IBinder callbacks) {
+ public boolean bindRemoteViewsService(String callingPackage, int appWidgetId, Intent intent,
+ IApplicationThread caller, IBinder activtiyToken, IServiceConnection connection,
+ int flags) {
final int userId = UserHandle.getCallingUserId();
-
if (DEBUG) {
Slog.i(TAG, "bindRemoteViewsService() " + userId);
}
- // Make sure the package runs under the caller uid.
- mSecurityPolicy.enforceCallFromPackage(callingPackage);
-
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
@@ -1251,76 +1249,35 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
mSecurityPolicy.enforceServiceExistsAndRequiresBindRemoteViewsPermission(
componentName, widget.provider.getUserId());
- // Good to go - the service pakcage is correct, it exists for the correct
+ // Good to go - the service package is correct, it exists for the correct
// user, and requires the bind permission.
- // If there is already a connection made for this service intent, then
- // disconnect from that first. (This does not allow multiple connections
- // to the same service under the same key).
- ServiceConnectionProxy connection = null;
- FilterComparison fc = new FilterComparison(intent);
- Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc);
-
- if (mBoundRemoteViewsServices.containsKey(key)) {
- connection = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key);
- connection.disconnect();
- unbindService(connection);
- mBoundRemoteViewsServices.remove(key);
- }
-
- // Bind to the RemoteViewsService (which will trigger a callback to the
- // RemoteViewsAdapter.onServiceConnected())
- connection = new ServiceConnectionProxy(callbacks);
- bindService(intent, connection, widget.provider.info.getProfile());
- mBoundRemoteViewsServices.put(key, connection);
-
- // Add it to the mapping of RemoteViewsService to appWidgetIds so that we
- // can determine when we can call back to the RemoteViewsService later to
- // destroy associated factories.
- Pair<Integer, FilterComparison> serviceId = Pair.create(widget.provider.id.uid, fc);
- incrementAppWidgetServiceRefCount(appWidgetId, serviceId);
- }
- }
-
- @Override
- public void unbindRemoteViewsService(String callingPackage, int appWidgetId, Intent intent) {
- final int userId = UserHandle.getCallingUserId();
-
- if (DEBUG) {
- Slog.i(TAG, "unbindRemoteViewsService() " + userId);
- }
-
- // Make sure the package runs under the caller uid.
- mSecurityPolicy.enforceCallFromPackage(callingPackage);
-
- synchronized (mLock) {
- ensureGroupStateLoadedLocked(userId);
-
- // Unbind from the RemoteViewsService (which will trigger a callback to the bound
- // RemoteViewsAdapter)
- Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
- new FilterComparison(intent));
- if (mBoundRemoteViewsServices.containsKey(key)) {
- // We don't need to use the appWidgetId until after we are sure there is something
- // to unbind. Note that this may mask certain issues with apps calling unbind()
- // more than necessary.
-
- // NOTE: The lookup is enforcing security across users by making
- // sure the caller can only access widgets it hosts or provides.
- Widget widget = lookupWidgetLocked(appWidgetId,
- Binder.getCallingUid(), callingPackage);
-
- if (widget == null) {
- throw new IllegalArgumentException("Bad widget id " + appWidgetId);
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ // Ask ActivityManager to bind it. Notice that we are binding the service with the
+ // caller app instead of DevicePolicyManagerService.
+ if(ActivityManager.getService().bindService(
+ caller, activtiyToken, intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ connection, flags, mContext.getOpPackageName(),
+ widget.provider.getUserId()) != 0) {
+
+ // Add it to the mapping of RemoteViewsService to appWidgetIds so that we
+ // can determine when we can call back to the RemoteViewsService later to
+ // destroy associated factories.
+ incrementAppWidgetServiceRefCount(appWidgetId,
+ Pair.create(widget.provider.id.uid, new FilterComparison(intent)));
+ return true;
}
-
- ServiceConnectionProxy connection = (ServiceConnectionProxy)
- mBoundRemoteViewsServices.get(key);
- connection.disconnect();
- mContext.unbindService(connection);
- mBoundRemoteViewsServices.remove(key);
+ } catch (RemoteException ex) {
+ // Same process, should not happen.
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
}
}
+
+ // Failed to bind.
+ return false;
}
@Override
@@ -1751,7 +1708,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
private void deleteAppWidgetLocked(Widget widget) {
// We first unbind all services that are bound to this id
- unbindAppWidgetRemoteViewsServicesLocked(widget);
+ // Check if we need to destroy any services (if no other app widgets are
+ // referencing the same service)
+ decrementAppWidgetServiceRefCount(widget);
Host host = widget.host;
host.widgets.remove(widget);
@@ -1793,28 +1752,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
- // Unbinds from a RemoteViewsService when we delete an app widget
- private void unbindAppWidgetRemoteViewsServicesLocked(Widget widget) {
- int appWidgetId = widget.appWidgetId;
- // Unbind all connections to Services bound to this AppWidgetId
- Iterator<Pair<Integer, Intent.FilterComparison>> it = mBoundRemoteViewsServices.keySet()
- .iterator();
- while (it.hasNext()) {
- final Pair<Integer, Intent.FilterComparison> key = it.next();
- if (key.first == appWidgetId) {
- final ServiceConnectionProxy conn = (ServiceConnectionProxy)
- mBoundRemoteViewsServices.get(key);
- conn.disconnect();
- mContext.unbindService(conn);
- it.remove();
- }
- }
-
- // Check if we need to destroy any services (if no other app widgets are
- // referencing the same service)
- decrementAppWidgetServiceRefCount(widget);
- }
-
// Destroys the cached factory on the RemoteViewsService's side related to the specified intent
private void destroyRemoteViewsService(final Intent intent, Widget widget) {
final ServiceConnection conn = new ServiceConnection() {
@@ -1850,7 +1787,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// Adds to the ref-count for a given RemoteViewsService intent
private void incrementAppWidgetServiceRefCount(int appWidgetId,
Pair<Integer, FilterComparison> serviceId) {
- HashSet<Integer> appWidgetIds = null;
+ final HashSet<Integer> appWidgetIds;
if (mRemoteViewsServicesAppWidgets.containsKey(serviceId)) {
appWidgetIds = mRemoteViewsServicesAppWidgets.get(serviceId);
} else {
@@ -1914,9 +1851,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// method with a wrong id. In that case, ignore the call.
return;
}
- long requestId = REQUEST_COUNTER.incrementAndGet();
+ long requestId = UPDATE_COUNTER.incrementAndGet();
if (widget != null) {
- widget.updateRequestIds.put(viewId, requestId);
+ widget.updateSequenceNos.put(viewId, requestId);
}
if (widget == null || widget.host == null || widget.host.zombie
|| widget.host.callbacks == null || widget.provider == null
@@ -1941,7 +1878,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
int appWidgetId, int viewId, long requestId) {
try {
callbacks.viewDataChanged(appWidgetId, viewId);
- host.lastWidgetUpdateRequestId = requestId;
+ host.lastWidgetUpdateSequenceNo = requestId;
} catch (RemoteException re) {
// It failed; remove the callback. No need to prune because
// we know that this host is still referenced by this instance.
@@ -1988,9 +1925,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
- long requestId = REQUEST_COUNTER.incrementAndGet();
+ long requestId = UPDATE_COUNTER.incrementAndGet();
if (widget != null) {
- widget.updateRequestIds.put(ID_VIEWS_UPDATE, requestId);
+ widget.updateSequenceNos.put(ID_VIEWS_UPDATE, requestId);
}
if (widget == null || widget.provider == null || widget.provider.zombie
|| widget.host.callbacks == null || widget.host.zombie) {
@@ -2013,7 +1950,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
int appWidgetId, RemoteViews views, long requestId) {
try {
callbacks.updateAppWidget(appWidgetId, views);
- host.lastWidgetUpdateRequestId = requestId;
+ host.lastWidgetUpdateSequenceNo = requestId;
} catch (RemoteException re) {
synchronized (mLock) {
Slog.e(TAG, "Widget host dead: " + host.id, re);
@@ -2023,11 +1960,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
private void scheduleNotifyProviderChangedLocked(Widget widget) {
- long requestId = REQUEST_COUNTER.incrementAndGet();
+ long requestId = UPDATE_COUNTER.incrementAndGet();
if (widget != null) {
// When the provider changes, reset everything else.
- widget.updateRequestIds.clear();
- widget.updateRequestIds.append(ID_PROVIDER_CHANGED, requestId);
+ widget.updateSequenceNos.clear();
+ widget.updateSequenceNos.append(ID_PROVIDER_CHANGED, requestId);
}
if (widget == null || widget.provider == null || widget.provider.zombie
|| widget.host.callbacks == null || widget.host.zombie) {
@@ -2050,7 +1987,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
int appWidgetId, AppWidgetProviderInfo info, long requestId) {
try {
callbacks.providerChanged(appWidgetId, info);
- host.lastWidgetUpdateRequestId = requestId;
+ host.lastWidgetUpdateSequenceNo = requestId;
} catch (RemoteException re) {
synchronized (mLock){
Slog.e(TAG, "Widget host dead: " + host.id, re);
@@ -3887,7 +3824,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
int tag = TAG_UNDEFINED; // for use while saving state (the index)
- long lastWidgetUpdateRequestId; // request id for the last update successfully sent
+ // Sequence no for the last update successfully sent. This is updated whenever a
+ // widget update is successfully sent to the host callbacks. As all new/undelivered updates
+ // will have sequenceNo greater than this, all those updates will be sent when the host
+ // callbacks are attached again.
+ long lastWidgetUpdateSequenceNo;
public int getUserId() {
return UserHandle.getUserId(id.uid);
@@ -3914,18 +3855,18 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
*/
public boolean getPendingUpdatesForId(int appWidgetId,
LongSparseArray<PendingHostUpdate> outUpdates) {
- long updateRequestId = lastWidgetUpdateRequestId;
+ long updateSequenceNo = lastWidgetUpdateSequenceNo;
int N = widgets.size();
for (int i = 0; i < N; i++) {
Widget widget = widgets.get(i);
if (widget.appWidgetId == appWidgetId) {
outUpdates.clear();
- for (int j = widget.updateRequestIds.size() - 1; j >= 0; j--) {
- long requestId = widget.updateRequestIds.valueAt(j);
- if (requestId <= updateRequestId) {
+ for (int j = widget.updateSequenceNos.size() - 1; j >= 0; j--) {
+ long requestId = widget.updateSequenceNos.valueAt(j);
+ if (requestId <= updateSequenceNo) {
continue;
}
- int id = widget.updateRequestIds.keyAt(j);
+ int id = widget.updateSequenceNos.keyAt(j);
final PendingHostUpdate update;
switch (id) {
case ID_PROVIDER_CHANGED:
@@ -4021,8 +3962,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
RemoteViews maskedViews;
Bundle options;
Host host;
- // Request ids for various operations
- SparseLongArray updateRequestIds = new SparseLongArray(2);
+ // Map of request type to updateSequenceNo.
+ SparseLongArray updateSequenceNos = new SparseLongArray(2);
@Override
public String toString() {
@@ -4048,40 +3989,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
- /**
- * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection. This
- * needs to be a static inner class since a reference to the ServiceConnection is held globally
- * and may lead us to leak AppWidgetService instances (if there were more than one).
- */
- private static final class ServiceConnectionProxy implements ServiceConnection {
- private final IRemoteViewsAdapterConnection mConnectionCb;
-
- ServiceConnectionProxy(IBinder connectionCb) {
- mConnectionCb = IRemoteViewsAdapterConnection.Stub
- .asInterface(connectionCb);
- }
-
- public void onServiceConnected(ComponentName name, IBinder service) {
- try {
- mConnectionCb.onServiceConnected(service);
- } catch (RemoteException re) {
- Slog.e(TAG, "Error passing service interface", re);
- }
- }
-
- public void onServiceDisconnected(ComponentName name) {
- disconnect();
- }
-
- public void disconnect() {
- try {
- mConnectionCb.onServiceDisconnected();
- } catch (RemoteException re) {
- Slog.e(TAG, "Error clearing service interface", re);
- }
- }
- }
-
private class LoadedWidgetState {
final Widget widget;
final int hostTag;
@@ -4635,7 +4542,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// reconstructed due to the restore
host.widgets.remove(widget);
provider.widgets.remove(widget);
- unbindAppWidgetRemoteViewsServicesLocked(widget);
+ // Check if we need to destroy any services (if no other app widgets are
+ // referencing the same service)
+ decrementAppWidgetServiceRefCount(widget);
removeWidgetLocked(widget);
}
}