Skip to content

Commit b71ccfc

Browse files
Amith YamasaniAndroid (Google) Code Review
authored andcommitted
Merge "Fix widget cross-talk between users due to Settings widget" into jb-mr1-dev
2 parents 2b1cab0 + 8320de8 commit b71ccfc

File tree

2 files changed

+62
-116
lines changed

2 files changed

+62
-116
lines changed

services/java/com/android/server/AppWidgetService.java

Lines changed: 42 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,28 @@
1717
package com.android.server;
1818

1919
import android.app.ActivityManagerNative;
20-
import android.app.AlarmManager;
21-
import android.app.PendingIntent;
22-
import android.appwidget.AppWidgetManager;
2320
import android.appwidget.AppWidgetProviderInfo;
2421
import android.content.BroadcastReceiver;
2522
import android.content.ComponentName;
2623
import android.content.Context;
2724
import android.content.Intent;
2825
import android.content.IntentFilter;
29-
import android.content.ServiceConnection;
3026
import android.content.pm.PackageManager;
3127
import android.os.Binder;
3228
import android.os.Bundle;
3329
import android.os.IBinder;
3430
import android.os.RemoteException;
3531
import android.os.UserHandle;
36-
import android.util.Pair;
3732
import android.util.Slog;
3833
import android.util.SparseArray;
3934
import android.widget.RemoteViews;
4035

4136
import com.android.internal.appwidget.IAppWidgetHost;
4237
import com.android.internal.appwidget.IAppWidgetService;
43-
import com.android.internal.widget.IRemoteViewsAdapterConnection;
38+
import com.android.internal.util.IndentingPrintWriter;
4439

4540
import java.io.FileDescriptor;
4641
import java.io.PrintWriter;
47-
import java.util.ArrayList;
4842
import java.util.List;
4943
import java.util.Locale;
5044

@@ -56,85 +50,11 @@ class AppWidgetService extends IAppWidgetService.Stub
5650
{
5751
private static final String TAG = "AppWidgetService";
5852

59-
/*
60-
* When identifying a Host or Provider based on the calling process, use the uid field.
61-
* When identifying a Host or Provider based on a package manager broadcast, use the
62-
* package given.
63-
*/
64-
65-
static class Provider {
66-
int uid;
67-
AppWidgetProviderInfo info;
68-
ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
69-
PendingIntent broadcast;
70-
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
71-
72-
int tag; // for use while saving state (the index)
73-
}
74-
75-
static class Host {
76-
int uid;
77-
int hostId;
78-
String packageName;
79-
ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
80-
IAppWidgetHost callbacks;
81-
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
82-
83-
int tag; // for use while saving state (the index)
84-
}
85-
86-
static class AppWidgetId {
87-
int appWidgetId;
88-
Provider provider;
89-
RemoteViews views;
90-
Host host;
91-
}
92-
93-
/**
94-
* Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection.
95-
* This needs to be a static inner class since a reference to the ServiceConnection is held
96-
* globally and may lead us to leak AppWidgetService instances (if there were more than one).
97-
*/
98-
static class ServiceConnectionProxy implements ServiceConnection {
99-
private final IBinder mConnectionCb;
100-
101-
ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
102-
mConnectionCb = connectionCb;
103-
}
104-
public void onServiceConnected(ComponentName name, IBinder service) {
105-
final IRemoteViewsAdapterConnection cb =
106-
IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
107-
try {
108-
cb.onServiceConnected(service);
109-
} catch (Exception e) {
110-
e.printStackTrace();
111-
}
112-
}
113-
public void onServiceDisconnected(ComponentName name) {
114-
disconnect();
115-
}
116-
public void disconnect() {
117-
final IRemoteViewsAdapterConnection cb =
118-
IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
119-
try {
120-
cb.onServiceDisconnected();
121-
} catch (Exception e) {
122-
e.printStackTrace();
123-
}
124-
}
125-
}
126-
12753
Context mContext;
12854
Locale mLocale;
12955
PackageManager mPackageManager;
130-
AlarmManager mAlarmManager;
131-
ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
132-
int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
133-
final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
134-
ArrayList<Host> mHosts = new ArrayList<Host>();
13556
boolean mSafeMode;
13657

137-
13858
private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
13959

14060
AppWidgetService(Context context) {
@@ -195,9 +115,16 @@ public void onReceive(Context context, Intent intent) {
195115
}, UserHandle.ALL, userFilter, null, null);
196116
}
197117

118+
/**
119+
* This returns the user id of the caller, if the caller is not the system process,
120+
* otherwise it assumes that the calls are from the lockscreen and hence are meant for the
121+
* current user. TODO: Instead, have lockscreen make explicit calls with userId
122+
*/
198123
private int getCallingOrCurrentUserId() {
199124
int callingUid = Binder.getCallingUid();
200-
if (callingUid == android.os.Process.myUid()) {
125+
// Also check the PID because Settings (power control widget) also runs as System UID
126+
if (callingUid == android.os.Process.myUid()
127+
&& Binder.getCallingPid() == android.os.Process.myPid()) {
201128
try {
202129
return ActivityManagerNative.getDefault().getCurrentUser().id;
203130
} catch (RemoteException re) {
@@ -272,31 +199,40 @@ public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
272199
}
273200

274201
public void onUserRemoved(int userId) {
275-
AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
276202
if (userId < 1) return;
277-
278-
if (impl == null) {
279-
AppWidgetServiceImpl.getSettingsFile(userId).delete();
280-
} else {
281-
impl.onUserRemoved();
203+
synchronized (mAppWidgetServices) {
204+
AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
205+
mAppWidgetServices.remove(userId);
206+
207+
if (impl == null) {
208+
AppWidgetServiceImpl.getSettingsFile(userId).delete();
209+
} else {
210+
impl.onUserRemoved();
211+
}
282212
}
283213
}
284214

285215
public void onUserStopped(int userId) {
286216
}
287217

288218
private AppWidgetServiceImpl getImplForUser(int userId) {
289-
AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
290-
if (service == null) {
291-
Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
292-
// TODO: Verify that it's a valid user
293-
service = new AppWidgetServiceImpl(mContext, userId);
294-
service.systemReady(mSafeMode);
295-
// Assume that BOOT_COMPLETED was received, as this is a non-primary user.
219+
boolean sendInitial = false;
220+
AppWidgetServiceImpl service;
221+
synchronized (mAppWidgetServices) {
222+
service = mAppWidgetServices.get(userId);
223+
if (service == null) {
224+
Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
225+
// TODO: Verify that it's a valid user
226+
service = new AppWidgetServiceImpl(mContext, userId);
227+
service.systemReady(mSafeMode);
228+
// Assume that BOOT_COMPLETED was received, as this is a non-primary user.
229+
mAppWidgetServices.append(userId, service);
230+
sendInitial = true;
231+
}
232+
}
233+
if (sendInitial) {
296234
service.sendInitialBroadcasts();
297-
mAppWidgetServices.append(userId, service);
298235
}
299-
300236
return service;
301237
}
302238

@@ -325,15 +261,6 @@ public Bundle getAppWidgetOptions(int appWidgetId) {
325261
return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId);
326262
}
327263

328-
static int[] getAppWidgetIds(Provider p) {
329-
int instancesSize = p.instances.size();
330-
int appWidgetIds[] = new int[instancesSize];
331-
for (int i=0; i<instancesSize; i++) {
332-
appWidgetIds[i] = p.instances.get(i).appWidgetId;
333-
}
334-
return appWidgetIds;
335-
}
336-
337264
@Override
338265
public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
339266
return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders();
@@ -378,9 +305,15 @@ public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
378305
@Override
379306
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
380307
// Dump the state of all the app widget providers
381-
for (int i = 0; i < mAppWidgetServices.size(); i++) {
382-
AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
383-
service.dump(fd, pw, args);
308+
synchronized (mAppWidgetServices) {
309+
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
310+
for (int i = 0; i < mAppWidgetServices.size(); i++) {
311+
pw.println("User: " + mAppWidgetServices.keyAt(i));
312+
ipw.increaseIndent();
313+
AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
314+
service.dump(fd, ipw, args);
315+
ipw.decreaseIndent();
316+
}
384317
}
385318
}
386319

services/java/com/android/server/AppWidgetServiceImpl.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ class AppWidgetServiceImpl {
8787
private static final String SETTINGS_FILENAME = "appwidgets.xml";
8888
private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
8989

90+
private static boolean DBG = false;
91+
9092
/*
9193
* When identifying a Host or Provider based on the calling process, use the uid field. When
9294
* identifying a Host or Provider based on a package manager broadcast, use the package given.
@@ -208,7 +210,12 @@ public void systemReady(boolean safeMode) {
208210
}
209211
}
210212

213+
private void log(String msg) {
214+
Slog.i(TAG, "u=" + mUserId + ": " + msg);
215+
}
216+
211217
void onConfigurationChanged() {
218+
if (DBG) log("Got onConfigurationChanged()");
212219
Locale revised = Locale.getDefault();
213220
if (revised == null || mLocale == null || !(revised.equals(mLocale))) {
214221
mLocale = revised;
@@ -235,6 +242,7 @@ void onConfigurationChanged() {
235242
}
236243

237244
void onBroadcastReceived(Intent intent) {
245+
if (DBG) log("onBroadcast " + intent);
238246
final String action = intent.getAction();
239247
boolean added = false;
240248
boolean changed = false;
@@ -425,7 +433,8 @@ public int allocateAppWidgetId(String packageName, int hostId) {
425433
mAppWidgetIds.add(id);
426434

427435
saveStateLocked();
428-
436+
if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId
437+
+ " id=" + appWidgetId);
429438
return appWidgetId;
430439
}
431440
}
@@ -518,6 +527,7 @@ void deleteAppWidgetLocked(AppWidgetId id) {
518527
}
519528

520529
void cancelBroadcasts(Provider p) {
530+
if (DBG) log("cancelBroadcasts for " + p);
521531
if (p.broadcast != null) {
522532
mAlarmManager.cancel(p.broadcast);
523533
long token = Binder.clearCallingIdentity();
@@ -531,6 +541,8 @@ void cancelBroadcasts(Provider p) {
531541
}
532542

533543
private void bindAppWidgetIdImpl(int appWidgetId, ComponentName provider, Bundle options) {
544+
if (DBG) log("bindAppWidgetIdImpl appwid=" + appWidgetId
545+
+ " provider=" + provider);
534546
final long ident = Binder.clearCallingIdentity();
535547
try {
536548
synchronized (mAppWidgetIds) {
@@ -825,12 +837,14 @@ public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
825837
}
826838

827839
public RemoteViews getAppWidgetViews(int appWidgetId) {
840+
if (DBG) log("getAppWidgetViews id=" + appWidgetId);
828841
synchronized (mAppWidgetIds) {
829842
ensureStateLoadedLocked();
830843
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
831844
if (id != null) {
832845
return cloneIfLocalBinder(id.views);
833846
}
847+
if (DBG) log(" couldn't find appwidgetid");
834848
return null;
835849
}
836850
}
@@ -854,7 +868,7 @@ public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
854868
if (appWidgetIds == null) {
855869
return;
856870
}
857-
871+
if (DBG) log("updateAppWidgetIds views: " + views);
858872
int bitmapMemoryUsage = 0;
859873
if (views != null) {
860874
bitmapMemoryUsage = views.estimateMemoryUsage();
@@ -1280,8 +1294,8 @@ void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) {
12801294
intent.setComponent(p.info.provider);
12811295
long token = Binder.clearCallingIdentity();
12821296
try {
1283-
p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
1284-
PendingIntent.FLAG_UPDATE_CURRENT);
1297+
p.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent,
1298+
PendingIntent.FLAG_UPDATE_CURRENT, new UserHandle(mUserId));
12851299
} finally {
12861300
Binder.restoreCallingIdentity(token);
12871301
}
@@ -1353,7 +1367,7 @@ private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
13531367
p.uid = activityInfo.applicationInfo.uid;
13541368

13551369
Resources res = mContext.getPackageManager()
1356-
.getResourcesForApplication(activityInfo.applicationInfo);
1370+
.getResourcesForApplicationAsUser(activityInfo.packageName, mUserId);
13571371

13581372
TypedArray sa = res.obtainAttributes(attrs,
13591373
com.android.internal.R.styleable.AppWidgetProviderInfo);
@@ -1597,8 +1611,7 @@ void readStateFromFileLocked(FileInputStream stream) {
15971611

15981612
final IPackageManager packageManager = AppGlobals.getPackageManager();
15991613
try {
1600-
packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0,
1601-
UserHandle.getCallingUserId());
1614+
packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0, mUserId);
16021615
} catch (RemoteException e) {
16031616
String[] pkgs = mContext.getPackageManager()
16041617
.currentToCanonicalPackageNames(new String[] { pkg });

0 commit comments

Comments
 (0)