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 17 package com.android.adservices.service.common; 18 19 import android.annotation.Nullable; 20 21 import com.android.adservices.LoggerFactory; 22 import com.android.adservices.data.common.UserProfileIdDao; 23 import com.android.adservices.data.common.UserProfileIdDaoSharedPreferencesImpl; 24 import com.android.adservices.shared.util.Clock; 25 import com.android.internal.annotations.GuardedBy; 26 import com.android.internal.annotations.VisibleForTesting; 27 28 import java.util.Objects; 29 import java.util.UUID; 30 31 /** Manager of user profile id. */ 32 public final class UserProfileIdManager { 33 private static final LoggerFactory.Logger LOGGER = LoggerFactory.getFledgeLogger(); 34 35 private static final Object SINGLETON_LOCK = new Object(); 36 37 private final UserProfileIdDao mUserProfileIdDao; 38 private final Clock mClock; 39 40 @GuardedBy("SINGLETON_LOCK") 41 private static volatile UserProfileIdManager sUserProfileIdManager; 42 43 @VisibleForTesting static final long MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24; 44 45 @VisibleForTesting UserProfileIdManager(final UserProfileIdDao userProfileIdDao, Clock clock)46 public UserProfileIdManager(final UserProfileIdDao userProfileIdDao, Clock clock) { 47 Objects.requireNonNull(userProfileIdDao); 48 Objects.requireNonNull(clock); 49 50 mUserProfileIdDao = userProfileIdDao; 51 mClock = clock; 52 } 53 54 /** Returns the singleton instance of the {@link UserProfileIdManager} */ getInstance()55 public static UserProfileIdManager getInstance() { 56 synchronized (SINGLETON_LOCK) { 57 if (sUserProfileIdManager == null) { 58 sUserProfileIdManager = 59 new UserProfileIdManager( 60 UserProfileIdDaoSharedPreferencesImpl.getInstance(), 61 Clock.getInstance()); 62 } 63 return sUserProfileIdManager; 64 } 65 } 66 67 /** 68 * Returns the user profile ID. 69 * 70 * <ol> 71 * <li>If user profile ID does not exist, create and persist a new ID; 72 * <li>Return the id in the storage. 73 * </ol> 74 */ 75 @Nullable getOrCreateId()76 public UUID getOrCreateId() { 77 UUID id = mUserProfileIdDao.getUserProfileId(); 78 79 if (id != null) { 80 return id; 81 } 82 83 LOGGER.v("User profile ID is not present, generating a new ID."); 84 id = UUID.randomUUID(); 85 mUserProfileIdDao.setUserProfileId(id); 86 return id; 87 } 88 89 /** 90 * Clear the user profile id storage in case of consent revoke. 91 * 92 * <p>We only clear the ID if it's persisted for more than 24 hours to prevent abuse vector 93 * whereby a malicious user regenerates consentIds by toggling consent on and off 94 */ deleteId()95 public void deleteId() { 96 long lastPersistedTimestamp = mUserProfileIdDao.getTimestamp(); 97 if (mClock.currentTimeMillis() >= lastPersistedTimestamp + MILLISECONDS_IN_DAY) { 98 mUserProfileIdDao.deleteStorage(); 99 } 100 } 101 } 102