Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad7b649b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix Test Harness Mode to work with new ADB file"

parents 2ba126cb 99a7d633
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.debug;

import java.io.File;

/**
 * This class allows the control of ADB-related functions that should only be called from the system
 * server.
@@ -41,4 +43,14 @@ public abstract class AdbManagerInternal {
     * Returns {@code true} if ADB debugging is enabled.
     */
    public abstract boolean isAdbEnabled();

    /**
     * Returns the file that contains all of the ADB keys used by the device.
     */
    public abstract File getAdbKeysFile();

    /**
     * Returns the file that contains all of the ADB keys and their last used time.
     */
    public abstract File getAdbTempKeysFile();
}
+37 −23
Original line number Diff line number Diff line
@@ -82,6 +82,9 @@ public class AdbDebuggingManager {
    private static final String ADB_DIRECTORY = "misc/adb";
    // This file contains keys that will always be allowed to connect to the device via adb.
    private static final String ADB_KEYS_FILE = "adb_keys";
    // This file contains keys that will be allowed to connect without user interaction as long
    // 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 = 4096;

    private final Context mContext;
@@ -263,7 +266,6 @@ public class AdbDebuggingManager {

        AdbDebuggingHandler(Looper looper) {
            super(looper);
            mAdbKeyStore = new AdbKeyStore();
        }

        /**
@@ -289,6 +291,7 @@ public class AdbDebuggingManager {
                    mThread = new AdbDebuggingThread();
                    mThread.start();

                    mAdbKeyStore = new AdbKeyStore();
                    break;

                case MESSAGE_ADB_DISABLED:
@@ -303,6 +306,9 @@ public class AdbDebuggingManager {
                        mThread = null;
                    }

                    cancelJobToUpdateAdbKeyStore();
                    mAdbKeyStore = null;
                    mConnectedKey = null;
                    break;

                case MESSAGE_ADB_ALLOW: {
@@ -532,7 +538,11 @@ public class AdbDebuggingManager {
        return new File(adbDir, fileName);
    }

    private File getUserKeyFile() {
    File getAdbTempKeysFile() {
        return getAdbFile(ADB_TEMP_KEYS_FILE);
    }

    File getUserKeyFile() {
        return getAdbFile(ADB_KEYS_FILE);
    }

@@ -668,9 +678,6 @@ public class AdbDebuggingManager {
        private Map<String, Long> mKeyMap;
        private File mKeyFile;
        private AtomicFile mAtomicKeyFile;
        // This file contains keys that will be allowed to connect without user interaction as long
        // as a subsequent connection occurs within the allowed duration.
        private static final String ADB_TEMP_KEYS_FILE = "adb_temp_keys.xml";
        private static final String XML_TAG_ADB_KEY = "adbKey";
        private static final String XML_ATTRIBUTE_KEY = "key";
        private static final String XML_ATTRIBUTE_LAST_CONNECTION = "lastConnection";
@@ -704,9 +711,9 @@ public class AdbDebuggingManager {
         */
        private void initKeyFile() {
            if (mKeyFile == null) {
                mKeyFile = getAdbFile(ADB_TEMP_KEYS_FILE);
                mKeyFile = getAdbTempKeysFile();
            }
            // getAdbFile can return null if the adb file cannot be obtained
            // getAdbTempKeysFile can return null if the adb file cannot be obtained
            if (mKeyFile != null) {
                mAtomicKeyFile = new AtomicFile(mKeyFile);
            }
@@ -767,7 +774,8 @@ public class AdbDebuggingManager {
        public void persistKeyStore() {
            // if there is nothing in the key map then ensure any keys left in the key store files
            // are deleted as well.
            if (mKeyMap.size() == 0) {
            filterOutOldKeys();
            if (mKeyMap.isEmpty()) {
                deleteKeyStore();
                return;
            }
@@ -784,22 +792,15 @@ public class AdbDebuggingManager {
                keyStream = mAtomicKeyFile.startWrite();
                serializer.setOutput(keyStream, StandardCharsets.UTF_8.name());
                serializer.startDocument(null, true);
                long allowedTime = getAllowedConnectionTime();
                long systemTime = System.currentTimeMillis();
                Iterator keyMapIterator = mKeyMap.entrySet().iterator();
                while (keyMapIterator.hasNext()) {
                    Map.Entry<String, Long> keyEntry = (Map.Entry) keyMapIterator.next();
                    long connectionTime = keyEntry.getValue();
                    if (systemTime < (connectionTime + allowedTime)) {

                for (Map.Entry<String, Long> keyEntry : mKeyMap.entrySet()) {
                    serializer.startTag(null, XML_TAG_ADB_KEY);
                    serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey());
                    serializer.attribute(null, XML_ATTRIBUTE_LAST_CONNECTION,
                            String.valueOf(keyEntry.getValue()));
                    serializer.endTag(null, XML_TAG_ADB_KEY);
                    } else {
                        keyMapIterator.remove();
                    }
                }

                serializer.endDocument();
                mAtomicKeyFile.finishWrite(keyStream);
            } catch (IOException e) {
@@ -808,6 +809,19 @@ public class AdbDebuggingManager {
            }
        }

        private void filterOutOldKeys() {
            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 (allowedTime != 0 && systemTime > (connectionTime + allowedTime)) {
                    keyMapIterator.remove();
                }
            }
        }

        /**
         * Removes all of the entries in the key map and deletes the key file.
         */
+11 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;

import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collections;
@@ -95,6 +96,16 @@ public class AdbService extends IAdbManager.Stub {
        public boolean isAdbEnabled() {
            return mAdbEnabled;
        }

        @Override
        public File getAdbKeysFile() {
            return mDebuggingManager.getUserKeyFile();
        }

        @Override
        public File getAdbTempKeysFile() {
            return mDebuggingManager.getAdbTempKeysFile();
        }
    }

    private final class AdbHandler extends Handler {
+75 −38
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.debug.AdbManagerInternal;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.IBinder;
@@ -42,6 +43,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
@@ -49,7 +51,6 @@ import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Set;

@@ -85,6 +86,7 @@ public class TestHarnessModeService extends SystemService {
                break;
            case PHASE_BOOT_COMPLETED:
                disableAutoSync();
                configureSettings();
                break;
        }
        super.onBootPhase(phase);
@@ -98,47 +100,60 @@ public class TestHarnessModeService extends SystemService {
            return;
        }
        mShouldSetUpTestHarnessMode = true;
        setUpAdb(testHarnessModeData);
        setDeviceProvisioned();
    }

    private void setUpAdb(byte[] testHarnessModeData) {
        ContentResolver cr = getContext().getContentResolver();
        // Disable the TTL for ADB keys before enabling ADB
        Settings.Global.putLong(cr, Settings.Global.ADB_ALLOWED_CONNECTION_TIME, 0);

        PersistentData persistentData = PersistentData.fromBytes(testHarnessModeData);

        SystemProperties.set(TEST_HARNESS_MODE_PROPERTY, persistentData.mEnabled ? "1" : "0");
        writeAdbKeysFile(persistentData);
        // Clear out the data block so that we don't revert the ADB keys on every boot.
        getPersistentDataBlock().clearTestHarnessModeData();
    }

        ContentResolver cr = getContext().getContentResolver();
        if (Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED, 0) == 0) {
            // Enable ADB
            Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1);
        } else {
            // ADB is already enabled, we should restart the service so it picks up the new keys
            android.os.SystemService.restart("adbd");
    private void disableAutoSync() {
        if (!mShouldSetUpTestHarnessMode) {
            return;
        }
        UserInfo primaryUser = UserManager.get(getContext()).getPrimaryUser();
        ContentResolver
            .setMasterSyncAutomaticallyAsUser(false, primaryUser.getUserHandle().getIdentifier());
    }

    private void configureSettings() {
        if (!mShouldSetUpTestHarnessMode) {
            return;
        }
        ContentResolver cr = getContext().getContentResolver();

        Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1);
        Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
        Settings.Global.putInt(cr, Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
        Settings.Global.putInt(
                cr,
                Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
                BatteryManager.BATTERY_PLUGGED_ANY);
        Settings.Global.putInt(cr, Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE, 1);
        Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);

        setDeviceProvisioned();
    }

    private void disableAutoSync() {
        if (!mShouldSetUpTestHarnessMode) {
            return;
        }
        UserInfo primaryUser = UserManager.get(getContext()).getPrimaryUser();
        ContentResolver
            .setMasterSyncAutomaticallyAsUser(false, primaryUser.getUserHandle().getIdentifier());
    private void writeAdbKeysFile(PersistentData persistentData) {
        AdbManagerInternal adbManager = LocalServices.getService(AdbManagerInternal.class);

        writeBytesToFile(persistentData.mAdbKeys, adbManager.getAdbKeysFile().toPath());
        writeBytesToFile(persistentData.mAdbTempKeys, adbManager.getAdbTempKeysFile().toPath());

        // Clear out the data block so that we don't revert the ADB keys on every boot.
        getPersistentDataBlock().clearTestHarnessModeData();
    }

    private void writeAdbKeysFile(PersistentData persistentData) {
        Path adbKeys = Paths.get("/data/misc/adb/adb_keys");
    private void writeBytesToFile(byte[] keys, Path adbKeys) {
        try {
            OutputStream fileOutputStream = Files.newOutputStream(adbKeys);
            fileOutputStream.write(persistentData.mAdbKeys);
            fileOutputStream.write(keys);
            fileOutputStream.close();

            Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(adbKeys);
@@ -219,23 +234,22 @@ public class TestHarnessModeService extends SystemService {
        }

        private int handleEnable() {
            Path adbKeys = Paths.get("/data/misc/adb/adb_keys");
            if (!Files.exists(adbKeys)) {
            AdbManagerInternal adbManager = LocalServices.getService(AdbManagerInternal.class);
            File adbKeys = adbManager.getAdbKeysFile();
            File adbTempKeys = adbManager.getAdbTempKeysFile();
            if (adbKeys == null && adbTempKeys == null) {
                // This should only be accessible on eng builds that haven't yet set up ADB keys
                getErrPrintWriter()
                    .println("No ADB keys stored; not enabling test harness mode");
                return 1;
            }

            try (InputStream inputStream = Files.newInputStream(adbKeys)) {
                long size = Files.size(adbKeys);
                byte[] adbKeysBytes = new byte[(int) size];
                int numBytes = inputStream.read(adbKeysBytes);
                if (numBytes != size) {
                    getErrPrintWriter().println("Failed to read all bytes of adb_keys");
                    return 1;
                }
                PersistentData persistentData = new PersistentData(true, adbKeysBytes);
            try {
                byte[] adbKeysBytes = getBytesFromFile(adbKeys);
                byte[] adbTempKeysBytes = getBytesFromFile(adbTempKeys);

                PersistentData persistentData =
                        new PersistentData(true, adbKeysBytes, adbTempKeysBytes);
                getPersistentDataBlock().setTestHarnessModeData(persistentData.toBytes());
            } catch (IOException e) {
                Slog.e(TAG, "Failed to store ADB keys.", e);
@@ -252,6 +266,22 @@ public class TestHarnessModeService extends SystemService {
            return 0;
        }

        private byte[] getBytesFromFile(File file) throws IOException {
            if (file == null || !file.exists()) {
                return new byte[0];
            }
            Path path = file.toPath();
            try (InputStream inputStream = Files.newInputStream(path)) {
                int size = (int) Files.size(path);
                byte[] bytes = new byte[size];
                int numBytes = inputStream.read(bytes);
                if (numBytes != size) {
                    throw new IOException("Failed to read the whole file");
                }
                return bytes;
            }
        }

        @Override
        public void onHelp() {
            PrintWriter pw = getOutPrintWriter();
@@ -290,15 +320,17 @@ public class TestHarnessModeService extends SystemService {
        final int mVersion;
        final boolean mEnabled;
        final byte[] mAdbKeys;
        final byte[] mAdbTempKeys;

        PersistentData(boolean enabled, byte[] adbKeys) {
            this(VERSION_1, enabled, adbKeys);
        PersistentData(boolean enabled, byte[] adbKeys, byte[] adbTempKeys) {
            this(VERSION_1, enabled, adbKeys, adbTempKeys);
        }

        PersistentData(int version, boolean enabled, byte[] adbKeys) {
        PersistentData(int version, boolean enabled, byte[] adbKeys, byte[] adbTempKeys) {
            this.mVersion = version;
            this.mEnabled = enabled;
            this.mAdbKeys = adbKeys;
            this.mAdbTempKeys = adbTempKeys;
        }

        static PersistentData fromBytes(byte[] bytes) {
@@ -309,7 +341,10 @@ public class TestHarnessModeService extends SystemService {
                int adbKeysLength = is.readInt();
                byte[] adbKeys = new byte[adbKeysLength];
                is.readFully(adbKeys);
                return new PersistentData(version, enabled, adbKeys);
                int adbTempKeysLength = is.readInt();
                byte[] adbTempKeys = new byte[adbTempKeysLength];
                is.readFully(adbTempKeys);
                return new PersistentData(version, enabled, adbKeys, adbTempKeys);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
@@ -323,6 +358,8 @@ public class TestHarnessModeService extends SystemService {
                dos.writeBoolean(mEnabled);
                dos.writeInt(mAdbKeys.length);
                dos.write(mAdbKeys);
                dos.writeInt(mAdbTempKeys.length);
                dos.write(mAdbTempKeys);
                dos.close();
                return os.toByteArray();
            } catch (IOException e) {