• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.system.virtualmachine;
18 
19 import android.app.job.JobScheduler;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.net.LinkAddress;
25 import android.net.TetheringManager;
26 import android.net.TetheringManager.StartTetheringCallback;
27 import android.net.TetheringManager.TetheringRequest;
28 import android.os.Handler;
29 import android.os.IBinder;
30 import android.os.ServiceManager;
31 import android.os.UserHandle;
32 import android.system.virtualizationmaintenance.IVirtualizationMaintenance;
33 import android.system.vmtethering.IVmTethering;
34 import android.util.Log;
35 
36 import com.android.internal.os.BackgroundThread;
37 import com.android.server.SystemService;
38 
39 import java.nio.file.Files;
40 import java.nio.file.Paths;
41 
42 /**
43  * This class exists to notify virtualization service of relevant things happening in the Android
44  * framework.
45  *
46  * <p>It currently is responsible for Secretkeeper-related maintenance - ensuring that we are not
47  * storing secrets for apps or users that no longer exist.
48  */
49 public class VirtualizationSystemService extends SystemService {
50     private static final String TAG = VirtualizationSystemService.class.getName();
51     private static final String MAINTENANCE_SERVICE_NAME =
52             "android.system.virtualizationmaintenance";
53     private Handler mHandler;
54     private final TetheringService mTetheringService;
55 
VirtualizationSystemService(Context context)56     public VirtualizationSystemService(Context context) {
57         super(context);
58         if (Files.exists(Paths.get("/apex/com.android.virt/bin/vmnic"))) {
59             mTetheringService = new TetheringService();
60         } else {
61             mTetheringService = null;
62         }
63     }
64 
65     @Override
onStart()66     public void onStart() {
67         if (mTetheringService != null) {
68             publishBinderService(IVmTethering.DESCRIPTOR, mTetheringService);
69         }
70     }
71 
72     @Override
onBootPhase(int phase)73     public void onBootPhase(int phase) {
74         if (phase != PHASE_BOOT_COMPLETED) return;
75 
76         mHandler = BackgroundThread.getHandler();
77         new Receiver().registerForBroadcasts();
78 
79         SecretkeeperJobService.scheduleJob(getContext().getSystemService(JobScheduler.class));
80     }
81 
notifyAppRemoved(int uid)82     private void notifyAppRemoved(int uid) {
83         try {
84             IVirtualizationMaintenance maintenance = connectToMaintenanceService();
85             maintenance.appRemoved(UserHandle.getUserId(uid), UserHandle.getAppId(uid));
86         } catch (Exception e) {
87             Log.e(TAG, "notifyAppRemoved failed", e);
88         }
89     }
90 
notifyUserRemoved(int userId)91     private void notifyUserRemoved(int userId) {
92         try {
93             IVirtualizationMaintenance maintenance = connectToMaintenanceService();
94             maintenance.userRemoved(userId);
95         } catch (Exception e) {
96             Log.e(TAG, "notifyUserRemoved failed", e);
97         }
98     }
99 
connectToMaintenanceService()100     static IVirtualizationMaintenance connectToMaintenanceService() {
101         IBinder binder = ServiceManager.waitForService(MAINTENANCE_SERVICE_NAME);
102         IVirtualizationMaintenance maintenance =
103                 IVirtualizationMaintenance.Stub.asInterface(binder);
104         if (maintenance == null) {
105             throw new IllegalStateException("Failed to connect to " + MAINTENANCE_SERVICE_NAME);
106         }
107         return maintenance;
108     }
109 
110     private class Receiver extends BroadcastReceiver {
registerForBroadcasts()111         public void registerForBroadcasts() {
112             Context allUsers = getContext().createContextAsUser(UserHandle.ALL, 0 /* flags */);
113 
114             allUsers.registerReceiver(this, new IntentFilter(Intent.ACTION_USER_REMOVED));
115 
116             IntentFilter packageFilter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
117             packageFilter.addDataScheme("package");
118             allUsers.registerReceiver(this, packageFilter);
119         }
120 
121         @Override
onReceive(Context context, Intent intent)122         public void onReceive(Context context, Intent intent) {
123             final String action = intent.getAction();
124             if (action == null) {
125                 return;
126             }
127 
128             switch (action) {
129                 case Intent.ACTION_USER_REMOVED:
130                     onUserRemoved(intent);
131                     break;
132                 case Intent.ACTION_PACKAGE_REMOVED:
133                     onPackageRemoved(intent);
134                     break;
135                 default:
136                     Log.e(TAG, "received unexpected intent: " + intent);
137                     break;
138             }
139         }
140 
onUserRemoved(Intent intent)141         private void onUserRemoved(Intent intent) {
142             int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
143             if (userId != UserHandle.USER_NULL) {
144                 mHandler.post(() -> notifyUserRemoved(userId));
145             }
146         }
147 
onPackageRemoved(Intent intent)148         private void onPackageRemoved(Intent intent) {
149             if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)
150                     || !intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false)) {
151                 // Package is being updated rather than uninstalled.
152                 return;
153             }
154             int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
155             if (uid != -1) {
156                 mHandler.post(() -> notifyAppRemoved(uid));
157             }
158         }
159     }
160 
161     private final class TetheringService extends IVmTethering.Stub {
162         private final TetheringManager tm = getContext().getSystemService(TetheringManager.class);
163 
164         @Override
enableVmTethering()165         public void enableVmTethering() {
166             final TetheringRequest tr =
167                     new TetheringRequest.Builder(TetheringManager.TETHERING_VIRTUAL)
168                             .setConnectivityScope(TetheringManager.CONNECTIVITY_SCOPE_GLOBAL)
169                             .build();
170 
171             StartTetheringCallback startTetheringCallback =
172                     new StartTetheringCallback() {
173                         @Override
174                         public void onTetheringStarted() {
175                             Log.i(TAG, "VM tethering started successfully");
176                         }
177 
178                         @Override
179                         public void onTetheringFailed(int resultCode) {
180                             Log.e(
181                                     TAG,
182                                     "VM tethering failed. Result Code: "
183                                             + Integer.toString(resultCode));
184                         }
185                     };
186             tm.startTethering(tr, c -> c.run() /* executor */, startTetheringCallback);
187         }
188 
189         @Override
disableVmTethering()190         public void disableVmTethering() {
191             tm.stopTethering(TetheringManager.TETHERING_VIRTUAL);
192         }
193     }
194 }
195