1 /* 2 * Copyright (C) 2017 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.cts.verifier.admin.tapjacking; 18 19 import android.content.Intent; 20 import android.content.res.AssetManager; 21 import android.graphics.PixelFormat; 22 import android.os.Bundle; 23 import android.provider.Settings; 24 import android.util.Log; 25 import android.util.TypedValue; 26 import android.view.Gravity; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.view.WindowManager; 30 import android.widget.Button; 31 import android.widget.Toast; 32 33 import com.android.cts.verifier.PassFailButtons; 34 import com.android.cts.verifier.R; 35 36 import java.io.BufferedReader; 37 import java.io.File; 38 import java.io.FileOutputStream; 39 import java.io.InputStream; 40 import java.io.InputStreamReader; 41 import java.io.OutputStream; 42 import java.util.Map; 43 import java.util.regex.Matcher; 44 import java.util.regex.Pattern; 45 46 public class UsbTest extends PassFailButtons.Activity { 47 48 private View mOverlay; 49 private Button mEscalateBtn; 50 private boolean auth = false; 51 private boolean first_attempt = true; 52 53 public static final String LOG_TAG = "UsbTest"; 54 55 @Override 56 protected void onCreate(Bundle savedInstanceState) { 57 super.onCreate(savedInstanceState); 58 setContentView(R.layout.tapjacking); 59 setPassFailButtonClickListeners(); 60 setInfoResources(R.string.usb_tapjacking_test, 61 R.string.usb_tapjacking_test_info, -1); 62 63 //initialise the escalate button and set a listener 64 mEscalateBtn = (Button) findViewById(R.id.tapjacking_btn); 65 mEscalateBtn.setEnabled(true); 66 mEscalateBtn.setOnClickListener(new View.OnClickListener() { 67 @Override 68 public void onClick(View v) { 69 if (!Settings.canDrawOverlays(v.getContext())) { 70 // show settings permission 71 startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)); 72 } 73 74 if (!Settings.canDrawOverlays(v.getContext())) { 75 Toast.makeText(v.getContext(), R.string.usb_tapjacking_error_toast2, 76 Toast.LENGTH_LONG).show(); 77 return; 78 } 79 80 if(!first_attempt && !auth){ 81 Toast.makeText(v.getContext(), 82 R.string.usb_tapjacking_error_toast, 83 Toast.LENGTH_LONG).show(); 84 return; 85 } 86 87 first_attempt = false; 88 escalatePriv(); 89 } 90 }); 91 92 // Ensure there is a binary at ie: cts/apps/CtsVerifier/assets/adb 93 AssetManager assetManager = getAssets(); 94 try { 95 //if the adb doesn't exist add it 96 File adb = new File(this.getFilesDir() + "/adb"); 97 InputStream myInput = assetManager.open("adb"); 98 OutputStream myOutput = new FileOutputStream(adb); 99 100 byte[] buffer = new byte[1024]; 101 int length; 102 103 while ((length = myInput.read(buffer)) > 0) { 104 myOutput.write(buffer, 0, length); 105 } 106 myInput.close(); 107 myOutput.flush(); 108 myOutput.close(); 109 110 //Set execute bit 111 adb.setExecutable(true); 112 } catch (Exception e) { 113 Log.e(LOG_TAG, "onCreate " + e.toString()); 114 } 115 } 116 117 private void escalatePriv() { 118 try { 119 File adb = new File(this.getFilesDir() + "/adb"); 120 //Check for unauthorised devices to connect to 121 ProcessBuilder builder = new ProcessBuilder( 122 adb.getAbsolutePath(), "devices"); 123 builder.directory(this.getFilesDir()); 124 125 Map<String, String> env = builder.environment(); 126 env.put("HOME", this.getFilesDir().toString()); 127 env.put("TMPDIR", this.getFilesDir().toString()); 128 129 Process adb_devices = builder.start(); 130 131 String output = getDevices(adb_devices.getInputStream()); 132 Log.d(LOG_TAG, output); 133 int rc = adb_devices.waitFor(); 134 135 //CASE: USB debugging not enabled and/or adbd not listening on a tcp port 136 if (output.isEmpty()) { 137 Log.d(LOG_TAG, 138 "USB debugging not enabled and/or adbd not listening on a tcp port"); 139 } 140 141 //CASE: We have a tcp port, however the device hasn't been authorized 142 if (output.toLowerCase().contains("unauthorized".toLowerCase())) { 143 //If we're here, then we most likely we have a RSA prompt 144 showOverlay(); 145 Log.d(LOG_TAG, "We haven't been authorized yet..."); 146 } else if(output.toLowerCase().contains("device".toLowerCase())){ 147 Log.d(LOG_TAG, "We have authorization"); 148 hideOverlay(); 149 auth = true; 150 } else { 151 hideOverlay(); 152 Log.d(LOG_TAG, "The port is probably in use by another process"); 153 auth = false; 154 } 155 156 } catch (Exception e) { 157 Log.e(LOG_TAG, "escalatePriv " + e.toString()); 158 } 159 160 //Check if we have been authorized and set auth 161 if(!auth){ 162 Log.d(LOG_TAG, "We're still not authenticated yet"); 163 } 164 } 165 166 private static String getDevices(InputStream s) throws Exception { 167 String[] terms = {"device", // We are authorized to use this device 168 "unauthorized", // We need to authenticate adb server to this daemon 169 "offline" }; // Device is most probably in use 170 171 172 BufferedReader br = new BufferedReader(new InputStreamReader(s)); 173 StringBuilder sb = new StringBuilder(); 174 String line; 175 while ((line = br.readLine()) != null) 176 { 177 sb.append(line).append("\n"); 178 } 179 180 br.close(); 181 Log.d(LOG_TAG, sb.toString()); 182 for(String t : terms) { 183 String pattern = "\\b" + t + "\\b"; 184 Pattern p = Pattern.compile(pattern); 185 Matcher m = p.matcher(sb.toString()); 186 if (m.find()){ 187 return sb.toString(); 188 } 189 } 190 191 return ""; 192 } 193 194 private void showOverlay() { 195 if (mOverlay != null) 196 return; 197 198 WindowManager windowManager = (WindowManager) getApplicationContext(). 199 getSystemService(WINDOW_SERVICE); 200 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams( 201 WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, 202 WindowManager.LayoutParams.FLAG_FULLSCREEN 203 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 204 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 205 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 206 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED 207 ); 208 layoutParams.format = PixelFormat.TRANSLUCENT; 209 layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; 210 layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; 211 layoutParams.x = 0; 212 layoutParams.y = dipToPx(-46); 213 layoutParams.gravity = Gravity.CENTER; 214 layoutParams.windowAnimations = 0; 215 216 mOverlay = View.inflate(getApplicationContext(), R.layout.usb_tapjacking_overlay, 217 null); 218 windowManager.addView(mOverlay, layoutParams); 219 } 220 221 private void hideOverlay() { 222 if (mOverlay != null) { 223 WindowManager windowManager = (WindowManager) getApplicationContext().getSystemService( 224 WINDOW_SERVICE); 225 windowManager.removeViewImmediate(mOverlay); 226 mOverlay = null; 227 } 228 } 229 230 private int dipToPx(int dip) { 231 return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, 232 getResources().getDisplayMetrics())); 233 } 234 235 @Override 236 public void onResume(){ 237 super.onResume(); 238 hideOverlay(); 239 240 //Check if we've been authorized 241 if(!first_attempt) { 242 try { 243 File adb = new File(this.getFilesDir() + "/adb"); 244 //Check for unauthorised devices to connect to 245 ProcessBuilder builder = new ProcessBuilder(adb.getAbsolutePath(), 246 "devices"); 247 builder.directory(this.getFilesDir()); 248 249 Map<String, String> env = builder.environment(); 250 env.put("HOME", this.getFilesDir().toString()); 251 env.put("TMPDIR", this.getFilesDir().toString()); 252 253 Process adb_devices = builder.start(); 254 255 String output = getDevices(adb_devices.getInputStream()); 256 Log.d(LOG_TAG, output); 257 int rc = adb_devices.waitFor(); 258 259 if (output.toLowerCase().contains("unauthorized".toLowerCase())) { 260 //The user didn't authorize the app, prompt for a app restart 261 auth = false; 262 }else if(output.toLowerCase().contains("device".toLowerCase())){ 263 //The user has authorized the app 264 auth = true; 265 } 266 } catch (Exception e) { 267 Log.e(LOG_TAG, e.toString()); 268 } finally { 269 escalatePriv(); 270 } 271 } 272 } 273 274 @Override 275 public void onStop() { 276 super.onStop(); 277 hideOverlay(); 278 } 279 } 280