blob: c0111a7a63a96dffbe8fa4e140b1d299b8951ab3 [file] [log] [blame]
/*
* Copyright (C) 2022 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.sdksandbox;
import static android.app.sdksandbox.SdkSandboxSystemServiceRegistry.ServiceMutator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.res.AssetManager;
import android.content.res.Resources;
import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
/**
* Refers to the context of the SDK loaded in the SDK sandbox process.
*
* <p>It is a wrapper of the client application (which loading SDK to the sandbox) context, to
* represent the context of the SDK loaded by that application.
*
* <p>An instance of the {@link SandboxedSdkContext} will be created by the SDK sandbox, and then
* attached to the {@link SandboxedSdkProvider} after the SDK is loaded.
*
* <p>Each sdk will get their own private storage directories and the file storage API on this
* object will utilize those areas.
*
* @hide
*/
public final class SandboxedSdkContext extends ContextWrapper {
private final Resources mResources;
private final AssetManager mAssets;
private final String mClientPackageName;
private final String mSdkName;
private final ApplicationInfo mSdkProviderInfo;
@Nullable private final File mCeDataDir;
@Nullable private final File mDeDataDir;
private final SdkSandboxSystemServiceRegistry mSdkSandboxSystemServiceRegistry;
private final ClassLoader mClassLoader;
private final boolean mCustomizedSdkContextEnabled;
public SandboxedSdkContext(
@NonNull Context baseContext,
@NonNull ClassLoader classLoader,
@NonNull String clientPackageName,
@NonNull ApplicationInfo info,
@NonNull String sdkName,
@Nullable String sdkCeDataDir,
@Nullable String sdkDeDataDir,
boolean isCustomizedSdkContextEnabled) {
this(
baseContext,
classLoader,
clientPackageName,
info,
sdkName,
sdkCeDataDir,
sdkDeDataDir,
isCustomizedSdkContextEnabled,
SdkSandboxSystemServiceRegistry.getInstance());
}
@VisibleForTesting
public SandboxedSdkContext(
@NonNull Context baseContext,
@NonNull ClassLoader classLoader,
@NonNull String clientPackageName,
@NonNull ApplicationInfo info,
@NonNull String sdkName,
@Nullable String sdkCeDataDir,
@Nullable String sdkDeDataDir,
boolean isCustomizedSdkContextEnabled,
SdkSandboxSystemServiceRegistry sdkSandboxSystemServiceRegistry) {
super(baseContext);
mClientPackageName = clientPackageName;
mSdkName = sdkName;
mSdkProviderInfo = info;
Resources resources = null;
try {
resources = baseContext.getPackageManager().getResourcesForApplication(info);
} catch (Exception ignored) {
}
if (resources != null) {
mResources = resources;
mAssets = resources.getAssets();
} else {
mResources = null;
mAssets = null;
}
mCeDataDir = (sdkCeDataDir != null) ? new File(sdkCeDataDir) : null;
mDeDataDir = (sdkDeDataDir != null) ? new File(sdkDeDataDir) : null;
mSdkSandboxSystemServiceRegistry = sdkSandboxSystemServiceRegistry;
mClassLoader = classLoader;
mCustomizedSdkContextEnabled = isCustomizedSdkContextEnabled;
}
/**
* Return a new Context object for the current SandboxedSdkContext but whose storage APIs are
* backed by sdk specific credential-protected storage.
*
* @see Context#isCredentialProtectedStorage()
*/
@Override
@NonNull
public Context createCredentialProtectedStorageContext() {
Context newBaseContext = getBaseContext().createCredentialProtectedStorageContext();
return new SandboxedSdkContext(
newBaseContext,
mClassLoader,
mClientPackageName,
mSdkProviderInfo,
mSdkName,
(mCeDataDir != null) ? mCeDataDir.toString() : null,
(mDeDataDir != null) ? mDeDataDir.toString() : null,
mCustomizedSdkContextEnabled);
}
/**
* Return a new Context object for the current SandboxedSdkContext but whose storage
* APIs are backed by sdk specific device-protected storage.
*
* @see Context#isDeviceProtectedStorage()
*/
@Override
@NonNull
public Context createDeviceProtectedStorageContext() {
Context newBaseContext = getBaseContext().createDeviceProtectedStorageContext();
return new SandboxedSdkContext(
newBaseContext,
mClassLoader,
mClientPackageName,
mSdkProviderInfo,
mSdkName,
(mCeDataDir != null) ? mCeDataDir.toString() : null,
(mDeDataDir != null) ? mDeDataDir.toString() : null,
mCustomizedSdkContextEnabled);
}
/**
* Returns the SDK name defined in the SDK's manifest.
*/
@NonNull
public String getSdkName() {
return mSdkName;
}
/**
* Returns the SDK package name defined in the SDK's manifest.
*
* @hide
*/
@NonNull
public String getSdkPackageName() {
return mSdkProviderInfo.packageName;
}
/**
* Returns the package name of the client application corresponding to the sandbox.
*
*/
@NonNull
public String getClientPackageName() {
return mClientPackageName;
}
/** Returns the resources defined in the SDK's .apk file. */
@Override
@Nullable
public Resources getResources() {
if (mCustomizedSdkContextEnabled) {
return getBaseContext().getResources();
}
return mResources;
}
/** Returns the assets defined in the SDK's .apk file. */
@Override
@Nullable
public AssetManager getAssets() {
if (mCustomizedSdkContextEnabled) {
return getBaseContext().getAssets();
}
return mAssets;
}
/** Returns sdk-specific internal storage directory. */
@Override
@Nullable
public File getDataDir() {
if (mCustomizedSdkContextEnabled) {
return getBaseContext().getDataDir();
}
File res = null;
if (isCredentialProtectedStorage()) {
res = mCeDataDir;
} else if (isDeviceProtectedStorage()) {
res = mDeDataDir;
}
if (res == null) {
throw new RuntimeException("No data directory found for sdk: " + getSdkName());
}
return res;
}
@Override
@Nullable
public Object getSystemService(String name) {
if (name == null) {
return null;
}
Object service = getBaseContext().getSystemService(name);
ServiceMutator serviceMutator = mSdkSandboxSystemServiceRegistry.getServiceMutator(name);
if (serviceMutator != null) {
service = serviceMutator.setContext(service, this);
}
return service;
}
@Override
public ClassLoader getClassLoader() {
if (mCustomizedSdkContextEnabled) {
return getBaseContext().getClassLoader();
}
return mClassLoader;
}
}