summaryrefslogtreecommitdiff
path: root/services/core/java/com/android/server/adb/AdbDebuggingManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/core/java/com/android/server/adb/AdbDebuggingManager.java')
-rw-r--r--services/core/java/com/android/server/adb/AdbDebuggingManager.java543
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();
- }
}