summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
authorJim Miller <jaggies@google.com>2013-02-07 16:53:32 -0800
committerJim Miller <jaggies@google.com>2013-02-20 15:41:14 -0800
commita75a883fe9ea1790803148f0a561473073e3f264 (patch)
treea76a69d684a9643db3e22b72155aeb849c85a7f5 /core/java/android
parent7a60c43d874bd047ea4b93b94c9b8771ea5739cc (diff)
downloadframeworks_base-a75a883fe9ea1790803148f0a561473073e3f264.zip
frameworks_base-a75a883fe9ea1790803148f0a561473073e3f264.tar.gz
frameworks_base-a75a883fe9ea1790803148f0a561473073e3f264.tar.bz2
Add explicit userId to AppWidget binder calls
Keyguard currently relies on being in the system process to grab the given user's widgets. When we split keyguard into a new process, it will need to have access to user-specific info to instantiate a specific user's widgets. In order to accomplish this, we add an explicit userid to each binder call as well as new permission check to allow keyguard access. This also fixes a potential race condition of having an incorrect user id due to an async call to change the user. Every binder call now has a specific user id. The user id is either the calling process user's id or an explicit one passed by applications like keyguard. It is created once when an AppWidgetManager is instantiated and remains for the lifetime of the object. Fixed bug where widgets sometimes didn't show up for secondary users. Moved permission check in AppWidgetService into getImplForUser() Refactored to use userid from context associated AppWidgetManager instance. Clean up AppWidgetHost to use userId from Context. Remove redundant userId check in checkPermission since it's handled by ActivityManager.handleIncomingUser() Removed redundant userid check. Upload after rebase... Change-Id: Iae3e20f2b342c323bb58768b3d22051510f8268b
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/appwidget/AppWidgetHost.java145
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java43
-rw-r--r--core/java/android/content/Context.java8
-rw-r--r--core/java/android/content/ContextWrapper.java6
4 files changed, 109 insertions, 93 deletions
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index fa3bf4d..a470e70 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -31,6 +31,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.TypedValue;
import android.widget.RemoteViews;
import android.widget.RemoteViews.OnClickHandler;
@@ -55,38 +56,39 @@ public class AppWidgetHost {
Context mContext;
String mPackageName;
+ Handler mHandler;
+ int mHostId;
+ Callbacks mCallbacks = new Callbacks();
+ final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>();
+ private OnClickHandler mOnClickHandler;
class Callbacks extends IAppWidgetHost.Stub {
- public void updateAppWidget(int appWidgetId, RemoteViews views) {
+ public void updateAppWidget(int appWidgetId, RemoteViews views, int userId) {
if (isLocalBinder() && views != null) {
views = views.clone();
- views.setUser(mUser);
+ views.setUser(new UserHandle(userId));
}
- Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
- msg.arg1 = appWidgetId;
- msg.obj = views;
+ Message msg = mHandler.obtainMessage(HANDLE_UPDATE, appWidgetId, userId, views);
msg.sendToTarget();
}
- public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
+ public void providerChanged(int appWidgetId, AppWidgetProviderInfo info, int userId) {
if (isLocalBinder() && info != null) {
info = info.clone();
}
- Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
- msg.arg1 = appWidgetId;
- msg.obj = info;
+ Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED,
+ appWidgetId, userId, info);
msg.sendToTarget();
}
- public void providersChanged() {
- Message msg = mHandler.obtainMessage(HANDLE_PROVIDERS_CHANGED);
+ public void providersChanged(int userId) {
+ Message msg = mHandler.obtainMessage(HANDLE_PROVIDERS_CHANGED, userId, 0);
msg.sendToTarget();
}
- public void viewDataChanged(int appWidgetId, int viewId) {
- Message msg = mHandler.obtainMessage(HANDLE_VIEW_DATA_CHANGED);
- msg.arg1 = appWidgetId;
- msg.arg2 = viewId;
+ public void viewDataChanged(int appWidgetId, int viewId, int userId) {
+ Message msg = mHandler.obtainMessage(HANDLE_VIEW_DATA_CHANGED,
+ appWidgetId, viewId, userId);
msg.sendToTarget();
}
}
@@ -99,7 +101,7 @@ public class AppWidgetHost {
public void handleMessage(Message msg) {
switch (msg.what) {
case HANDLE_UPDATE: {
- updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);
+ updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj, msg.arg2);
break;
}
case HANDLE_PROVIDER_CHANGED: {
@@ -107,26 +109,17 @@ public class AppWidgetHost {
break;
}
case HANDLE_PROVIDERS_CHANGED: {
- onProvidersChanged();
+ onProvidersChanged(msg.arg1);
break;
}
case HANDLE_VIEW_DATA_CHANGED: {
- viewDataChanged(msg.arg1, msg.arg2);
+ viewDataChanged(msg.arg1, msg.arg2, (Integer) msg.obj);
break;
}
}
}
}
- Handler mHandler;
-
- int mHostId;
- Callbacks mCallbacks = new Callbacks();
- final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>();
- private OnClickHandler mOnClickHandler;
- // Optionally set by lockscreen
- private UserHandle mUser;
-
public AppWidgetHost(Context context, int hostId) {
this(context, hostId, null, context.getMainLooper());
}
@@ -140,14 +133,9 @@ public class AppWidgetHost {
mOnClickHandler = handler;
mHandler = new UpdateHandler(looper);
mDisplayMetrics = context.getResources().getDisplayMetrics();
- mUser = Process.myUserHandle();
bindService();
}
- /** @hide */
- public void setUserId(int userId) {
- mUser = new UserHandle(userId);
- }
private static void bindService() {
synchronized (sServiceLock) {
@@ -163,23 +151,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>();
+ final int userId = mContext.getUserId();
try {
if (mPackageName == null) {
mPackageName = mContext.getPackageName();
}
- updatedIds = sService.startListeningAsUser(
+ updatedIds = sService.startListening(
mCallbacks, mPackageName, mHostId, updatedViews, userId);
}
catch (RemoteException e) {
@@ -191,7 +171,7 @@ public class AppWidgetHost {
if (updatedViews.get(i) != null) {
updatedViews.get(i).setUser(new UserHandle(userId));
}
- updateAppWidgetView(updatedIds[i], updatedViews.get(i));
+ updateAppWidgetView(updatedIds[i], updatedViews.get(i), userId);
}
}
@@ -201,26 +181,14 @@ public class AppWidgetHost {
*/
public void stopListening() {
try {
- sService.stopListeningAsUser(mHostId, UserHandle.myUserId());
+ sService.stopListening(mHostId, mContext.getUserId());
}
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
+ // This is here because keyguard needs it since it'll be switching users after this call.
+ // If it turns out other apps need to call this often, we should re-think how this works.
clearViews();
}
@@ -230,11 +198,12 @@ public class AppWidgetHost {
* @return a appWidgetId
*/
public int allocateAppWidgetId() {
+
try {
if (mPackageName == null) {
mPackageName = mContext.getPackageName();
}
- return sService.allocateAppWidgetId(mPackageName, mHostId);
+ return sService.allocateAppWidgetId(mPackageName, mHostId, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -247,7 +216,7 @@ public class AppWidgetHost {
* @return a appWidgetId
* @hide
*/
- public static int allocateAppWidgetIdForSystem(int hostId) {
+ public static int allocateAppWidgetIdForSystem(int hostId, int userId) {
checkCallerIsSystem();
try {
if (sService == null) {
@@ -256,7 +225,7 @@ public class AppWidgetHost {
Context systemContext =
(Context) ActivityThread.currentActivityThread().getSystemContext();
String packageName = systemContext.getPackageName();
- return sService.allocateAppWidgetId(packageName, hostId);
+ return sService.allocateAppWidgetId(packageName, hostId, userId);
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
@@ -272,7 +241,7 @@ public class AppWidgetHost {
if (sService == null) {
bindService();
}
- return sService.getAppWidgetIdsForHost(mHostId);
+ return sService.getAppWidgetIdsForHost(mHostId, mContext.getUserId());
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
@@ -297,7 +266,7 @@ public class AppWidgetHost {
synchronized (mViews) {
mViews.remove(appWidgetId);
try {
- sService.deleteAppWidgetId(appWidgetId);
+ sService.deleteAppWidgetId(appWidgetId, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -309,13 +278,13 @@ public class AppWidgetHost {
* Stop listening to changes for this AppWidget.
* @hide
*/
- public static void deleteAppWidgetIdForSystem(int appWidgetId) {
+ public static void deleteAppWidgetIdForSystem(int appWidgetId, int userId) {
checkCallerIsSystem();
try {
if (sService == null) {
bindService();
}
- sService.deleteAppWidgetId(appWidgetId);
+ sService.deleteAppWidgetId(appWidgetId, userId);
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
@@ -331,7 +300,7 @@ public class AppWidgetHost {
*/
public void deleteHost() {
try {
- sService.deleteHost(mHostId);
+ sService.deleteHost(mHostId, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -347,8 +316,16 @@ public class AppWidgetHost {
* </ul>
*/
public static void deleteAllHosts() {
+ deleteAllHosts(UserHandle.myUserId());
+ }
+
+ /**
+ * Private method containing a userId
+ * @hide
+ */
+ public static void deleteAllHosts(int userId) {
try {
- sService.deleteAllHosts();
+ sService.deleteAllHosts(userId);
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -361,8 +338,9 @@ public class AppWidgetHost {
*/
public final AppWidgetHostView createView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
+ final int userId = context.getUserId();
AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
- view.setUserId(mUser.getIdentifier());
+ view.setUserId(userId);
view.setOnClickHandler(mOnClickHandler);
view.setAppWidget(appWidgetId, appWidget);
synchronized (mViews) {
@@ -370,9 +348,9 @@ public class AppWidgetHost {
}
RemoteViews views;
try {
- views = sService.getAppWidgetViews(appWidgetId);
+ views = sService.getAppWidgetViews(appWidgetId, userId);
if (views != null) {
- views.setUser(mUser);
+ views.setUser(new UserHandle(mContext.getUserId()));
}
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -422,10 +400,20 @@ public class AppWidgetHost {
* are added, updated or removed, or widget components are enabled or disabled.)
*/
protected void onProvidersChanged() {
- // Do nothing
+ onProvidersChanged(mContext.getUserId());
}
- void updateAppWidgetView(int appWidgetId, RemoteViews views) {
+ /**
+ * Private method containing a userId
+ * @hide
+ */
+ protected void onProvidersChanged(int userId) {
+ checkUserMatch(userId);
+ // Does nothing
+ }
+
+ void updateAppWidgetView(int appWidgetId, RemoteViews views, int userId) {
+ checkUserMatch(userId);
AppWidgetHostView v;
synchronized (mViews) {
v = mViews.get(appWidgetId);
@@ -435,7 +423,8 @@ public class AppWidgetHost {
}
}
- void viewDataChanged(int appWidgetId, int viewId) {
+ void viewDataChanged(int appWidgetId, int viewId, int userId) {
+ checkUserMatch(userId);
AppWidgetHostView v;
synchronized (mViews) {
v = mViews.get(appWidgetId);
@@ -445,6 +434,16 @@ public class AppWidgetHost {
}
}
+ // Ensure that the userId passed to us agrees with the one associated with this instance
+ // of AppWidgetHost.
+ // TODO: This should be removed in production code.
+ private void checkUserMatch(int userId) {
+ if (userId != mContext.getUserId()) {
+ throw new IllegalStateException(
+ "User ids don't match, userId=" + userId + ", mUserId=" + mContext.getUserId());
+ }
+ }
+
/**
* Clear the list of Views that have been created by this AppWidgetHost.
*/
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 6b1c3e2..e68d23a 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -16,6 +16,7 @@
package android.appwidget;
+import android.app.ActivityManagerNative;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -268,8 +269,8 @@ public class AppWidgetManager {
/**
* Sent when the custom extras for an AppWidget change.
*
- * @see AppWidgetProvider#onAppWidgetOptionsChanged
- * AppWidgetProvider.onAppWidgetOptionsChanged(Context context,
+ * @see AppWidgetProvider#onAppWidgetOptionsChanged
+ * AppWidgetProvider.onAppWidgetOptionsChanged(Context context,
* AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras)
*/
public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
@@ -352,7 +353,7 @@ public class AppWidgetManager {
* It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
* and outside of the handler.
* This method will only work when called from the uid that owns the AppWidget provider.
- *
+ *
* <p>
* The total Bitmap memory used by the RemoteViews object cannot exceed that required to
* fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.
@@ -362,7 +363,7 @@ public class AppWidgetManager {
*/
public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
try {
- sService.updateAppWidgetIds(appWidgetIds, views);
+ sService.updateAppWidgetIds(appWidgetIds, views, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -382,7 +383,7 @@ public class AppWidgetManager {
*/
public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
try {
- sService.updateAppWidgetOptions(appWidgetId, options);
+ sService.updateAppWidgetOptions(appWidgetId, options, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -402,7 +403,7 @@ public class AppWidgetManager {
*/
public Bundle getAppWidgetOptions(int appWidgetId) {
try {
- return sService.getAppWidgetOptions(appWidgetId);
+ return sService.getAppWidgetOptions(appWidgetId, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -436,7 +437,7 @@ public class AppWidgetManager {
* Perform an incremental update or command on the widget(s) specified by appWidgetIds.
*
* This update differs from {@link #updateAppWidget(int[], RemoteViews)} in that the
- * RemoteViews object which is passed is understood to be an incomplete representation of the
+ * RemoteViews object which is passed is understood to be an incomplete representation of the
* widget, and hence does not replace the cached representation of the widget. As of API
* level 17, the new properties set within the views objects will be appended to the cached
* representation of the widget, and hence will persist.
@@ -458,7 +459,7 @@ public class AppWidgetManager {
*/
public void partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views) {
try {
- sService.partiallyUpdateAppWidgetIds(appWidgetIds, views);
+ sService.partiallyUpdateAppWidgetIds(appWidgetIds, views, mContext.getUserId());
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
@@ -507,7 +508,7 @@ public class AppWidgetManager {
*/
public void updateAppWidget(ComponentName provider, RemoteViews views) {
try {
- sService.updateAppWidgetProvider(provider, views);
+ sService.updateAppWidgetProvider(provider, views, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -523,7 +524,7 @@ public class AppWidgetManager {
*/
public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
try {
- sService.notifyAppWidgetViewDataChanged(appWidgetIds, viewId);
+ sService.notifyAppWidgetViewDataChanged(appWidgetIds, viewId, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -557,7 +558,8 @@ public class AppWidgetManager {
*/
public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
try {
- List<AppWidgetProviderInfo> providers = sService.getInstalledProviders(categoryFilter);
+ List<AppWidgetProviderInfo> providers = sService.getInstalledProviders(categoryFilter,
+ mContext.getUserId());
for (AppWidgetProviderInfo info : providers) {
// Converting complex to dp.
info.minWidth =
@@ -584,7 +586,8 @@ public class AppWidgetManager {
*/
public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
try {
- AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId);
+ AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId,
+ mContext.getUserId());
if (info != null) {
// Converting complex to dp.
info.minWidth =
@@ -617,7 +620,7 @@ public class AppWidgetManager {
*/
public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
try {
- sService.bindAppWidgetId(appWidgetId, provider, null);
+ sService.bindAppWidgetId(appWidgetId, provider, null, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -641,7 +644,7 @@ public class AppWidgetManager {
*/
public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
try {
- sService.bindAppWidgetId(appWidgetId, provider, options);
+ sService.bindAppWidgetId(appWidgetId, provider, options, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -667,7 +670,7 @@ public class AppWidgetManager {
}
try {
return sService.bindAppWidgetIdIfAllowed(
- mContext.getPackageName(), appWidgetId, provider, null);
+ mContext.getPackageName(), appWidgetId, provider, null, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -696,8 +699,8 @@ public class AppWidgetManager {
return false;
}
try {
- return sService.bindAppWidgetIdIfAllowed(
- mContext.getPackageName(), appWidgetId, provider, options);
+ return sService.bindAppWidgetIdIfAllowed(mContext.getPackageName(), appWidgetId,
+ provider, options, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -715,7 +718,7 @@ public class AppWidgetManager {
*/
public boolean hasBindAppWidgetPermission(String packageName) {
try {
- return sService.hasBindAppWidgetPermission(packageName);
+ return sService.hasBindAppWidgetPermission(packageName, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -733,7 +736,7 @@ public class AppWidgetManager {
*/
public void setBindAppWidgetPermission(String packageName, boolean permission) {
try {
- sService.setBindAppWidgetPermission(packageName, permission);
+ sService.setBindAppWidgetPermission(packageName, permission, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -794,7 +797,7 @@ public class AppWidgetManager {
*/
public int[] getAppWidgetIds(ComponentName provider) {
try {
- return sService.getAppWidgetIds(provider);
+ return sService.getAppWidgetIds(provider, mContext.getUserId());
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c964af4..8a9eed2 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2691,6 +2691,14 @@ public abstract class Context {
throws PackageManager.NameNotFoundException;
/**
+ * Get the userId associated with this context
+ * @return user id
+ *
+ * @hide
+ */
+ public abstract int getUserId();
+
+ /**
* Return a new Context object for the current Context but whose resources
* are adjusted to match the given Configuration. Each call to this method
* returns a new instance of a Context object; Context objects are not
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 736dd99..2f1bf8c 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -623,6 +623,12 @@ public class ContextWrapper extends Context {
return mBase.createPackageContextAsUser(packageName, flags, user);
}
+ /** @hide */
+ @Override
+ public int getUserId() {
+ return mBase.getUserId();
+ }
+
@Override
public Context createConfigurationContext(Configuration overrideConfiguration) {
return mBase.createConfigurationContext(overrideConfiguration);