blob: d3ae415223e0026be91344d79dbe7cb3a799ff23 [file] [log] [blame]
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Parcel;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
// These test binders purport to support an interface whose canonical
// interface name is ServiceTest.SERVICE_LOCAL
// Temporarily suppress, this test is causing unit test suite run to fail
// TODO: remove this suppress
@Suppress
public class ServiceTest extends ActivityTestsBase {
public static final String SERVICE_LOCAL =
"com.android.frameworks.coretests.activity.SERVICE_LOCAL";
public static final String SERVICE_LOCAL_GRANTED =
"com.android.frameworks.coretests.activity.SERVICE_LOCAL_GRANTED";
public static final String SERVICE_LOCAL_DENIED =
"com.android.frameworks.coretests.activity.SERVICE_LOCAL_DENIED";
public static final String REPORT_OBJ_NAME = "report";
public static final int STARTED_CODE = 1;
public static final int DESTROYED_CODE = 2;
public static final int SET_REPORTER_CODE = 3;
public static final int UNBIND_CODE = 4;
public static final int REBIND_CODE = 5;
public static final int STATE_START_1 = 0;
public static final int STATE_START_2 = 1;
public static final int STATE_UNBIND = 2;
public static final int STATE_DESTROY = 3;
public static final int STATE_REBIND = 4;
public static final int STATE_UNBIND_ONLY = 5;
public int mStartState;
public IBinder mStartReceiver = new Binder() {
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
//Log.i("ServiceTest", "Received code " + code + " in state " + mStartState);
if (code == STARTED_CODE) {
data.enforceInterface(SERVICE_LOCAL);
int count = data.readInt();
if (mStartState == STATE_START_1) {
if (count == 1) {
finishGood();
} else {
finishBad("onStart() again on an object when it should have been the first time");
}
} else if (mStartState == STATE_START_2) {
if (count == 2) {
finishGood();
} else {
finishBad("onStart() the first time on an object when it should have been the second time");
}
} else {
finishBad("onStart() was called when not expected (state="+mStartState+")");
}
return true;
} else if (code == DESTROYED_CODE) {
data.enforceInterface(SERVICE_LOCAL);
if (mStartState == STATE_DESTROY) {
finishGood();
} else {
finishBad("onDestroy() was called when not expected (state="+mStartState+")");
}
return true;
} else if (code == UNBIND_CODE) {
data.enforceInterface(SERVICE_LOCAL);
if (mStartState == STATE_UNBIND) {
mStartState = STATE_DESTROY;
} else if (mStartState == STATE_UNBIND_ONLY) {
finishGood();
} else {
finishBad("onUnbind() was called when not expected (state="+mStartState+")");
}
return true;
} else if (code == REBIND_CODE) {
data.enforceInterface(SERVICE_LOCAL);
if (mStartState == STATE_REBIND) {
finishGood();
} else {
finishBad("onRebind() was called when not expected (state="+mStartState+")");
}
return true;
} else {
return super.onTransact(code, data, reply, flags);
}
}
};
public class EmptyConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
}
public void onServiceDisconnected(ComponentName name) {
}
}
public class TestConnection implements ServiceConnection {
private final boolean mExpectDisconnect;
private final boolean mSetReporter;
private boolean mMonitor;
private int mCount;
public TestConnection(boolean expectDisconnect, boolean setReporter) {
mExpectDisconnect = expectDisconnect;
mSetReporter = setReporter;
mMonitor = !setReporter;
}
void setMonitor(boolean v) {
mMonitor = v;
}
public void onServiceConnected(ComponentName name, IBinder service) {
if (mSetReporter) {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(SERVICE_LOCAL);
data.writeStrongBinder(mStartReceiver);
try {
service.transact(SET_REPORTER_CODE, data, null, 0);
} catch (RemoteException e) {
finishBad("DeadObjectException when sending reporting object");
}
data.recycle();
}
if (mMonitor) {
mCount++;
if (mStartState == STATE_START_1) {
if (mCount == 1) {
finishGood();
} else {
finishBad("onServiceConnected() again on an object when it should have been the first time");
}
} else if (mStartState == STATE_START_2) {
if (mCount == 2) {
finishGood();
} else {
finishBad("onServiceConnected() the first time on an object when it should have been the second time");
}
} else {
finishBad("onServiceConnected() called unexpectedly");
}
}
}
public void onServiceDisconnected(ComponentName name) {
if (mMonitor) {
if (mStartState == STATE_DESTROY) {
if (mExpectDisconnect) {
finishGood();
} else {
finishBad("onServiceDisconnected() when it shouldn't have been");
}
} else {
finishBad("onServiceDisconnected() called unexpectedly");
}
}
}
}
void startExpectResult(Intent service) {
startExpectResult(service, new Bundle());
}
void startExpectResult(Intent service, Bundle bundle) {
bundle.putIBinder(REPORT_OBJ_NAME, mStartReceiver);
boolean success = false;
try {
//Log.i("foo", "STATE_START_1");
mStartState = STATE_START_1;
getContext().startService(new Intent(service).putExtras(bundle));
waitForResultOrThrow(5 * 1000, "service to start first time");
//Log.i("foo", "STATE_START_2");
mStartState = STATE_START_2;
getContext().startService(new Intent(service).putExtras(bundle));
waitForResultOrThrow(5 * 1000, "service to start second time");
success = true;
} finally {
if (!success) {
try {
getContext().stopService(service);
} catch (Exception e) {
// eat
}
}
}
//Log.i("foo", "STATE_DESTROY");
mStartState = STATE_DESTROY;
getContext().stopService(service);
waitForResultOrThrow(5 * 1000, "service to be destroyed");
}
void startExpectNoPermission(Intent service) {
try {
getContext().startService(service);
fail("Expected security exception when starting " + service);
} catch (SecurityException e) {
// expected
}
}
void bindExpectResult(Intent service) {
TestConnection conn = new TestConnection(true, false);
TestConnection conn2 = new TestConnection(false, false);
boolean success = false;
try {
// Expect to see the TestConnection connected.
mStartState = STATE_START_1;
getContext().bindService(service, conn, 0);
getContext().startService(service);
waitForResultOrThrow(5 * 1000, "existing connection to receive service");
// Expect to see the second TestConnection connected.
getContext().bindService(service, conn2, 0);
waitForResultOrThrow(5 * 1000, "new connection to receive service");
getContext().unbindService(conn2);
success = true;
} finally {
if (!success) {
try {
getContext().stopService(service);
getContext().unbindService(conn);
getContext().unbindService(conn2);
} catch (Exception e) {
// eat
}
}
}
// Expect to see the TestConnection disconnected.
mStartState = STATE_DESTROY;
getContext().stopService(service);
waitForResultOrThrow(5 * 1000, "existing connection to lose service");
getContext().unbindService(conn);
conn = new TestConnection(true, true);
success = false;
try {
// Expect to see the TestConnection connected.
conn.setMonitor(true);
mStartState = STATE_START_1;
getContext().bindService(service, conn, 0);
getContext().startService(service);
waitForResultOrThrow(5 * 1000, "existing connection to receive service");
success = true;
} finally {
if (!success) {
try {
getContext().stopService(service);
getContext().unbindService(conn);
} catch (Exception e) {
// eat
}
}
}
// Expect to see the service unbind and then destroyed.
conn.setMonitor(false);
mStartState = STATE_UNBIND;
getContext().stopService(service);
waitForResultOrThrow(5 * 1000, "existing connection to lose service");
getContext().unbindService(conn);
conn = new TestConnection(true, true);
success = false;
try {
// Expect to see the TestConnection connected.
conn.setMonitor(true);
mStartState = STATE_START_1;
getContext().bindService(service, conn, 0);
getContext().startService(service);
waitForResultOrThrow(5 * 1000, "existing connection to receive service");
success = true;
} finally {
if (!success) {
try {
getContext().stopService(service);
getContext().unbindService(conn);
} catch (Exception e) {
// eat
}
}
}
// Expect to see the service unbind but not destroyed.
conn.setMonitor(false);
mStartState = STATE_UNBIND_ONLY;
getContext().unbindService(conn);
waitForResultOrThrow(5 * 1000, "existing connection to unbind service");
// Expect to see the service rebound.
mStartState = STATE_REBIND;
getContext().bindService(service, conn, 0);
waitForResultOrThrow(5 * 1000, "existing connection to rebind service");
// Expect to see the service unbind and then destroyed.
mStartState = STATE_UNBIND;
getContext().stopService(service);
waitForResultOrThrow(5 * 1000, "existing connection to lose service");
getContext().unbindService(conn);
}
void bindAutoExpectResult(Intent service) {
TestConnection conn = new TestConnection(false, true);
boolean success = false;
try {
conn.setMonitor(true);
mStartState = STATE_START_1;
getContext().bindService(
service, conn, Context.BIND_AUTO_CREATE);
waitForResultOrThrow(5 * 1000, "connection to start and receive service");
success = true;
} finally {
if (!success) {
try {
getContext().unbindService(conn);
} catch (Exception e) {
// eat
}
}
}
mStartState = STATE_UNBIND;
getContext().unbindService(conn);
waitForResultOrThrow(5 * 1000, "disconnecting from service");
}
void bindExpectNoPermission(Intent service) {
TestConnection conn = new TestConnection(false, false);
try {
getContext().bindService(service, conn, Context.BIND_AUTO_CREATE);
fail("Expected security exception when binding " + service);
} catch (SecurityException e) {
// expected
} finally {
getContext().unbindService(conn);
}
}
@MediumTest
public void testLocalStartClass() throws Exception {
startExpectResult(new Intent(getContext(), LocalService.class));
}
@MediumTest
public void testLocalStartAction() throws Exception {
startExpectResult(new Intent(SERVICE_LOCAL));
}
@MediumTest
public void testLocalBindClass() throws Exception {
bindExpectResult(new Intent(getContext(), LocalService.class));
}
@MediumTest
public void testLocalBindAction() throws Exception {
bindExpectResult(new Intent(SERVICE_LOCAL));
}
@MediumTest
public void testLocalBindAutoClass() throws Exception {
bindAutoExpectResult(new Intent(getContext(), LocalService.class));
}
@MediumTest
public void testLocalBindAutoAction() throws Exception {
bindAutoExpectResult(new Intent(SERVICE_LOCAL));
}
@MediumTest
public void testLocalStartClassPermissionGranted() throws Exception {
startExpectResult(new Intent(getContext(), LocalGrantedService.class));
}
@MediumTest
public void testLocalStartActionPermissionGranted() throws Exception {
startExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
}
@MediumTest
public void testLocalBindClassPermissionGranted() throws Exception {
bindExpectResult(new Intent(getContext(), LocalGrantedService.class));
}
@MediumTest
public void testLocalBindActionPermissionGranted() throws Exception {
bindExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
}
@MediumTest
public void testLocalBindAutoClassPermissionGranted() throws Exception {
bindAutoExpectResult(new Intent(getContext(), LocalGrantedService.class));
}
@MediumTest
public void testLocalBindAutoActionPermissionGranted() throws Exception {
bindAutoExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
}
@MediumTest
public void testLocalStartClassPermissionDenied() throws Exception {
startExpectNoPermission(new Intent(getContext(), LocalDeniedService.class));
}
@MediumTest
public void testLocalStartActionPermissionDenied() throws Exception {
startExpectNoPermission(new Intent(SERVICE_LOCAL_DENIED));
}
@MediumTest
public void testLocalBindClassPermissionDenied() throws Exception {
bindExpectNoPermission(new Intent(getContext(), LocalDeniedService.class));
}
@MediumTest
public void testLocalBindActionPermissionDenied() throws Exception {
bindExpectNoPermission(new Intent(SERVICE_LOCAL_DENIED));
}
@MediumTest
public void testLocalUnbindTwice() throws Exception {
EmptyConnection conn = new EmptyConnection();
getContext().bindService(
new Intent(SERVICE_LOCAL_GRANTED), conn, 0);
getContext().unbindService(conn);
try {
getContext().unbindService(conn);
fail("No exception thrown on second unbind");
} catch (IllegalArgumentException e) {
//Log.i("foo", "Unbind exception", e);
}
}
}