Merge "Fix widget cross-talk between users due to Settings widget" into jb-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b71ccfcf9b
@@ -17,34 +17,28 @@
|
|||||||
package com.android.server;
|
package com.android.server;
|
||||||
|
|
||||||
import android.app.ActivityManagerNative;
|
import android.app.ActivityManagerNative;
|
||||||
import android.app.AlarmManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.appwidget.AppWidgetManager;
|
|
||||||
import android.appwidget.AppWidgetProviderInfo;
|
import android.appwidget.AppWidgetProviderInfo;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.ServiceConnection;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.util.Pair;
|
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
import com.android.internal.appwidget.IAppWidgetHost;
|
import com.android.internal.appwidget.IAppWidgetHost;
|
||||||
import com.android.internal.appwidget.IAppWidgetService;
|
import com.android.internal.appwidget.IAppWidgetService;
|
||||||
import com.android.internal.widget.IRemoteViewsAdapterConnection;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@@ -56,85 +50,11 @@ class AppWidgetService extends IAppWidgetService.Stub
|
|||||||
{
|
{
|
||||||
private static final String TAG = "AppWidgetService";
|
private static final String TAG = "AppWidgetService";
|
||||||
|
|
||||||
/*
|
|
||||||
* When identifying a Host or Provider based on the calling process, use the uid field.
|
|
||||||
* When identifying a Host or Provider based on a package manager broadcast, use the
|
|
||||||
* package given.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static class Provider {
|
|
||||||
int uid;
|
|
||||||
AppWidgetProviderInfo info;
|
|
||||||
ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
|
|
||||||
PendingIntent broadcast;
|
|
||||||
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
|
|
||||||
|
|
||||||
int tag; // for use while saving state (the index)
|
|
||||||
}
|
|
||||||
|
|
||||||
static class Host {
|
|
||||||
int uid;
|
|
||||||
int hostId;
|
|
||||||
String packageName;
|
|
||||||
ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
|
|
||||||
IAppWidgetHost callbacks;
|
|
||||||
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
|
|
||||||
|
|
||||||
int tag; // for use while saving state (the index)
|
|
||||||
}
|
|
||||||
|
|
||||||
static class AppWidgetId {
|
|
||||||
int appWidgetId;
|
|
||||||
Provider provider;
|
|
||||||
RemoteViews views;
|
|
||||||
Host host;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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).
|
|
||||||
*/
|
|
||||||
static class ServiceConnectionProxy implements ServiceConnection {
|
|
||||||
private final IBinder mConnectionCb;
|
|
||||||
|
|
||||||
ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
|
|
||||||
mConnectionCb = connectionCb;
|
|
||||||
}
|
|
||||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
|
||||||
final IRemoteViewsAdapterConnection cb =
|
|
||||||
IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
|
|
||||||
try {
|
|
||||||
cb.onServiceConnected(service);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void onServiceDisconnected(ComponentName name) {
|
|
||||||
disconnect();
|
|
||||||
}
|
|
||||||
public void disconnect() {
|
|
||||||
final IRemoteViewsAdapterConnection cb =
|
|
||||||
IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
|
|
||||||
try {
|
|
||||||
cb.onServiceDisconnected();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Context mContext;
|
Context mContext;
|
||||||
Locale mLocale;
|
Locale mLocale;
|
||||||
PackageManager mPackageManager;
|
PackageManager mPackageManager;
|
||||||
AlarmManager mAlarmManager;
|
|
||||||
ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
|
|
||||||
int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
|
|
||||||
final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
|
|
||||||
ArrayList<Host> mHosts = new ArrayList<Host>();
|
|
||||||
boolean mSafeMode;
|
boolean mSafeMode;
|
||||||
|
|
||||||
|
|
||||||
private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
|
private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
|
||||||
|
|
||||||
AppWidgetService(Context context) {
|
AppWidgetService(Context context) {
|
||||||
@@ -195,9 +115,16 @@ class AppWidgetService extends IAppWidgetService.Stub
|
|||||||
}, UserHandle.ALL, userFilter, null, null);
|
}, UserHandle.ALL, userFilter, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This returns the user id of the caller, if the caller is not the system process,
|
||||||
|
* otherwise it assumes that the calls are from the lockscreen and hence are meant for the
|
||||||
|
* current user. TODO: Instead, have lockscreen make explicit calls with userId
|
||||||
|
*/
|
||||||
private int getCallingOrCurrentUserId() {
|
private int getCallingOrCurrentUserId() {
|
||||||
int callingUid = Binder.getCallingUid();
|
int callingUid = Binder.getCallingUid();
|
||||||
if (callingUid == android.os.Process.myUid()) {
|
// Also check the PID because Settings (power control widget) also runs as System UID
|
||||||
|
if (callingUid == android.os.Process.myUid()
|
||||||
|
&& Binder.getCallingPid() == android.os.Process.myPid()) {
|
||||||
try {
|
try {
|
||||||
return ActivityManagerNative.getDefault().getCurrentUser().id;
|
return ActivityManagerNative.getDefault().getCurrentUser().id;
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
@@ -272,13 +199,16 @@ class AppWidgetService extends IAppWidgetService.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onUserRemoved(int userId) {
|
public void onUserRemoved(int userId) {
|
||||||
AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
|
|
||||||
if (userId < 1) return;
|
if (userId < 1) return;
|
||||||
|
synchronized (mAppWidgetServices) {
|
||||||
if (impl == null) {
|
AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
|
||||||
AppWidgetServiceImpl.getSettingsFile(userId).delete();
|
mAppWidgetServices.remove(userId);
|
||||||
} else {
|
|
||||||
impl.onUserRemoved();
|
if (impl == null) {
|
||||||
|
AppWidgetServiceImpl.getSettingsFile(userId).delete();
|
||||||
|
} else {
|
||||||
|
impl.onUserRemoved();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,17 +216,23 @@ class AppWidgetService extends IAppWidgetService.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
private AppWidgetServiceImpl getImplForUser(int userId) {
|
private AppWidgetServiceImpl getImplForUser(int userId) {
|
||||||
AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
|
boolean sendInitial = false;
|
||||||
if (service == null) {
|
AppWidgetServiceImpl service;
|
||||||
Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
|
synchronized (mAppWidgetServices) {
|
||||||
// TODO: Verify that it's a valid user
|
service = mAppWidgetServices.get(userId);
|
||||||
service = new AppWidgetServiceImpl(mContext, userId);
|
if (service == null) {
|
||||||
service.systemReady(mSafeMode);
|
Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
|
||||||
// Assume that BOOT_COMPLETED was received, as this is a non-primary user.
|
// TODO: Verify that it's a valid user
|
||||||
service.sendInitialBroadcasts();
|
service = new AppWidgetServiceImpl(mContext, userId);
|
||||||
mAppWidgetServices.append(userId, service);
|
service.systemReady(mSafeMode);
|
||||||
|
// Assume that BOOT_COMPLETED was received, as this is a non-primary user.
|
||||||
|
mAppWidgetServices.append(userId, service);
|
||||||
|
sendInitial = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sendInitial) {
|
||||||
|
service.sendInitialBroadcasts();
|
||||||
}
|
}
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,15 +261,6 @@ class AppWidgetService extends IAppWidgetService.Stub
|
|||||||
return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId);
|
return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int[] getAppWidgetIds(Provider p) {
|
|
||||||
int instancesSize = p.instances.size();
|
|
||||||
int appWidgetIds[] = new int[instancesSize];
|
|
||||||
for (int i=0; i<instancesSize; i++) {
|
|
||||||
appWidgetIds[i] = p.instances.get(i).appWidgetId;
|
|
||||||
}
|
|
||||||
return appWidgetIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
|
public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
|
||||||
return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders();
|
return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders();
|
||||||
@@ -378,9 +305,15 @@ class AppWidgetService extends IAppWidgetService.Stub
|
|||||||
@Override
|
@Override
|
||||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
// Dump the state of all the app widget providers
|
// Dump the state of all the app widget providers
|
||||||
for (int i = 0; i < mAppWidgetServices.size(); i++) {
|
synchronized (mAppWidgetServices) {
|
||||||
AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
|
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
|
||||||
service.dump(fd, pw, args);
|
for (int i = 0; i < mAppWidgetServices.size(); i++) {
|
||||||
|
pw.println("User: " + mAppWidgetServices.keyAt(i));
|
||||||
|
ipw.increaseIndent();
|
||||||
|
AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
|
||||||
|
service.dump(fd, ipw, args);
|
||||||
|
ipw.decreaseIndent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ class AppWidgetServiceImpl {
|
|||||||
private static final String SETTINGS_FILENAME = "appwidgets.xml";
|
private static final String SETTINGS_FILENAME = "appwidgets.xml";
|
||||||
private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
|
private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
|
||||||
|
|
||||||
|
private static boolean DBG = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When identifying a Host or Provider based on the calling process, use the uid field. When
|
* When identifying a Host or Provider based on the calling process, use the uid field. When
|
||||||
* identifying a Host or Provider based on a package manager broadcast, use the package given.
|
* identifying a Host or Provider based on a package manager broadcast, use the package given.
|
||||||
@@ -208,7 +210,12 @@ class AppWidgetServiceImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void log(String msg) {
|
||||||
|
Slog.i(TAG, "u=" + mUserId + ": " + msg);
|
||||||
|
}
|
||||||
|
|
||||||
void onConfigurationChanged() {
|
void onConfigurationChanged() {
|
||||||
|
if (DBG) log("Got onConfigurationChanged()");
|
||||||
Locale revised = Locale.getDefault();
|
Locale revised = Locale.getDefault();
|
||||||
if (revised == null || mLocale == null || !(revised.equals(mLocale))) {
|
if (revised == null || mLocale == null || !(revised.equals(mLocale))) {
|
||||||
mLocale = revised;
|
mLocale = revised;
|
||||||
@@ -235,6 +242,7 @@ class AppWidgetServiceImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onBroadcastReceived(Intent intent) {
|
void onBroadcastReceived(Intent intent) {
|
||||||
|
if (DBG) log("onBroadcast " + intent);
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
boolean added = false;
|
boolean added = false;
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
@@ -425,7 +433,8 @@ class AppWidgetServiceImpl {
|
|||||||
mAppWidgetIds.add(id);
|
mAppWidgetIds.add(id);
|
||||||
|
|
||||||
saveStateLocked();
|
saveStateLocked();
|
||||||
|
if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId
|
||||||
|
+ " id=" + appWidgetId);
|
||||||
return appWidgetId;
|
return appWidgetId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -518,6 +527,7 @@ class AppWidgetServiceImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cancelBroadcasts(Provider p) {
|
void cancelBroadcasts(Provider p) {
|
||||||
|
if (DBG) log("cancelBroadcasts for " + p);
|
||||||
if (p.broadcast != null) {
|
if (p.broadcast != null) {
|
||||||
mAlarmManager.cancel(p.broadcast);
|
mAlarmManager.cancel(p.broadcast);
|
||||||
long token = Binder.clearCallingIdentity();
|
long token = Binder.clearCallingIdentity();
|
||||||
@@ -531,6 +541,8 @@ class AppWidgetServiceImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void bindAppWidgetIdImpl(int appWidgetId, ComponentName provider, Bundle options) {
|
private void bindAppWidgetIdImpl(int appWidgetId, ComponentName provider, Bundle options) {
|
||||||
|
if (DBG) log("bindAppWidgetIdImpl appwid=" + appWidgetId
|
||||||
|
+ " provider=" + provider);
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mAppWidgetIds) {
|
synchronized (mAppWidgetIds) {
|
||||||
@@ -825,12 +837,14 @@ class AppWidgetServiceImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public RemoteViews getAppWidgetViews(int appWidgetId) {
|
public RemoteViews getAppWidgetViews(int appWidgetId) {
|
||||||
|
if (DBG) log("getAppWidgetViews id=" + appWidgetId);
|
||||||
synchronized (mAppWidgetIds) {
|
synchronized (mAppWidgetIds) {
|
||||||
ensureStateLoadedLocked();
|
ensureStateLoadedLocked();
|
||||||
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
|
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
return cloneIfLocalBinder(id.views);
|
return cloneIfLocalBinder(id.views);
|
||||||
}
|
}
|
||||||
|
if (DBG) log(" couldn't find appwidgetid");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -854,7 +868,7 @@ class AppWidgetServiceImpl {
|
|||||||
if (appWidgetIds == null) {
|
if (appWidgetIds == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (DBG) log("updateAppWidgetIds views: " + views);
|
||||||
int bitmapMemoryUsage = 0;
|
int bitmapMemoryUsage = 0;
|
||||||
if (views != null) {
|
if (views != null) {
|
||||||
bitmapMemoryUsage = views.estimateMemoryUsage();
|
bitmapMemoryUsage = views.estimateMemoryUsage();
|
||||||
@@ -1280,8 +1294,8 @@ class AppWidgetServiceImpl {
|
|||||||
intent.setComponent(p.info.provider);
|
intent.setComponent(p.info.provider);
|
||||||
long token = Binder.clearCallingIdentity();
|
long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
|
p.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
PendingIntent.FLAG_UPDATE_CURRENT, new UserHandle(mUserId));
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(token);
|
Binder.restoreCallingIdentity(token);
|
||||||
}
|
}
|
||||||
@@ -1353,7 +1367,7 @@ class AppWidgetServiceImpl {
|
|||||||
p.uid = activityInfo.applicationInfo.uid;
|
p.uid = activityInfo.applicationInfo.uid;
|
||||||
|
|
||||||
Resources res = mContext.getPackageManager()
|
Resources res = mContext.getPackageManager()
|
||||||
.getResourcesForApplication(activityInfo.applicationInfo);
|
.getResourcesForApplicationAsUser(activityInfo.packageName, mUserId);
|
||||||
|
|
||||||
TypedArray sa = res.obtainAttributes(attrs,
|
TypedArray sa = res.obtainAttributes(attrs,
|
||||||
com.android.internal.R.styleable.AppWidgetProviderInfo);
|
com.android.internal.R.styleable.AppWidgetProviderInfo);
|
||||||
@@ -1597,8 +1611,7 @@ class AppWidgetServiceImpl {
|
|||||||
|
|
||||||
final IPackageManager packageManager = AppGlobals.getPackageManager();
|
final IPackageManager packageManager = AppGlobals.getPackageManager();
|
||||||
try {
|
try {
|
||||||
packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0,
|
packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0, mUserId);
|
||||||
UserHandle.getCallingUserId());
|
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
String[] pkgs = mContext.getPackageManager()
|
String[] pkgs = mContext.getPackageManager()
|
||||||
.currentToCanonicalPackageNames(new String[] { pkg });
|
.currentToCanonicalPackageNames(new String[] { pkg });
|
||||||
|
|||||||
Reference in New Issue
Block a user