From ee68fd889c2dfcd895b8e73fc39d7b97826dc3d8 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Thu, 23 Jun 2016 13:12:23 -0400 Subject: [PATCH] QS: Don't use ComponentName to identify tiles Evidently some apps redirect/obscure tiles in a way that makes creating a ComponentName from the TileService useless. Instead generate a token which will be a much more stable way of identifying tiles henceforth. Change-Id: Id68550bcdcdc3e3987f09380f258610e7a5aca85 Fixes: 29121793 --- .../service/quicksettings/IQSService.aidl | 16 ++--- .../android/service/quicksettings/Tile.java | 37 ++-------- .../service/quicksettings/TileService.java | 24 ++++--- .../systemui/qs/external/CustomTile.java | 2 +- .../qs/external/QSTileServiceWrapper.java | 4 ++ .../qs/external/TileLifecycleManager.java | 9 ++- .../qs/external/TileServiceManager.java | 6 ++ .../systemui/qs/external/TileServices.java | 72 ++++++++++--------- .../systemui/statusbar/phone/QSTileHost.java | 4 +- .../external/TileLifecycleManagerTests.java | 2 +- 10 files changed, 90 insertions(+), 86 deletions(-) diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl index bf963570b040e..d03ff93be5cee 100644 --- a/core/java/android/service/quicksettings/IQSService.aidl +++ b/core/java/android/service/quicksettings/IQSService.aidl @@ -23,16 +23,16 @@ import android.service.quicksettings.Tile; * @hide */ interface IQSService { - Tile getTile(in ComponentName component); - void updateQsTile(in Tile tile); - void updateStatusIcon(in Tile tile, in Icon icon, + Tile getTile(in IBinder tile); + void updateQsTile(in Tile tile, in IBinder service); + void updateStatusIcon(in IBinder tile, in Icon icon, String contentDescription); - void onShowDialog(in Tile tile); - void onStartActivity(in Tile tile); + void onShowDialog(in IBinder tile); + void onStartActivity(in IBinder tile); boolean isLocked(); boolean isSecure(); - void startUnlockAndRun(in Tile tile); + void startUnlockAndRun(in IBinder tile); - void onDialogHidden(in Tile tile); - void onStartSuccessful(in Tile tile); + void onDialogHidden(in IBinder tile); + void onStartSuccessful(in IBinder tile); } diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java index 3d7d53ea67e8a..4b81a72608522 100644 --- a/core/java/android/service/quicksettings/Tile.java +++ b/core/java/android/service/quicksettings/Tile.java @@ -15,8 +15,8 @@ */ package android.service.quicksettings; -import android.content.ComponentName; import android.graphics.drawable.Icon; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; @@ -59,7 +59,7 @@ public final class Tile implements Parcelable { */ public static final int STATE_ACTIVE = 2; - private ComponentName mComponentName; + private IBinder mToken; private Icon mIcon; private CharSequence mLabel; private CharSequence mContentDescription; @@ -78,29 +78,15 @@ public final class Tile implements Parcelable { /** * @hide */ - public Tile(ComponentName componentName) { - mComponentName = componentName; + public Tile() { } /** * @hide */ - public void setService(IQSService service) { + public void setService(IQSService service, IBinder stub) { mService = service; - } - - /** - * @hide - */ - public ComponentName getComponentName() { - return mComponentName; - } - - /** - * @hide - */ - public IQSService getQsService() { - return mService; + mToken = stub; } /** @@ -193,7 +179,7 @@ public final class Tile implements Parcelable { */ public void updateTile() { try { - mService.updateQsTile(this); + mService.updateQsTile(this, mToken); } catch (RemoteException e) { Log.e(TAG, "Couldn't update tile"); } @@ -201,12 +187,6 @@ public final class Tile implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - if (mComponentName != null) { - dest.writeByte((byte) 1); - mComponentName.writeToParcel(dest, flags); - } else { - dest.writeByte((byte) 0); - } if (mIcon != null) { dest.writeByte((byte) 1); mIcon.writeToParcel(dest, flags); @@ -219,11 +199,6 @@ public final class Tile implements Parcelable { } private void readFromParcel(Parcel source) { - if (source.readByte() != 0) { - mComponentName = ComponentName.CREATOR.createFromParcel(source); - } else { - mComponentName = null; - } if (source.readByte() != 0) { mIcon = Icon.CREATOR.createFromParcel(source); } else { diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java index 50411ab7d15e9..887f4b6577b91 100644 --- a/core/java/android/service/quicksettings/TileService.java +++ b/core/java/android/service/quicksettings/TileService.java @@ -120,6 +120,11 @@ public class TileService extends Service { */ public static final String EXTRA_SERVICE = "service"; + /** + * @hide + */ + public static final String EXTRA_TOKEN = "token"; + /** * @hide */ @@ -132,6 +137,7 @@ public class TileService extends Service { private IBinder mToken; private IQSService mService; private Runnable mUnlockRunnable; + private IBinder mTileToken; @Override public void onDestroy() { @@ -197,7 +203,7 @@ public class TileService extends Service { public final void setStatusIcon(Icon icon, String contentDescription) { if (mService != null) { try { - mService.updateStatusIcon(mTile, icon, contentDescription); + mService.updateStatusIcon(mTileToken, icon, contentDescription); } catch (RemoteException e) { } } @@ -224,14 +230,14 @@ public class TileService extends Service { @Override public void onViewDetachedFromWindow(View v) { try { - mService.onDialogHidden(getQsTile()); + mService.onDialogHidden(mTileToken); } catch (RemoteException e) { } } }); dialog.show(); try { - mService.onShowDialog(mTile); + mService.onShowDialog(mTileToken); } catch (RemoteException e) { } } @@ -246,7 +252,7 @@ public class TileService extends Service { public final void unlockAndRun(Runnable runnable) { mUnlockRunnable = runnable; try { - mService.startUnlockAndRun(mTile); + mService.startUnlockAndRun(mTileToken); } catch (RemoteException e) { } } @@ -292,7 +298,7 @@ public class TileService extends Service { public final void startActivityAndCollapse(Intent intent) { startActivity(intent); try { - mService.onStartActivity(mTile); + mService.onStartActivity(mTileToken); } catch (RemoteException e) { } } @@ -311,14 +317,14 @@ public class TileService extends Service { @Override public IBinder onBind(Intent intent) { mService = IQSService.Stub.asInterface(intent.getIBinderExtra(EXTRA_SERVICE)); + mTileToken = intent.getIBinderExtra(EXTRA_TOKEN); try { - ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT); - mTile = mService.getTile(component); + mTile = mService.getTile(mTileToken); } catch (RemoteException e) { throw new RuntimeException("Unable to reach IQSService", e); } if (mTile != null) { - mTile.setService(mService); + mTile.setService(mService, mTileToken); mHandler.sendEmptyMessage(H.MSG_START_SUCCESS); } return new IQSTileService.Stub() { @@ -403,7 +409,7 @@ public class TileService extends Service { break; case MSG_START_SUCCESS: try { - mService.onStartSuccessful(mTile); + mService.onStartSuccessful(mTileToken); } catch (RemoteException e) { } break; diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index 569a567c25fab..b36221d83cd63 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -71,7 +71,7 @@ public class CustomTile extends QSTile implements TileChangeListen super(host); mWindowManager = WindowManagerGlobal.getWindowManagerService(); mComponent = ComponentName.unflattenFromString(action); - mTile = new Tile(mComponent); + mTile = new Tile(); setTileIcon(); mServiceManager = host.getTileServices().getTileWrapper(this); mService = mServiceManager.getTileService(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java index 407453c6e3b26..451e1f6ca8272 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java @@ -94,4 +94,8 @@ public class QSTileServiceWrapper { return false; } } + + public IQSTileService getService() { + return mService; + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java index 79f9de6b4bf7e..681005c2d08d2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java @@ -26,6 +26,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ServiceInfo; import android.net.Uri; +import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; @@ -37,6 +38,7 @@ import android.service.quicksettings.TileService; import android.support.annotation.VisibleForTesting; import android.util.ArraySet; import android.util.Log; + import libcore.util.Objects; import java.util.Set; @@ -67,6 +69,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements private final Handler mHandler; private final Intent mIntent; private final UserHandle mUser; + private final IBinder mToken = new Binder(); private Set mQueuedMessages = new ArraySet<>(); private QSTileServiceWrapper mWrapper; @@ -88,7 +91,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements mHandler = handler; mIntent = intent; mIntent.putExtra(TileService.EXTRA_SERVICE, service.asBinder()); - mIntent.putExtra(TileService.EXTRA_COMPONENT, intent.getComponent()); + mIntent.putExtra(TileService.EXTRA_TOKEN, mToken); mUser = user; if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser); } @@ -396,6 +399,10 @@ public class TileLifecycleManager extends BroadcastReceiver implements handleDeath(); } + public IBinder getToken() { + return mToken; + } + public interface TileChangeListener { void onTileChanged(ComponentName tile); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java index 3d030f977fbc4..f3e4d607aaaaf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Handler; +import android.os.IBinder; import android.os.UserHandle; import android.service.quicksettings.IQSTileService; import android.service.quicksettings.Tile; @@ -32,6 +33,7 @@ import android.service.quicksettings.TileService; import android.support.annotation.VisibleForTesting; import android.util.Log; +import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener; import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener; import java.util.List; @@ -106,6 +108,10 @@ public class TileServiceManager { return mStateManager; } + public IBinder getToken() { + return mStateManager.getToken(); + } + public void setBindRequested(boolean bindRequested) { if (mBindRequested == bindRequested) return; mBindRequested = bindRequested; diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java index 6f0bed2f5445e..575f198acf461 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -25,10 +25,12 @@ import android.content.pm.PackageManager; import android.graphics.drawable.Icon; import android.os.Binder; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.service.quicksettings.IQSService; +import android.service.quicksettings.IQSTileService; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; import android.util.ArrayMap; @@ -52,6 +54,7 @@ public class TileServices extends IQSService.Stub { private final ArrayMap mServices = new ArrayMap<>(); private final ArrayMap mTiles = new ArrayMap<>(); + private final ArrayMap mTokenMap = new ArrayMap<>(); private final Context mContext; private final Handler mHandler; private final Handler mMainHandler; @@ -82,6 +85,7 @@ public class TileServices extends IQSService.Stub { synchronized (mServices) { mServices.put(tile, service); mTiles.put(component, tile); + mTokenMap.put(service.getToken(), tile); } return service; } @@ -95,6 +99,7 @@ public class TileServices extends IQSService.Stub { service.setBindAllowed(false); service.handleDestroy(); mServices.remove(tile); + mTokenMap.remove(service.getToken()); mTiles.remove(tile.getComponent()); final String slot = tile.getComponent().getClassName(); mMainHandler.post(new Runnable() { @@ -138,8 +143,9 @@ public class TileServices extends IQSService.Stub { } } - private void verifyCaller(String packageName) { + private void verifyCaller(CustomTile tile) { try { + String packageName = tile.getComponent().getPackageName(); int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, Binder.getCallingUserHandle().getIdentifier()); if (Binder.getCallingUid() != uid) { @@ -170,10 +176,9 @@ public class TileServices extends IQSService.Stub { } @Override - public void updateQsTile(Tile tile) { - ComponentName componentName = tile.getComponentName(); - verifyCaller(componentName.getPackageName()); - CustomTile customTile = getTileForComponent(componentName); + public void updateQsTile(Tile tile, IBinder token) { + CustomTile customTile = getTileForToken(token); + verifyCaller(customTile); if (customTile != null) { synchronized (mServices) { final TileServiceManager tileServiceManager = mServices.get(customTile); @@ -186,10 +191,9 @@ public class TileServices extends IQSService.Stub { } @Override - public void onStartSuccessful(Tile tile) { - ComponentName componentName = tile.getComponentName(); - verifyCaller(componentName.getPackageName()); - CustomTile customTile = getTileForComponent(componentName); + public void onStartSuccessful(IBinder token) { + CustomTile customTile = getTileForToken(token); + verifyCaller(customTile); if (customTile != null) { synchronized (mServices) { final TileServiceManager tileServiceManager = mServices.get(customTile); @@ -200,10 +204,9 @@ public class TileServices extends IQSService.Stub { } @Override - public void onShowDialog(Tile tile) { - ComponentName componentName = tile.getComponentName(); - verifyCaller(componentName.getPackageName()); - CustomTile customTile = getTileForComponent(componentName); + public void onShowDialog(IBinder token) { + CustomTile customTile = getTileForToken(token); + verifyCaller(customTile); if (customTile != null) { customTile.onDialogShown(); mHost.collapsePanels(); @@ -212,10 +215,9 @@ public class TileServices extends IQSService.Stub { } @Override - public void onDialogHidden(Tile tile) { - ComponentName componentName = tile.getComponentName(); - verifyCaller(componentName.getPackageName()); - CustomTile customTile = getTileForComponent(componentName); + public void onDialogHidden(IBinder token) { + CustomTile customTile = getTileForToken(token); + verifyCaller(customTile); if (customTile != null) { mServices.get(customTile).setShowingDialog(false); customTile.onDialogHidden(); @@ -223,23 +225,22 @@ public class TileServices extends IQSService.Stub { } @Override - public void onStartActivity(Tile tile) { - ComponentName componentName = tile.getComponentName(); - verifyCaller(componentName.getPackageName()); - CustomTile customTile = getTileForComponent(componentName); + public void onStartActivity(IBinder token) { + CustomTile customTile = getTileForToken(token); + verifyCaller(customTile); if (customTile != null) { mHost.collapsePanels(); } } @Override - public void updateStatusIcon(Tile tile, Icon icon, String contentDescription) { - final ComponentName componentName = tile.getComponentName(); - String packageName = componentName.getPackageName(); - verifyCaller(packageName); - CustomTile customTile = getTileForComponent(componentName); + public void updateStatusIcon(IBinder token, Icon icon, String contentDescription) { + CustomTile customTile = getTileForToken(token); + verifyCaller(customTile); if (customTile != null) { try { + ComponentName componentName = customTile.getComponent(); + String packageName = componentName.getPackageName(); UserHandle userHandle = getCallingUserHandle(); PackageInfo info = mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userHandle.getIdentifier()); @@ -263,9 +264,9 @@ public class TileServices extends IQSService.Stub { } @Override - public Tile getTile(ComponentName componentName) { - verifyCaller(componentName.getPackageName()); - CustomTile customTile = getTileForComponent(componentName); + public Tile getTile(IBinder token) { + CustomTile customTile = getTileForToken(token); + verifyCaller(customTile); if (customTile != null) { return customTile.getQsTile(); } @@ -273,10 +274,9 @@ public class TileServices extends IQSService.Stub { } @Override - public void startUnlockAndRun(Tile tile) { - ComponentName componentName = tile.getComponentName(); - verifyCaller(componentName.getPackageName()); - CustomTile customTile = getTileForComponent(componentName); + public void startUnlockAndRun(IBinder token) { + CustomTile customTile = getTileForToken(token); + verifyCaller(customTile); if (customTile != null) { customTile.startUnlockAndRun(); } @@ -294,6 +294,12 @@ public class TileServices extends IQSService.Stub { return keyguardMonitor.isSecure() && keyguardMonitor.isShowing(); } + private CustomTile getTileForToken(IBinder token) { + synchronized (mServices) { + return mTokenMap.get(token); + } + } + private CustomTile getTileForComponent(ComponentName component) { synchronized (mServices) { return mTiles.get(component); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index 011ec22d2b3b5..18948211a17d4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -407,7 +407,7 @@ public class QSTileHost implements QSTile.Host, Tunable { ComponentName component = CustomTile.getComponentFromSpec(tileSpec); Intent intent = new Intent().setComponent(component); TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(), - mContext, mServices, new Tile(component), intent, + mContext, mServices, new Tile(), intent, new UserHandle(ActivityManager.getCurrentUser())); lifecycleManager.onStopListening(); lifecycleManager.onTileRemoved(); @@ -421,7 +421,7 @@ public class QSTileHost implements QSTile.Host, Tunable { ComponentName component = CustomTile.getComponentFromSpec(tileSpec); Intent intent = new Intent().setComponent(component); TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(), - mContext, mServices, new Tile(component), intent, + mContext, mServices, new Tile(), intent, new UserHandle(ActivityManager.getCurrentUser())); lifecycleManager.onTileAdded(); lifecycleManager.flushMessagesAndUnbind(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java index c93377a68f5dc..7703c5867d383 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java @@ -58,7 +58,7 @@ public class TileLifecycleManagerTests extends AndroidTestCase { mHandler = new Handler(mThread.getLooper()); ComponentName component = new ComponentName(mContext, FakeTileService.class); mStateManager = new TileLifecycleManager(mHandler, getContext(), - Mockito.mock(IQSService.class), new Tile(component), + Mockito.mock(IQSService.class), new Tile(), new Intent().setComponent(component), new UserHandle(UserHandle.myUserId())); mCallbacks.clear();