Loading core/res/AndroidManifest.xml +4 −0 Original line number Diff line number Diff line Loading @@ -5344,6 +5344,10 @@ android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.people.data.DataMaintenanceService" android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.autofill.AutofillCompatAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" Loading services/core/java/com/android/server/people/PeopleServiceInternal.java +11 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.people; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.os.CancellationSignal; import android.service.appprediction.IPredictionService; /** Loading @@ -24,17 +26,24 @@ import android.service.appprediction.IPredictionService; */ public abstract class PeopleServiceInternal extends IPredictionService.Stub { /** * Prunes the data for the specified user. Called by {@link * com.android.server.people.data.DataMaintenanceService} when the device is idle. */ public abstract void pruneDataForUser(@UserIdInt int userId, @NonNull CancellationSignal signal); /** * The number conversation infos will be dynamic, based on the currently installed apps on the * device. All of which should be combined into a single blob to be backed up. */ public abstract byte[] backupConversationInfos(@NonNull int userId); public abstract byte[] backupConversationInfos(@UserIdInt int userId); /** * Multiple conversation infos may exist in the restore payload, child classes are required to * manage the restoration based on how individual conversation infos were originally combined * during backup. */ public abstract void restoreConversationInfos(@NonNull int userId, @NonNull String key, public abstract void restoreConversationInfos(@UserIdInt int userId, @NonNull String key, @NonNull byte[] payload); } services/people/java/com/android/server/people/PeopleService.java +17 −9 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.people; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionSessionId; import android.app.prediction.AppTarget; Loading @@ -24,6 +25,7 @@ import android.app.prediction.AppTargetEvent; import android.app.prediction.IPredictionCallback; import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.CancellationSignal; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Slog; Loading Loading @@ -138,6 +140,21 @@ public class PeopleService extends SystemService { }); } @Override public void pruneDataForUser(@UserIdInt int userId, @NonNull CancellationSignal signal) { mDataManager.pruneDataForUser(userId, signal); } @Override public byte[] backupConversationInfos(@UserIdInt int userId) { return new byte[0]; } @Override public void restoreConversationInfos(@UserIdInt int userId, @NonNull String key, @NonNull byte[] payload) { } @VisibleForTesting SessionInfo getSessionInfo(AppPredictionSessionId sessionId) { return mSessions.get(sessionId); Loading @@ -160,14 +177,5 @@ public class PeopleService extends SystemService { Slog.e(TAG, "Failed to calling callback" + e); } } @Override public byte[] backupConversationInfos(int userId) { return new byte[0]; } @Override public void restoreConversationInfos(int userId, String key, byte[] payload) { } } } services/people/java/com/android/server/people/data/ConversationStore.java +4 −2 Original line number Diff line number Diff line Loading @@ -133,10 +133,11 @@ class ConversationStore { } @MainThread synchronized void deleteConversation(@NonNull String shortcutId) { @Nullable synchronized ConversationInfo deleteConversation(@NonNull String shortcutId) { ConversationInfo conversationInfo = mConversationInfoMap.remove(shortcutId); if (conversationInfo == null) { return; return null; } LocusId locusId = conversationInfo.getLocusId(); Loading @@ -159,6 +160,7 @@ class ConversationStore { mNotifChannelIdToShortcutIdMap.remove(notifChannelId); } scheduleUpdateConversationsOnDisk(); return conversationInfo; } synchronized void forAllConversations(@NonNull Consumer<ConversationInfo> consumer) { Loading services/people/java/com/android/server/people/data/DataMaintenanceService.java 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.people.data; import android.annotation.UserIdInt; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.os.CancellationSignal; import com.android.server.LocalServices; import com.android.server.people.PeopleServiceInternal; import java.util.concurrent.TimeUnit; /** * This service runs periodically to ensure the data consistency and the retention policy for a * specific user's data. */ public class DataMaintenanceService extends JobService { private static final long JOB_RUN_INTERVAL = TimeUnit.HOURS.toMillis(24); /** This job ID must be unique within the system server. */ private static final int BASE_JOB_ID = 0xC315BD7; // 204561367 static void scheduleJob(Context context, @UserIdInt int userId) { int jobId = getJobId(userId); JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); if (jobScheduler.getPendingJob(jobId) == null) { ComponentName component = new ComponentName(context, DataMaintenanceService.class); JobInfo newJob = new JobInfo.Builder(jobId, component) .setRequiresDeviceIdle(true) .setPeriodic(JOB_RUN_INTERVAL) .build(); jobScheduler.schedule(newJob); } } static void cancelJob(Context context, @UserIdInt int userId) { JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); jobScheduler.cancel(getJobId(userId)); } private CancellationSignal mSignal; @Override public boolean onStartJob(JobParameters params) { int userId = getUserId(params.getJobId()); mSignal = new CancellationSignal(); new Thread(() -> { PeopleServiceInternal peopleServiceInternal = LocalServices.getService(PeopleServiceInternal.class); peopleServiceInternal.pruneDataForUser(userId, mSignal); jobFinished(params, mSignal.isCanceled()); }).start(); return true; } @Override public boolean onStopJob(JobParameters params) { if (mSignal != null) { mSignal.cancel(); } return false; } private static int getJobId(@UserIdInt int userId) { return BASE_JOB_ID + userId; } private static @UserIdInt int getUserId(int jobId) { return jobId - BASE_JOB_ID; } } Loading
core/res/AndroidManifest.xml +4 −0 Original line number Diff line number Diff line Loading @@ -5344,6 +5344,10 @@ android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.people.data.DataMaintenanceService" android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.autofill.AutofillCompatAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" Loading
services/core/java/com/android/server/people/PeopleServiceInternal.java +11 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.people; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.os.CancellationSignal; import android.service.appprediction.IPredictionService; /** Loading @@ -24,17 +26,24 @@ import android.service.appprediction.IPredictionService; */ public abstract class PeopleServiceInternal extends IPredictionService.Stub { /** * Prunes the data for the specified user. Called by {@link * com.android.server.people.data.DataMaintenanceService} when the device is idle. */ public abstract void pruneDataForUser(@UserIdInt int userId, @NonNull CancellationSignal signal); /** * The number conversation infos will be dynamic, based on the currently installed apps on the * device. All of which should be combined into a single blob to be backed up. */ public abstract byte[] backupConversationInfos(@NonNull int userId); public abstract byte[] backupConversationInfos(@UserIdInt int userId); /** * Multiple conversation infos may exist in the restore payload, child classes are required to * manage the restoration based on how individual conversation infos were originally combined * during backup. */ public abstract void restoreConversationInfos(@NonNull int userId, @NonNull String key, public abstract void restoreConversationInfos(@UserIdInt int userId, @NonNull String key, @NonNull byte[] payload); }
services/people/java/com/android/server/people/PeopleService.java +17 −9 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.people; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionSessionId; import android.app.prediction.AppTarget; Loading @@ -24,6 +25,7 @@ import android.app.prediction.AppTargetEvent; import android.app.prediction.IPredictionCallback; import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.CancellationSignal; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Slog; Loading Loading @@ -138,6 +140,21 @@ public class PeopleService extends SystemService { }); } @Override public void pruneDataForUser(@UserIdInt int userId, @NonNull CancellationSignal signal) { mDataManager.pruneDataForUser(userId, signal); } @Override public byte[] backupConversationInfos(@UserIdInt int userId) { return new byte[0]; } @Override public void restoreConversationInfos(@UserIdInt int userId, @NonNull String key, @NonNull byte[] payload) { } @VisibleForTesting SessionInfo getSessionInfo(AppPredictionSessionId sessionId) { return mSessions.get(sessionId); Loading @@ -160,14 +177,5 @@ public class PeopleService extends SystemService { Slog.e(TAG, "Failed to calling callback" + e); } } @Override public byte[] backupConversationInfos(int userId) { return new byte[0]; } @Override public void restoreConversationInfos(int userId, String key, byte[] payload) { } } }
services/people/java/com/android/server/people/data/ConversationStore.java +4 −2 Original line number Diff line number Diff line Loading @@ -133,10 +133,11 @@ class ConversationStore { } @MainThread synchronized void deleteConversation(@NonNull String shortcutId) { @Nullable synchronized ConversationInfo deleteConversation(@NonNull String shortcutId) { ConversationInfo conversationInfo = mConversationInfoMap.remove(shortcutId); if (conversationInfo == null) { return; return null; } LocusId locusId = conversationInfo.getLocusId(); Loading @@ -159,6 +160,7 @@ class ConversationStore { mNotifChannelIdToShortcutIdMap.remove(notifChannelId); } scheduleUpdateConversationsOnDisk(); return conversationInfo; } synchronized void forAllConversations(@NonNull Consumer<ConversationInfo> consumer) { Loading
services/people/java/com/android/server/people/data/DataMaintenanceService.java 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.people.data; import android.annotation.UserIdInt; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.os.CancellationSignal; import com.android.server.LocalServices; import com.android.server.people.PeopleServiceInternal; import java.util.concurrent.TimeUnit; /** * This service runs periodically to ensure the data consistency and the retention policy for a * specific user's data. */ public class DataMaintenanceService extends JobService { private static final long JOB_RUN_INTERVAL = TimeUnit.HOURS.toMillis(24); /** This job ID must be unique within the system server. */ private static final int BASE_JOB_ID = 0xC315BD7; // 204561367 static void scheduleJob(Context context, @UserIdInt int userId) { int jobId = getJobId(userId); JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); if (jobScheduler.getPendingJob(jobId) == null) { ComponentName component = new ComponentName(context, DataMaintenanceService.class); JobInfo newJob = new JobInfo.Builder(jobId, component) .setRequiresDeviceIdle(true) .setPeriodic(JOB_RUN_INTERVAL) .build(); jobScheduler.schedule(newJob); } } static void cancelJob(Context context, @UserIdInt int userId) { JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); jobScheduler.cancel(getJobId(userId)); } private CancellationSignal mSignal; @Override public boolean onStartJob(JobParameters params) { int userId = getUserId(params.getJobId()); mSignal = new CancellationSignal(); new Thread(() -> { PeopleServiceInternal peopleServiceInternal = LocalServices.getService(PeopleServiceInternal.class); peopleServiceInternal.pruneDataForUser(userId, mSignal); jobFinished(params, mSignal.isCanceled()); }).start(); return true; } @Override public boolean onStopJob(JobParameters params) { if (mSignal != null) { mSignal.cancel(); } return false; } private static int getJobId(@UserIdInt int userId) { return BASE_JOB_ID + userId; } private static @UserIdInt int getUserId(int jobId) { return jobId - BASE_JOB_ID; } }