1 /* 2 * Copyright (C) 2023 The Android Open Source Project 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.android.tradefed.util.image; 17 18 import com.android.annotations.VisibleForTesting; 19 20 import com.google.common.cache.CacheBuilder; 21 import com.google.common.cache.CacheLoader; 22 import com.google.common.cache.LoadingCache; 23 24 import java.io.IOException; 25 import java.util.concurrent.TimeUnit; 26 27 /** 28 * For some of the incremental device update, we need the baseline files to compute diffs. This 29 * utility helps keeping track of them. 30 */ 31 public class DeviceImageTracker { 32 33 private static DeviceImageTracker sDefaultInstance; 34 35 private final LoadingCache<String, FileCacheTracker> mImageCache; 36 37 /** Track information of the device image cached and its metadata */ 38 public class FileCacheTracker { 39 public String buildId; 40 public String branch; 41 public String flavor; 42 FileCacheTracker( String buildId, String branch, String flavor)43 FileCacheTracker( 44 String buildId, 45 String branch, 46 String flavor) { 47 this.buildId = buildId; 48 this.branch = branch; 49 this.flavor = flavor; 50 } 51 } 52 getDefaultCache()53 public static DeviceImageTracker getDefaultCache() { 54 if (sDefaultInstance == null) { 55 sDefaultInstance = new DeviceImageTracker(); 56 } 57 return sDefaultInstance; 58 } 59 60 @VisibleForTesting DeviceImageTracker()61 protected DeviceImageTracker() { 62 mImageCache = 63 CacheBuilder.newBuilder() 64 .maximumSize(20) 65 .expireAfterAccess(1, TimeUnit.DAYS) 66 .build( 67 new CacheLoader<String, FileCacheTracker>() { 68 @Override 69 public FileCacheTracker load(String key) throws IOException { 70 // We manually seed and manage the cache 71 // no need to load. 72 return null; 73 } 74 }); 75 Runtime.getRuntime() 76 .addShutdownHook( 77 new Thread() { 78 @Override 79 public void run() { 80 cleanUp(); 81 } 82 }); 83 } 84 85 /** 86 * Tracks a given device image to the device serial that was flashed with it 87 * 88 * @param serial The device that was flashed with the image. 89 * @param buildId The build id associated with the device image. 90 * @param branch The branch associated with the device image. 91 * @param flavor The build flavor associated with the device image. 92 */ trackUpdatedDeviceImage( String serial, String buildId, String branch, String flavor)93 public void trackUpdatedDeviceImage( 94 String serial, 95 String buildId, 96 String branch, 97 String flavor) { 98 mImageCache.put( 99 serial, 100 new FileCacheTracker( 101 buildId, 102 branch, 103 flavor)); 104 } 105 invalidateTracking(String serial)106 public void invalidateTracking(String serial) { 107 mImageCache.invalidate(serial); 108 } 109 110 @VisibleForTesting cleanUp()111 protected void cleanUp() { 112 mImageCache.invalidateAll(); 113 } 114 115 /** Returns the device image that was tracked for the device. Null if none was tracked. */ getBaselineDeviceImage(String serial)116 public FileCacheTracker getBaselineDeviceImage(String serial) { 117 return mImageCache.getIfPresent(serial); 118 } 119 } 120