Merge "Fix race condition in TileServices" into qt-dev

am: 5e23231f82

Change-Id: I8175c8a2cdafc9ee5edc1ea5eb568ab1a4f0618f
This commit is contained in:
Fabian Kozynski
2019-05-10 07:39:51 -07:00
committed by android-build-merger
4 changed files with 53 additions and 2 deletions

View File

@@ -32,6 +32,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.WindowManager;
@@ -79,6 +80,9 @@ import com.android.internal.R;
*/
public class TileService extends Service {
private static final String TAG = "TileService";
private static final boolean DEBUG = false;
/**
* An activity that provides a user interface for adjusting TileService
* preferences. Optional but recommended for apps that implement a
@@ -381,18 +385,26 @@ public class TileService extends Service {
private static final int MSG_TILE_CLICKED = 5;
private static final int MSG_UNLOCK_COMPLETE = 6;
private static final int MSG_START_SUCCESS = 7;
private final String mTileServiceName;
public H(Looper looper) {
super(looper);
mTileServiceName = TileService.this.getClass().getSimpleName();
}
private void logMessage(String message) {
Log.d(TAG, mTileServiceName + " Handler - " + message);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_TILE_ADDED:
if (DEBUG) logMessage("MSG_TILE_ADDED");
TileService.this.onTileAdded();
break;
case MSG_TILE_REMOVED:
if (DEBUG) logMessage("MSG_TILE_REMOVED");
if (mListening) {
mListening = false;
TileService.this.onStopListening();
@@ -400,27 +412,32 @@ public class TileService extends Service {
TileService.this.onTileRemoved();
break;
case MSG_STOP_LISTENING:
if (DEBUG) logMessage("MSG_STOP_LISTENING");
if (mListening) {
mListening = false;
TileService.this.onStopListening();
}
break;
case MSG_START_LISTENING:
if (DEBUG) logMessage("MSG_START_LISTENING");
if (!mListening) {
mListening = true;
TileService.this.onStartListening();
}
break;
case MSG_TILE_CLICKED:
if (DEBUG) logMessage("MSG_TILE_CLICKED");
mToken = (IBinder) msg.obj;
TileService.this.onClick();
break;
case MSG_UNLOCK_COMPLETE:
if (DEBUG) logMessage("MSG_UNLOCK_COMPLETE");
if (mUnlockRunnable != null) {
mUnlockRunnable.run();
}
break;
case MSG_START_SUCCESS:
if (DEBUG) logMessage("MSG_START_SUCCESS");
try {
mService.onStartSuccessful(mTileToken);
} catch (RemoteException e) {

View File

@@ -69,6 +69,7 @@ public class TileServiceManager {
// Whether we have a pending bind going out to the service without a response yet.
// This defaults to true to ensure tiles start out unavailable.
private boolean mPendingBind = true;
private boolean mStarted = false;
TileServiceManager(TileServices tileServices, Handler handler, ComponentName component,
Tile tile) {
@@ -90,7 +91,23 @@ public class TileServiceManager {
Context context = mServices.getContext();
context.registerReceiverAsUser(mUninstallReceiver,
new UserHandle(ActivityManager.getCurrentUser()), filter, null, mHandler);
ComponentName component = tileLifecycleManager.getComponent();
}
boolean isLifecycleStarted() {
return mStarted;
}
/**
* Starts the TileLifecycleManager by adding the corresponding component as a Tile and
* binding to it if needed.
*
* This method should be called after constructing a TileServiceManager to guarantee that the
* TileLifecycleManager has added the tile and bound to it at least once.
*/
void startLifecycleManagerAndAddTile() {
mStarted = true;
ComponentName component = mStateManager.getComponent();
Context context = mServices.getContext();
if (!TileLifecycleManager.isTileAdded(context, component)) {
TileLifecycleManager.setTileAdded(context, component, true);
mStateManager.onTileAdded();

View File

@@ -51,6 +51,7 @@ import java.util.Comparator;
public class TileServices extends IQSService.Stub {
static final int DEFAULT_MAX_BOUND = 3;
static final int REDUCED_MAX_BOUND = 1;
private static final String TAG = "TileServices";
private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>();
private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
@@ -87,6 +88,8 @@ public class TileServices extends IQSService.Stub {
mTiles.put(component, tile);
mTokenMap.put(service.getToken(), tile);
}
// Makes sure binding only happens after the maps have been populated
service.startLifecycleManagerAndAddTile();
return service;
}
@@ -179,6 +182,11 @@ public class TileServices extends IQSService.Stub {
verifyCaller(customTile);
synchronized (mServices) {
final TileServiceManager tileServiceManager = mServices.get(customTile);
if (tileServiceManager == null || !tileServiceManager.isLifecycleStarted()) {
Log.e(TAG, "TileServiceManager not started for " + customTile.getComponent(),
new IllegalStateException());
return;
}
tileServiceManager.clearPendingBind();
tileServiceManager.setLastUpdate(System.currentTimeMillis());
}
@@ -194,6 +202,13 @@ public class TileServices extends IQSService.Stub {
verifyCaller(customTile);
synchronized (mServices) {
final TileServiceManager tileServiceManager = mServices.get(customTile);
// This should not happen as the TileServiceManager should have been started for the
// first bind to happen.
if (tileServiceManager == null || !tileServiceManager.isLifecycleStarted()) {
Log.e(TAG, "TileServiceManager not started for " + customTile.getComponent(),
new IllegalStateException());
return;
}
tileServiceManager.clearPendingBind();
}
customTile.refreshState();

View File

@@ -19,6 +19,7 @@ import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.os.Handler;
@@ -88,7 +89,7 @@ public class TileServicesTest extends SysuiTestCase {
assertEquals(NUM_FAKES, mManagers.size());
for (int i = 0; i < NUM_FAKES; i++) {
Mockito.when(mManagers.get(i).getBindPriority()).thenReturn(i);
when(mManagers.get(i).getBindPriority()).thenReturn(i);
}
mTileService.recalculateBindAllowance();
for (int i = 0; i < NUM_FAKES; i++) {
@@ -145,6 +146,7 @@ public class TileServicesTest extends SysuiTestCase {
protected TileServiceManager onCreateTileService(ComponentName component, Tile qsTile) {
TileServiceManager manager = mock(TileServiceManager.class);
mManagers.add(manager);
when(manager.isLifecycleStarted()).thenReturn(true);
return manager;
}
}