Skip to content

Commit 580ee8b

Browse files
Adam CohenAndroid (Google) Code Review
authored andcommitted
Merge "Fixing AppWidgetService / AppWidgetHost to work in system process" into jb-mr1-dev
2 parents 62d2d62 + 3ff2d86 commit 580ee8b

File tree

5 files changed

+77
-25
lines changed

5 files changed

+77
-25
lines changed

api/current.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4476,6 +4476,7 @@ package android.appwidget {
44764476
public class AppWidgetProviderInfo implements android.os.Parcelable {
44774477
ctor public AppWidgetProviderInfo();
44784478
ctor public AppWidgetProviderInfo(android.os.Parcel);
4479+
method public android.appwidget.AppWidgetProviderInfo clone();
44794480
method public int describeContents();
44804481
method public void writeToParcel(android.os.Parcel, int);
44814482
field public static final android.os.Parcelable.Creator CREATOR;

core/java/android/appwidget/AppWidgetHost.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import android.app.ActivityThread;
2323
import android.content.Context;
24+
import android.os.Binder;
2425
import android.os.Handler;
2526
import android.os.IBinder;
2627
import android.os.Looper;
@@ -57,13 +58,19 @@ public class AppWidgetHost {
5758

5859
class Callbacks extends IAppWidgetHost.Stub {
5960
public void updateAppWidget(int appWidgetId, RemoteViews views) {
61+
if (isLocalBinder() && views != null) {
62+
views = views.clone();
63+
}
6064
Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
6165
msg.arg1 = appWidgetId;
6266
msg.obj = views;
6367
msg.sendToTarget();
6468
}
6569

6670
public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
71+
if (isLocalBinder() && info != null) {
72+
info = info.clone();
73+
}
6774
Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
6875
msg.arg1 = appWidgetId;
6976
msg.obj = info;
@@ -225,6 +232,10 @@ private static void checkCallerIsSystem() {
225232
throw new SecurityException("Disallowed call for uid " + uid);
226233
}
227234

235+
private boolean isLocalBinder() {
236+
return Process.myPid() == Binder.getCallingPid();
237+
}
238+
228239
/**
229240
* Stop listening to changes for this AppWidget.
230241
*/

core/java/android/appwidget/AppWidgetProviderInfo.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,28 @@ public void writeToParcel(android.os.Parcel out, int flags) {
281281
out.writeInt(this.widgetFeatures);
282282
}
283283

284+
@Override
285+
public AppWidgetProviderInfo clone() {
286+
AppWidgetProviderInfo that = new AppWidgetProviderInfo();
287+
that.provider = this.provider == null ? null : this.provider.clone();
288+
that.minWidth = this.minWidth;
289+
that.minHeight = this.minHeight;
290+
that.minResizeWidth = this.minResizeHeight;
291+
that.minResizeHeight = this.minResizeHeight;
292+
that.updatePeriodMillis = this.updatePeriodMillis;
293+
that.initialLayout = that.initialLayout;
294+
that.initialKeyguardLayout = this.initialKeyguardLayout;
295+
that.configure = this.configure == null ? null : this.configure.clone();
296+
that.label = this.label == null ? null : this.label.substring(0);
297+
that.icon = this.icon;
298+
that.previewImage = this.previewImage;
299+
that.autoAdvanceViewId = this.autoAdvanceViewId;
300+
that.resizeMode = this.resizeMode;
301+
that.widgetCategory = this.widgetCategory;
302+
that.widgetFeatures = this.widgetFeatures;
303+
return that;
304+
}
305+
284306
public int describeContents() {
285307
return 0;
286308
}

core/java/android/widget/RemoteViews.java

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,11 @@ public String getUniqueKey() {
237237
* @hide
238238
*/
239239
public void mergeRemoteViews(RemoteViews newRv) {
240+
if (newRv == null) return;
240241
// We first copy the new RemoteViews, as the process of merging modifies the way the actions
241242
// reference the bitmap cache. We don't want to modify the object as it may need to
242243
// be merged and applied multiple times.
243-
Parcel p = Parcel.obtain();
244-
newRv.writeToParcel(p, 0);
245-
RemoteViews copy = new RemoteViews(p);
244+
RemoteViews copy = newRv.clone();
246245

247246
HashMap<String, Action> map = new HashMap<String, Action>();
248247
if (mActions == null) {
@@ -261,7 +260,7 @@ public void mergeRemoteViews(RemoteViews newRv) {
261260
for (int i = 0; i < count; i++) {
262261
Action a = newActions.get(i);
263262
String key = newActions.get(i).getUniqueKey();
264-
int mergeBehavior = map.get(key).mergeBehavior();
263+
int mergeBehavior = newActions.get(i).mergeBehavior();
265264
if (map.containsKey(key) && mergeBehavior == Action.MERGE_REPLACE) {
266265
mActions.remove(map.get(key));
267266
map.remove(key);
@@ -1581,23 +1580,12 @@ private RemoteViews(Parcel parcel, BitmapCache bitmapCache) {
15811580
recalculateMemoryUsage();
15821581
}
15831582

1584-
@Override
1585-
public RemoteViews clone() {
1586-
RemoteViews that;
1587-
if (!hasLandscapeAndPortraitLayouts()) {
1588-
that = new RemoteViews(mPackage, mLayoutId);
15891583

1590-
if (mActions != null) {
1591-
that.mActions = (ArrayList<Action>)mActions.clone();
1592-
}
1593-
} else {
1594-
RemoteViews land = mLandscape.clone();
1595-
RemoteViews port = mPortrait.clone();
1596-
that = new RemoteViews(land, port);
1597-
}
1598-
// update the memory usage stats of the cloned RemoteViews
1599-
that.recalculateMemoryUsage();
1600-
return that;
1584+
public RemoteViews clone() {
1585+
Parcel p = Parcel.obtain();
1586+
writeToParcel(p, 0);
1587+
p.setDataPosition(0);
1588+
return new RemoteViews(p);
16011589
}
16021590

16031591
public String getPackage() {

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

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ private void bindAppWidgetIdImpl(int appWidgetId, ComponentName provider, Bundle
534534
final long ident = Binder.clearCallingIdentity();
535535
try {
536536
synchronized (mAppWidgetIds) {
537+
options = cloneIfLocalBinder(options);
537538
ensureStateLoadedLocked();
538539
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
539540
if (id == null) {
@@ -817,7 +818,7 @@ public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
817818
ensureStateLoadedLocked();
818819
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
819820
if (id != null && id.provider != null && !id.provider.zombie) {
820-
return id.provider.info;
821+
return cloneIfLocalBinder(id.provider.info);
821822
}
822823
return null;
823824
}
@@ -828,7 +829,7 @@ public RemoteViews getAppWidgetViews(int appWidgetId) {
828829
ensureStateLoadedLocked();
829830
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
830831
if (id != null) {
831-
return id.views;
832+
return cloneIfLocalBinder(id.views);
832833
}
833834
return null;
834835
}
@@ -842,7 +843,7 @@ public List<AppWidgetProviderInfo> getInstalledProviders() {
842843
for (int i = 0; i < N; i++) {
843844
Provider p = mInstalledProviders.get(i);
844845
if (!p.zombie) {
845-
result.add(p.info);
846+
result.add(cloneIfLocalBinder(p.info));
846847
}
847848
}
848849
return result;
@@ -881,6 +882,7 @@ public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
881882

882883
public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
883884
synchronized (mAppWidgetIds) {
885+
options = cloneIfLocalBinder(options);
884886
ensureStateLoadedLocked();
885887
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
886888

@@ -907,7 +909,7 @@ public Bundle getAppWidgetOptions(int appWidgetId) {
907909
ensureStateLoadedLocked();
908910
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
909911
if (id != null && id.options != null) {
910-
return id.options;
912+
return cloneIfLocalBinder(id.options);
911913
} else {
912914
return Bundle.EMPTY;
913915
}
@@ -1062,6 +1064,34 @@ public void onServiceDisconnected(android.content.ComponentName name) {
10621064
}
10631065
}
10641066

1067+
private boolean isLocalBinder() {
1068+
return Process.myPid() == Binder.getCallingPid();
1069+
}
1070+
1071+
private RemoteViews cloneIfLocalBinder(RemoteViews rv) {
1072+
if (isLocalBinder() && rv != null) {
1073+
return rv.clone();
1074+
}
1075+
return rv;
1076+
}
1077+
1078+
private AppWidgetProviderInfo cloneIfLocalBinder(AppWidgetProviderInfo info) {
1079+
if (isLocalBinder() && info != null) {
1080+
return info.clone();
1081+
}
1082+
return info;
1083+
}
1084+
1085+
private Bundle cloneIfLocalBinder(Bundle bundle) {
1086+
// Note: this is only a shallow copy. For now this will be fine, but it could be problematic
1087+
// if we start adding objects to the options. Further, it would only be an issue if keyguard
1088+
// used such options.
1089+
if (isLocalBinder() && bundle != null) {
1090+
return (Bundle) bundle.clone();
1091+
}
1092+
return bundle;
1093+
}
1094+
10651095
public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
10661096
List<RemoteViews> updatedViews) {
10671097
int callingUid = enforceCallingUid(packageName);
@@ -1078,7 +1108,7 @@ public int[] startListening(IAppWidgetHost callbacks, String packageName, int ho
10781108
for (int i = 0; i < N; i++) {
10791109
AppWidgetId id = instances.get(i);
10801110
updatedIds[i] = id.appWidgetId;
1081-
updatedViews.add(id.views);
1111+
updatedViews.add(cloneIfLocalBinder(id.views));
10821112
}
10831113
return updatedIds;
10841114
}

0 commit comments

Comments
 (0)