Loading services/appfunctions/java/com/android/server/appfunctions/AppFunctionAccessHistory.java 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * 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.android.server.appfunctions; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.appfunctions.ExecuteAppFunctionAidlRequest; import android.database.Cursor; /** Manages the AppFunction Access Histories. */ public interface AppFunctionAccessHistory extends AutoCloseable { /** Queries the AppFunction access histories. */ @Nullable Cursor queryAppFunctionAccessHistory( @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder); /** * Inserts an AppFunction access history. * * @return The row id or -1 if fail to insert. */ @WorkerThread long insertAppFunctionAccessHistory( @NonNull ExecuteAppFunctionAidlRequest aidlRequest, long duration); /** * Deletes expired AppFunction access histories. * * @param retentionMillis The maximum age of records to keep, in milliseconds. Records older * than this will be deleted. */ @WorkerThread void deleteExpiredAppFunctionAccessHistories(long retentionMillis); /** Deletes AppFunction access histories that are associated with the given packageName. */ @WorkerThread void deleteAppFunctionAccessHistories(@NonNull String packageName); /** Deletes all AppFunction access histories. */ @WorkerThread void deleteAll(); } services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java +6 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.appfunctions; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; Loading @@ -42,6 +43,11 @@ public final class AppFunctionExecutors { Executors.newSingleThreadExecutor( new NamedThreadFactory("AppFunctionsLoggingExecutors")); /** Executor for scheduled tasks. */ public static final ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor( new NamedThreadFactory("AppFunctionScheduledExecutors")); static { THREAD_POOL_EXECUTOR.allowCoreThreadTimeOut(true); } Loading services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java +36 −2 Original line number Diff line number Diff line Loading @@ -16,29 +16,63 @@ package com.android.server.appfunctions; import static com.android.server.appfunctions.AppFunctionExecutors.SCHEDULED_EXECUTOR_SERVICE; import android.annotation.NonNull; import android.app.UriGrantsManager; import android.app.appfunctions.AppFunctionAccessServiceInterface; import android.app.appfunctions.AppFunctionManagerConfiguration; import android.content.Context; import android.content.pm.PackageManagerInternal; import android.os.Environment; import android.os.UserHandle; import com.android.internal.os.BackgroundThread; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.uri.UriGrantsManagerInternal; import java.io.File; import java.util.Objects; import java.util.function.Function; /** Service that manages app functions. */ public class AppFunctionManagerService extends SystemService { private static final String AGENT_ALLOWLIST_FILE_NAME = "agent_allowlist.txt"; private static final String APP_FUNCTIONS_DIR = "appfunctions"; private final AppFunctionManagerServiceImpl mServiceImpl; public AppFunctionManagerService(Context context) { super(context); mServiceImpl = new AppFunctionManagerServiceImpl( context, LocalServices.getService(PackageManagerInternal.class), context, LocalServices.getService(PackageManagerInternal.class), LocalServices.getService(AppFunctionAccessServiceInterface.class), UriGrantsManager.getService(), LocalServices.getService(UriGrantsManagerInternal.class)); LocalServices.getService(UriGrantsManagerInternal.class), new AppFunctionsLoggerWrapper(context), new AppFunctionAgentAllowlistStorage( new File( new File( Environment.getDataSystemDirectory(), APP_FUNCTIONS_DIR), AGENT_ALLOWLIST_FILE_NAME)), new MultiUserAppFunctionAccessHistory( new ServiceConfigImpl(), SCHEDULED_EXECUTOR_SERVICE, /* userAccessHistoryFactory */ new Function<>() { @Override @NonNull public AppFunctionAccessHistory apply( @NonNull UserHandle userHandle) { Objects.requireNonNull(userHandle); return new AppFunctionSQLiteAccessHistory( context.createContextAsUser( userHandle, /* flags= */ 0)); } }), BackgroundThread.getExecutor()); } @Override Loading services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +55 −28 Original line number Diff line number Diff line Loading @@ -72,7 +72,6 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; import android.os.CancellationSignal; import android.os.Environment; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.OutcomeReceiver; Loading @@ -81,6 +80,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.permission.flags.Flags; Loading @@ -95,14 +95,12 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageMonitor; import com.android.internal.infra.AndroidFuture; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.server.FgThread; import com.android.server.SystemService; import com.android.server.SystemService.TargetUser; import com.android.server.uri.UriGrantsManagerInternal; import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; Loading @@ -120,8 +118,6 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { private static final String ALLOWLISTED_APP_FUNCTIONS_AGENTS = "allowlisted_app_functions_agents"; private static final String NAMESPACE_MACHINE_LEARNING = "machine_learning"; private static final String AGENT_ALLOWLIST_FILE_NAME = "agent_allowlist.txt"; private static final String APP_FUNCTIONS_DIR = "appfunctions"; private static final String SHELL_PKG = "com.android.shell"; private static final Uri ADDITIONAL_AGENTS_URI = Settings.Secure.getUriFor( Loading @@ -148,6 +144,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { private final DeviceSettingHelper mDeviceSettingHelper; private final MultiUserAppFunctionAccessHistory mMultiUserAppFunctionAccessHistory; private final Object mAgentAllowlistLock = new Object(); // Any agents hardcoded by the system Loading Loading @@ -179,7 +177,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { } }; private final Executor mWorkerExecutor; private final Executor mBackgroundExecutor; private final AppFunctionAgentAllowlistStorage mAgentAllowlistStorage; Loading @@ -188,7 +186,11 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { @NonNull PackageManagerInternal packageManagerInternal, @NonNull AppFunctionAccessServiceInterface appFunctionAccessServiceInterface, @NonNull IUriGrantsManager uriGrantsManager, @NonNull UriGrantsManagerInternal uriGrantsManagerInternal) { @NonNull UriGrantsManagerInternal uriGrantsManagerInternal, @NonNull AppFunctionsLoggerWrapper loggerWrapper, @NonNull AppFunctionAgentAllowlistStorage agentAllowlistStorage, @NonNull MultiUserAppFunctionAccessHistory multiUserAppFunctionAccessHistory, @NonNull Executor backgroundExecutor) { this( context, new RemoteServiceCallerImpl<>( Loading @@ -199,21 +201,18 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { Objects.requireNonNull(context.getSystemService(UserManager.class))), new ServiceHelperImpl(context), new ServiceConfigImpl(), new AppFunctionsLoggerWrapper(context), loggerWrapper, packageManagerInternal, appFunctionAccessServiceInterface, uriGrantsManager, uriGrantsManagerInternal, new DeviceSettingHelperImpl(context), new AppFunctionAgentAllowlistStorage( new File( new File(Environment.getDataSystemDirectory(), APP_FUNCTIONS_DIR), AGENT_ALLOWLIST_FILE_NAME)), THREAD_POOL_EXECUTOR); agentAllowlistStorage, multiUserAppFunctionAccessHistory, backgroundExecutor); } @VisibleForTesting AppFunctionManagerServiceImpl( private AppFunctionManagerServiceImpl( Context context, RemoteServiceCaller<IAppFunctionService> remoteServiceCaller, CallerValidator callerValidator, Loading @@ -226,21 +225,26 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { UriGrantsManagerInternal uriGrantsManagerInternal, DeviceSettingHelper deviceSettingHelper, AppFunctionAgentAllowlistStorage agentAllowlistStorage, Executor workerExecutor) { MultiUserAppFunctionAccessHistory multiUserAppFunctionAccessHistory, Executor backgroundExecutor) { mContext = Objects.requireNonNull(context); mRemoteServiceCaller = Objects.requireNonNull(remoteServiceCaller); mCallerValidator = Objects.requireNonNull(callerValidator); mInternalServiceHelper = Objects.requireNonNull(appFunctionInternalServiceHelper); mServiceConfig = serviceConfig; mLoggerWrapper = loggerWrapper; mServiceConfig = Objects.requireNonNull(serviceConfig); mLoggerWrapper = Objects.requireNonNull(loggerWrapper); mPackageManagerInternal = Objects.requireNonNull(packageManagerInternal); mAppFunctionAccessService = Objects.requireNonNull(appFunctionAccessServiceInterface); mUriGrantsManager = Objects.requireNonNull(uriGrantsManager); mUriGrantsManagerInternal = Objects.requireNonNull(uriGrantsManagerInternal); mPermissionOwner = mUriGrantsManagerInternal.newUriPermissionOwner("appfunctions"); mDeviceSettingHelper = deviceSettingHelper; mPermissionOwner = Objects.requireNonNull( mUriGrantsManagerInternal.newUriPermissionOwner("appfunctions")); mDeviceSettingHelper = Objects.requireNonNull(deviceSettingHelper); mAgentAllowlistStorage = Objects.requireNonNull(agentAllowlistStorage); mWorkerExecutor = Objects.requireNonNull(workerExecutor); mMultiUserAppFunctionAccessHistory = Objects.requireNonNull(multiUserAppFunctionAccessHistory); mBackgroundExecutor = Objects.requireNonNull(backgroundExecutor); } /** Called when the user is unlocked. */ Loading @@ -251,6 +255,9 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { PackageMonitor pkgMonitorForUser = AppFunctionPackageMonitor.registerPackageMonitorForUser(mContext, user); mPackageMonitors.append(user.getUserIdentifier(), pkgMonitorForUser); if (accessCheckFlagsEnabled()) { mMultiUserAppFunctionAccessHistory.onUserUnlocked(user); } } /** Called when the user is stopping. */ Loading @@ -264,6 +271,9 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { mPackageMonitors.get(userIdentifier).unregister(); mPackageMonitors.delete(userIdentifier); } if (accessCheckFlagsEnabled()) { mMultiUserAppFunctionAccessHistory.onUserStopping(user); } } @Override Loading Loading @@ -305,23 +315,18 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { /** * Called during different phases of the system boot process. * * <p>This method is used to initialize AppFunctionManagerService components that depend on * other system services being ready. Specifically, it handles reading DeviceConfig properties * related to allowed agent package signatures and registers a listener for changes to these * properties. * * @param phase The current boot phase, as defined in {@link SystemService}. This method * specifically acts on {@link SystemService#PHASE_SYSTEM_SERVICES_READY}. */ public void onBootPhase(int phase) { if (!Flags.appFunctionAccessServiceEnabled()) return; if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { mWorkerExecutor.execute(() -> mBackgroundExecutor.execute(() -> updateAgentAllowlist(/* readFromDeviceConfig */ true, /* readFromSecureSetting= */ true)); DeviceConfig.addOnPropertiesChangedListener( NAMESPACE_MACHINE_LEARNING, BackgroundThread.getExecutor(), mBackgroundExecutor, mDeviceConfigListener); mContext.getContentResolver().registerContentObserver(ADDITIONAL_AGENTS_URI, false, mAdbAgentObserver); Loading Loading @@ -1093,6 +1098,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { long executionStartTimeMillis) { mLoggerWrapper.logAppFunctionSuccess( requestInternal, result, callingUid, executionStartTimeMillis); recordAppFunctionAccess(requestInternal, executionStartTimeMillis); } @Override Loading @@ -1103,6 +1109,27 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { error.getErrorCode(), callingUid, executionStartTimeMillis); recordAppFunctionAccess(requestInternal, executionStartTimeMillis); } }); } private void recordAppFunctionAccess( @NonNull ExecuteAppFunctionAidlRequest aidlRequest, long executionStartTimeMillis) { if (!accessCheckFlagsEnabled()) return; final long duration = SystemClock.elapsedRealtime() - executionStartTimeMillis; mBackgroundExecutor.execute( () -> { try { mMultiUserAppFunctionAccessHistory .asUser(aidlRequest.getUserHandle()) .insertAppFunctionAccessHistory(aidlRequest, duration); } catch (IllegalStateException e) { Slog.e( TAG, "Fail to insert new access history to user " + aidlRequest.getUserHandle().getIdentifier(), e); } }); } Loading services/appfunctions/java/com/android/server/appfunctions/AppFunctionAccessDatabaseHelper.java→services/appfunctions/java/com/android/server/appfunctions/AppFunctionSQLiteAccessHistory.java +8 −21 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.server.appfunctions; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.appfunctions.AppFunctionAttribution; import android.app.appfunctions.AppFunctionManager.AccessHistory; import android.app.appfunctions.ExecuteAppFunctionAidlRequest; Loading @@ -35,7 +34,8 @@ import android.util.Slog; import java.util.Objects; /** The database helper for managing AppFunction access histories. */ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { public final class AppFunctionSQLiteAccessHistory extends SQLiteOpenHelper implements AppFunctionAccessHistory { private static final class AccessHistoryTable { static final String DB_TABLE = "appfunction_access"; Loading Loading @@ -85,7 +85,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "AppFunctionDatabase"; AppFunctionAccessDatabaseHelper(@NonNull Context context) { AppFunctionSQLiteAccessHistory(@NonNull Context context) { super(context, DB_NAME, /* factory= */ null, DB_VERSION); } Loading @@ -102,7 +102,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {} /** Queries the AppFunction access histories. */ @Override @Nullable public Cursor queryAppFunctionAccessHistory( @Nullable String[] projection, Loading Loading @@ -134,12 +134,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { } } /** * Inserts an AppFunction access history to the given database. * * @return The row id or -1 if fail to insert. */ @WorkerThread @Override public long insertAppFunctionAccessHistory( @NonNull ExecuteAppFunctionAidlRequest aidlRequest, long duration) { Objects.requireNonNull(aidlRequest); Loading Loading @@ -193,13 +188,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { return values; } /** * Deletes expired AppFunction access histories from the database. * * @param retentionMillis The maximum age of records to keep, in milliseconds. Records older * than this will be deleted. */ @WorkerThread @Override public void deleteExpiredAppFunctionAccessHistories(long retentionMillis) { try { final SQLiteDatabase db = getWritableDatabase(); Loading @@ -212,8 +201,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { } } /** Deletes AppFunction access histories that are associated with the given packageName. */ @WorkerThread @Override public void deleteAppFunctionAccessHistories(@NonNull String packageName) { Objects.requireNonNull(packageName); Loading @@ -233,8 +221,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { } } /** Deletes all AppFunction access histories. */ @WorkerThread @Override public void deleteAll() { try { final SQLiteDatabase db = getWritableDatabase(); Loading Loading
services/appfunctions/java/com/android/server/appfunctions/AppFunctionAccessHistory.java 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * 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.android.server.appfunctions; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.appfunctions.ExecuteAppFunctionAidlRequest; import android.database.Cursor; /** Manages the AppFunction Access Histories. */ public interface AppFunctionAccessHistory extends AutoCloseable { /** Queries the AppFunction access histories. */ @Nullable Cursor queryAppFunctionAccessHistory( @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder); /** * Inserts an AppFunction access history. * * @return The row id or -1 if fail to insert. */ @WorkerThread long insertAppFunctionAccessHistory( @NonNull ExecuteAppFunctionAidlRequest aidlRequest, long duration); /** * Deletes expired AppFunction access histories. * * @param retentionMillis The maximum age of records to keep, in milliseconds. Records older * than this will be deleted. */ @WorkerThread void deleteExpiredAppFunctionAccessHistories(long retentionMillis); /** Deletes AppFunction access histories that are associated with the given packageName. */ @WorkerThread void deleteAppFunctionAccessHistories(@NonNull String packageName); /** Deletes all AppFunction access histories. */ @WorkerThread void deleteAll(); }
services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java +6 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.appfunctions; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; Loading @@ -42,6 +43,11 @@ public final class AppFunctionExecutors { Executors.newSingleThreadExecutor( new NamedThreadFactory("AppFunctionsLoggingExecutors")); /** Executor for scheduled tasks. */ public static final ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor( new NamedThreadFactory("AppFunctionScheduledExecutors")); static { THREAD_POOL_EXECUTOR.allowCoreThreadTimeOut(true); } Loading
services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java +36 −2 Original line number Diff line number Diff line Loading @@ -16,29 +16,63 @@ package com.android.server.appfunctions; import static com.android.server.appfunctions.AppFunctionExecutors.SCHEDULED_EXECUTOR_SERVICE; import android.annotation.NonNull; import android.app.UriGrantsManager; import android.app.appfunctions.AppFunctionAccessServiceInterface; import android.app.appfunctions.AppFunctionManagerConfiguration; import android.content.Context; import android.content.pm.PackageManagerInternal; import android.os.Environment; import android.os.UserHandle; import com.android.internal.os.BackgroundThread; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.uri.UriGrantsManagerInternal; import java.io.File; import java.util.Objects; import java.util.function.Function; /** Service that manages app functions. */ public class AppFunctionManagerService extends SystemService { private static final String AGENT_ALLOWLIST_FILE_NAME = "agent_allowlist.txt"; private static final String APP_FUNCTIONS_DIR = "appfunctions"; private final AppFunctionManagerServiceImpl mServiceImpl; public AppFunctionManagerService(Context context) { super(context); mServiceImpl = new AppFunctionManagerServiceImpl( context, LocalServices.getService(PackageManagerInternal.class), context, LocalServices.getService(PackageManagerInternal.class), LocalServices.getService(AppFunctionAccessServiceInterface.class), UriGrantsManager.getService(), LocalServices.getService(UriGrantsManagerInternal.class)); LocalServices.getService(UriGrantsManagerInternal.class), new AppFunctionsLoggerWrapper(context), new AppFunctionAgentAllowlistStorage( new File( new File( Environment.getDataSystemDirectory(), APP_FUNCTIONS_DIR), AGENT_ALLOWLIST_FILE_NAME)), new MultiUserAppFunctionAccessHistory( new ServiceConfigImpl(), SCHEDULED_EXECUTOR_SERVICE, /* userAccessHistoryFactory */ new Function<>() { @Override @NonNull public AppFunctionAccessHistory apply( @NonNull UserHandle userHandle) { Objects.requireNonNull(userHandle); return new AppFunctionSQLiteAccessHistory( context.createContextAsUser( userHandle, /* flags= */ 0)); } }), BackgroundThread.getExecutor()); } @Override Loading
services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +55 −28 Original line number Diff line number Diff line Loading @@ -72,7 +72,6 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; import android.os.CancellationSignal; import android.os.Environment; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.OutcomeReceiver; Loading @@ -81,6 +80,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.permission.flags.Flags; Loading @@ -95,14 +95,12 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageMonitor; import com.android.internal.infra.AndroidFuture; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.server.FgThread; import com.android.server.SystemService; import com.android.server.SystemService.TargetUser; import com.android.server.uri.UriGrantsManagerInternal; import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; Loading @@ -120,8 +118,6 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { private static final String ALLOWLISTED_APP_FUNCTIONS_AGENTS = "allowlisted_app_functions_agents"; private static final String NAMESPACE_MACHINE_LEARNING = "machine_learning"; private static final String AGENT_ALLOWLIST_FILE_NAME = "agent_allowlist.txt"; private static final String APP_FUNCTIONS_DIR = "appfunctions"; private static final String SHELL_PKG = "com.android.shell"; private static final Uri ADDITIONAL_AGENTS_URI = Settings.Secure.getUriFor( Loading @@ -148,6 +144,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { private final DeviceSettingHelper mDeviceSettingHelper; private final MultiUserAppFunctionAccessHistory mMultiUserAppFunctionAccessHistory; private final Object mAgentAllowlistLock = new Object(); // Any agents hardcoded by the system Loading Loading @@ -179,7 +177,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { } }; private final Executor mWorkerExecutor; private final Executor mBackgroundExecutor; private final AppFunctionAgentAllowlistStorage mAgentAllowlistStorage; Loading @@ -188,7 +186,11 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { @NonNull PackageManagerInternal packageManagerInternal, @NonNull AppFunctionAccessServiceInterface appFunctionAccessServiceInterface, @NonNull IUriGrantsManager uriGrantsManager, @NonNull UriGrantsManagerInternal uriGrantsManagerInternal) { @NonNull UriGrantsManagerInternal uriGrantsManagerInternal, @NonNull AppFunctionsLoggerWrapper loggerWrapper, @NonNull AppFunctionAgentAllowlistStorage agentAllowlistStorage, @NonNull MultiUserAppFunctionAccessHistory multiUserAppFunctionAccessHistory, @NonNull Executor backgroundExecutor) { this( context, new RemoteServiceCallerImpl<>( Loading @@ -199,21 +201,18 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { Objects.requireNonNull(context.getSystemService(UserManager.class))), new ServiceHelperImpl(context), new ServiceConfigImpl(), new AppFunctionsLoggerWrapper(context), loggerWrapper, packageManagerInternal, appFunctionAccessServiceInterface, uriGrantsManager, uriGrantsManagerInternal, new DeviceSettingHelperImpl(context), new AppFunctionAgentAllowlistStorage( new File( new File(Environment.getDataSystemDirectory(), APP_FUNCTIONS_DIR), AGENT_ALLOWLIST_FILE_NAME)), THREAD_POOL_EXECUTOR); agentAllowlistStorage, multiUserAppFunctionAccessHistory, backgroundExecutor); } @VisibleForTesting AppFunctionManagerServiceImpl( private AppFunctionManagerServiceImpl( Context context, RemoteServiceCaller<IAppFunctionService> remoteServiceCaller, CallerValidator callerValidator, Loading @@ -226,21 +225,26 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { UriGrantsManagerInternal uriGrantsManagerInternal, DeviceSettingHelper deviceSettingHelper, AppFunctionAgentAllowlistStorage agentAllowlistStorage, Executor workerExecutor) { MultiUserAppFunctionAccessHistory multiUserAppFunctionAccessHistory, Executor backgroundExecutor) { mContext = Objects.requireNonNull(context); mRemoteServiceCaller = Objects.requireNonNull(remoteServiceCaller); mCallerValidator = Objects.requireNonNull(callerValidator); mInternalServiceHelper = Objects.requireNonNull(appFunctionInternalServiceHelper); mServiceConfig = serviceConfig; mLoggerWrapper = loggerWrapper; mServiceConfig = Objects.requireNonNull(serviceConfig); mLoggerWrapper = Objects.requireNonNull(loggerWrapper); mPackageManagerInternal = Objects.requireNonNull(packageManagerInternal); mAppFunctionAccessService = Objects.requireNonNull(appFunctionAccessServiceInterface); mUriGrantsManager = Objects.requireNonNull(uriGrantsManager); mUriGrantsManagerInternal = Objects.requireNonNull(uriGrantsManagerInternal); mPermissionOwner = mUriGrantsManagerInternal.newUriPermissionOwner("appfunctions"); mDeviceSettingHelper = deviceSettingHelper; mPermissionOwner = Objects.requireNonNull( mUriGrantsManagerInternal.newUriPermissionOwner("appfunctions")); mDeviceSettingHelper = Objects.requireNonNull(deviceSettingHelper); mAgentAllowlistStorage = Objects.requireNonNull(agentAllowlistStorage); mWorkerExecutor = Objects.requireNonNull(workerExecutor); mMultiUserAppFunctionAccessHistory = Objects.requireNonNull(multiUserAppFunctionAccessHistory); mBackgroundExecutor = Objects.requireNonNull(backgroundExecutor); } /** Called when the user is unlocked. */ Loading @@ -251,6 +255,9 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { PackageMonitor pkgMonitorForUser = AppFunctionPackageMonitor.registerPackageMonitorForUser(mContext, user); mPackageMonitors.append(user.getUserIdentifier(), pkgMonitorForUser); if (accessCheckFlagsEnabled()) { mMultiUserAppFunctionAccessHistory.onUserUnlocked(user); } } /** Called when the user is stopping. */ Loading @@ -264,6 +271,9 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { mPackageMonitors.get(userIdentifier).unregister(); mPackageMonitors.delete(userIdentifier); } if (accessCheckFlagsEnabled()) { mMultiUserAppFunctionAccessHistory.onUserStopping(user); } } @Override Loading Loading @@ -305,23 +315,18 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { /** * Called during different phases of the system boot process. * * <p>This method is used to initialize AppFunctionManagerService components that depend on * other system services being ready. Specifically, it handles reading DeviceConfig properties * related to allowed agent package signatures and registers a listener for changes to these * properties. * * @param phase The current boot phase, as defined in {@link SystemService}. This method * specifically acts on {@link SystemService#PHASE_SYSTEM_SERVICES_READY}. */ public void onBootPhase(int phase) { if (!Flags.appFunctionAccessServiceEnabled()) return; if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { mWorkerExecutor.execute(() -> mBackgroundExecutor.execute(() -> updateAgentAllowlist(/* readFromDeviceConfig */ true, /* readFromSecureSetting= */ true)); DeviceConfig.addOnPropertiesChangedListener( NAMESPACE_MACHINE_LEARNING, BackgroundThread.getExecutor(), mBackgroundExecutor, mDeviceConfigListener); mContext.getContentResolver().registerContentObserver(ADDITIONAL_AGENTS_URI, false, mAdbAgentObserver); Loading Loading @@ -1093,6 +1098,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { long executionStartTimeMillis) { mLoggerWrapper.logAppFunctionSuccess( requestInternal, result, callingUid, executionStartTimeMillis); recordAppFunctionAccess(requestInternal, executionStartTimeMillis); } @Override Loading @@ -1103,6 +1109,27 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { error.getErrorCode(), callingUid, executionStartTimeMillis); recordAppFunctionAccess(requestInternal, executionStartTimeMillis); } }); } private void recordAppFunctionAccess( @NonNull ExecuteAppFunctionAidlRequest aidlRequest, long executionStartTimeMillis) { if (!accessCheckFlagsEnabled()) return; final long duration = SystemClock.elapsedRealtime() - executionStartTimeMillis; mBackgroundExecutor.execute( () -> { try { mMultiUserAppFunctionAccessHistory .asUser(aidlRequest.getUserHandle()) .insertAppFunctionAccessHistory(aidlRequest, duration); } catch (IllegalStateException e) { Slog.e( TAG, "Fail to insert new access history to user " + aidlRequest.getUserHandle().getIdentifier(), e); } }); } Loading
services/appfunctions/java/com/android/server/appfunctions/AppFunctionAccessDatabaseHelper.java→services/appfunctions/java/com/android/server/appfunctions/AppFunctionSQLiteAccessHistory.java +8 −21 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.server.appfunctions; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.appfunctions.AppFunctionAttribution; import android.app.appfunctions.AppFunctionManager.AccessHistory; import android.app.appfunctions.ExecuteAppFunctionAidlRequest; Loading @@ -35,7 +34,8 @@ import android.util.Slog; import java.util.Objects; /** The database helper for managing AppFunction access histories. */ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { public final class AppFunctionSQLiteAccessHistory extends SQLiteOpenHelper implements AppFunctionAccessHistory { private static final class AccessHistoryTable { static final String DB_TABLE = "appfunction_access"; Loading Loading @@ -85,7 +85,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "AppFunctionDatabase"; AppFunctionAccessDatabaseHelper(@NonNull Context context) { AppFunctionSQLiteAccessHistory(@NonNull Context context) { super(context, DB_NAME, /* factory= */ null, DB_VERSION); } Loading @@ -102,7 +102,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {} /** Queries the AppFunction access histories. */ @Override @Nullable public Cursor queryAppFunctionAccessHistory( @Nullable String[] projection, Loading Loading @@ -134,12 +134,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { } } /** * Inserts an AppFunction access history to the given database. * * @return The row id or -1 if fail to insert. */ @WorkerThread @Override public long insertAppFunctionAccessHistory( @NonNull ExecuteAppFunctionAidlRequest aidlRequest, long duration) { Objects.requireNonNull(aidlRequest); Loading Loading @@ -193,13 +188,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { return values; } /** * Deletes expired AppFunction access histories from the database. * * @param retentionMillis The maximum age of records to keep, in milliseconds. Records older * than this will be deleted. */ @WorkerThread @Override public void deleteExpiredAppFunctionAccessHistories(long retentionMillis) { try { final SQLiteDatabase db = getWritableDatabase(); Loading @@ -212,8 +201,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { } } /** Deletes AppFunction access histories that are associated with the given packageName. */ @WorkerThread @Override public void deleteAppFunctionAccessHistories(@NonNull String packageName) { Objects.requireNonNull(packageName); Loading @@ -233,8 +221,7 @@ public final class AppFunctionAccessDatabaseHelper extends SQLiteOpenHelper { } } /** Deletes all AppFunction access histories. */ @WorkerThread @Override public void deleteAll() { try { final SQLiteDatabase db = getWritableDatabase(); Loading