1 /* 2 * Copyright (C) 2022 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.app.sdksandbox; 18 19 import static android.app.sdksandbox.SdkSandboxSystemServiceRegistry.ServiceMutator; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.content.Context; 24 import android.content.ContextWrapper; 25 import android.content.pm.ApplicationInfo; 26 import android.content.res.AssetManager; 27 import android.content.res.Resources; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 31 import java.io.File; 32 33 /** 34 * Refers to the context of the SDK loaded in the SDK sandbox process. 35 * 36 * <p>It is a wrapper of the client application (which loading SDK to the sandbox) context, to 37 * represent the context of the SDK loaded by that application. 38 * 39 * <p>An instance of the {@link SandboxedSdkContext} will be created by the SDK sandbox, and then 40 * attached to the {@link SandboxedSdkProvider} after the SDK is loaded. 41 * 42 * <p>Each sdk will get their own private storage directories and the file storage API on this 43 * object will utilize those areas. 44 * 45 * @hide 46 */ 47 public final class SandboxedSdkContext extends ContextWrapper { 48 49 private final Resources mResources; 50 private final AssetManager mAssets; 51 private final String mClientPackageName; 52 private final String mSdkName; 53 private final ApplicationInfo mSdkProviderInfo; 54 @Nullable private final File mCeDataDir; 55 @Nullable private final File mDeDataDir; 56 private final SdkSandboxSystemServiceRegistry mSdkSandboxSystemServiceRegistry; 57 private final ClassLoader mClassLoader; 58 private final boolean mCustomizedSdkContextEnabled; 59 SandboxedSdkContext( @onNull Context baseContext, @NonNull ClassLoader classLoader, @NonNull String clientPackageName, @NonNull ApplicationInfo info, @NonNull String sdkName, @Nullable String sdkCeDataDir, @Nullable String sdkDeDataDir, boolean isCustomizedSdkContextEnabled)60 public SandboxedSdkContext( 61 @NonNull Context baseContext, 62 @NonNull ClassLoader classLoader, 63 @NonNull String clientPackageName, 64 @NonNull ApplicationInfo info, 65 @NonNull String sdkName, 66 @Nullable String sdkCeDataDir, 67 @Nullable String sdkDeDataDir, 68 boolean isCustomizedSdkContextEnabled) { 69 this( 70 baseContext, 71 classLoader, 72 clientPackageName, 73 info, 74 sdkName, 75 sdkCeDataDir, 76 sdkDeDataDir, 77 isCustomizedSdkContextEnabled, 78 SdkSandboxSystemServiceRegistry.getInstance()); 79 } 80 81 @VisibleForTesting SandboxedSdkContext( @onNull Context baseContext, @NonNull ClassLoader classLoader, @NonNull String clientPackageName, @NonNull ApplicationInfo info, @NonNull String sdkName, @Nullable String sdkCeDataDir, @Nullable String sdkDeDataDir, boolean isCustomizedSdkContextEnabled, SdkSandboxSystemServiceRegistry sdkSandboxSystemServiceRegistry)82 public SandboxedSdkContext( 83 @NonNull Context baseContext, 84 @NonNull ClassLoader classLoader, 85 @NonNull String clientPackageName, 86 @NonNull ApplicationInfo info, 87 @NonNull String sdkName, 88 @Nullable String sdkCeDataDir, 89 @Nullable String sdkDeDataDir, 90 boolean isCustomizedSdkContextEnabled, 91 SdkSandboxSystemServiceRegistry sdkSandboxSystemServiceRegistry) { 92 super(baseContext); 93 mClientPackageName = clientPackageName; 94 mSdkName = sdkName; 95 mSdkProviderInfo = info; 96 Resources resources = null; 97 try { 98 resources = baseContext.getPackageManager().getResourcesForApplication(info); 99 } catch (Exception ignored) { 100 } 101 102 if (resources != null) { 103 mResources = resources; 104 mAssets = resources.getAssets(); 105 } else { 106 mResources = null; 107 mAssets = null; 108 } 109 110 mCeDataDir = (sdkCeDataDir != null) ? new File(sdkCeDataDir) : null; 111 mDeDataDir = (sdkDeDataDir != null) ? new File(sdkDeDataDir) : null; 112 113 mSdkSandboxSystemServiceRegistry = sdkSandboxSystemServiceRegistry; 114 mClassLoader = classLoader; 115 mCustomizedSdkContextEnabled = isCustomizedSdkContextEnabled; 116 } 117 118 /** 119 * Return a new Context object for the current SandboxedSdkContext but whose storage APIs are 120 * backed by sdk specific credential-protected storage. 121 * 122 * @see Context#isCredentialProtectedStorage() 123 */ 124 @Override 125 @NonNull createCredentialProtectedStorageContext()126 public Context createCredentialProtectedStorageContext() { 127 Context newBaseContext = getBaseContext().createCredentialProtectedStorageContext(); 128 return new SandboxedSdkContext( 129 newBaseContext, 130 mClassLoader, 131 mClientPackageName, 132 mSdkProviderInfo, 133 mSdkName, 134 (mCeDataDir != null) ? mCeDataDir.toString() : null, 135 (mDeDataDir != null) ? mDeDataDir.toString() : null, 136 mCustomizedSdkContextEnabled); 137 } 138 139 /** 140 * Return a new Context object for the current SandboxedSdkContext but whose storage 141 * APIs are backed by sdk specific device-protected storage. 142 * 143 * @see Context#isDeviceProtectedStorage() 144 */ 145 @Override 146 @NonNull createDeviceProtectedStorageContext()147 public Context createDeviceProtectedStorageContext() { 148 Context newBaseContext = getBaseContext().createDeviceProtectedStorageContext(); 149 return new SandboxedSdkContext( 150 newBaseContext, 151 mClassLoader, 152 mClientPackageName, 153 mSdkProviderInfo, 154 mSdkName, 155 (mCeDataDir != null) ? mCeDataDir.toString() : null, 156 (mDeDataDir != null) ? mDeDataDir.toString() : null, 157 mCustomizedSdkContextEnabled); 158 } 159 160 /** 161 * Returns the SDK name defined in the SDK's manifest. 162 */ 163 @NonNull getSdkName()164 public String getSdkName() { 165 return mSdkName; 166 } 167 168 /** 169 * Returns the SDK package name defined in the SDK's manifest. 170 * 171 * @hide 172 */ 173 @NonNull getSdkPackageName()174 public String getSdkPackageName() { 175 return mSdkProviderInfo.packageName; 176 } 177 178 /** 179 * Returns the package name of the client application corresponding to the sandbox. 180 * 181 */ 182 @NonNull getClientPackageName()183 public String getClientPackageName() { 184 return mClientPackageName; 185 } 186 187 /** Returns the resources defined in the SDK's .apk file. */ 188 @Override 189 @Nullable getResources()190 public Resources getResources() { 191 if (mCustomizedSdkContextEnabled) { 192 return getBaseContext().getResources(); 193 } 194 return mResources; 195 } 196 197 /** Returns the assets defined in the SDK's .apk file. */ 198 @Override 199 @Nullable getAssets()200 public AssetManager getAssets() { 201 if (mCustomizedSdkContextEnabled) { 202 return getBaseContext().getAssets(); 203 } 204 return mAssets; 205 } 206 207 /** Returns sdk-specific internal storage directory. */ 208 @Override 209 @Nullable getDataDir()210 public File getDataDir() { 211 if (mCustomizedSdkContextEnabled) { 212 return getBaseContext().getDataDir(); 213 } 214 215 File res = null; 216 if (isCredentialProtectedStorage()) { 217 res = mCeDataDir; 218 } else if (isDeviceProtectedStorage()) { 219 res = mDeDataDir; 220 } 221 if (res == null) { 222 throw new RuntimeException("No data directory found for sdk: " + getSdkName()); 223 } 224 return res; 225 } 226 227 @Override 228 @Nullable getSystemService(String name)229 public Object getSystemService(String name) { 230 if (name == null) { 231 return null; 232 } 233 Object service = getBaseContext().getSystemService(name); 234 ServiceMutator serviceMutator = mSdkSandboxSystemServiceRegistry.getServiceMutator(name); 235 if (serviceMutator != null) { 236 service = serviceMutator.setContext(service, this); 237 } 238 return service; 239 } 240 241 @Override getClassLoader()242 public ClassLoader getClassLoader() { 243 if (mCustomizedSdkContextEnabled) { 244 return getBaseContext().getClassLoader(); 245 } 246 return mClassLoader; 247 } 248 } 249