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 
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.content.pm.SharedLibraryInfo;
23 import android.os.IBinder;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 
27 import java.util.Objects;
28 
29 /**
30  * Represents an SDK loaded in the sandbox process.
31  *
32  * <p>Returned in response to {@link SdkSandboxManager#loadSdk}, on success. An application can
33  * obtain it by calling {@link SdkSandboxManager#loadSdk}. It should use this object to obtain an
34  * interface to the SDK through {@link #getInterface()}.
35  *
36  * <p>The SDK should create it when {@link SandboxedSdkProvider#onLoadSdk} is called, and drop all
37  * references to it when {@link SandboxedSdkProvider#beforeUnloadSdk()} is called. Additionally, the
38  * SDK should fail calls made to the {@code IBinder} returned from {@link #getInterface()} after
39  * {@link SandboxedSdkProvider#beforeUnloadSdk()} has been called.
40  */
41 public final class SandboxedSdk implements Parcelable {
42     public static final @NonNull Creator<SandboxedSdk> CREATOR =
43             new Creator<SandboxedSdk>() {
44                 @Override
45                 public SandboxedSdk createFromParcel(Parcel in) {
46                     return new SandboxedSdk(in);
47                 }
48 
49                 @Override
50                 public SandboxedSdk[] newArray(int size) {
51                     return new SandboxedSdk[size];
52                 }
53             };
54     private IBinder mInterface;
55     private @Nullable SharedLibraryInfo mSharedLibraryInfo;
56 
57     /**
58      * Creates a {@link SandboxedSdk} object.
59      *
60      * @param sdkInterface The SDK's interface. This will be the entrypoint into the sandboxed SDK
61      *     for the application. The SDK should keep this valid until it's loaded in the sandbox, and
62      *     start failing calls to this interface once it has been unloaded.
63      *     <p>This interface can later be retrieved using {@link #getInterface()}.
64      */
SandboxedSdk(@onNull IBinder sdkInterface)65     public SandboxedSdk(@NonNull IBinder sdkInterface) {
66         mInterface = sdkInterface;
67     }
68 
SandboxedSdk(@onNull Parcel in)69     private SandboxedSdk(@NonNull Parcel in) {
70         mInterface = in.readStrongBinder();
71         if (in.readInt() != 0) {
72             mSharedLibraryInfo = SharedLibraryInfo.CREATOR.createFromParcel(in);
73         }
74     }
75 
76     /**
77      * Attaches information about the SDK like name, version and others which may be useful to
78      * identify the SDK.
79      *
80      * <p>This is used by the system service to attach the library info to the {@link SandboxedSdk}
81      * object return by the SDK after it has been loaded
82      *
83      * @param sharedLibraryInfo The SDK's library info. This contains the name, version and other
84      *     details about the sdk.
85      * @throws IllegalStateException if a base sharedLibraryInfo has already been set.
86      * @hide
87      */
attachSharedLibraryInfo(@onNull SharedLibraryInfo sharedLibraryInfo)88     public void attachSharedLibraryInfo(@NonNull SharedLibraryInfo sharedLibraryInfo) {
89         if (mSharedLibraryInfo != null) {
90             throw new IllegalStateException("SharedLibraryInfo already set");
91         }
92         Objects.requireNonNull(sharedLibraryInfo, "SharedLibraryInfo cannot be null");
93         mSharedLibraryInfo = sharedLibraryInfo;
94     }
95 
96     /**
97      * Returns the interface to the SDK that was loaded in response to {@link
98      * SdkSandboxManager#loadSdk}. A {@code null} interface is returned if the Binder has since
99      * become unavailable, in response to the SDK being unloaded.
100      */
getInterface()101     public @Nullable IBinder getInterface() {
102         // This will be null if the remote SDK has been unloaded and the IBinder originally provided
103         // is now a dead object.
104         return mInterface;
105     }
106 
107     /**
108      * Returns the {@link SharedLibraryInfo} for the SDK.
109      *
110      * @throws IllegalStateException if the system service has not yet attached {@link
111      *     SharedLibraryInfo} to the {@link SandboxedSdk} object sent by the SDK.
112      */
getSharedLibraryInfo()113     public @NonNull SharedLibraryInfo getSharedLibraryInfo() {
114         if (mSharedLibraryInfo == null) {
115             throw new IllegalStateException(
116                     "SharedLibraryInfo has not been set. This is populated by our system service "
117                             + "once the SandboxedSdk is sent back from as a response to "
118                             + "android.app.sdksandbox.SandboxedSdkProvider$onLoadSdk. Please use "
119                             + "android.app.sdksandbox.SdkSandboxManager#getSandboxedSdks or "
120                             + "android.app.sdksandbox.SdkSandboxController#getSandboxedSdks to "
121                             + "get the correctly populated SandboxedSdks.");
122         }
123         return mSharedLibraryInfo;
124     }
125 
126     /** {@inheritDoc} */
127     @Override
describeContents()128     public int describeContents() {
129         return 0;
130     }
131 
132     /** {@inheritDoc} */
133     @Override
writeToParcel(@onNull Parcel dest, int flags)134     public void writeToParcel(@NonNull Parcel dest, int flags) {
135         dest.writeStrongBinder(mInterface);
136         if (mSharedLibraryInfo != null) {
137             dest.writeInt(1);
138             mSharedLibraryInfo.writeToParcel(dest, 0);
139         } else {
140             dest.writeInt(0);
141         }
142     }
143 }
144