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.
*/
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;
ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>();
@ -161,7 +170,8 @@ public class AppWidgetHost {
if (mPackageName == null) {
mPackageName = mContext.getPackageName();
}
updatedIds = sService.startListening(mCallbacks, mPackageName, mHostId, updatedViews);
updatedIds = sService.startListeningAsUser(
mCallbacks, mPackageName, mHostId, updatedViews, userId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@ -179,13 +189,29 @@ public class AppWidgetHost {
*/
public void stopListening() {
try {
sService.stopListening(mHostId);
sService.stopListeningAsUser(mHostId, UserHandle.myUserId());
}
catch (RemoteException 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.
*

View File

@ -23,6 +23,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.util.TypedValue;
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
* RemoteViewsAdapter.
* @param connection The callback interface to be notified when a connection is made or lost.
* @param userHandle The user to bind to.
* @hide
*/
public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
UserHandle userHandle) {
try {
sService.bindRemoteViewsService(appWidgetId, intent, connection);
sService.bindRemoteViewsService(appWidgetId, intent, connection,
userHandle.getIdentifier());
}
catch (RemoteException 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 intent The intent of the service which will be providing the data to the
* RemoteViewsAdapter.
* @param userHandle The user to unbind from.
* @hide
*/
public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
public void unbindRemoteViewsService(int appWidgetId, Intent intent, UserHandle userHandle) {
try {
sService.unbindRemoteViewsService(appWidgetId, intent);
sService.unbindRemoteViewsService(appWidgetId, intent, userHandle.getIdentifier());
}
catch (RemoteException 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.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
@ -40,6 +42,7 @@ import android.widget.RemoteViews.OnClickHandler;
import com.android.internal.widget.IRemoteViewsAdapterConnection;
import com.android.internal.widget.IRemoteViewsFactory;
import com.android.internal.widget.LockPatternUtils;
/**
* 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).
private boolean mDataReady = false;
int mUserId;
/**
* An interface for the RemoteAdapter to notify other classes when adapters
* 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) {
if (!mIsConnecting) {
try {
RemoteViewsAdapter adapter;
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;
} catch (Exception e) {
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) {
try {
RemoteViewsAdapter adapter;
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;
} catch (Exception e) {
Log.e("RemoteViewsAdapterServiceConnection", "unbind(): " + e.getMessage());
@ -761,6 +781,12 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
}
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
if (intent.hasExtra(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,
out List<RemoteViews> updatedViews);
int[] startListeningAsUser(IAppWidgetHost host, String packageName, int hostId,
out List<RemoteViews> updatedViews, int userId);
void stopListening(int hostId);
void stopListeningAsUser(int hostId, int userId);
int allocateAppWidgetId(String packageName, int hostId);
void deleteAppWidgetId(int appWidgetId);
void deleteHost(int hostId);
@ -56,8 +59,8 @@ interface IAppWidgetService {
void bindAppWidgetId(int appWidgetId, in ComponentName provider, in Bundle options);
boolean bindAppWidgetIdIfAllowed(
in String packageName, int appWidgetId, in ComponentName provider, in Bundle options);
void bindRemoteViewsService(int appWidgetId, in Intent intent, in IBinder connection);
void unbindRemoteViewsService(int appWidgetId, in Intent intent);
void bindRemoteViewsService(int appWidgetId, in Intent intent, in IBinder connection, int userId);
void unbindRemoteViewsService(int appWidgetId, in Intent intent, int userId);
int[] getAppWidgetIds(in ComponentName provider);
}

View File

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

View File

@ -196,9 +196,14 @@ class AppWidgetService extends IAppWidgetService.Stub
}
@Override
public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
throws RemoteException {
getImplForUser(getCallingOrCurrentUserId()).bindRemoteViewsService(
public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
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).bindRemoteViewsService(
appWidgetId, intent, connection);
}
@ -209,6 +214,17 @@ class AppWidgetService extends IAppWidgetService.Stub
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) {
if (userId < 1) return;
synchronized (mAppWidgetServices) {
@ -306,8 +322,24 @@ class AppWidgetService extends IAppWidgetService.Stub
}
@Override
public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
getImplForUser(getCallingOrCurrentUserId()).unbindRemoteViewsService(
public void stopListeningAsUser(int hostId, 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).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);
}

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
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 {
@ -476,7 +485,7 @@ class AppWidgetServiceImpl {
boolean changed = false;
for (int i = N - 1; i >= 0; i--) {
Host host = mHosts.get(i);
if (host.uid == callingUid) {
if (host.uidMatches(callingUid)) {
deleteHostLocked(host);
changed = true;
}
@ -744,8 +753,6 @@ class AppWidgetServiceImpl {
conn.disconnect();
mContext.unbindService(conn);
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++) {
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
if (id == null) {
String message = "AppWidgetId NPE: mUserId=" + mUserId
+ ", callingUid=" + Binder.getCallingUid()
+ ", appWidgetIds[i]=" + appWidgetIds[i]
+ "\n mAppWidgets:\n" + getUserWidgets();
throw new NullPointerException(message);
}
if (id.views != null) {
Slog.w(TAG, "widget id " + appWidgetIds[i] + " not found!");
} else if (id.views != null) {
// Only trigger a partial update for a widget if it has received a full update
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) {
if (appWidgetIds == null) {
return;
@ -1186,7 +1176,7 @@ class AppWidgetServiceImpl {
}
boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) {
if (id.host.uid == callingUid) {
if (id.host.uidMatches(callingUid)) {
// Apps hosting the AppWidget have access to it.
return true;
}
@ -1229,7 +1219,7 @@ class AppWidgetServiceImpl {
final int N = mHosts.size();
for (int i = 0; i < N; i++) {
Host h = mHosts.get(i);
if (h.uid == uid && h.hostId == hostId) {
if (h.uidMatches(uid) && h.hostId == hostId) {
return h;
}
}