/* * 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 com.android.server.sdksandbox; import static android.app.sdksandbox.SdkSandboxManager.REQUEST_SURFACE_PACKAGE_SDK_NOT_LOADED; import static android.app.sdksandbox.SdkSandboxManager.SDK_SANDBOX_PROCESS_NOT_AVAILABLE; import android.annotation.IntDef; import android.annotation.Nullable; import android.app.sdksandbox.ILoadSdkCallback; import android.app.sdksandbox.IRequestSurfacePackageCallback; import android.app.sdksandbox.IUnloadSdkCallback; import android.app.sdksandbox.LoadSdkException; import android.app.sdksandbox.LogUtil; import android.app.sdksandbox.SandboxLatencyInfo; import android.app.sdksandbox.SandboxedSdk; import android.app.sdksandbox.SdkSandboxManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.SharedLibraryInfo; import android.os.Bundle; import android.os.DeadObjectException; import android.os.IBinder; import android.os.RemoteException; import android.util.ArraySet; import android.util.Log; import android.view.SurfaceControlViewHost; import com.android.internal.annotations.GuardedBy; import com.android.sdksandbox.ILoadSdkInSandboxCallback; import com.android.sdksandbox.IRequestSurfacePackageFromSdkCallback; import com.android.sdksandbox.ISdkSandboxManagerToSdkSandboxCallback; import com.android.sdksandbox.ISdkSandboxService; import com.android.sdksandbox.IUnloadSdkInSandboxCallback; import com.android.server.sdksandbox.helpers.PackageManagerHelper; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Represents the lifecycle of a single request to load an SDK for a specific app. * *
A new instance of this class must be created for every load request of an SDK. This class also * maintains a link to the remote SDK loaded in the sandbox if any, and communicates with it. */ class LoadSdkSession { private static final String TAG = "SdkSandboxManager"; private static final String PROPERTY_SDK_PROVIDER_CLASS_NAME = "android.sdksandbox.PROPERTY_SDK_PROVIDER_CLASS_NAME"; /** @hide */ @IntDef(value = {LOAD_PENDING, LOADED, LOAD_FAILED, UNLOADED}) @Retention(RetentionPolicy.SOURCE) public @interface LoadStatus {} /** * Represents the initial state of the SDK, when a request to load it has arrived but not yet * been completed. * *
Once the state of an SDK transitions out of LOAD_PENDING, it cannot be reset to * LOAD_PENDING as this state is the representation of a specific load request for an SDK. * *
The state can be LOAD_FAILED if the sandbox could not properly initialize the SDK, SDK is * invalid, the sandbox died while in the middle of loading etc. If the SDK load failed, this * same session cannot be used to load the SDK again. * *
The status cannot be reset to LOAD_PENDING as this class is meant to represent a single
* load request.
*/
@GuardedBy("mLock")
@LoadStatus
private int mStatus = LOAD_PENDING;
// The sandbox in which this SDK is supposed to be loaded.
@GuardedBy("mLock")
private ISdkSandboxService mSandboxService = null;
// Used for communication with the remotely loaded SDK in the sandbox.
private final RemoteSdkLink mRemoteSdkLink;
// Maintain all surface package requests whose callbacks have not been invoked yet.
@GuardedBy("mLock")
private final ArraySet Overview of communication:
*
* We maintain a link for each unique {app, remoteSdk} pair, which is identified with {@code
* sdkName}.
*/
private class RemoteSdkLink extends ILoadSdkInSandboxCallback.Stub {
@Nullable private volatile SandboxedSdk mSandboxedSdk;
@GuardedBy("this")
@Nullable
private ISdkSandboxManagerToSdkSandboxCallback mManagerToSdkCallback;
@Override
public void onLoadSdkSuccess(
SandboxedSdk sandboxedSdk,
ISdkSandboxManagerToSdkSandboxCallback callback,
SandboxLatencyInfo sandboxLatencyInfo) {
sandboxLatencyInfo.setTimeSystemServerReceivedCallFromSandbox(
mInjector.elapsedRealtime());
synchronized (this) {
// Keep reference to callback so that manager service can
// callback to remote SDK loaded.
mManagerToSdkCallback = callback;
// Attach the SharedLibraryInfo for the loaded SDK to the SandboxedSdk.
sandboxedSdk.attachSharedLibraryInfo(mSdkProviderInfo.getSdkInfo());
// Keep reference to SandboxedSdk so that manager service can
// keep log of all loaded SDKs and their binders for communication.
mSandboxedSdk = sandboxedSdk;
}
handleLoadSuccess(sandboxLatencyInfo);
}
@Override
public void onLoadSdkError(
LoadSdkException exception, SandboxLatencyInfo sandboxLatencyInfo) {
sandboxLatencyInfo.setTimeSystemServerReceivedCallFromSandbox(
mInjector.elapsedRealtime());
if (exception.getLoadSdkErrorCode()
== ILoadSdkInSandboxCallback.LOAD_SDK_INSTANTIATION_ERROR) {
mSdkSandboxManagerService.handleFailedSandboxInitialization(mCallingInfo);
}
handleLoadFailure(
updateLoadSdkErrorCode(exception),
sandboxLatencyInfo);
}
private LoadSdkException updateLoadSdkErrorCode(LoadSdkException exception) {
@SdkSandboxManager.LoadSdkErrorCode
int newErrorCode = toSdkSandboxManagerLoadSdkErrorCode(exception.getLoadSdkErrorCode());
return new LoadSdkException(
newErrorCode,
exception.getMessage(),
exception.getCause(),
exception.getExtraInformation());
}
@SdkSandboxManager.LoadSdkErrorCode
private int toSdkSandboxManagerLoadSdkErrorCode(int sdkSandboxErrorCode) {
switch (sdkSandboxErrorCode) {
case ILoadSdkInSandboxCallback.LOAD_SDK_ALREADY_LOADED:
return SdkSandboxManager.LOAD_SDK_ALREADY_LOADED;
case ILoadSdkInSandboxCallback.LOAD_SDK_NOT_FOUND:
return SdkSandboxManager.LOAD_SDK_NOT_FOUND;
case ILoadSdkInSandboxCallback.LOAD_SDK_PROVIDER_INIT_ERROR:
case ILoadSdkInSandboxCallback.LOAD_SDK_INSTANTIATION_ERROR:
case ILoadSdkInSandboxCallback.LOAD_SDK_INTERNAL_ERROR:
return SdkSandboxManager.LOAD_SDK_INTERNAL_ERROR;
case SdkSandboxManager.LOAD_SDK_SDK_DEFINED_ERROR:
return sdkSandboxErrorCode;
default:
Log.e(
TAG,
"Error code "
+ sdkSandboxErrorCode
+ " has no mapping to the SdkSandboxManager error codes");
return SdkSandboxManager.LOAD_SDK_INTERNAL_ERROR;
}
}
public void requestSurfacePackage(
IBinder hostToken,
int displayId,
int width,
int height,
SandboxLatencyInfo sandboxLatencyInfo,
Bundle params,
IRequestSurfacePackageCallback callback) {
sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
try {
synchronized (this) {
mManagerToSdkCallback.onSurfacePackageRequested(
hostToken,
displayId,
width,
height,
params,
sandboxLatencyInfo,
new IRequestSurfacePackageFromSdkCallback.Stub() {
@Override
public void onSurfacePackageReady(
SurfaceControlViewHost.SurfacePackage surfacePackage,
int surfacePackageId,
Bundle params,
SandboxLatencyInfo sandboxLatencyInfo) {
sandboxLatencyInfo.setTimeSystemServerReceivedCallFromSandbox(
mInjector.elapsedRealtime());
LogUtil.d(TAG, "onSurfacePackageReady received");
handleSurfacePackageReady(
surfacePackage,
surfacePackageId,
params,
sandboxLatencyInfo,
callback);
}
@Override
public void onSurfacePackageError(
int errorCode,
String errorMsg,
SandboxLatencyInfo sandboxLatencyInfo) {
sandboxLatencyInfo.setTimeSystemServerReceivedCallFromSandbox(
mInjector.elapsedRealtime());
int sdkSandboxManagerErrorCode =
toSdkSandboxManagerRequestSurfacePackageErrorCode(
errorCode);
handleSurfacePackageError(
sdkSandboxManagerErrorCode,
errorMsg,
sandboxLatencyInfo,
callback);
}
});
}
} catch (DeadObjectException e) {
LogUtil.d(
TAG,
mCallingInfo
+ " requested surface package from SDK "
+ mSdkName
+ " but sandbox is not alive");
handleSurfacePackageError(
REQUEST_SURFACE_PACKAGE_SDK_NOT_LOADED,
"SDK " + mSdkName + " is not loaded",
sandboxLatencyInfo,
callback);
} catch (RemoteException e) {
String errorMsg = "Failed to requestSurfacePackage";
Log.w(TAG, errorMsg, e);
handleSurfacePackageError(
SdkSandboxManager.REQUEST_SURFACE_PACKAGE_INTERNAL_ERROR,
errorMsg + ": " + e,
sandboxLatencyInfo,
callback);
}
}
@SdkSandboxManager.RequestSurfacePackageErrorCode
private int toSdkSandboxManagerRequestSurfacePackageErrorCode(int sdkSandboxErrorCode) {
if (sdkSandboxErrorCode
== IRequestSurfacePackageFromSdkCallback.SURFACE_PACKAGE_INTERNAL_ERROR) {
return SdkSandboxManager.REQUEST_SURFACE_PACKAGE_INTERNAL_ERROR;
}
Log.e(
TAG,
"Error code"
+ sdkSandboxErrorCode
+ "has no mapping to the SdkSandboxManager error codes");
return SdkSandboxManager.REQUEST_SURFACE_PACKAGE_INTERNAL_ERROR;
}
}
private SdkProviderInfo createSdkProviderInfo() throws PackageManager.NameNotFoundException {
PackageManagerHelper packageManagerHelper =
new PackageManagerHelper(mContext, mCallingInfo.getUid());
SharedLibraryInfo sharedLibrary =
packageManagerHelper.getSdkSharedLibraryInfoForSdk(
mCallingInfo.getPackageName(), mSdkName);
String sdkProviderClassName;
try {
sdkProviderClassName =
packageManagerHelper
.getProperty(
PROPERTY_SDK_PROVIDER_CLASS_NAME,
sharedLibrary.getDeclaringPackage().getPackageName())
.getString();
} catch (PackageManager.NameNotFoundException e) {
throw new PackageManager.NameNotFoundException(
PROPERTY_SDK_PROVIDER_CLASS_NAME + " property");
}
ApplicationInfo applicationInfo =
packageManagerHelper.getApplicationInfoForSharedLibrary(
sharedLibrary,
PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES
| PackageManager.MATCH_ANY_USER);
return new SdkProviderInfo(applicationInfo, sharedLibrary, sdkProviderClassName);
}
ApplicationInfo getApplicationInfo() {
return mSdkProviderInfo.getApplicationInfo();
}
/** Class which retrieves and stores the sdkName, sdkProviderClassName, and ApplicationInfo */
static class SdkProviderInfo {
private final ApplicationInfo mApplicationInfo;
private final SharedLibraryInfo mSdkInfo;
private final String mSdkProviderClassName;
private SdkProviderInfo(
ApplicationInfo applicationInfo,
SharedLibraryInfo sdkInfo,
String sdkProviderClassName) {
mApplicationInfo = applicationInfo;
mSdkInfo = sdkInfo;
mSdkProviderClassName = sdkProviderClassName;
}
public SharedLibraryInfo getSdkInfo() {
return mSdkInfo;
}
public String getSdkProviderClassName() {
return mSdkProviderClassName;
}
public ApplicationInfo getApplicationInfo() {
return mApplicationInfo;
}
}
}
*
*
*