/* * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.android.libraries.mobiledatadownload.internal.util; import android.content.Context; import android.util.Base64; import com.google.android.libraries.mobiledatadownload.internal.logging.LogUtil; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal; import com.google.mobiledatadownload.internal.MetadataProto.GroupKey; import com.google.protobuf.InvalidProtocolBufferException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; /** Stores and provides access to file group metadata using SharedPreferences. */ public final class FileGroupsMetadataUtil { private static final String TAG = "FileGroupsMetadataUtil"; // Name of file groups SharedPreferences. public static final String MDD_FILE_GROUPS = "gms_icing_mdd_groups"; // Name of file groups group key properties SharedPreferences. public static final String MDD_FILE_GROUP_KEY_PROPERTIES = "gms_icing_mdd_group_key_properties"; // TODO(b/144033163): Migrate the Garbage Collector File to PDS. public static final String MDD_GARBAGE_COLLECTION_FILE = "gms_icing_mdd_garbage_file"; /** Group key Deserialization exception. */ public static class GroupKeyDeserializationException extends Exception { GroupKeyDeserializationException(String msg, Throwable cause) { super(msg, cause); } } // TODO(b/144033163): Migrate the Garbage Collector File to PDS. public static List getAllStaleGroups(File garbageCollectorFile) { FileInputStream inputStream; try { inputStream = new FileInputStream(garbageCollectorFile); } catch (FileNotFoundException e) { LogUtil.d("File %s not found while reading.", garbageCollectorFile.getAbsolutePath()); return ImmutableList.of(); } ByteBuffer buf; try { buf = ByteBuffer.allocate((int) garbageCollectorFile.length()); } catch (IllegalArgumentException e) { LogUtil.e(e, "%s: Exception while reading from stale groups into buffer.", TAG); return ImmutableList.of(); } List fileGroups = null; try { inputStream.getChannel().read(buf); // Rewind so that we can read from the start of the buffer. buf.rewind(); // tail_crc == false, means that each message has its own crc fileGroups = ProtoLiteUtil.readFromBuffer( buf, DataFileGroupInternal.class, DataFileGroupInternal.parser(), false /*tail crc*/); inputStream.close(); } catch (IOException e) { LogUtil.e(e, "%s: IOException occurred while reading file groups.", TAG); } return fileGroups == null ? ImmutableList.of() : fileGroups; } public static File getGarbageCollectorFile(Context context, Optional instanceId) { String fileName = instanceId != null && instanceId.isPresent() ? MDD_GARBAGE_COLLECTION_FILE + instanceId.get() : MDD_GARBAGE_COLLECTION_FILE; return new File(context.getFilesDir(), fileName); } // TODO(b/129702287): Move away from proto based serialization. public static String getSerializedGroupKey(GroupKey groupKey) { byte[] byteValue = groupKey.toByteArray(); return Base64.encodeToString(byteValue, Base64.NO_PADDING | Base64.NO_WRAP); } /** * Converts a string representing a serialized GroupKey into a GroupKey. * * @return groupKey if able to parse string key properly. * @throws GroupKeyDeserializationException when unable to parse string key */ // TODO(b/129702287): Move away from proto based deserialization. public static GroupKey deserializeGroupKey(String serializedGroupKey) throws GroupKeyDeserializationException { try { return SharedPreferencesUtil.parseLiteFromEncodedString( serializedGroupKey, GroupKey.parser()); } catch (NullPointerException | InvalidProtocolBufferException e) { throw new GroupKeyDeserializationException( "Failed to deserialize key:" + serializedGroupKey, e); } } private FileGroupsMetadataUtil() {} }