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