1 /* 2 * Copyright 2022 Google LLC 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.libraries.mobiledatadownload.internal.util; 17 18 import static com.google.android.libraries.mobiledatadownload.internal.MddConstants.SPLIT_CHAR; 19 20 import android.content.Context; 21 import com.google.android.libraries.mobiledatadownload.SilentFeedback; 22 import com.google.android.libraries.mobiledatadownload.internal.Migrations; 23 import com.google.common.base.Splitter; 24 import com.google.mobiledatadownload.TransformProto.Transforms; 25 import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal.AllowedReaders; 26 import com.google.mobiledatadownload.internal.MetadataProto.NewFileKey; 27 import com.google.protobuf.InvalidProtocolBufferException; 28 import java.util.List; 29 30 /** Utilities needed by multiple implementations of {@link SharedFilesMetadata}. */ 31 public final class SharedFilesMetadataUtil { 32 33 private static final String TAG = "SharedFilesMetadataUtil"; 34 35 // Stores the mapping from FileKey:SharedFile. 36 public static final String MDD_SHARED_FILES = "gms_icing_mdd_shared_files"; 37 38 /** File key Deserialization exception. */ 39 public static class FileKeyDeserializationException extends Exception { FileKeyDeserializationException(String msg)40 FileKeyDeserializationException(String msg) { 41 super(msg); 42 } 43 FileKeyDeserializationException(String msg, Throwable cause)44 FileKeyDeserializationException(String msg, Throwable cause) { 45 super(msg, cause); 46 } 47 } 48 getSerializedFileKey( NewFileKey newFileKey, Context context, SilentFeedback silentFeedback)49 public static String getSerializedFileKey( 50 NewFileKey newFileKey, Context context, SilentFeedback silentFeedback) { 51 switch (Migrations.getCurrentVersion(context, silentFeedback)) { 52 case NEW_FILE_KEY: 53 return serializeNewFileKey(newFileKey); 54 case ADD_DOWNLOAD_TRANSFORM: 55 return serializeNewFileKeyWithDownloadTransform(newFileKey); 56 case USE_CHECKSUM_ONLY: 57 return serializeNewFileKeyWithChecksumOnly(newFileKey); 58 } 59 return serializeNewFileKey(newFileKey); 60 } 61 serializeNewFileKey(NewFileKey newFileKey)62 public static String serializeNewFileKey(NewFileKey newFileKey) { 63 return new StringBuilder(newFileKey.getUrlToDownload()) 64 .append(SPLIT_CHAR) 65 .append(newFileKey.getByteSize()) 66 .append(SPLIT_CHAR) 67 .append(newFileKey.getChecksum()) 68 .append(SPLIT_CHAR) 69 .append(newFileKey.getAllowedReaders().getNumber()) 70 .toString(); 71 } 72 serializeNewFileKeyWithDownloadTransform(NewFileKey newFileKey)73 public static String serializeNewFileKeyWithDownloadTransform(NewFileKey newFileKey) { 74 return new StringBuilder(newFileKey.getUrlToDownload()) 75 .append(SPLIT_CHAR) 76 .append(newFileKey.getByteSize()) 77 .append(SPLIT_CHAR) 78 .append(newFileKey.getChecksum()) 79 .append(SPLIT_CHAR) 80 .append(newFileKey.getAllowedReaders().getNumber()) 81 .append(SPLIT_CHAR) 82 .append( 83 newFileKey.hasDownloadTransforms() 84 ? SharedPreferencesUtil.serializeProto(newFileKey.getDownloadTransforms()) 85 : "") 86 .toString(); 87 } 88 serializeNewFileKeyWithChecksumOnly(NewFileKey newFileKey)89 public static String serializeNewFileKeyWithChecksumOnly(NewFileKey newFileKey) { 90 return new StringBuilder(newFileKey.getChecksum()) 91 .append(SPLIT_CHAR) 92 .append(newFileKey.getAllowedReaders().getNumber()) 93 .toString(); 94 } 95 96 // incompatible argument for parameter value of setAllowedReaders. 97 @SuppressWarnings("nullness:argument.type.incompatible") deserializeNewFileKey( String serializedFileKey, Context context, SilentFeedback silentFeedback)98 public static NewFileKey deserializeNewFileKey( 99 String serializedFileKey, Context context, SilentFeedback silentFeedback) 100 throws FileKeyDeserializationException { 101 List<String> fileKeyComponents = Splitter.on(SPLIT_CHAR).splitToList(serializedFileKey); 102 NewFileKey.Builder newFileKey; 103 104 switch (Migrations.getCurrentVersion(context, silentFeedback)) { 105 case ADD_DOWNLOAD_TRANSFORM: 106 if (fileKeyComponents.size() != 5) { 107 throw new FileKeyDeserializationException( 108 "Bad-format" + " serializedFileKey" + " = " + serializedFileKey); 109 } 110 newFileKey = 111 NewFileKey.newBuilder() 112 .setUrlToDownload(fileKeyComponents.get(0)) 113 .setByteSize(Integer.parseInt(fileKeyComponents.get(1))) 114 .setChecksum(fileKeyComponents.get(2)) 115 .setAllowedReaders( 116 AllowedReaders.forNumber(Integer.parseInt(fileKeyComponents.get(3)))); 117 if (fileKeyComponents.get(4) != null && !fileKeyComponents.get(4).isEmpty()) { 118 try { 119 newFileKey.setDownloadTransforms( 120 SharedPreferencesUtil.parseLiteFromEncodedString( 121 fileKeyComponents.get(4), Transforms.parser())); 122 } catch (InvalidProtocolBufferException e) { 123 throw new FileKeyDeserializationException( 124 "Failed to deserialize key:" + serializedFileKey, e); 125 } 126 } 127 break; 128 case USE_CHECKSUM_ONLY: 129 if (fileKeyComponents.size() != 2) { 130 throw new FileKeyDeserializationException( 131 "Bad-format" + " serializedFileKey" + " = s" + serializedFileKey); 132 } 133 newFileKey = 134 NewFileKey.newBuilder() 135 .setChecksum(fileKeyComponents.get(0)) 136 .setAllowedReaders( 137 AllowedReaders.forNumber(Integer.parseInt(fileKeyComponents.get(1)))); 138 break; 139 default: // Fall through 140 if (fileKeyComponents.size() != 4) { 141 throw new FileKeyDeserializationException( 142 "Bad-format" + " serializedFileKey" + " = " + serializedFileKey); 143 } 144 newFileKey = 145 NewFileKey.newBuilder() 146 .setUrlToDownload(fileKeyComponents.get(0)) 147 .setByteSize(Integer.parseInt(fileKeyComponents.get(1))) 148 .setChecksum(fileKeyComponents.get(2)) 149 .setAllowedReaders( 150 AllowedReaders.forNumber(Integer.parseInt(fileKeyComponents.get(3)))); 151 } 152 return newFileKey.build(); 153 } 154 SharedFilesMetadataUtil()155 private SharedFilesMetadataUtil() {} 156 } 157