1 /* 2 * Copyright (C) 2020 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.commands.uinput; 18 19 import android.util.Log; 20 import android.util.SparseArray; 21 22 import java.io.File; 23 import java.io.FileInputStream; 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.io.InputStreamReader; 27 import java.io.UnsupportedEncodingException; 28 import java.util.Objects; 29 30 /** 31 * Uinput class encapsulates execution of "uinput" command. It parses the provided input stream 32 * parameters as JSON file format, extract event entries and perform commands of event entries. 33 * Uinput device will be created when performing registration command and used to inject events. 34 */ 35 public class Uinput { 36 private static final String TAG = "UINPUT"; 37 38 private final Event.Reader mReader; 39 private final SparseArray<Device> mDevices; 40 usage()41 private static void usage() { 42 error("Usage: uinput [FILE]"); 43 } 44 45 /** 46 * Commandline "uinput" binary main entry 47 */ main(String[] args)48 public static void main(String[] args) { 49 if (args.length != 1) { 50 usage(); 51 System.exit(1); 52 } 53 54 InputStream stream = null; 55 try { 56 if (args[0].equals("-")) { 57 stream = System.in; 58 } else { 59 File f = new File(args[0]); 60 stream = new FileInputStream(f); 61 } 62 (new Uinput(stream)).run(); 63 } catch (Exception e) { 64 error("Uinput injection failed.", e); 65 System.exit(1); 66 } finally { 67 try { 68 stream.close(); 69 } catch (IOException e) { 70 } 71 } 72 } 73 Uinput(InputStream in)74 private Uinput(InputStream in) { 75 mDevices = new SparseArray<Device>(); 76 try { 77 mReader = new Event.Reader(new InputStreamReader(in, "UTF-8")); 78 } catch (UnsupportedEncodingException e) { 79 throw new RuntimeException(e); 80 } 81 } 82 run()83 private void run() { 84 try { 85 Event e = null; 86 while ((e = mReader.getNextEvent()) != null) { 87 process(e); 88 } 89 } catch (IOException ex) { 90 error("Error reading in events.", ex); 91 } 92 93 for (int i = 0; i < mDevices.size(); i++) { 94 mDevices.valueAt(i).close(); 95 } 96 } 97 process(Event e)98 private void process(Event e) { 99 final int index = mDevices.indexOfKey(e.getId()); 100 if (index < 0) { 101 if (e.getCommand() != Event.Command.REGISTER) { 102 Log.e(TAG, "Unknown device id specified. Ignoring event."); 103 return; 104 } 105 registerDevice(e); 106 return; 107 } 108 109 final Device d = mDevices.valueAt(index); 110 switch (Objects.requireNonNull(e.getCommand())) { 111 case REGISTER -> 112 error("Device id=" + e.getId() + " is already registered. Ignoring event."); 113 case INJECT -> d.injectEvent(e.getInjections()); 114 case DELAY -> d.addDelay(e.getDuration()); 115 case SYNC -> d.syncEvent(e.getSyncToken()); 116 } 117 } 118 registerDevice(Event e)119 private void registerDevice(Event e) { 120 if (!Event.Command.REGISTER.equals(e.getCommand())) { 121 throw new IllegalStateException( 122 "Tried to send command \"" + e.getCommand() + "\" to an unregistered device!"); 123 } 124 int id = e.getId(); 125 Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), e.getBus(), 126 e.getConfiguration(), e.getFfEffectsMax(), e.getAbsInfo(), e.getPort()); 127 mDevices.append(id, d); 128 } 129 error(String msg)130 private static void error(String msg) { 131 error(msg, null); 132 } 133 error(String msg, Exception e)134 private static void error(String msg, Exception e) { 135 Log.e(TAG, msg); 136 if (e != null) { 137 Log.e(TAG, Log.getStackTraceString(e)); 138 } 139 } 140 } 141