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:
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user