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

Commit 07ff6f58 authored by Sal Savage's avatar Sal Savage
Browse files

Validate the image handle we parse before using it

Tag: #stability
Bug: 182596296
Test: atest BluetoothInstrumentationTests
Change-Id: Ib670834d6687c182c4ae65d3a5a7a0d88b012dfd
parent c67de112
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ public class AvrcpCoverArtManager {
        }

        public String getHandleUuid(String handle) {
            if (handle == null) return null;
            if (isValidImageHandle(handle)) return null;
            String newUuid = UUID.randomUUID().toString();
            String existingUuid = mUuids.putIfAbsent(handle, newUuid);
            if (existingUuid != null) return existingUuid;
@@ -121,6 +121,24 @@ public class AvrcpCoverArtManager {
        }
    }

    /**
     * Validate an image handle meets the AVRCP and BIP specifications
     *
     * By the BIP specification that AVRCP uses, "Image handles are 7 character long strings
     * containing only the digits 0 to 9."
     *
     * @return True if the input string is a valid image handle
     */
    public static boolean isValidImageHandle(String handle) {
        if (handle == null || handle.length() != 7) return false;
        for (char c : handle.toCharArray()) {
            if (!Character.isDigit(c)) {
                return false;
            }
        }
        return true;
    }

    public AvrcpCoverArtManager(AvrcpControllerService service, Callback callback) {
        mService = service;
        mCoverArtStorage = new AvrcpCoverArtStorage(mService);
@@ -225,7 +243,7 @@ public class AvrcpCoverArtManager {
     */
    public String getUuidForHandle(BluetoothDevice device, String handle) {
        AvrcpBipSession session = getSession(device);
        if (session == null || handle == null) return null;
        if (session == null || !isValidImageHandle(handle)) return null;
        return session.getHandleUuid(handle);
    }

+7 −3
Original line number Diff line number Diff line
@@ -232,6 +232,10 @@ public class AvrcpItem {
        return new MediaItem(descriptionBuilder.build(), flags);
    }

    private static String parseImageHandle(String handle) {
        return AvrcpCoverArtManager.isValidImageHandle(handle) ? handle : null;
    }

    @Override
    public String toString() {
        return "AvrcpItem{mUuid=" + mUuid + ", mUid=" + mUid + ", mItemType=" + mItemType
@@ -338,7 +342,7 @@ public class AvrcpItem {
                        }
                        break;
                    case MEDIA_ATTRIBUTE_COVER_ART_HANDLE:
                        mAvrcpItem.mCoverArtHandle = attrMap[i];
                        mAvrcpItem.mCoverArtHandle = parseImageHandle(attrMap[i]);
                        break;
                }
            }
@@ -515,13 +519,13 @@ public class AvrcpItem {
        }

        /**
         * Set the cover art handle for the AvrcpItem you are building
         * Set the cover art handle for the AvrcpItem you are building.
         *
         * @param coverArtHandle The cover art image handle provided by a remote device
         * @return This object, so you can continue building
         */
        public Builder setCoverArtHandle(String coverArtHandle) {
            mAvrcpItem.mCoverArtHandle = coverArtHandle;
            mAvrcpItem.mCoverArtHandle = parseImageHandle(coverArtHandle);
            return this;
        }

+213 −5
Original line number Diff line number Diff line
@@ -72,7 +72,7 @@ public final class AvrcpItemTest {
        long totalTracks = 12;
        String genre = "Viking Metal";
        long playingTime = 301;
        String artHandle = "abc123";
        String artHandle = "0000001";
        Uri uri = Uri.parse("content://somewhere");
        Uri uri2 = Uri.parse("content://somewhereelse");

@@ -119,7 +119,7 @@ public final class AvrcpItemTest {
        String totalTracks = "12";
        String genre = "Viking Metal";
        String playingTime = "301";
        String artHandle = "abc123";
        String artHandle = "0000001";

        int[] attrIds = new int[]{
            MEDIA_ATTRIBUTE_TITLE,
@@ -171,7 +171,7 @@ public final class AvrcpItemTest {
        String totalTracks = "12";
        String genre = "Viking Metal";
        String playingTime = "301";
        String artHandle = "abc123";
        String artHandle = "0000001";

        int[] attrIds = new int[]{
            MEDIA_ATTRIBUTE_TITLE,
@@ -222,6 +222,214 @@ public final class AvrcpItemTest {
        Assert.assertEquals(null, item.getCoverArtLocation());
    }

    @Test
    public void buildAvrcpItemFromAvrcpAttributes_imageHandleTooShort() {
        String title = "Aaaaargh";
        String artist = "Bluetooth";
        String album = "The Best Protocol";
        String trackNumber = "1";
        String totalTracks = "12";
        String genre = "Viking Metal";
        String playingTime = "301";
        String artHandle = "000001"; // length 6 and not 7

        int[] attrIds = new int[]{
            MEDIA_ATTRIBUTE_TITLE,
            MEDIA_ATTRIBUTE_ARTIST_NAME,
            MEDIA_ATTRIBUTE_ALBUM_NAME,
            MEDIA_ATTRIBUTE_TRACK_NUMBER,
            MEDIA_ATTRIBUTE_TOTAL_TRACK_NUMBER,
            MEDIA_ATTRIBUTE_GENRE,
            MEDIA_ATTRIBUTE_PLAYING_TIME,
            MEDIA_ATTRIBUTE_COVER_ART_HANDLE
        };

        String[] attrMap = new String[]{
            title,
            artist,
            album,
            trackNumber,
            totalTracks,
            genre,
            playingTime,
            artHandle
        };

        AvrcpItem.Builder builder = new AvrcpItem.Builder();
        builder.fromAvrcpAttributeArray(attrIds, attrMap);
        AvrcpItem item = builder.build();

        Assert.assertEquals(null, item.getDevice());
        Assert.assertEquals(false, item.isPlayable());
        Assert.assertEquals(false, item.isBrowsable());
        Assert.assertEquals(0, item.getUid());
        Assert.assertEquals(null, item.getUuid());
        Assert.assertEquals(null, item.getDisplayableName());
        Assert.assertEquals(title, item.getTitle());
        Assert.assertEquals(artist, item.getArtistName());
        Assert.assertEquals(album, item.getAlbumName());
        Assert.assertEquals(1, item.getTrackNumber());
        Assert.assertEquals(12, item.getTotalNumberOfTracks());
        Assert.assertEquals(null, item.getCoverArtHandle());
        Assert.assertEquals(null, item.getCoverArtLocation());
    }

    @Test
    public void buildAvrcpItemFromAvrcpAttributes_imageHandleEmpty() {
        String title = "Aaaaargh";
        String artist = "Bluetooth";
        String album = "The Best Protocol";
        String trackNumber = "1";
        String totalTracks = "12";
        String genre = "Viking Metal";
        String playingTime = "301";
        String artHandle = "";

        int[] attrIds = new int[]{
            MEDIA_ATTRIBUTE_TITLE,
            MEDIA_ATTRIBUTE_ARTIST_NAME,
            MEDIA_ATTRIBUTE_ALBUM_NAME,
            MEDIA_ATTRIBUTE_TRACK_NUMBER,
            MEDIA_ATTRIBUTE_TOTAL_TRACK_NUMBER,
            MEDIA_ATTRIBUTE_GENRE,
            MEDIA_ATTRIBUTE_PLAYING_TIME,
            MEDIA_ATTRIBUTE_COVER_ART_HANDLE
        };

        String[] attrMap = new String[]{
            title,
            artist,
            album,
            trackNumber,
            totalTracks,
            genre,
            playingTime,
            artHandle
        };

        AvrcpItem.Builder builder = new AvrcpItem.Builder();
        builder.fromAvrcpAttributeArray(attrIds, attrMap);
        AvrcpItem item = builder.build();

        Assert.assertEquals(null, item.getDevice());
        Assert.assertEquals(false, item.isPlayable());
        Assert.assertEquals(false, item.isBrowsable());
        Assert.assertEquals(0, item.getUid());
        Assert.assertEquals(null, item.getUuid());
        Assert.assertEquals(null, item.getDisplayableName());
        Assert.assertEquals(title, item.getTitle());
        Assert.assertEquals(artist, item.getArtistName());
        Assert.assertEquals(album, item.getAlbumName());
        Assert.assertEquals(1, item.getTrackNumber());
        Assert.assertEquals(12, item.getTotalNumberOfTracks());
        Assert.assertEquals(null, item.getCoverArtHandle());
        Assert.assertEquals(null, item.getCoverArtLocation());
    }

    @Test
    public void buildAvrcpItemFromAvrcpAttributes_imageHandleNull() {
        String title = "Aaaaargh";
        String artist = "Bluetooth";
        String album = "The Best Protocol";
        String trackNumber = "1";
        String totalTracks = "12";
        String genre = "Viking Metal";
        String playingTime = "301";
        String artHandle = null;

        int[] attrIds = new int[]{
            MEDIA_ATTRIBUTE_TITLE,
            MEDIA_ATTRIBUTE_ARTIST_NAME,
            MEDIA_ATTRIBUTE_ALBUM_NAME,
            MEDIA_ATTRIBUTE_TRACK_NUMBER,
            MEDIA_ATTRIBUTE_TOTAL_TRACK_NUMBER,
            MEDIA_ATTRIBUTE_GENRE,
            MEDIA_ATTRIBUTE_PLAYING_TIME,
            MEDIA_ATTRIBUTE_COVER_ART_HANDLE
        };

        String[] attrMap = new String[]{
            title,
            artist,
            album,
            trackNumber,
            totalTracks,
            genre,
            playingTime,
            artHandle
        };

        AvrcpItem.Builder builder = new AvrcpItem.Builder();
        builder.fromAvrcpAttributeArray(attrIds, attrMap);
        AvrcpItem item = builder.build();

        Assert.assertEquals(null, item.getDevice());
        Assert.assertEquals(false, item.isPlayable());
        Assert.assertEquals(false, item.isBrowsable());
        Assert.assertEquals(0, item.getUid());
        Assert.assertEquals(null, item.getUuid());
        Assert.assertEquals(null, item.getDisplayableName());
        Assert.assertEquals(title, item.getTitle());
        Assert.assertEquals(artist, item.getArtistName());
        Assert.assertEquals(album, item.getAlbumName());
        Assert.assertEquals(1, item.getTrackNumber());
        Assert.assertEquals(12, item.getTotalNumberOfTracks());
        Assert.assertEquals(null, item.getCoverArtHandle());
        Assert.assertEquals(null, item.getCoverArtLocation());
    }

    @Test
    public void buildAvrcpItemFromAvrcpAttributes_imageHandleNotDigits() {
        String title = "Aaaaargh";
        String artist = "Bluetooth";
        String album = "The Best Protocol";
        String trackNumber = "1";
        String totalTracks = "12";
        String genre = "Viking Metal";
        String playingTime = "301";
        String artHandle = "123abcd";

        int[] attrIds = new int[]{
            MEDIA_ATTRIBUTE_TITLE,
            MEDIA_ATTRIBUTE_ARTIST_NAME,
            MEDIA_ATTRIBUTE_ALBUM_NAME,
            MEDIA_ATTRIBUTE_TRACK_NUMBER,
            MEDIA_ATTRIBUTE_TOTAL_TRACK_NUMBER,
            MEDIA_ATTRIBUTE_GENRE,
            MEDIA_ATTRIBUTE_PLAYING_TIME,
            MEDIA_ATTRIBUTE_COVER_ART_HANDLE
        };

        String[] attrMap = new String[]{
            title,
            artist,
            album,
            trackNumber,
            totalTracks,
            genre,
            playingTime,
            artHandle
        };

        AvrcpItem.Builder builder = new AvrcpItem.Builder();
        builder.fromAvrcpAttributeArray(attrIds, attrMap);
        AvrcpItem item = builder.build();

        Assert.assertEquals(null, item.getDevice());
        Assert.assertEquals(false, item.isPlayable());
        Assert.assertEquals(false, item.isBrowsable());
        Assert.assertEquals(0, item.getUid());
        Assert.assertEquals(null, item.getUuid());
        Assert.assertEquals(null, item.getDisplayableName());
        Assert.assertEquals(title, item.getTitle());
        Assert.assertEquals(artist, item.getArtistName());
        Assert.assertEquals(album, item.getAlbumName());
        Assert.assertEquals(1, item.getTrackNumber());
        Assert.assertEquals(12, item.getTotalNumberOfTracks());
        Assert.assertEquals(null, item.getCoverArtHandle());
        Assert.assertEquals(null, item.getCoverArtLocation());
    }

    @Test
    public void updateCoverArtLocation() {
        Uri uri = Uri.parse("content://somewhere");
@@ -246,7 +454,7 @@ public final class AvrcpItemTest {
        long totalTracks = 12;
        String genre = "Viking Metal";
        long playingTime = 301;
        String artHandle = "abc123";
        String artHandle = "0000001";
        Uri uri = Uri.parse("content://somewhere");

        AvrcpItem.Builder builder = new AvrcpItem.Builder();
@@ -303,7 +511,7 @@ public final class AvrcpItemTest {
        long totalTracks = 12;
        String genre = "Viking Metal";
        long playingTime = 301;
        String artHandle = "abc123";
        String artHandle = "0000001";
        Uri uri = Uri.parse("content://somewhere");
        int type = AvrcpItem.FOLDER_TITLES;