• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 an
14  * limitations under the License.
15  */
16 
17 package com.android.server;
18 
19 import android.annotation.EnforcePermission;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.content.Context;
23 import android.hardware.ISerialManager;
24 import android.hardware.SerialManagerInternal;
25 import android.os.ParcelFileDescriptor;
26 import android.os.PermissionEnforcer;
27 import android.system.ErrnoException;
28 import android.system.Os;
29 import android.system.OsConstants;
30 import android.util.Slog;
31 
32 import com.android.internal.annotations.GuardedBy;
33 import com.android.internal.util.Preconditions;
34 
35 import java.io.File;
36 import java.io.FileDescriptor;
37 import java.util.ArrayList;
38 import java.util.LinkedHashMap;
39 import java.util.function.Supplier;
40 
41 @android.ravenwood.annotation.RavenwoodKeepWholeClass
42 public class SerialService extends ISerialManager.Stub {
43     private static final String TAG = "SerialService";
44 
45     private final Context mContext;
46 
47     @GuardedBy("mSerialPorts")
48     private final LinkedHashMap<String, Supplier<ParcelFileDescriptor>> mSerialPorts =
49             new LinkedHashMap<>();
50 
51     private static final String PREFIX_VIRTUAL = "virtual:";
52 
SerialService(Context context)53     public SerialService(Context context) {
54         super(PermissionEnforcer.fromContext(context));
55         mContext = context;
56 
57         synchronized (mSerialPorts) {
58             final String[] serialPorts = getSerialPorts(context);
59             for (String serialPort : serialPorts) {
60                 mSerialPorts.put(serialPort, () -> {
61                     return tryOpen(serialPort);
62                 });
63             }
64         }
65     }
66 
getSerialPorts(Context context)67     private static String[] getSerialPorts(Context context) {
68         return context.getResources().getStringArray(
69                 com.android.internal.R.array.config_serialPorts);
70     }
71 
72     public static class Lifecycle extends SystemService {
73         private SerialService mService;
74 
Lifecycle(Context context)75         public Lifecycle(Context context) {
76             super(context);
77         }
78 
79         @Override
onStart()80         public void onStart() {
81             mService = new SerialService(getContext());
82             publishBinderService(Context.SERIAL_SERVICE, mService);
83             publishLocalService(SerialManagerInternal.class, mService.mInternal);
84         }
85     }
86 
87     @EnforcePermission(android.Manifest.permission.SERIAL_PORT)
getSerialPorts()88     public String[] getSerialPorts() {
89         super.getSerialPorts_enforcePermission();
90 
91         synchronized (mSerialPorts) {
92             final ArrayList<String> ports = new ArrayList<>();
93             for (String path : mSerialPorts.keySet()) {
94                 if (path.startsWith(PREFIX_VIRTUAL) || new File(path).exists()) {
95                     ports.add(path);
96                 }
97             }
98             return ports.toArray(new String[ports.size()]);
99         }
100     }
101 
102     @EnforcePermission(android.Manifest.permission.SERIAL_PORT)
openSerialPort(String path)103     public ParcelFileDescriptor openSerialPort(String path) {
104         super.openSerialPort_enforcePermission();
105 
106         synchronized (mSerialPorts) {
107             final Supplier<ParcelFileDescriptor> supplier = mSerialPorts.get(path);
108             if (supplier != null) {
109                 return supplier.get();
110             } else {
111                 throw new IllegalArgumentException("Invalid serial port " + path);
112             }
113         }
114     }
115 
116     private final SerialManagerInternal mInternal = new SerialManagerInternal() {
117         @Override
118         public void addVirtualSerialPortForTest(@NonNull String name,
119                 @NonNull Supplier<ParcelFileDescriptor> supplier) {
120             synchronized (mSerialPorts) {
121                 Preconditions.checkState(!mSerialPorts.containsKey(name),
122                         "Port " + name + " already defined");
123                 Preconditions.checkArgument(name.startsWith(PREFIX_VIRTUAL),
124                         "Port " + name + " must be under " + PREFIX_VIRTUAL);
125                 mSerialPorts.put(name, supplier);
126             }
127         }
128 
129         @Override
130         public void removeVirtualSerialPortForTest(@NonNull String name) {
131             synchronized (mSerialPorts) {
132                 Preconditions.checkState(mSerialPorts.containsKey(name),
133                         "Port " + name + " not yet defined");
134                 Preconditions.checkArgument(name.startsWith(PREFIX_VIRTUAL),
135                         "Port " + name + " must be under " + PREFIX_VIRTUAL);
136                 mSerialPorts.remove(name);
137             }
138         }
139     };
140 
tryOpen(String path)141     private static @Nullable ParcelFileDescriptor tryOpen(String path) {
142         try {
143             FileDescriptor fd = Os.open(path, OsConstants.O_RDWR | OsConstants.O_NOCTTY, 0);
144             return new ParcelFileDescriptor(fd);
145         } catch (ErrnoException e) {
146             Slog.e(TAG, "Could not open: " + path, e);
147             // We return null to preserve API semantics from earlier implementation variants.
148             return null;
149         }
150     }
151 }
152