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 com.android.server.sdksandbox;
18 
19 import static com.android.sdksandbox.flags.Flags.sdkSandboxDexVerifier;
20 
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.PackageInfo;
25 import android.content.pm.PackageManager;
26 import android.os.Build;
27 import android.os.Handler;
28 import android.os.HandlerThread;
29 import android.os.OutcomeReceiver;
30 import android.os.Process;
31 import android.provider.DeviceConfig;
32 import android.util.Log;
33 
34 import com.android.internal.annotations.VisibleForTesting;
35 import com.android.server.sdksandbox.verifier.SdkDexVerifier;
36 
37 /**
38  * Broadcast Receiver for receiving new Sdk install requests and verifying Sdk code before running
39  * it in Sandbox.
40  *
41  * @hide
42  */
43 public class SdkSandboxVerifierReceiver extends BroadcastReceiver {
44 
45     private static final String TAG = "SdkSandboxVerifier";
46     private Handler mHandler;
47     private SdkDexVerifier mSdkDexVerifier;
48 
SdkSandboxVerifierReceiver()49     public SdkSandboxVerifierReceiver() {
50         HandlerThread handlerThread =
51                 new HandlerThread("DexVerifierHandlerThread", Process.THREAD_PRIORITY_BACKGROUND);
52         handlerThread.start();
53         mHandler = new Handler(handlerThread.getLooper());
54     }
55 
56     @Override
onReceive(Context context, Intent intent)57     public void onReceive(Context context, Intent intent) {
58         if (!Intent.ACTION_PACKAGE_NEEDS_VERIFICATION.equals(intent.getAction())) {
59             return;
60         }
61 
62         Log.d(TAG, "Received sdk sandbox verification intent " + intent.toString());
63         Log.d(TAG, "Extras " + intent.getExtras());
64 
65         verifySdkHandler(context, intent, mHandler);
66     }
67 
68     @VisibleForTesting
setSdkDexVerifier(SdkDexVerifier sdkDexVerifier)69     void setSdkDexVerifier(SdkDexVerifier sdkDexVerifier) {
70         mSdkDexVerifier = sdkDexVerifier;
71     }
72 
73     @VisibleForTesting
verifySdkHandler(Context context, Intent intent, Handler handler)74     void verifySdkHandler(Context context, Intent intent, Handler handler) {
75         int verificationId = intent.getIntExtra(PackageManager.EXTRA_VERIFICATION_ID, -1);
76 
77         boolean isRestrictionsEnabled =
78                 sdkSandboxDexVerifier()
79                         && DeviceConfig.getBoolean(
80                                 DeviceConfig.NAMESPACE_ADSERVICES,
81                                 SdkSandboxManagerService.PROPERTY_ENFORCE_RESTRICTIONS,
82                                 SdkSandboxManagerService.DEFAULT_VALUE_ENFORCE_RESTRICTIONS);
83         if (!isRestrictionsEnabled) {
84             context.getPackageManager()
85                     .verifyPendingInstall(verificationId, PackageManager.VERIFICATION_ALLOW);
86             Log.d(TAG, "Restrictions disabled. Sent VERIFICATION_ALLOW");
87             return;
88         }
89 
90         String apkPath = intent.getData() != null ? intent.getData().getPath() : null;
91 
92         PackageInfo packageInfo =
93                 apkPath != null
94                         ? context.getPackageManager().getPackageArchiveInfo(apkPath, /* flags */ 0)
95                         : null;
96 
97         if (packageInfo == null) {
98             Log.e(TAG, "Package data to verify was absent or invalid.");
99             context.getPackageManager()
100                     .verifyPendingInstall(verificationId, PackageManager.VERIFICATION_REJECT);
101             return;
102         }
103 
104         if (mSdkDexVerifier == null) {
105             mSdkDexVerifier = SdkDexVerifier.getInstance();
106         }
107         int targetSdkVersion =
108                 packageInfo.applicationInfo != null
109                         ? packageInfo.applicationInfo.targetSdkVersion
110                         : Build.VERSION.SDK_INT;
111         handler.post(
112                 () ->
113                         mSdkDexVerifier.startDexVerification(
114                                 apkPath,
115                                 packageInfo.packageName,
116                                 targetSdkVersion,
117                                 new OutcomeReceiver<Void, Exception>() {
118                                     @Override
119                                     public void onResult(Void result) {}
120 
121                                     @Override
122                                     public void onError(Exception e) {
123                                         Log.e(TAG, "Error at SdkSandboxVerifierReceiver", e);
124                                     }
125                                 }));
126 
127         // Verification will continue to run on background, return VERIFICATION_ALLOW to
128         // unblock install
129         context.getPackageManager()
130                 .verifyPendingInstall(verificationId, PackageManager.VERIFICATION_ALLOW);
131         Log.d(TAG, "Sent VERIFICATION_ALLOW");
132     }
133 }
134