• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.server.pm.pkg.mutate;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.ComponentName;
22 import android.content.pm.ApplicationInfo;
23 import android.content.pm.PackageManager;
24 import android.content.pm.overlay.OverlayPaths;
25 import android.util.ArraySet;
26 
27 import com.android.server.pm.PackageSetting;
28 import com.android.server.pm.pkg.PackageUserStateImpl;
29 import com.android.server.pm.pkg.SuspendParams;
30 
31 import java.util.concurrent.atomic.AtomicLong;
32 import java.util.function.Function;
33 
34 public class PackageStateMutator {
35 
36     private static final AtomicLong sStateChangeSequence = new AtomicLong();
37 
38     private final StateWriteWrapper mStateWrite = new StateWriteWrapper();
39 
40     private final Function<String, PackageSetting> mActiveStateFunction;
41     private final Function<String, PackageSetting> mDisabledStateFunction;
42 
PackageStateMutator(@onNull Function<String, PackageSetting> activeStateFunction, @NonNull Function<String, PackageSetting> disabledStateFunction)43     public PackageStateMutator(@NonNull Function<String, PackageSetting> activeStateFunction,
44             @NonNull Function<String, PackageSetting> disabledStateFunction) {
45         mActiveStateFunction = activeStateFunction;
46         mDisabledStateFunction = disabledStateFunction;
47     }
48 
onPackageStateChanged()49     public static void onPackageStateChanged() {
50         sStateChangeSequence.incrementAndGet();
51     }
52 
53     @NonNull
forPackage(@onNull String packageName)54     public PackageStateWrite forPackage(@NonNull String packageName) {
55         return mStateWrite.setState(mActiveStateFunction.apply(packageName));
56     }
57 
58     @Nullable
forPackageNullable(@onNull String packageName)59     public PackageStateWrite forPackageNullable(@NonNull String packageName) {
60         final PackageSetting packageState = mActiveStateFunction.apply(packageName);
61         mStateWrite.setState(packageState);
62         if (packageState == null) {
63             return null;
64         }
65 
66         return mStateWrite.setState(packageState);
67     }
68 
69     @NonNull
forDisabledSystemPackage(@onNull String packageName)70     public PackageStateWrite forDisabledSystemPackage(@NonNull String packageName) {
71         return mStateWrite.setState(mDisabledStateFunction.apply(packageName));
72     }
73 
74     @Nullable
forDisabledSystemPackageNullable(@onNull String packageName)75     public PackageStateWrite forDisabledSystemPackageNullable(@NonNull String packageName) {
76         final PackageSetting packageState = mDisabledStateFunction.apply(packageName);
77         if (packageState == null) {
78             return null;
79         }
80 
81         return mStateWrite.setState(packageState);
82     }
83 
84     @NonNull
initialState(int changedPackagesSequenceNumber)85     public InitialState initialState(int changedPackagesSequenceNumber) {
86         return new InitialState(changedPackagesSequenceNumber, sStateChangeSequence.get());
87     }
88 
89     /**
90      * @return null if initial state is null or if nothing has changed, otherwise return result
91      * with what changed
92      */
93     @Nullable
generateResult(@ullable InitialState state, int changedPackagesSequenceNumber)94     public Result generateResult(@Nullable InitialState state, int changedPackagesSequenceNumber) {
95         if (state == null) {
96             return Result.SUCCESS;
97         }
98 
99         boolean packagesChanged = changedPackagesSequenceNumber != state.mPackageSequence;
100         boolean stateChanged = sStateChangeSequence.get() != state.mStateSequence;
101         if (packagesChanged && stateChanged) {
102             return Result.PACKAGES_AND_STATE_CHANGED;
103         } else if (packagesChanged) {
104             return Result.PACKAGES_CHANGED;
105         } else if (stateChanged) {
106             return Result.STATE_CHANGED;
107         } else {
108             return Result.SUCCESS;
109         }
110     }
111 
112     public static class InitialState {
113 
114         private final int mPackageSequence;
115         private final long mStateSequence;
116 
InitialState(int packageSequence, long stateSequence)117         public InitialState(int packageSequence, long stateSequence) {
118             mPackageSequence = packageSequence;
119             mStateSequence = stateSequence;
120         }
121     }
122 
123     public static class Result {
124 
125         public static final Result SUCCESS = new Result(true, false, false, false);
126         public static final Result PACKAGES_CHANGED = new Result(false, true, false, false);
127         public static final Result STATE_CHANGED = new Result(false, false, true, false);
128         public static final Result PACKAGES_AND_STATE_CHANGED = new Result(false, true, true, false);
129         public static final Result SPECIFIC_PACKAGE_NULL = new Result(false, false, true, true);
130 
131         private final boolean mCommitted;
132         private final boolean mPackagesChanged;
133         private final boolean mStateChanged;
134         private final boolean mSpecificPackageNull;
135 
Result(boolean committed, boolean packagesChanged, boolean stateChanged, boolean specificPackageNull)136         public Result(boolean committed, boolean packagesChanged, boolean stateChanged,
137                 boolean specificPackageNull) {
138             mCommitted = committed;
139             mPackagesChanged = packagesChanged;
140             mStateChanged = stateChanged;
141             mSpecificPackageNull = specificPackageNull;
142         }
143 
isCommitted()144         public boolean isCommitted() {
145             return mCommitted;
146         }
147 
isPackagesChanged()148         public boolean isPackagesChanged() {
149             return mPackagesChanged;
150         }
151 
isStateChanged()152         public boolean isStateChanged() {
153             return mStateChanged;
154         }
155 
isSpecificPackageNull()156         public boolean isSpecificPackageNull() {
157             return mSpecificPackageNull;
158         }
159     }
160 
161     private static class StateWriteWrapper implements PackageStateWrite {
162 
163         private final UserStateWriteWrapper mUserStateWrite = new UserStateWriteWrapper();
164 
165         @NonNull
166         private PackageSetting mState;
167 
setState(PackageSetting state)168         public StateWriteWrapper setState(PackageSetting state) {
169             this.mState = state;
170             return this;
171         }
172 
173         @NonNull
174         @Override
userState(int userId)175         public PackageUserStateWrite userState(int userId) {
176             return mUserStateWrite.setStates(
177                     mState == null ? null : mState.getOrCreateUserState(userId));
178         }
179 
180         @Override
onChanged()181         public void onChanged() {
182             if (mState != null) {
183                 mState.onChanged();
184             }
185         }
186 
187         @Override
setLastPackageUsageTime(int reason, long timeInMillis)188         public PackageStateWrite setLastPackageUsageTime(int reason, long timeInMillis) {
189             if (mState != null) {
190                 mState.getTransientState().setLastPackageUsageTimeInMills(reason, timeInMillis);
191             }
192             return this;
193         }
194 
195         @Override
setHiddenUntilInstalled(boolean value)196         public PackageStateWrite setHiddenUntilInstalled(boolean value) {
197             if (mState != null) {
198                 mState.getTransientState().setHiddenUntilInstalled(value);
199             }
200             return this;
201         }
202 
203         @NonNull
204         @Override
setRequiredForSystemUser(boolean requiredForSystemUser)205         public PackageStateWrite setRequiredForSystemUser(boolean requiredForSystemUser) {
206             if (mState != null) {
207                 if (requiredForSystemUser) {
208                     mState.setPrivateFlags(mState.getPrivateFlags()
209                             | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
210                 } else {
211                     mState.setPrivateFlags(mState.getPrivateFlags()
212                             & ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
213                 }
214             }
215             return this;
216         }
217 
218         @NonNull
219         @Override
setMimeGroup(@onNull String mimeGroup, @NonNull ArraySet<String> mimeTypes)220         public PackageStateWrite setMimeGroup(@NonNull String mimeGroup,
221                 @NonNull ArraySet<String> mimeTypes) {
222             if (mState != null) {
223                 mState.setMimeGroup(mimeGroup, mimeTypes);
224             }
225             return this;
226         }
227 
228         @NonNull
229         @Override
setCategoryOverride(@pplicationInfo.Category int category)230         public PackageStateWrite setCategoryOverride(@ApplicationInfo.Category int category) {
231             if (mState != null) {
232                 mState.setCategoryOverride(category);
233             }
234             return this;
235         }
236 
237         @NonNull
238         @Override
setUpdateAvailable(boolean updateAvailable)239         public PackageStateWrite setUpdateAvailable(boolean updateAvailable) {
240             if (mState != null) {
241                 mState.setUpdateAvailable(updateAvailable);
242             }
243             return this;
244         }
245 
246         @NonNull
247         @Override
setLoadingProgress(float progress)248         public PackageStateWrite setLoadingProgress(float progress) {
249             if (mState != null) {
250                 mState.setLoadingProgress(progress);
251             }
252             return this;
253         }
254 
255         @NonNull
256         @Override
setOverrideSeInfo(@ullable String newSeInfo)257         public PackageStateWrite setOverrideSeInfo(@Nullable String newSeInfo) {
258             if (mState != null) {
259                 mState.getTransientState().setOverrideSeInfo(newSeInfo);
260             }
261             return this;
262         }
263 
264         @NonNull
265         @Override
setInstaller(@onNull String installerPackageName)266         public PackageStateWrite setInstaller(@NonNull String installerPackageName) {
267             if (mState != null) {
268                 mState.setInstallerPackageName(installerPackageName);
269             }
270             return this;
271         }
272 
273         private static class UserStateWriteWrapper implements PackageUserStateWrite {
274 
275             @Nullable
276             private PackageUserStateImpl mUserState;
277 
setStates(@ullable PackageUserStateImpl userState)278             public UserStateWriteWrapper setStates(@Nullable PackageUserStateImpl userState) {
279                 mUserState = userState;
280                 return this;
281             }
282 
283             @NonNull
284             @Override
setInstalled(boolean installed)285             public PackageUserStateWrite setInstalled(boolean installed) {
286                 if (mUserState != null) {
287                     mUserState.setInstalled(installed);
288                 }
289                 return this;
290             }
291 
292             @NonNull
293             @Override
setUninstallReason(int reason)294             public PackageUserStateWrite setUninstallReason(int reason) {
295                 if (mUserState != null) {
296                     mUserState.setUninstallReason(reason);
297                 }
298                 return this;
299             }
300 
301             @NonNull
302             @Override
setDistractionFlags( @ackageManager.DistractionRestriction int restrictionFlags)303             public PackageUserStateWrite setDistractionFlags(
304                     @PackageManager.DistractionRestriction int restrictionFlags) {
305                 if (mUserState != null) {
306                     mUserState.setDistractionFlags(restrictionFlags);
307                 }
308                 return this;
309             }
310 
311             @NonNull
312             @Override
putSuspendParams(@onNull String suspendingPackage, @Nullable SuspendParams suspendParams)313             public PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
314                     @Nullable SuspendParams suspendParams) {
315                 if (mUserState != null) {
316                     mUserState.putSuspendParams(suspendingPackage, suspendParams);
317                 }
318                 return this;
319             }
320 
321             @NonNull
322             @Override
removeSuspension(@onNull String suspendingPackage)323             public PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage) {
324                 if (mUserState != null) {
325                     mUserState.removeSuspension(suspendingPackage);
326                 }
327                 return this;
328             }
329 
330             @NonNull
331             @Override
setHidden(boolean hidden)332             public PackageUserStateWrite setHidden(boolean hidden) {
333                 if (mUserState != null) {
334                     mUserState.setHidden(hidden);
335                 }
336                 return this;
337             }
338 
339             @NonNull
340             @Override
setStopped(boolean stopped)341             public PackageUserStateWrite setStopped(boolean stopped) {
342                 if (mUserState != null) {
343                     mUserState.setStopped(stopped);
344                 }
345                 return this;
346             }
347 
348             @NonNull
349             @Override
setNotLaunched(boolean notLaunched)350             public PackageUserStateWrite setNotLaunched(boolean notLaunched) {
351                 if (mUserState != null) {
352                     mUserState.setNotLaunched(notLaunched);
353                 }
354                 return this;
355             }
356 
357             @NonNull
358             @Override
setOverlayPaths(@onNull OverlayPaths overlayPaths)359             public PackageUserStateWrite setOverlayPaths(@NonNull OverlayPaths overlayPaths) {
360                 if (mUserState != null) {
361                     mUserState.setOverlayPaths(overlayPaths);
362                 }
363                 return this;
364             }
365 
366             @NonNull
367             @Override
setOverlayPathsForLibrary(@onNull String libraryName, @Nullable OverlayPaths overlayPaths)368             public PackageUserStateWrite setOverlayPathsForLibrary(@NonNull String libraryName,
369                     @Nullable OverlayPaths overlayPaths) {
370                 if (mUserState != null) {
371                     mUserState.setSharedLibraryOverlayPaths(libraryName, overlayPaths);
372                 }
373                 return this;
374             }
375 
376             @NonNull
377             @Override
setHarmfulAppWarning(@ullable String warning)378             public PackageUserStateWrite setHarmfulAppWarning(@Nullable String warning) {
379                 if (mUserState != null) {
380                     mUserState.setHarmfulAppWarning(warning);
381                 }
382                 return this;
383             }
384 
385             @NonNull
386             @Override
setSplashScreenTheme(@ullable String theme)387             public PackageUserStateWrite setSplashScreenTheme(@Nullable String theme) {
388                 if (mUserState != null) {
389                     mUserState.setSplashScreenTheme(theme);
390                 }
391                 return this;
392             }
393 
394             @NonNull
395             @Override
setComponentLabelIcon(@onNull ComponentName componentName, @Nullable String nonLocalizedLabel, @Nullable Integer icon)396             public PackageUserStateWrite setComponentLabelIcon(@NonNull ComponentName componentName,
397                     @Nullable String nonLocalizedLabel, @Nullable Integer icon) {
398                 if (mUserState != null) {
399                     mUserState.overrideLabelAndIcon(componentName, nonLocalizedLabel, icon);
400                 }
401                 return null;
402             }
403         }
404     }
405 }
406