1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.adservices.ondevicepersonalization; 18 19 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertTrue; 22 23 import android.adservices.ondevicepersonalization.aidl.IDataAccessService; 24 import android.adservices.ondevicepersonalization.aidl.IDataAccessServiceCallback; 25 import android.adservices.ondevicepersonalization.aidl.IFederatedComputeCallback; 26 import android.adservices.ondevicepersonalization.aidl.IFederatedComputeService; 27 import android.adservices.ondevicepersonalization.aidl.IIsolatedModelService; 28 import android.adservices.ondevicepersonalization.aidl.IIsolatedModelServiceCallback; 29 import android.adservices.ondevicepersonalization.aidl.IIsolatedService; 30 import android.adservices.ondevicepersonalization.aidl.IIsolatedServiceCallback; 31 import android.content.Context; 32 import android.federatedcompute.common.TrainingOptions; 33 import android.net.Uri; 34 import android.os.Bundle; 35 import android.os.PersistableBundle; 36 import android.os.RemoteException; 37 38 import androidx.test.core.app.ApplicationProvider; 39 import androidx.test.filters.SmallTest; 40 41 import com.android.federatedcompute.internal.util.AbstractServiceBinder; 42 import com.android.ondevicepersonalization.internal.util.ByteArrayParceledSlice; 43 import com.android.ondevicepersonalization.internal.util.PersistableBundleUtils; 44 45 import org.junit.After; 46 import org.junit.AfterClass; 47 import org.junit.Before; 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 import org.junit.runners.Parameterized; 51 52 import java.util.Arrays; 53 import java.util.Collection; 54 import java.util.concurrent.CountDownLatch; 55 import java.util.concurrent.TimeUnit; 56 57 @SmallTest 58 @RunWith(Parameterized.class) 59 public class IsolatedServiceExceptionSafetyTest { 60 61 private final Context mContext = ApplicationProvider.getApplicationContext(); 62 63 private IIsolatedService mIsolatedService; 64 private static AbstractServiceBinder<IIsolatedService> sServiceBinder; 65 private int mCallbackErrorCode; 66 private int mIsolatedServiceErrorCode; 67 private byte[] mSerializedExceptionInfo; 68 private CountDownLatch mLatch; 69 70 @Parameterized.Parameter(0) 71 public String operation; 72 73 @Parameterized.Parameters data()74 public static Collection<Object[]> data() { 75 return Arrays.asList( 76 new Object[][] { 77 {RuntimeException.class.getName()}, 78 {NullPointerException.class.getName()}, 79 {IllegalArgumentException.class.getName()} 80 }); 81 } 82 83 @Before setUp()84 public void setUp() throws Exception { 85 if (sServiceBinder == null) { 86 sServiceBinder = 87 AbstractServiceBinder.getIsolatedServiceBinderByServiceName( 88 mContext, 89 "android.adservices.ondevicepersonalization." 90 + "IsolatedServiceExceptionSafetyTestImpl", 91 mContext.getPackageName(), 92 "testIsolatedProcess", 93 0, 94 IIsolatedService.Stub::asInterface); 95 } 96 97 mIsolatedService = sServiceBinder.getService(Runnable::run); 98 mLatch = new CountDownLatch(1); 99 } 100 101 @After tearDown()102 public void tearDown() { 103 mIsolatedService = null; 104 mCallbackErrorCode = 0; 105 } 106 107 @AfterClass tearDownClass()108 public static void tearDownClass() { 109 sServiceBinder.unbindFromService(); 110 } 111 112 @Test testOnRequestExceptions()113 public void testOnRequestExceptions() throws Exception { 114 PersistableBundle appParams = new PersistableBundle(); 115 appParams.putString("ex", operation); 116 ExecuteInputParcel input = 117 new ExecuteInputParcel.Builder() 118 .setAppPackageName("com.testapp") 119 .setSerializedAppParams(new ByteArrayParceledSlice( 120 PersistableBundleUtils.toByteArray(appParams))) 121 .build(); 122 Bundle params = new Bundle(); 123 params.putParcelable(Constants.EXTRA_INPUT, input); 124 params.putBinder(Constants.EXTRA_DATA_ACCESS_SERVICE_BINDER, new TestDataAccessService()); 125 params.putBinder( 126 Constants.EXTRA_FEDERATED_COMPUTE_SERVICE_BINDER, 127 new TestFederatedComputeService()); 128 params.putBinder(Constants.EXTRA_MODEL_SERVICE_BINDER, new TestIsolatedModelService()); 129 mIsolatedService.onRequest(Constants.OP_EXECUTE, params, new TestServiceCallback()); 130 assertTrue(mLatch.await(5000, TimeUnit.MILLISECONDS)); 131 assertEquals(Constants.STATUS_INTERNAL_ERROR, mCallbackErrorCode); 132 } 133 134 @Test testOnDownloadExceptions()135 public void testOnDownloadExceptions() throws Exception { 136 DownloadInputParcel input = 137 new DownloadInputParcel.Builder() 138 .setDataAccessServiceBinder(new TestDataAccessService(operation)) 139 .build(); 140 Bundle params = new Bundle(); 141 params.putParcelable(Constants.EXTRA_INPUT, input); 142 params.putBinder(Constants.EXTRA_DATA_ACCESS_SERVICE_BINDER, new TestDataAccessService()); 143 params.putBinder( 144 Constants.EXTRA_FEDERATED_COMPUTE_SERVICE_BINDER, 145 new TestFederatedComputeService()); 146 mIsolatedService.onRequest(Constants.OP_DOWNLOAD, params, new TestServiceCallback()); 147 assertTrue(mLatch.await(5000, TimeUnit.MILLISECONDS)); 148 assertEquals(Constants.STATUS_INTERNAL_ERROR, mCallbackErrorCode); 149 } 150 151 @Test testOnRender()152 public void testOnRender() throws Exception { 153 RenderInputParcel input = 154 new RenderInputParcel.Builder() 155 .setRenderingConfig( 156 new RenderingConfig.Builder().addKey(operation).build()) 157 .build(); 158 Bundle params = new Bundle(); 159 params.putParcelable(Constants.EXTRA_INPUT, input); 160 params.putBinder(Constants.EXTRA_DATA_ACCESS_SERVICE_BINDER, new TestDataAccessService()); 161 mIsolatedService.onRequest(Constants.OP_RENDER, params, new TestServiceCallback()); 162 assertTrue(mLatch.await(5000, TimeUnit.MILLISECONDS)); 163 assertEquals(Constants.STATUS_INTERNAL_ERROR, mCallbackErrorCode); 164 } 165 166 @Test testOnEvent()167 public void testOnEvent() throws Exception { 168 PersistableBundle appParams = new PersistableBundle(); 169 appParams.putString("ex", operation); 170 Bundle params = new Bundle(); 171 params.putParcelable( 172 Constants.EXTRA_INPUT, 173 new EventInputParcel.Builder().setParameters(appParams).build()); 174 params.putBinder(Constants.EXTRA_DATA_ACCESS_SERVICE_BINDER, new TestDataAccessService()); 175 params.putBinder(Constants.EXTRA_MODEL_SERVICE_BINDER, new TestIsolatedModelService()); 176 mIsolatedService.onRequest(Constants.OP_WEB_VIEW_EVENT, params, new TestServiceCallback()); 177 assertTrue(mLatch.await(5000, TimeUnit.MILLISECONDS)); 178 assertEquals(Constants.STATUS_INTERNAL_ERROR, mCallbackErrorCode); 179 } 180 181 @Test testOnTrainingExamples()182 public void testOnTrainingExamples() throws Exception { 183 TrainingExamplesInputParcel input = 184 new TrainingExamplesInputParcel.Builder() 185 .setPopulationName("") 186 .setTaskName(operation) 187 .setResumptionToken(new byte[] {0}) 188 .build(); 189 Bundle params = new Bundle(); 190 params.putParcelable(Constants.EXTRA_INPUT, input); 191 params.putBinder(Constants.EXTRA_DATA_ACCESS_SERVICE_BINDER, new TestDataAccessService()); 192 mIsolatedService.onRequest( 193 Constants.OP_TRAINING_EXAMPLE, params, new TestServiceCallback()); 194 assertTrue(mLatch.await(5000, TimeUnit.MILLISECONDS)); 195 assertEquals(Constants.STATUS_INTERNAL_ERROR, mCallbackErrorCode); 196 } 197 198 @Test testOnWebTrigger()199 public void testOnWebTrigger() throws Exception { 200 WebTriggerInputParcel input = 201 new WebTriggerInputParcel.Builder( 202 Uri.parse("http://desturl"), operation, new byte[] {1, 2, 3}) 203 .build(); 204 Bundle params = new Bundle(); 205 params.putParcelable(Constants.EXTRA_INPUT, input); 206 params.putBinder(Constants.EXTRA_DATA_ACCESS_SERVICE_BINDER, new TestDataAccessService()); 207 params.putBinder(Constants.EXTRA_MODEL_SERVICE_BINDER, new TestIsolatedModelService()); 208 mIsolatedService.onRequest(Constants.OP_WEB_TRIGGER, params, new TestServiceCallback()); 209 assertTrue(mLatch.await(5000, TimeUnit.MILLISECONDS)); 210 assertEquals(Constants.STATUS_INTERNAL_ERROR, mCallbackErrorCode); 211 } 212 213 class TestServiceCallback extends IIsolatedServiceCallback.Stub { 214 @Override onSuccess(Bundle result)215 public void onSuccess(Bundle result) { 216 mLatch.countDown(); 217 } 218 219 @Override onError( int errorCode, int isolatedServiceErrorCode, byte[] serializedExceptionInfo)220 public void onError( 221 int errorCode, 222 int isolatedServiceErrorCode, 223 byte[] serializedExceptionInfo) { 224 mCallbackErrorCode = errorCode; 225 mIsolatedServiceErrorCode = isolatedServiceErrorCode; 226 mSerializedExceptionInfo = serializedExceptionInfo; 227 mLatch.countDown(); 228 } 229 } 230 231 static class TestDataAccessService extends IDataAccessService.Stub { 232 233 String mOp; 234 TestDataAccessService(String operation)235 TestDataAccessService(String operation) { 236 this.mOp = operation; 237 } 238 TestDataAccessService()239 TestDataAccessService() { 240 mOp = null; 241 } 242 243 @Override onRequest(int operation, Bundle params, IDataAccessServiceCallback callback)244 public void onRequest(int operation, Bundle params, IDataAccessServiceCallback callback) { 245 // pass parameters for onDownloadCompleted testing 246 if (mOp != null) { 247 Bundle bndl = new Bundle(); 248 bndl.putParcelable( 249 Constants.EXTRA_RESULT, new ByteArrayParceledSlice(mOp.getBytes())); 250 try { 251 callback.onSuccess(bndl); 252 } catch (RemoteException e) { 253 throw new RuntimeException(e); 254 } 255 } 256 } 257 258 @Override logApiCallStats(int apiName, long latencyMillis, int responseCode)259 public void logApiCallStats(int apiName, long latencyMillis, int responseCode) {} 260 } 261 262 static class TestFederatedComputeService extends IFederatedComputeService.Stub { 263 @Override schedule(TrainingOptions trainingOptions, IFederatedComputeCallback callback)264 public void schedule(TrainingOptions trainingOptions, IFederatedComputeCallback callback) {} 265 cancel(String populationName, IFederatedComputeCallback callback)266 public void cancel(String populationName, IFederatedComputeCallback callback) {} 267 } 268 269 static class TestIsolatedModelService extends IIsolatedModelService.Stub { 270 @Override runInference(Bundle params, IIsolatedModelServiceCallback callback)271 public void runInference(Bundle params, IIsolatedModelServiceCallback callback) {} 272 } 273 } 274