am c566b43d: Fix crosstalk between users for widgets hosted in lockscreen

* commit 'c566b43d02596cba437e9a2723e9f989297cca72':
  Fix crosstalk between users for widgets hosted in lockscreen
This commit is contained in:
Amith Yamasani
2012-11-30 18:44:36 -08:00
committed by Android Git Automerger
7 changed files with 126 additions and 41 deletions

View File

@ -154,6 +154,15 @@ public class AppWidgetHost {
* becomes visible, i.e. from onStart() in your Activity. * becomes visible, i.e. from onStart() in your Activity.
*/ */
public void startListening() { public void startListening() {
startListeningAsUser(UserHandle.myUserId());
}
/**
* Start receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity
* becomes visible, i.e. from onStart() in your Activity.
* @hide
*/
public void startListeningAsUser(int userId) {
int[] updatedIds; int[] updatedIds;
ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>(); ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>();
@ -161,7 +170,8 @@ public class AppWidgetHost {
if (mPackageName == null) { if (mPackageName == null) {
mPackageName = mContext.getPackageName(); mPackageName = mContext.getPackageName();
} }
updatedIds = sService.startListening(mCallbacks, mPackageName, mHostId, updatedViews); updatedIds = sService.startListeningAsUser(
mCallbacks, mPackageName, mHostId, updatedViews, userId);
} }
catch (RemoteException e) { catch (RemoteException e) {
throw new RuntimeException("system server dead?", e); throw new RuntimeException("system server dead?", e);
@ -179,13 +189,29 @@ public class AppWidgetHost {
*/ */
public void stopListening() { public void stopListening() {
try { try {
sService.stopListening(mHostId); sService.stopListeningAsUser(mHostId, UserHandle.myUserId());
} }
catch (RemoteException e) { catch (RemoteException e) {
throw new RuntimeException("system server dead?", e); throw new RuntimeException("system server dead?", e);
} }
} }
/**
* Stop receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity is
* no longer visible, i.e. from onStop() in your Activity.
* @hide
*/
public void stopListeningAsUser(int userId) {
try {
sService.stopListeningAsUser(mHostId, userId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
// Also clear the views
clearViews();
}
/** /**
* Get a appWidgetId for a host in the calling process. * Get a appWidgetId for a host in the calling process.
* *

View File

@ -23,6 +23,7 @@ import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.TypedValue; import android.util.TypedValue;
import android.widget.RemoteViews; import android.widget.RemoteViews;
@ -749,11 +750,14 @@ public class AppWidgetManager {
* @param intent The intent of the service which will be providing the data to the * @param intent The intent of the service which will be providing the data to the
* RemoteViewsAdapter. * RemoteViewsAdapter.
* @param connection The callback interface to be notified when a connection is made or lost. * @param connection The callback interface to be notified when a connection is made or lost.
* @param userHandle The user to bind to.
* @hide * @hide
*/ */
public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) { public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
UserHandle userHandle) {
try { try {
sService.bindRemoteViewsService(appWidgetId, intent, connection); sService.bindRemoteViewsService(appWidgetId, intent, connection,
userHandle.getIdentifier());
} }
catch (RemoteException e) { catch (RemoteException e) {
throw new RuntimeException("system server dead?", e); throw new RuntimeException("system server dead?", e);
@ -769,11 +773,12 @@ public class AppWidgetManager {
* @param appWidgetId The AppWidget instance for which to bind the RemoteViewsService. * @param appWidgetId The AppWidget instance for which to bind the RemoteViewsService.
* @param intent The intent of the service which will be providing the data to the * @param intent The intent of the service which will be providing the data to the
* RemoteViewsAdapter. * RemoteViewsAdapter.
* @param userHandle The user to unbind from.
* @hide * @hide
*/ */
public void unbindRemoteViewsService(int appWidgetId, Intent intent) { public void unbindRemoteViewsService(int appWidgetId, Intent intent, UserHandle userHandle) {
try { try {
sService.unbindRemoteViewsService(appWidgetId, intent); sService.unbindRemoteViewsService(appWidgetId, intent, userHandle.getIdentifier());
} }
catch (RemoteException e) { catch (RemoteException e) {
throw new RuntimeException("system server dead?", e); throw new RuntimeException("system server dead?", e);

View File

@ -29,7 +29,9 @@ import android.os.HandlerThread;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -40,6 +42,7 @@ import android.widget.RemoteViews.OnClickHandler;
import com.android.internal.widget.IRemoteViewsAdapterConnection; import com.android.internal.widget.IRemoteViewsAdapterConnection;
import com.android.internal.widget.IRemoteViewsFactory; import com.android.internal.widget.IRemoteViewsFactory;
import com.android.internal.widget.LockPatternUtils;
/** /**
* An adapter to a RemoteViewsService which fetches and caches RemoteViews * An adapter to a RemoteViewsService which fetches and caches RemoteViews
@ -106,6 +109,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
// construction (happens when we have a cached FixedSizeRemoteViewsCache). // construction (happens when we have a cached FixedSizeRemoteViewsCache).
private boolean mDataReady = false; private boolean mDataReady = false;
int mUserId;
/** /**
* An interface for the RemoteAdapter to notify other classes when adapters * An interface for the RemoteAdapter to notify other classes when adapters
* are actually connected to/disconnected from their actual services. * are actually connected to/disconnected from their actual services.
@ -146,8 +151,16 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
public synchronized void bind(Context context, int appWidgetId, Intent intent) { public synchronized void bind(Context context, int appWidgetId, Intent intent) {
if (!mIsConnecting) { if (!mIsConnecting) {
try { try {
RemoteViewsAdapter adapter;
final AppWidgetManager mgr = AppWidgetManager.getInstance(context); final AppWidgetManager mgr = AppWidgetManager.getInstance(context);
mgr.bindRemoteViewsService(appWidgetId, intent, asBinder()); if (Process.myUid() == Process.SYSTEM_UID
&& (adapter = mAdapter.get()) != null) {
mgr.bindRemoteViewsService(appWidgetId, intent, asBinder(),
new UserHandle(adapter.mUserId));
} else {
mgr.bindRemoteViewsService(appWidgetId, intent, asBinder(),
Process.myUserHandle());
}
mIsConnecting = true; mIsConnecting = true;
} catch (Exception e) { } catch (Exception e) {
Log.e("RemoteViewsAdapterServiceConnection", "bind(): " + e.getMessage()); Log.e("RemoteViewsAdapterServiceConnection", "bind(): " + e.getMessage());
@ -159,8 +172,15 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
public synchronized void unbind(Context context, int appWidgetId, Intent intent) { public synchronized void unbind(Context context, int appWidgetId, Intent intent) {
try { try {
RemoteViewsAdapter adapter;
final AppWidgetManager mgr = AppWidgetManager.getInstance(context); final AppWidgetManager mgr = AppWidgetManager.getInstance(context);
mgr.unbindRemoteViewsService(appWidgetId, intent); if (Process.myUid() == Process.SYSTEM_UID
&& (adapter = mAdapter.get()) != null) {
mgr.unbindRemoteViewsService(appWidgetId, intent,
new UserHandle(adapter.mUserId));
} else {
mgr.unbindRemoteViewsService(appWidgetId, intent, Process.myUserHandle());
}
mIsConnecting = false; mIsConnecting = false;
} catch (Exception e) { } catch (Exception e) {
Log.e("RemoteViewsAdapterServiceConnection", "unbind(): " + e.getMessage()); Log.e("RemoteViewsAdapterServiceConnection", "unbind(): " + e.getMessage());
@ -761,6 +781,12 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
} }
mRequestedViews = new RemoteViewsFrameLayoutRefSet(); mRequestedViews = new RemoteViewsFrameLayoutRefSet();
if (Process.myUid() == Process.SYSTEM_UID) {
mUserId = new LockPatternUtils(context).getCurrentUser();
} else {
mUserId = UserHandle.myUserId();
}
// Strip the previously injected app widget id from service intent // Strip the previously injected app widget id from service intent
if (intent.hasExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID)) { if (intent.hasExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID)) {
intent.removeExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID); intent.removeExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID);

View File

@ -32,7 +32,10 @@ interface IAppWidgetService {
// //
int[] startListening(IAppWidgetHost host, String packageName, int hostId, int[] startListening(IAppWidgetHost host, String packageName, int hostId,
out List<RemoteViews> updatedViews); out List<RemoteViews> updatedViews);
int[] startListeningAsUser(IAppWidgetHost host, String packageName, int hostId,
out List<RemoteViews> updatedViews, int userId);
void stopListening(int hostId); void stopListening(int hostId);
void stopListeningAsUser(int hostId, int userId);
int allocateAppWidgetId(String packageName, int hostId); int allocateAppWidgetId(String packageName, int hostId);
void deleteAppWidgetId(int appWidgetId); void deleteAppWidgetId(int appWidgetId);
void deleteHost(int hostId); void deleteHost(int hostId);
@ -56,8 +59,8 @@ interface IAppWidgetService {
void bindAppWidgetId(int appWidgetId, in ComponentName provider, in Bundle options); void bindAppWidgetId(int appWidgetId, in ComponentName provider, in Bundle options);
boolean bindAppWidgetIdIfAllowed( boolean bindAppWidgetIdIfAllowed(
in String packageName, int appWidgetId, in ComponentName provider, in Bundle options); in String packageName, int appWidgetId, in ComponentName provider, in Bundle options);
void bindRemoteViewsService(int appWidgetId, in Intent intent, in IBinder connection); void bindRemoteViewsService(int appWidgetId, in Intent intent, in IBinder connection, int userId);
void unbindRemoteViewsService(int appWidgetId, in Intent intent); void unbindRemoteViewsService(int appWidgetId, in Intent intent, int userId);
int[] getAppWidgetIds(in ComponentName provider); int[] getAppWidgetIds(in ComponentName provider);
} }

View File

@ -101,6 +101,8 @@ public class KeyguardHostView extends KeyguardViewBase {
private boolean mSafeModeEnabled; private boolean mSafeModeEnabled;
private boolean mUserSetupCompleted; private boolean mUserSetupCompleted;
// User for whom this host view was created
private int mUserId;
/*package*/ interface TransportCallback { /*package*/ interface TransportCallback {
void onListenerDetached(); void onListenerDetached();
@ -127,6 +129,7 @@ public class KeyguardHostView extends KeyguardViewBase {
public KeyguardHostView(Context context, AttributeSet attrs) { public KeyguardHostView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
mLockPatternUtils = new LockPatternUtils(context); mLockPatternUtils = new LockPatternUtils(context);
mUserId = mLockPatternUtils.getCurrentUser();
mAppWidgetHost = new AppWidgetHost( mAppWidgetHost = new AppWidgetHost(
context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper()); context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper());
cleanupAppWidgetIds(); cleanupAppWidgetIds();
@ -338,14 +341,14 @@ public class KeyguardHostView extends KeyguardViewBase {
@Override @Override
protected void onAttachedToWindow() { protected void onAttachedToWindow() {
super.onAttachedToWindow(); super.onAttachedToWindow();
mAppWidgetHost.startListening(); mAppWidgetHost.startListeningAsUser(mUserId);
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks); KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks);
} }
@Override @Override
protected void onDetachedFromWindow() { protected void onDetachedFromWindow() {
super.onDetachedFromWindow(); super.onDetachedFromWindow();
mAppWidgetHost.stopListening(); mAppWidgetHost.stopListeningAsUser(mUserId);
KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks); KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks);
} }

View File

@ -196,9 +196,14 @@ class AppWidgetService extends IAppWidgetService.Stub
} }
@Override @Override
public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
throws RemoteException { int userId) throws RemoteException {
getImplForUser(getCallingOrCurrentUserId()).bindRemoteViewsService( if (Binder.getCallingPid() != android.os.Process.myPid()
&& userId != UserHandle.getCallingUserId()) {
throw new SecurityException("Call from non-system process. Calling uid = "
+ Binder.getCallingUid());
}
getImplForUser(userId).bindRemoteViewsService(
appWidgetId, intent, connection); appWidgetId, intent, connection);
} }
@ -209,6 +214,17 @@ class AppWidgetService extends IAppWidgetService.Stub
packageName, hostId, updatedViews); packageName, hostId, updatedViews);
} }
@Override
public int[] startListeningAsUser(IAppWidgetHost host, String packageName, int hostId,
List<RemoteViews> updatedViews, int userId) throws RemoteException {
if (Binder.getCallingPid() != android.os.Process.myPid()
&& userId != UserHandle.getCallingUserId()) {
throw new SecurityException("Call from non-system process. Calling uid = "
+ Binder.getCallingUid());
}
return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews);
}
public void onUserRemoved(int userId) { public void onUserRemoved(int userId) {
if (userId < 1) return; if (userId < 1) return;
synchronized (mAppWidgetServices) { synchronized (mAppWidgetServices) {
@ -306,8 +322,24 @@ class AppWidgetService extends IAppWidgetService.Stub
} }
@Override @Override
public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException { public void stopListeningAsUser(int hostId, int userId) throws RemoteException {
getImplForUser(getCallingOrCurrentUserId()).unbindRemoteViewsService( if (Binder.getCallingPid() != android.os.Process.myPid()
&& userId != UserHandle.getCallingUserId()) {
throw new SecurityException("Call from non-system process. Calling uid = "
+ Binder.getCallingUid());
}
getImplForUser(userId).stopListening(hostId);
}
@Override
public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId)
throws RemoteException {
if (Binder.getCallingPid() != android.os.Process.myPid()
&& userId != UserHandle.getCallingUserId()) {
throw new SecurityException("Call from non-system process. Calling uid = "
+ Binder.getCallingUid());
}
getImplForUser(userId).unbindRemoteViewsService(
appWidgetId, intent); appWidgetId, intent);
} }

View File

@ -116,6 +116,15 @@ class AppWidgetServiceImpl {
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 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) int tag; // for use while saving state (the index)
boolean uidMatches(int callingUid) {
if (UserHandle.getAppId(callingUid) == Process.myUid()) {
// For a host that's in the system process, ignore the user id
return UserHandle.isSameApp(this.uid, callingUid);
} else {
return this.uid == callingUid;
}
}
} }
static class AppWidgetId { static class AppWidgetId {
@ -476,7 +485,7 @@ class AppWidgetServiceImpl {
boolean changed = false; boolean changed = false;
for (int i = N - 1; i >= 0; i--) { for (int i = N - 1; i >= 0; i--) {
Host host = mHosts.get(i); Host host = mHosts.get(i);
if (host.uid == callingUid) { if (host.uidMatches(callingUid)) {
deleteHostLocked(host); deleteHostLocked(host);
changed = true; changed = true;
} }
@ -744,8 +753,6 @@ class AppWidgetServiceImpl {
conn.disconnect(); conn.disconnect();
mContext.unbindService(conn); mContext.unbindService(conn);
mBoundRemoteViewsServices.remove(key); mBoundRemoteViewsServices.remove(key);
} else {
Log.e("AppWidgetService", "Error (unbindRemoteViewsService): Connection not bound");
} }
} }
} }
@ -968,13 +975,8 @@ class AppWidgetServiceImpl {
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
if (id == null) { if (id == null) {
String message = "AppWidgetId NPE: mUserId=" + mUserId Slog.w(TAG, "widget id " + appWidgetIds[i] + " not found!");
+ ", callingUid=" + Binder.getCallingUid() } else if (id.views != null) {
+ ", appWidgetIds[i]=" + appWidgetIds[i]
+ "\n mAppWidgets:\n" + getUserWidgets();
throw new NullPointerException(message);
}
if (id.views != null) {
// Only trigger a partial update for a widget if it has received a full update // Only trigger a partial update for a widget if it has received a full update
updateAppWidgetInstanceLocked(id, views, true); updateAppWidgetInstanceLocked(id, views, true);
} }
@ -982,18 +984,6 @@ class AppWidgetServiceImpl {
} }
} }
private String getUserWidgets() {
StringBuffer sb = new StringBuffer();
for (AppWidgetId widget: mAppWidgetIds) {
sb.append(" id="); sb.append(widget.appWidgetId);
sb.append(", hostUid="); sb.append(widget.host.uid);
sb.append(", provider="); sb.append(widget.provider.info.provider.toString());
sb.append("\n");
}
sb.append("\n");
return sb.toString();
}
public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) { public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
if (appWidgetIds == null) { if (appWidgetIds == null) {
return; return;
@ -1186,7 +1176,7 @@ class AppWidgetServiceImpl {
} }
boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) { boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) {
if (id.host.uid == callingUid) { if (id.host.uidMatches(callingUid)) {
// Apps hosting the AppWidget have access to it. // Apps hosting the AppWidget have access to it.
return true; return true;
} }
@ -1229,7 +1219,7 @@ class AppWidgetServiceImpl {
final int N = mHosts.size(); final int N = mHosts.size();
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
Host h = mHosts.get(i); Host h = mHosts.get(i);
if (h.uid == uid && h.hostId == hostId) { if (h.uidMatches(uid) && h.hostId == hostId) {
return h; return h;
} }
} }