am 580ee8b0: Merge "Fixing AppWidgetService / AppWidgetHost to work in system process" into jb-mr1-dev

* commit '580ee8b0c6e1aea1e2e1d60499b603b9168b44f0':
  Fixing AppWidgetService / AppWidgetHost to work in system process
This commit is contained in:
Adam Cohen
2012-09-27 11:18:59 -07:00
committed by Android Git Automerger
5 changed files with 77 additions and 25 deletions

View File

@@ -4476,6 +4476,7 @@ package android.appwidget {
public class AppWidgetProviderInfo implements android.os.Parcelable { public class AppWidgetProviderInfo implements android.os.Parcelable {
ctor public AppWidgetProviderInfo(); ctor public AppWidgetProviderInfo();
ctor public AppWidgetProviderInfo(android.os.Parcel); ctor public AppWidgetProviderInfo(android.os.Parcel);
method public android.appwidget.AppWidgetProviderInfo clone();
method public int describeContents(); method public int describeContents();
method public void writeToParcel(android.os.Parcel, int); method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR; field public static final android.os.Parcelable.Creator CREATOR;

View File

@@ -21,6 +21,7 @@ import java.util.HashMap;
import android.app.ActivityThread; import android.app.ActivityThread;
import android.content.Context; import android.content.Context;
import android.os.Binder;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
@@ -57,6 +58,9 @@ public class AppWidgetHost {
class Callbacks extends IAppWidgetHost.Stub { class Callbacks extends IAppWidgetHost.Stub {
public void updateAppWidget(int appWidgetId, RemoteViews views) { public void updateAppWidget(int appWidgetId, RemoteViews views) {
if (isLocalBinder() && views != null) {
views = views.clone();
}
Message msg = mHandler.obtainMessage(HANDLE_UPDATE); Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
msg.arg1 = appWidgetId; msg.arg1 = appWidgetId;
msg.obj = views; msg.obj = views;
@@ -64,6 +68,9 @@ public class AppWidgetHost {
} }
public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) { public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
if (isLocalBinder() && info != null) {
info = info.clone();
}
Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED); Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
msg.arg1 = appWidgetId; msg.arg1 = appWidgetId;
msg.obj = info; msg.obj = info;
@@ -225,6 +232,10 @@ public class AppWidgetHost {
throw new SecurityException("Disallowed call for uid " + uid); throw new SecurityException("Disallowed call for uid " + uid);
} }
private boolean isLocalBinder() {
return Process.myPid() == Binder.getCallingPid();
}
/** /**
* Stop listening to changes for this AppWidget. * Stop listening to changes for this AppWidget.
*/ */

View File

@@ -281,6 +281,28 @@ public class AppWidgetProviderInfo implements Parcelable {
out.writeInt(this.widgetFeatures); out.writeInt(this.widgetFeatures);
} }
@Override
public AppWidgetProviderInfo clone() {
AppWidgetProviderInfo that = new AppWidgetProviderInfo();
that.provider = this.provider == null ? null : this.provider.clone();
that.minWidth = this.minWidth;
that.minHeight = this.minHeight;
that.minResizeWidth = this.minResizeHeight;
that.minResizeHeight = this.minResizeHeight;
that.updatePeriodMillis = this.updatePeriodMillis;
that.initialLayout = that.initialLayout;
that.initialKeyguardLayout = this.initialKeyguardLayout;
that.configure = this.configure == null ? null : this.configure.clone();
that.label = this.label == null ? null : this.label.substring(0);
that.icon = this.icon;
that.previewImage = this.previewImage;
that.autoAdvanceViewId = this.autoAdvanceViewId;
that.resizeMode = this.resizeMode;
that.widgetCategory = this.widgetCategory;
that.widgetFeatures = this.widgetFeatures;
return that;
}
public int describeContents() { public int describeContents() {
return 0; return 0;
} }

View File

@@ -237,12 +237,11 @@ public class RemoteViews implements Parcelable, Filter {
* @hide * @hide
*/ */
public void mergeRemoteViews(RemoteViews newRv) { public void mergeRemoteViews(RemoteViews newRv) {
if (newRv == null) return;
// We first copy the new RemoteViews, as the process of merging modifies the way the actions // We first copy the new RemoteViews, as the process of merging modifies the way the actions
// reference the bitmap cache. We don't want to modify the object as it may need to // reference the bitmap cache. We don't want to modify the object as it may need to
// be merged and applied multiple times. // be merged and applied multiple times.
Parcel p = Parcel.obtain(); RemoteViews copy = newRv.clone();
newRv.writeToParcel(p, 0);
RemoteViews copy = new RemoteViews(p);
HashMap<String, Action> map = new HashMap<String, Action>(); HashMap<String, Action> map = new HashMap<String, Action>();
if (mActions == null) { if (mActions == null) {
@@ -261,7 +260,7 @@ public class RemoteViews implements Parcelable, Filter {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
Action a = newActions.get(i); Action a = newActions.get(i);
String key = newActions.get(i).getUniqueKey(); String key = newActions.get(i).getUniqueKey();
int mergeBehavior = map.get(key).mergeBehavior(); int mergeBehavior = newActions.get(i).mergeBehavior();
if (map.containsKey(key) && mergeBehavior == Action.MERGE_REPLACE) { if (map.containsKey(key) && mergeBehavior == Action.MERGE_REPLACE) {
mActions.remove(map.get(key)); mActions.remove(map.get(key));
map.remove(key); map.remove(key);
@@ -1581,23 +1580,12 @@ public class RemoteViews implements Parcelable, Filter {
recalculateMemoryUsage(); recalculateMemoryUsage();
} }
@Override
public RemoteViews clone() {
RemoteViews that;
if (!hasLandscapeAndPortraitLayouts()) {
that = new RemoteViews(mPackage, mLayoutId);
if (mActions != null) { public RemoteViews clone() {
that.mActions = (ArrayList<Action>)mActions.clone(); Parcel p = Parcel.obtain();
} writeToParcel(p, 0);
} else { p.setDataPosition(0);
RemoteViews land = mLandscape.clone(); return new RemoteViews(p);
RemoteViews port = mPortrait.clone();
that = new RemoteViews(land, port);
}
// update the memory usage stats of the cloned RemoteViews
that.recalculateMemoryUsage();
return that;
} }
public String getPackage() { public String getPackage() {

View File

@@ -534,6 +534,7 @@ class AppWidgetServiceImpl {
final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();
try { try {
synchronized (mAppWidgetIds) { synchronized (mAppWidgetIds) {
options = cloneIfLocalBinder(options);
ensureStateLoadedLocked(); ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id == null) { if (id == null) {
@@ -817,7 +818,7 @@ class AppWidgetServiceImpl {
ensureStateLoadedLocked(); ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id != null && id.provider != null && !id.provider.zombie) { if (id != null && id.provider != null && !id.provider.zombie) {
return id.provider.info; return cloneIfLocalBinder(id.provider.info);
} }
return null; return null;
} }
@@ -828,7 +829,7 @@ class AppWidgetServiceImpl {
ensureStateLoadedLocked(); ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id != null) { if (id != null) {
return id.views; return cloneIfLocalBinder(id.views);
} }
return null; return null;
} }
@@ -842,7 +843,7 @@ class AppWidgetServiceImpl {
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
Provider p = mInstalledProviders.get(i); Provider p = mInstalledProviders.get(i);
if (!p.zombie) { if (!p.zombie) {
result.add(p.info); result.add(cloneIfLocalBinder(p.info));
} }
} }
return result; return result;
@@ -881,6 +882,7 @@ class AppWidgetServiceImpl {
public void updateAppWidgetOptions(int appWidgetId, Bundle options) { public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
synchronized (mAppWidgetIds) { synchronized (mAppWidgetIds) {
options = cloneIfLocalBinder(options);
ensureStateLoadedLocked(); ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
@@ -907,7 +909,7 @@ class AppWidgetServiceImpl {
ensureStateLoadedLocked(); ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id != null && id.options != null) { if (id != null && id.options != null) {
return id.options; return cloneIfLocalBinder(id.options);
} else { } else {
return Bundle.EMPTY; return Bundle.EMPTY;
} }
@@ -1062,6 +1064,34 @@ class AppWidgetServiceImpl {
} }
} }
private boolean isLocalBinder() {
return Process.myPid() == Binder.getCallingPid();
}
private RemoteViews cloneIfLocalBinder(RemoteViews rv) {
if (isLocalBinder() && rv != null) {
return rv.clone();
}
return rv;
}
private AppWidgetProviderInfo cloneIfLocalBinder(AppWidgetProviderInfo info) {
if (isLocalBinder() && info != null) {
return info.clone();
}
return info;
}
private Bundle cloneIfLocalBinder(Bundle bundle) {
// Note: this is only a shallow copy. For now this will be fine, but it could be problematic
// if we start adding objects to the options. Further, it would only be an issue if keyguard
// used such options.
if (isLocalBinder() && bundle != null) {
return (Bundle) bundle.clone();
}
return bundle;
}
public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId, public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
List<RemoteViews> updatedViews) { List<RemoteViews> updatedViews) {
int callingUid = enforceCallingUid(packageName); int callingUid = enforceCallingUid(packageName);
@@ -1078,7 +1108,7 @@ class AppWidgetServiceImpl {
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
AppWidgetId id = instances.get(i); AppWidgetId id = instances.get(i);
updatedIds[i] = id.appWidgetId; updatedIds[i] = id.appWidgetId;
updatedViews.add(id.views); updatedViews.add(cloneIfLocalBinder(id.views));
} }
return updatedIds; return updatedIds;
} }