1 /*
2  * Copyright (C) 2019 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 package android.car.usb.handler;
17 
18 import static android.content.Intent.ACTION_USER_SWITCHED;
19 
20 import android.app.ActivityManager;
21 import android.app.Notification;
22 import android.app.NotificationChannel;
23 import android.app.NotificationManager;
24 import android.app.Service;
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.hardware.usb.UsbDevice;
30 import android.hardware.usb.UsbManager;
31 import android.os.Binder;
32 import android.os.UserHandle;
33 import android.util.Log;
34 
35 import java.util.ArrayList;
36 
37 /**
38  * Starts the {@link UsbHostManagementActivity} for each connected usb device when {@link
39  * #onStartCommand(Intent, int, int)} is called. This is meant to allow this activity to start for
40  * connected devices on start up, without holding up processing of the LOCKED_BOOT_COMPLETED intent.
41  */
42 public class BootUsbService extends Service {
43     private static final String TAG = BootUsbService.class.getSimpleName();
44     private static final int NOTIFICATION_ID = 1;
45 
46     static final String USB_DEVICE_LIST_KEY = "usb_device_list";
47 
48     private ArrayList<UsbDevice> mDeviceList;
49     private boolean mReceiverRegistered = false;
50     private final BroadcastReceiver mUserSwitchBroadcastReceiver = new BroadcastReceiver() {
51         @Override
52         public void onReceive(Context context, Intent intent) {
53             processDevices();
54             unregisterUserSwitchReceiver();
55         }
56     };
57 
58     @Override
onBind(Intent intent)59     public Binder onBind(Intent intent) {
60         return null;
61     }
62 
63     @Override
onCreate()64     public void onCreate() {
65         String notificationIdString =
66                 getResources().getString(R.string.usb_boot_service_notification);
67         NotificationManager notificationManager = getSystemService(NotificationManager.class);
68         NotificationChannel notificationChannel =
69                 new NotificationChannel(
70                         notificationIdString,
71                         "Car Usb Handler enumeration",
72                         NotificationManager.IMPORTANCE_NONE);
73         notificationManager.createNotificationChannel(notificationChannel);
74         Notification notification =
75                 new Notification.Builder(
76                         this, notificationIdString).setSmallIcon(R.drawable.ic_launcher).build();
77         // CarUsbHandler runs in the background, so startForeground must be explicitly called.
78         startForeground(NOTIFICATION_ID, notification);
79     }
80 
81     @Override
onStartCommand(Intent intent, int flags, int startId)82     public int onStartCommand(Intent intent, int flags, int startId) {
83         mDeviceList = intent.getParcelableArrayListExtra(USB_DEVICE_LIST_KEY);
84         // If the current user is still the system user, wait until the non system user becomes the
85         // current/foreground user. Otherwise, we can go ahead and start processing the USB devices
86         // immediately.
87         if (ActivityManager.getCurrentUser() == UserHandle.USER_SYSTEM) {
88             Log.d(TAG, "Current user is still the system user, waiting for user switch");
89             registerUserSwitchReceiver();
90         } else {
91             processDevices();
92         }
93 
94         return START_NOT_STICKY;
95     }
96 
97     @Override
onDestroy()98     public void onDestroy() {
99         unregisterUserSwitchReceiver();
100     }
101 
processDevices()102     private void processDevices() {
103         Log.d(TAG, "Processing connected USB devices and starting handlers");
104         for (UsbDevice device : mDeviceList) {
105             handle(this, device);
106         }
107         stopSelf();
108     }
109 
handle(Context context, UsbDevice device)110     private void handle(Context context, UsbDevice device) {
111         Intent manageDevice = new Intent(context, UsbHostManagementActivity.class);
112         manageDevice.setAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
113         manageDevice.putExtra(UsbManager.EXTRA_DEVICE, device);
114         manageDevice.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
115         context.startActivityAsUser(manageDevice, UserHandle.CURRENT);
116     }
117 
registerUserSwitchReceiver()118     private void registerUserSwitchReceiver() {
119         if (!mReceiverRegistered) {
120             registerReceiver(mUserSwitchBroadcastReceiver, new IntentFilter(ACTION_USER_SWITCHED));
121             mReceiverRegistered = true;
122         }
123     }
124 
unregisterUserSwitchReceiver()125     private void unregisterUserSwitchReceiver() {
126         if (mReceiverRegistered) {
127             unregisterReceiver(mUserSwitchBroadcastReceiver);
128             mReceiverRegistered = false;
129         }
130     }
131 }
132