diff options
Diffstat (limited to 'services/core/java/com/android/server/adb/AdbDebuggingManager.java')
-rw-r--r-- | services/core/java/com/android/server/adb/AdbDebuggingManager.java | 543 |
1 files changed, 313 insertions, 230 deletions
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java index 56990eda3e78..297d28dadde3 100644 --- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java +++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java @@ -19,7 +19,7 @@ package com.android.server.adb; import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull; import android.annotation.NonNull; -import android.annotation.Nullable; +import android.annotation.TestApi; import android.app.ActivityManager; import android.app.Notification; import android.app.NotificationChannel; @@ -102,26 +102,11 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; /** - * Provides communication to the Android Debug Bridge daemon to allow, deny, or clear public keys + * Provides communication to the Android Debug Bridge daemon to allow, deny, or clear public keysi * that are authorized to connect to the ADB service itself. - * - * <p>The AdbDebuggingManager controls two files: - * <ol> - * <li>adb_keys - * <li>adb_temp_keys.xml - * </ol> - * - * <p>The ADB Daemon (adbd) reads <em>only</em> the adb_keys file for authorization. Public keys - * from registered hosts are stored in adb_keys, one entry per line. - * - * <p>AdbDebuggingManager also keeps adb_temp_keys.xml, which is used for two things - * <ol> - * <li>Removing unused keys from the adb_keys file - * <li>Managing authorized WiFi access points for ADB over WiFi - * </ol> */ public class AdbDebuggingManager { - private static final String TAG = AdbDebuggingManager.class.getSimpleName(); + private static final String TAG = "AdbDebuggingManager"; private static final boolean DEBUG = false; private static final boolean MDNS_DEBUG = false; @@ -133,20 +118,18 @@ public class AdbDebuggingManager { // as a subsequent connection occurs within the allowed duration. private static final String ADB_TEMP_KEYS_FILE = "adb_temp_keys.xml"; private static final int BUFFER_SIZE = 65536; - private static final Ticker SYSTEM_TICKER = () -> System.currentTimeMillis(); private final Context mContext; private final ContentResolver mContentResolver; - @VisibleForTesting final AdbDebuggingHandler mHandler; - @Nullable private AdbDebuggingThread mThread; + private final Handler mHandler; + private AdbDebuggingThread mThread; private boolean mAdbUsbEnabled = false; private boolean mAdbWifiEnabled = false; private String mFingerprints; // A key can be used more than once (e.g. USB, wifi), so need to keep a refcount - private final Map<String, Integer> mConnectedKeys = new HashMap<>(); - private final String mConfirmComponent; - @Nullable private final File mUserKeyFile; - @Nullable private final File mTempKeysFile; + private final Map<String, Integer> mConnectedKeys; + private String mConfirmComponent; + private final File mTestUserKeyFile; private static final String WIFI_PERSISTENT_CONFIG_PROPERTY = "persist.adb.tls_server.enable"; @@ -155,44 +138,37 @@ public class AdbDebuggingManager { private static final int PAIRING_CODE_LENGTH = 6; private PairingThread mPairingThread = null; // A list of keys connected via wifi - private final Set<String> mWifiConnectedKeys = new HashSet<>(); + private final Set<String> mWifiConnectedKeys; // The current info of the adbwifi connection. - private AdbConnectionInfo mAdbConnectionInfo = new AdbConnectionInfo(); + private AdbConnectionInfo mAdbConnectionInfo; // Polls for a tls port property when adb wifi is enabled private AdbConnectionPortPoller mConnectionPortPoller; private final PortListenerImpl mPortListener = new PortListenerImpl(); - private final Ticker mTicker; public AdbDebuggingManager(Context context) { - this( - context, - /* confirmComponent= */ null, - getAdbFile(ADB_KEYS_FILE), - getAdbFile(ADB_TEMP_KEYS_FILE), - /* adbDebuggingThread= */ null, - SYSTEM_TICKER); + mHandler = new AdbDebuggingHandler(FgThread.get().getLooper()); + mContext = context; + mContentResolver = mContext.getContentResolver(); + mTestUserKeyFile = null; + mConnectedKeys = new HashMap<String, Integer>(); + mWifiConnectedKeys = new HashSet<String>(); + mAdbConnectionInfo = new AdbConnectionInfo(); } /** * Constructor that accepts the component to be invoked to confirm if the user wants to allow * an adb connection from the key. */ - @VisibleForTesting - AdbDebuggingManager( - Context context, - String confirmComponent, - File testUserKeyFile, - File tempKeysFile, - AdbDebuggingThread adbDebuggingThread, - Ticker ticker) { + @TestApi + protected AdbDebuggingManager(Context context, String confirmComponent, File testUserKeyFile) { + mHandler = new AdbDebuggingHandler(FgThread.get().getLooper()); mContext = context; mContentResolver = mContext.getContentResolver(); mConfirmComponent = confirmComponent; - mUserKeyFile = testUserKeyFile; - mTempKeysFile = tempKeysFile; - mThread = adbDebuggingThread; - mTicker = ticker; - mHandler = new AdbDebuggingHandler(FgThread.get().getLooper(), mThread); + mTestUserKeyFile = testUserKeyFile; + mConnectedKeys = new HashMap<String, Integer>(); + mWifiConnectedKeys = new HashSet<String>(); + mAdbConnectionInfo = new AdbConnectionInfo(); } static void sendBroadcastWithDebugPermission(@NonNull Context context, @NonNull Intent intent, @@ -213,7 +189,8 @@ public class AdbDebuggingManager { // consisting of only letters, digits, and hyphens, must begin and end // with a letter or digit, must not contain consecutive hyphens, and // must contain at least one letter. - @VisibleForTesting static final String SERVICE_PROTOCOL = "adb-tls-pairing"; + @VisibleForTesting + static final String SERVICE_PROTOCOL = "adb-tls-pairing"; private final String mServiceType = String.format("_%s._tcp.", SERVICE_PROTOCOL); private int mPort; @@ -375,24 +352,16 @@ public class AdbDebuggingManager { } } - @VisibleForTesting - static class AdbDebuggingThread extends Thread { + class AdbDebuggingThread extends Thread { private boolean mStopped; private LocalSocket mSocket; private OutputStream mOutputStream; private InputStream mInputStream; - private Handler mHandler; - @VisibleForTesting AdbDebuggingThread() { super(TAG); } - @VisibleForTesting - void setHandler(Handler handler) { - mHandler = handler; - } - @Override public void run() { if (DEBUG) Slog.d(TAG, "Entering thread"); @@ -567,7 +536,7 @@ public class AdbDebuggingManager { } } - private static class AdbConnectionInfo { + class AdbConnectionInfo { private String mBssid; private String mSsid; private int mPort; @@ -774,14 +743,11 @@ public class AdbDebuggingManager { // Notification when adbd socket is disconnected. static final int MSG_ADBD_SOCKET_DISCONNECTED = 27; - // === Messages from other parts of the system - private static final int MESSAGE_KEY_FILES_UPDATED = 28; - // === Messages we can send to adbd =========== static final String MSG_DISCONNECT_DEVICE = "DD"; static final String MSG_DISABLE_ADBDWIFI = "DA"; - @Nullable @VisibleForTesting AdbKeyStore mAdbKeyStore; + private AdbKeyStore mAdbKeyStore; // Usb, Wi-Fi transports can be enabled together or separately, so don't break the framework // connection unless all transport types are disconnected. @@ -796,19 +762,19 @@ public class AdbDebuggingManager { } }; - /** Constructor that accepts the AdbDebuggingThread to which responses should be sent. */ - @VisibleForTesting - AdbDebuggingHandler(Looper looper, AdbDebuggingThread thread) { + AdbDebuggingHandler(Looper looper) { super(looper); - mThread = thread; } - /** Initialize the AdbKeyStore so tests can grab mAdbKeyStore immediately. */ - @VisibleForTesting - void initKeyStore() { - if (mAdbKeyStore == null) { - mAdbKeyStore = new AdbKeyStore(); - } + /** + * Constructor that accepts the AdbDebuggingThread to which responses should be sent + * and the AdbKeyStore to be used to store the temporary grants. + */ + @TestApi + AdbDebuggingHandler(Looper looper, AdbDebuggingThread thread, AdbKeyStore adbKeyStore) { + super(looper); + mThread = thread; + mAdbKeyStore = adbKeyStore; } // Show when at least one device is connected. @@ -839,7 +805,6 @@ public class AdbDebuggingManager { registerForAuthTimeChanges(); mThread = new AdbDebuggingThread(); - mThread.setHandler(mHandler); mThread.start(); mAdbKeyStore.updateKeyStore(); @@ -860,7 +825,8 @@ public class AdbDebuggingManager { if (!mConnectedKeys.isEmpty()) { for (Map.Entry<String, Integer> entry : mConnectedKeys.entrySet()) { - mAdbKeyStore.setLastConnectionTime(entry.getKey(), mTicker.currentTimeMillis()); + mAdbKeyStore.setLastConnectionTime(entry.getKey(), + System.currentTimeMillis()); } sendPersistKeyStoreMessage(); mConnectedKeys.clear(); @@ -870,7 +836,9 @@ public class AdbDebuggingManager { } public void handleMessage(Message msg) { - initKeyStore(); + if (mAdbKeyStore == null) { + mAdbKeyStore = new AdbKeyStore(); + } switch (msg.what) { case MESSAGE_ADB_ENABLED: @@ -905,7 +873,7 @@ public class AdbDebuggingManager { if (!mConnectedKeys.containsKey(key)) { mConnectedKeys.put(key, 1); } - mAdbKeyStore.setLastConnectionTime(key, mTicker.currentTimeMillis()); + mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); sendPersistKeyStoreMessage(); scheduleJobToUpdateAdbKeyStore(); } @@ -952,7 +920,9 @@ public class AdbDebuggingManager { mConnectedKeys.clear(); // If the key store has not yet been instantiated then do so now; this avoids // the unnecessary creation of the key store when adb is not enabled. - initKeyStore(); + if (mAdbKeyStore == null) { + mAdbKeyStore = new AdbKeyStore(); + } mWifiConnectedKeys.clear(); mAdbKeyStore.deleteKeyStore(); cancelJobToUpdateAdbKeyStore(); @@ -967,8 +937,7 @@ public class AdbDebuggingManager { alwaysAllow = true; int refcount = mConnectedKeys.get(key) - 1; if (refcount == 0) { - mAdbKeyStore.setLastConnectionTime( - key, mTicker.currentTimeMillis()); + mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); sendPersistKeyStoreMessage(); scheduleJobToUpdateAdbKeyStore(); mConnectedKeys.remove(key); @@ -994,7 +963,7 @@ public class AdbDebuggingManager { if (!mConnectedKeys.isEmpty()) { for (Map.Entry<String, Integer> entry : mConnectedKeys.entrySet()) { mAdbKeyStore.setLastConnectionTime(entry.getKey(), - mTicker.currentTimeMillis()); + System.currentTimeMillis()); } sendPersistKeyStoreMessage(); scheduleJobToUpdateAdbKeyStore(); @@ -1015,7 +984,7 @@ public class AdbDebuggingManager { } else { mConnectedKeys.put(key, mConnectedKeys.get(key) + 1); } - mAdbKeyStore.setLastConnectionTime(key, mTicker.currentTimeMillis()); + mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); sendPersistKeyStoreMessage(); scheduleJobToUpdateAdbKeyStore(); logAdbConnectionChanged(key, AdbProtoEnums.AUTOMATICALLY_ALLOWED, true); @@ -1237,10 +1206,6 @@ public class AdbDebuggingManager { } break; } - case MESSAGE_KEY_FILES_UPDATED: { - mAdbKeyStore.reloadKeyMap(); - break; - } } } @@ -1412,7 +1377,8 @@ public class AdbDebuggingManager { AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL); // Add the key into the keystore - mAdbKeyStore.setLastConnectionTime(publicKey, mTicker.currentTimeMillis()); + mAdbKeyStore.setLastConnectionTime(publicKey, + System.currentTimeMillis()); sendPersistKeyStoreMessage(); scheduleJobToUpdateAdbKeyStore(); } @@ -1483,13 +1449,19 @@ public class AdbDebuggingManager { extras.add(new AbstractMap.SimpleEntry<String, String>("ssid", ssid)); extras.add(new AbstractMap.SimpleEntry<String, String>("bssid", bssid)); int currentUserId = ActivityManager.getCurrentUser(); - String componentString = - Resources.getSystem().getString( - R.string.config_customAdbWifiNetworkConfirmationComponent); - ComponentName componentName = ComponentName.unflattenFromString(componentString); UserInfo userInfo = UserManager.get(mContext).getUserInfo(currentUserId); + String componentString; + if (userInfo.isAdmin()) { + componentString = Resources.getSystem().getString( + com.android.internal.R.string.config_customAdbWifiNetworkConfirmationComponent); + } else { + componentString = Resources.getSystem().getString( + com.android.internal.R.string.config_customAdbWifiNetworkConfirmationComponent); + } + ComponentName componentName = ComponentName.unflattenFromString(componentString); if (startConfirmationActivity(componentName, userInfo.getUserHandle(), extras) - || startConfirmationService(componentName, userInfo.getUserHandle(), extras)) { + || startConfirmationService(componentName, userInfo.getUserHandle(), + extras)) { return; } Slog.e(TAG, "Unable to start customAdbWifiNetworkConfirmation[SecondaryUser]Component " @@ -1571,7 +1543,7 @@ public class AdbDebuggingManager { /** * Returns a new File with the specified name in the adb directory. */ - private static File getAdbFile(String fileName) { + private File getAdbFile(String fileName) { File dataDir = Environment.getDataDirectory(); File adbDir = new File(dataDir, ADB_DIRECTORY); @@ -1584,38 +1556,66 @@ public class AdbDebuggingManager { } File getAdbTempKeysFile() { - return mTempKeysFile; + return getAdbFile(ADB_TEMP_KEYS_FILE); } File getUserKeyFile() { - return mUserKeyFile; + return mTestUserKeyFile == null ? getAdbFile(ADB_KEYS_FILE) : mTestUserKeyFile; } - private void writeKeys(Iterable<String> keys) { - if (mUserKeyFile == null) { - return; + private void writeKey(String key) { + try { + File keyFile = getUserKeyFile(); + + if (keyFile == null) { + return; + } + + FileOutputStream fo = new FileOutputStream(keyFile, true); + fo.write(key.getBytes()); + fo.write('\n'); + fo.close(); + + FileUtils.setPermissions(keyFile.toString(), + FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP, -1, -1); + } catch (IOException ex) { + Slog.e(TAG, "Error writing key:" + ex); } + } - AtomicFile atomicKeyFile = new AtomicFile(mUserKeyFile); - // Note: Do not use a try-with-resources with the FileOutputStream, because AtomicFile - // requires that it's cleaned up with AtomicFile.failWrite(); + private void writeKeys(Iterable<String> keys) { + AtomicFile atomicKeyFile = null; FileOutputStream fo = null; try { + File keyFile = getUserKeyFile(); + + if (keyFile == null) { + return; + } + + atomicKeyFile = new AtomicFile(keyFile); fo = atomicKeyFile.startWrite(); for (String key : keys) { fo.write(key.getBytes()); fo.write('\n'); } atomicKeyFile.finishWrite(fo); + + FileUtils.setPermissions(keyFile.toString(), + FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP, -1, -1); } catch (IOException ex) { Slog.e(TAG, "Error writing keys: " + ex); - atomicKeyFile.failWrite(fo); - return; + if (atomicKeyFile != null) { + atomicKeyFile.failWrite(fo); + } } + } - FileUtils.setPermissions( - mUserKeyFile.toString(), - FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP, -1, -1); + private void deleteKeyFile() { + File keyFile = getUserKeyFile(); + if (keyFile != null) { + keyFile.delete(); + } } /** @@ -1745,13 +1745,6 @@ public class AdbDebuggingManager { } /** - * Notify that they key files were updated so the AdbKeyManager reloads the keys. - */ - public void notifyKeyFilesUpdated() { - mHandler.sendEmptyMessage(AdbDebuggingHandler.MESSAGE_KEY_FILES_UPDATED); - } - - /** * Sends a message to the handler to persist the keystore. */ private void sendPersistKeyStoreMessage() { @@ -1785,7 +1778,7 @@ public class AdbDebuggingManager { try { dump.write("keystore", AdbDebuggingManagerProto.KEYSTORE, - FileUtils.readTextFile(mTempKeysFile, 0, null)); + FileUtils.readTextFile(getAdbTempKeysFile(), 0, null)); } catch (IOException e) { Slog.i(TAG, "Cannot read keystore: ", e); } @@ -1799,12 +1792,12 @@ public class AdbDebuggingManager { * ADB_ALLOWED_CONNECTION_TIME setting. */ class AdbKeyStore { + private Map<String, Long> mKeyMap; + private Set<String> mSystemKeys; + private File mKeyFile; private AtomicFile mAtomicKeyFile; - private final Set<String> mSystemKeys; - private final Map<String, Long> mKeyMap = new HashMap<>(); - private final List<String> mTrustedNetworks = new ArrayList<>(); - + private List<String> mTrustedNetworks; private static final int KEYSTORE_VERSION = 1; private static final int MAX_SUPPORTED_KEYSTORE_VERSION = 1; private static final String XML_KEYSTORE_START_TAG = "keyStore"; @@ -1826,22 +1819,26 @@ public class AdbDebuggingManager { public static final long NO_PREVIOUS_CONNECTION = 0; /** - * Create an AdbKeyStore instance. - * - * <p>Upon creation, we parse {@link #mTempKeysFile} to determine authorized WiFi APs and - * retrieve the map of stored ADB keys and their last connected times. After that, we read - * the {@link #mUserKeyFile}, and any keys that exist in that file that do not exist in the - * map are added to the map (for backwards compatibility). + * Constructor that uses the default location for the persistent adb keystore. */ AdbKeyStore() { - initKeyFile(); - readTempKeysFile(); - mSystemKeys = getSystemKeysFromFile(SYSTEM_KEY_FILE); - addExistingUserKeysToKeyStore(); + init(); } - public void reloadKeyMap() { - readTempKeysFile(); + /** + * Constructor that uses the specified file as the location for the persistent adb keystore. + */ + AdbKeyStore(File keyFile) { + mKeyFile = keyFile; + init(); + } + + private void init() { + initKeyFile(); + mKeyMap = getKeyMap(); + mTrustedNetworks = getTrustedNetworks(); + mSystemKeys = getSystemKeysFromFile(SYSTEM_KEY_FILE); + addUserKeysToKeyStore(); } public void addTrustedNetwork(String bssid) { @@ -1880,6 +1877,7 @@ public class AdbDebuggingManager { public void removeKey(String key) { if (mKeyMap.containsKey(key)) { mKeyMap.remove(key); + writeKeys(mKeyMap.keySet()); sendPersistKeyStoreMessage(); } } @@ -1888,9 +1886,12 @@ public class AdbDebuggingManager { * Initializes the key file that will be used to persist the adb grants. */ private void initKeyFile() { - // mTempKeysFile can be null if the adb file cannot be obtained - if (mTempKeysFile != null) { - mAtomicKeyFile = new AtomicFile(mTempKeysFile); + if (mKeyFile == null) { + mKeyFile = getAdbTempKeysFile(); + } + // getAdbTempKeysFile can return null if the adb file cannot be obtained + if (mKeyFile != null) { + mAtomicKeyFile = new AtomicFile(mKeyFile); } } @@ -1931,108 +1932,201 @@ public class AdbDebuggingManager { } /** - * Update the key map and the trusted networks list with values parsed from the temp keys - * file. + * Returns the key map with the keys and last connection times from the key file. */ - private void readTempKeysFile() { - mKeyMap.clear(); - mTrustedNetworks.clear(); + private Map<String, Long> getKeyMap() { + Map<String, Long> keyMap = new HashMap<String, Long>(); + // if the AtomicFile could not be instantiated before attempt again; if it still fails + // return an empty key map. if (mAtomicKeyFile == null) { initKeyFile(); if (mAtomicKeyFile == null) { - Slog.e( - TAG, - "Unable to obtain the key file, " + mTempKeysFile + ", for reading"); - return; + Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for reading"); + return keyMap; } } if (!mAtomicKeyFile.exists()) { - return; + return keyMap; } try (FileInputStream keyStream = mAtomicKeyFile.openRead()) { - TypedXmlPullParser parser; - try { - parser = Xml.resolvePullParser(keyStream); - XmlUtils.beginDocument(parser, XML_KEYSTORE_START_TAG); - + TypedXmlPullParser parser = Xml.resolvePullParser(keyStream); + // Check for supported keystore version. + XmlUtils.beginDocument(parser, XML_KEYSTORE_START_TAG); + if (parser.next() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if (tagName == null || !XML_KEYSTORE_START_TAG.equals(tagName)) { + Slog.e(TAG, "Expected " + XML_KEYSTORE_START_TAG + ", but got tag=" + + tagName); + return keyMap; + } int keystoreVersion = parser.getAttributeInt(null, XML_ATTRIBUTE_VERSION); if (keystoreVersion > MAX_SUPPORTED_KEYSTORE_VERSION) { Slog.e(TAG, "Keystore version=" + keystoreVersion + " not supported (max_supported=" + MAX_SUPPORTED_KEYSTORE_VERSION + ")"); - return; + return keyMap; + } + } + while (parser.next() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if (tagName == null) { + break; + } else if (!tagName.equals(XML_TAG_ADB_KEY)) { + XmlUtils.skipCurrentTag(parser); + continue; } - } catch (XmlPullParserException e) { - // This could be because the XML document doesn't start with - // XML_KEYSTORE_START_TAG. Try again, instead just starting the document with - // the adbKey tag (the old format). - parser = Xml.resolvePullParser(keyStream); + String key = parser.getAttributeValue(null, XML_ATTRIBUTE_KEY); + long connectionTime; + try { + connectionTime = parser.getAttributeLong(null, + XML_ATTRIBUTE_LAST_CONNECTION); + } catch (XmlPullParserException e) { + Slog.e(TAG, + "Caught a NumberFormatException parsing the last connection time: " + + e); + XmlUtils.skipCurrentTag(parser); + continue; + } + keyMap.put(key, connectionTime); } - readKeyStoreContents(parser); } catch (IOException e) { Slog.e(TAG, "Caught an IOException parsing the XML key file: ", e); } catch (XmlPullParserException e) { - Slog.e(TAG, "Caught XmlPullParserException parsing the XML key file: ", e); - } - } - - private void readKeyStoreContents(TypedXmlPullParser parser) - throws XmlPullParserException, IOException { - // This parser is very forgiving. For backwards-compatibility, we simply iterate through - // all the tags in the file, skipping over anything that's not an <adbKey> tag or a - // <wifiAP> tag. Invalid tags (such as ones that don't have a valid "lastConnection" - // attribute) are simply ignored. - while ((parser.next()) != XmlPullParser.END_DOCUMENT) { - String tagName = parser.getName(); - if (XML_TAG_ADB_KEY.equals(tagName)) { - addAdbKeyToKeyMap(parser); - } else if (XML_TAG_WIFI_ACCESS_POINT.equals(tagName)) { - addTrustedNetworkToTrustedNetworks(parser); - } else { - Slog.w(TAG, "Ignoring tag '" + tagName + "'. Not recognized."); - } - XmlUtils.skipCurrentTag(parser); + Slog.w(TAG, "Caught XmlPullParserException parsing the XML key file: ", e); + // The file could be written in a format prior to introducing keystore tag. + return getKeyMapBeforeKeystoreVersion(); } + return keyMap; } - private void addAdbKeyToKeyMap(TypedXmlPullParser parser) { - String key = parser.getAttributeValue(null, XML_ATTRIBUTE_KEY); - try { - long connectionTime = - parser.getAttributeLong(null, XML_ATTRIBUTE_LAST_CONNECTION); - mKeyMap.put(key, connectionTime); - } catch (XmlPullParserException e) { - Slog.e(TAG, "Error reading adbKey attributes", e); + + /** + * Returns the key map with the keys and last connection times from the key file. + * This implementation was prior to adding the XML_KEYSTORE_START_TAG. + */ + private Map<String, Long> getKeyMapBeforeKeystoreVersion() { + Map<String, Long> keyMap = new HashMap<String, Long>(); + // if the AtomicFile could not be instantiated before attempt again; if it still fails + // return an empty key map. + if (mAtomicKeyFile == null) { + initKeyFile(); + if (mAtomicKeyFile == null) { + Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for reading"); + return keyMap; + } + } + if (!mAtomicKeyFile.exists()) { + return keyMap; + } + try (FileInputStream keyStream = mAtomicKeyFile.openRead()) { + TypedXmlPullParser parser = Xml.resolvePullParser(keyStream); + XmlUtils.beginDocument(parser, XML_TAG_ADB_KEY); + while (parser.next() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if (tagName == null) { + break; + } else if (!tagName.equals(XML_TAG_ADB_KEY)) { + XmlUtils.skipCurrentTag(parser); + continue; + } + String key = parser.getAttributeValue(null, XML_ATTRIBUTE_KEY); + long connectionTime; + try { + connectionTime = parser.getAttributeLong(null, + XML_ATTRIBUTE_LAST_CONNECTION); + } catch (XmlPullParserException e) { + Slog.e(TAG, + "Caught a NumberFormatException parsing the last connection time: " + + e); + XmlUtils.skipCurrentTag(parser); + continue; + } + keyMap.put(key, connectionTime); + } + } catch (IOException | XmlPullParserException e) { + Slog.e(TAG, "Caught an exception parsing the XML key file: ", e); } + return keyMap; } - private void addTrustedNetworkToTrustedNetworks(TypedXmlPullParser parser) { - String bssid = parser.getAttributeValue(null, XML_ATTRIBUTE_WIFI_BSSID); - mTrustedNetworks.add(bssid); + /** + * Returns the map of trusted networks from the keystore file. + * + * This was implemented in keystore version 1. + */ + private List<String> getTrustedNetworks() { + List<String> trustedNetworks = new ArrayList<String>(); + // if the AtomicFile could not be instantiated before attempt again; if it still fails + // return an empty key map. + if (mAtomicKeyFile == null) { + initKeyFile(); + if (mAtomicKeyFile == null) { + Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for reading"); + return trustedNetworks; + } + } + if (!mAtomicKeyFile.exists()) { + return trustedNetworks; + } + try (FileInputStream keyStream = mAtomicKeyFile.openRead()) { + TypedXmlPullParser parser = Xml.resolvePullParser(keyStream); + // Check for supported keystore version. + XmlUtils.beginDocument(parser, XML_KEYSTORE_START_TAG); + if (parser.next() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if (tagName == null || !XML_KEYSTORE_START_TAG.equals(tagName)) { + Slog.e(TAG, "Expected " + XML_KEYSTORE_START_TAG + ", but got tag=" + + tagName); + return trustedNetworks; + } + int keystoreVersion = parser.getAttributeInt(null, XML_ATTRIBUTE_VERSION); + if (keystoreVersion > MAX_SUPPORTED_KEYSTORE_VERSION) { + Slog.e(TAG, "Keystore version=" + keystoreVersion + + " not supported (max_supported=" + + MAX_SUPPORTED_KEYSTORE_VERSION); + return trustedNetworks; + } + } + while (parser.next() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if (tagName == null) { + break; + } else if (!tagName.equals(XML_TAG_WIFI_ACCESS_POINT)) { + XmlUtils.skipCurrentTag(parser); + continue; + } + String bssid = parser.getAttributeValue(null, XML_ATTRIBUTE_WIFI_BSSID); + trustedNetworks.add(bssid); + } + } catch (IOException | XmlPullParserException | NumberFormatException e) { + Slog.e(TAG, "Caught an exception parsing the XML key file: ", e); + } + return trustedNetworks; } /** * Updates the keystore with keys that were previously set to be always allowed before the * connection time of keys was tracked. */ - private void addExistingUserKeysToKeyStore() { - if (mUserKeyFile == null || !mUserKeyFile.exists()) { - return; - } + private void addUserKeysToKeyStore() { + File userKeyFile = getUserKeyFile(); boolean mapUpdated = false; - try (BufferedReader in = new BufferedReader(new FileReader(mUserKeyFile))) { - String key; - while ((key = in.readLine()) != null) { - // if the keystore does not contain the key from the user key file then add - // it to the Map with the current system time to prevent it from expiring - // immediately if the user is actively using this key. - if (!mKeyMap.containsKey(key)) { - mKeyMap.put(key, mTicker.currentTimeMillis()); - mapUpdated = true; + if (userKeyFile != null && userKeyFile.exists()) { + try (BufferedReader in = new BufferedReader(new FileReader(userKeyFile))) { + long time = System.currentTimeMillis(); + String key; + while ((key = in.readLine()) != null) { + // if the keystore does not contain the key from the user key file then add + // it to the Map with the current system time to prevent it from expiring + // immediately if the user is actively using this key. + if (!mKeyMap.containsKey(key)) { + mKeyMap.put(key, time); + mapUpdated = true; + } } + } catch (IOException e) { + Slog.e(TAG, "Caught an exception reading " + userKeyFile + ": " + e); } - } catch (IOException e) { - Slog.e(TAG, "Caught an exception reading " + mUserKeyFile + ": " + e); } if (mapUpdated) { sendPersistKeyStoreMessage(); @@ -2053,9 +2147,7 @@ public class AdbDebuggingManager { if (mAtomicKeyFile == null) { initKeyFile(); if (mAtomicKeyFile == null) { - Slog.e( - TAG, - "Unable to obtain the key file, " + mTempKeysFile + ", for writing"); + Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for writing"); return; } } @@ -2086,21 +2178,17 @@ public class AdbDebuggingManager { Slog.e(TAG, "Caught an exception writing the key map: ", e); mAtomicKeyFile.failWrite(keyStream); } - writeKeys(mKeyMap.keySet()); } private boolean filterOutOldKeys() { - long allowedTime = getAllowedConnectionTime(); - if (allowedTime == 0) { - return false; - } boolean keysDeleted = false; - long systemTime = mTicker.currentTimeMillis(); + long allowedTime = getAllowedConnectionTime(); + long systemTime = System.currentTimeMillis(); Iterator<Map.Entry<String, Long>> keyMapIterator = mKeyMap.entrySet().iterator(); while (keyMapIterator.hasNext()) { Map.Entry<String, Long> keyEntry = keyMapIterator.next(); long connectionTime = keyEntry.getValue(); - if (systemTime > (connectionTime + allowedTime)) { + if (allowedTime != 0 && systemTime > (connectionTime + allowedTime)) { keyMapIterator.remove(); keysDeleted = true; } @@ -2124,7 +2212,7 @@ public class AdbDebuggingManager { if (allowedTime == 0) { return minExpiration; } - long systemTime = mTicker.currentTimeMillis(); + long systemTime = System.currentTimeMillis(); Iterator<Map.Entry<String, Long>> keyMapIterator = mKeyMap.entrySet().iterator(); while (keyMapIterator.hasNext()) { Map.Entry<String, Long> keyEntry = keyMapIterator.next(); @@ -2145,9 +2233,7 @@ public class AdbDebuggingManager { public void deleteKeyStore() { mKeyMap.clear(); mTrustedNetworks.clear(); - if (mUserKeyFile != null) { - mUserKeyFile.delete(); - } + deleteKeyFile(); if (mAtomicKeyFile == null) { return; } @@ -2174,8 +2260,7 @@ public class AdbDebuggingManager { * is set to true the time will be set even if it is older than the previously written * connection time. */ - @VisibleForTesting - void setLastConnectionTime(String key, long connectionTime, boolean force) { + public void setLastConnectionTime(String key, long connectionTime, boolean force) { // Do not set the connection time to a value that is earlier than what was previously // stored as the last connection time unless force is set. if (mKeyMap.containsKey(key) && mKeyMap.get(key) >= connectionTime && !force) { @@ -2186,6 +2271,11 @@ public class AdbDebuggingManager { if (mSystemKeys.contains(key)) { return; } + // if this is the first time the key is being added then write it to the key file as + // well. + if (!mKeyMap.containsKey(key)) { + writeKey(key); + } mKeyMap.put(key, connectionTime); } @@ -2217,8 +2307,12 @@ public class AdbDebuggingManager { long allowedConnectionTime = getAllowedConnectionTime(); // if the allowed connection time is 0 then revert to the previous behavior of always // allowing previously granted adb grants. - return allowedConnectionTime == 0 - || (mTicker.currentTimeMillis() < (lastConnectionTime + allowedConnectionTime)); + if (allowedConnectionTime == 0 || (System.currentTimeMillis() < (lastConnectionTime + + allowedConnectionTime))) { + return true; + } else { + return false; + } } /** @@ -2230,15 +2324,4 @@ public class AdbDebuggingManager { return mTrustedNetworks.contains(bssid); } } - - /** - * A Guava-like interface for getting the current system time. - * - * This allows us to swap a fake ticker in for testing to reduce "Thread.sleep()" calls and test - * for exact expected times instead of random ones. - */ - @VisibleForTesting - interface Ticker { - long currentTimeMillis(); - } } |