diff options
| author | Jim Miller <jaggies@google.com> | 2013-02-07 16:53:32 -0800 |
|---|---|---|
| committer | Jim Miller <jaggies@google.com> | 2013-02-20 15:41:14 -0800 |
| commit | a75a883fe9ea1790803148f0a561473073e3f264 (patch) | |
| tree | a76a69d684a9643db3e22b72155aeb849c85a7f5 /core/java/android/appwidget/AppWidgetHost.java | |
| parent | 7a60c43d874bd047ea4b93b94c9b8771ea5739cc (diff) | |
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/appwidget/AppWidgetHost.java')
| -rw-r--r-- | core/java/android/appwidget/AppWidgetHost.java | 145 |
1 files changed, 72 insertions, 73 deletions
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java index fa3bf4d32a6d..a470e704f0c4 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. */ |
