• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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;
18 
19 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
20 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
21 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
22 
23 import android.content.pm.ApplicationInfo;
24 import android.content.pm.IntentFilterVerificationInfo;
25 import android.content.pm.PackageManager;
26 import android.content.pm.PackageUserState;
27 import android.os.storage.VolumeInfo;
28 import android.service.pm.PackageProto;
29 import android.util.ArraySet;
30 import android.util.SparseArray;
31 import android.util.proto.ProtoOutputStream;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.google.android.collect.Lists;
35 
36 import java.io.File;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.List;
40 import java.util.Set;
41 
42 /**
43  * Settings base class for pending and resolved classes.
44  */
45 abstract class PackageSettingBase extends SettingBase {
46 
47     private static final int[] EMPTY_INT_ARRAY = new int[0];
48 
49     /**
50      * Indicates the state of installation. Used by PackageManager to figure out
51      * incomplete installations. Say a package is being installed (the state is
52      * set to PKG_INSTALL_INCOMPLETE) and remains so till the package
53      * installation is successful or unsuccessful in which case the
54      * PackageManager will no longer maintain state information associated with
55      * the package. If some exception(like device freeze or battery being pulled
56      * out) occurs during installation of a package, the PackageManager needs
57      * this information to clean up the previously failed installation.
58      */
59     static final int PKG_INSTALL_COMPLETE = 1;
60     static final int PKG_INSTALL_INCOMPLETE = 0;
61 
62     final String name;
63     final String realName;
64 
65     String parentPackageName;
66     List<String> childPackageNames;
67 
68     /**
69      * Path where this package was found on disk. For monolithic packages
70      * this is path to single base APK file; for cluster packages this is
71      * path to the cluster directory.
72      */
73     File codePath;
74     String codePathString;
75     File resourcePath;
76     String resourcePathString;
77 
78     String[] usesStaticLibraries;
79     int[] usesStaticLibrariesVersions;
80 
81     /**
82      * The path under which native libraries have been unpacked. This path is
83      * always derived at runtime, and is only stored here for cleanup when a
84      * package is uninstalled.
85      */
86     @Deprecated
87     String legacyNativeLibraryPathString;
88 
89     /**
90      * The primary CPU abi for this package.
91      */
92     String primaryCpuAbiString;
93 
94     /**
95      * The secondary CPU abi for this package.
96      */
97     String secondaryCpuAbiString;
98 
99     /**
100      * The install time CPU override, if any. This value is written at install time
101      * and doesn't change during the life of an install. If non-null,
102      * {@code primaryCpuAbiString} will contain the same value.
103      */
104     String cpuAbiOverrideString;
105 
106     long timeStamp;
107     long firstInstallTime;
108     long lastUpdateTime;
109     int versionCode;
110 
111     boolean uidError;
112 
113     PackageSignatures signatures;
114 
115     boolean installPermissionsFixed;
116 
117     PackageKeySetData keySetData = new PackageKeySetData();
118 
119     static final PackageUserState DEFAULT_USER_STATE = new PackageUserState();
120 
121     // Whether this package is currently stopped, thus can not be
122     // started until explicitly launched by the user.
123     private final SparseArray<PackageUserState> userState = new SparseArray<PackageUserState>();
124 
125     int installStatus = PKG_INSTALL_COMPLETE;
126 
127     /**
128      * Non-persisted value. During an "upgrade without restart", we need the set
129      * of all previous code paths so we can surgically add the new APKs to the
130      * active classloader. If at any point an application is upgraded with a
131      * restart, this field will be cleared since the classloader would be created
132      * using the full set of code paths when the package's process is started.
133      */
134     Set<String> oldCodePaths;
135     PackageSettingBase origPackage;
136 
137     /** Package name of the app that installed this package */
138     String installerPackageName;
139     /** Indicates if the package that installed this app has been uninstalled */
140     boolean isOrphaned;
141     /** UUID of {@link VolumeInfo} hosting this app */
142     String volumeUuid;
143     /** The category of this app, as hinted by the installer */
144     int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
145     /** Whether or not an update is available. Ostensibly only for instant apps. */
146     boolean updateAvailable;
147 
148     IntentFilterVerificationInfo verificationInfo;
149 
PackageSettingBase(String name, String realName, File codePath, File resourcePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, int pVersionCode, int pkgFlags, int pkgPrivateFlags, String parentPackageName, List<String> childPackageNames, String[] usesStaticLibraries, int[] usesStaticLibrariesVersions)150     PackageSettingBase(String name, String realName, File codePath, File resourcePath,
151             String legacyNativeLibraryPathString, String primaryCpuAbiString,
152             String secondaryCpuAbiString, String cpuAbiOverrideString,
153             int pVersionCode, int pkgFlags, int pkgPrivateFlags,
154             String parentPackageName, List<String> childPackageNames,
155             String[] usesStaticLibraries, int[] usesStaticLibrariesVersions) {
156         super(pkgFlags, pkgPrivateFlags);
157         this.name = name;
158         this.realName = realName;
159         this.parentPackageName = parentPackageName;
160         this.childPackageNames = (childPackageNames != null)
161                 ? new ArrayList<>(childPackageNames) : null;
162         this.usesStaticLibraries = usesStaticLibraries;
163         this.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
164         init(codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString,
165                 secondaryCpuAbiString, cpuAbiOverrideString, pVersionCode);
166     }
167 
168     /**
169      * New instance of PackageSetting with one-level-deep cloning.
170      * <p>
171      * IMPORTANT: With a shallow copy, we do NOT create new contained objects.
172      * This means, for example, changes to the user state of the original PackageSetting
173      * will also change the user state in its copy.
174      */
PackageSettingBase(PackageSettingBase base, String realName)175     PackageSettingBase(PackageSettingBase base, String realName) {
176         super(base);
177         name = base.name;
178         this.realName = realName;
179         doCopy(base);
180     }
181 
init(File codePath, File resourcePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, int pVersionCode)182     void init(File codePath, File resourcePath, String legacyNativeLibraryPathString,
183               String primaryCpuAbiString, String secondaryCpuAbiString,
184               String cpuAbiOverrideString, int pVersionCode) {
185         this.codePath = codePath;
186         this.codePathString = codePath.toString();
187         this.resourcePath = resourcePath;
188         this.resourcePathString = resourcePath.toString();
189         this.legacyNativeLibraryPathString = legacyNativeLibraryPathString;
190         this.primaryCpuAbiString = primaryCpuAbiString;
191         this.secondaryCpuAbiString = secondaryCpuAbiString;
192         this.cpuAbiOverrideString = cpuAbiOverrideString;
193         this.versionCode = pVersionCode;
194         this.signatures = new PackageSignatures();
195     }
196 
setInstallerPackageName(String packageName)197     public void setInstallerPackageName(String packageName) {
198         installerPackageName = packageName;
199     }
200 
getInstallerPackageName()201     public String getInstallerPackageName() {
202         return installerPackageName;
203     }
204 
setVolumeUuid(String volumeUuid)205     public void setVolumeUuid(String volumeUuid) {
206         this.volumeUuid = volumeUuid;
207     }
208 
getVolumeUuid()209     public String getVolumeUuid() {
210         return volumeUuid;
211     }
212 
setInstallStatus(int newStatus)213     public void setInstallStatus(int newStatus) {
214         installStatus = newStatus;
215     }
216 
getInstallStatus()217     public int getInstallStatus() {
218         return installStatus;
219     }
220 
setTimeStamp(long newStamp)221     public void setTimeStamp(long newStamp) {
222         timeStamp = newStamp;
223     }
224 
setUpdateAvailable(boolean updateAvailable)225     public void setUpdateAvailable(boolean updateAvailable) {
226         this.updateAvailable = updateAvailable;
227     }
228 
isUpdateAvailable()229     public boolean isUpdateAvailable() {
230         return updateAvailable;
231     }
232 
233     /**
234      * Makes a shallow copy of the given package settings.
235      *
236      * NOTE: For some fields [such as keySetData, signatures, userState, verificationInfo, etc...],
237      * the original object is copied and a new one is not created.
238      */
copyFrom(PackageSettingBase orig)239     public void copyFrom(PackageSettingBase orig) {
240         super.copyFrom(orig);
241         doCopy(orig);
242     }
243 
doCopy(PackageSettingBase orig)244     private void doCopy(PackageSettingBase orig) {
245         childPackageNames = (orig.childPackageNames != null)
246                 ? new ArrayList<>(orig.childPackageNames) : null;
247         codePath = orig.codePath;
248         codePathString = orig.codePathString;
249         cpuAbiOverrideString = orig.cpuAbiOverrideString;
250         firstInstallTime = orig.firstInstallTime;
251         installPermissionsFixed = orig.installPermissionsFixed;
252         installStatus = orig.installStatus;
253         installerPackageName = orig.installerPackageName;
254         isOrphaned = orig.isOrphaned;
255         keySetData = orig.keySetData;
256         lastUpdateTime = orig.lastUpdateTime;
257         legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString;
258         // Intentionally skip oldCodePaths; it's not relevant for copies
259         origPackage = orig.origPackage;
260         parentPackageName = orig.parentPackageName;
261         primaryCpuAbiString = orig.primaryCpuAbiString;
262         resourcePath = orig.resourcePath;
263         resourcePathString = orig.resourcePathString;
264         secondaryCpuAbiString = orig.secondaryCpuAbiString;
265         signatures = orig.signatures;
266         timeStamp = orig.timeStamp;
267         uidError = orig.uidError;
268         userState.clear();
269         for (int i=0; i<orig.userState.size(); i++) {
270             userState.put(orig.userState.keyAt(i), orig.userState.valueAt(i));
271         }
272         verificationInfo = orig.verificationInfo;
273         versionCode = orig.versionCode;
274         volumeUuid = orig.volumeUuid;
275         categoryHint = orig.categoryHint;
276         usesStaticLibraries = orig.usesStaticLibraries != null
277                 ? Arrays.copyOf(orig.usesStaticLibraries,
278                         orig.usesStaticLibraries.length) : null;
279         usesStaticLibrariesVersions = orig.usesStaticLibrariesVersions != null
280                 ? Arrays.copyOf(orig.usesStaticLibrariesVersions,
281                        orig.usesStaticLibrariesVersions.length) : null;
282         updateAvailable = orig.updateAvailable;
283     }
284 
modifyUserState(int userId)285     private PackageUserState modifyUserState(int userId) {
286         PackageUserState state = userState.get(userId);
287         if (state == null) {
288             state = new PackageUserState();
289             userState.put(userId, state);
290         }
291         return state;
292     }
293 
readUserState(int userId)294     public PackageUserState readUserState(int userId) {
295         PackageUserState state = userState.get(userId);
296         if (state == null) {
297             return DEFAULT_USER_STATE;
298         }
299         state.categoryHint = categoryHint;
300         return state;
301     }
302 
setEnabled(int state, int userId, String callingPackage)303     void setEnabled(int state, int userId, String callingPackage) {
304         PackageUserState st = modifyUserState(userId);
305         st.enabled = state;
306         st.lastDisableAppCaller = callingPackage;
307     }
308 
getEnabled(int userId)309     int getEnabled(int userId) {
310         return readUserState(userId).enabled;
311     }
312 
getLastDisabledAppCaller(int userId)313     String getLastDisabledAppCaller(int userId) {
314         return readUserState(userId).lastDisableAppCaller;
315     }
316 
setInstalled(boolean inst, int userId)317     void setInstalled(boolean inst, int userId) {
318         modifyUserState(userId).installed = inst;
319     }
320 
getInstalled(int userId)321     boolean getInstalled(int userId) {
322         return readUserState(userId).installed;
323     }
324 
getInstallReason(int userId)325     int getInstallReason(int userId) {
326         return readUserState(userId).installReason;
327     }
328 
setInstallReason(int installReason, int userId)329     void setInstallReason(int installReason, int userId) {
330         modifyUserState(userId).installReason = installReason;
331     }
332 
setOverlayPaths(List<String> overlayPaths, int userId)333     void setOverlayPaths(List<String> overlayPaths, int userId) {
334         modifyUserState(userId).overlayPaths = overlayPaths == null ? null :
335             overlayPaths.toArray(new String[overlayPaths.size()]);
336     }
337 
getOverlayPaths(int userId)338     String[] getOverlayPaths(int userId) {
339         return readUserState(userId).overlayPaths;
340     }
341 
342     /** Only use for testing. Do NOT use in production code. */
343     @VisibleForTesting
getUserState()344     SparseArray<PackageUserState> getUserState() {
345         return userState;
346     }
347 
isAnyInstalled(int[] users)348     boolean isAnyInstalled(int[] users) {
349         for (int user: users) {
350             if (readUserState(user).installed) {
351                 return true;
352             }
353         }
354         return false;
355     }
356 
queryInstalledUsers(int[] users, boolean installed)357     int[] queryInstalledUsers(int[] users, boolean installed) {
358         int num = 0;
359         for (int user : users) {
360             if (getInstalled(user) == installed) {
361                 num++;
362             }
363         }
364         int[] res = new int[num];
365         num = 0;
366         for (int user : users) {
367             if (getInstalled(user) == installed) {
368                 res[num] = user;
369                 num++;
370             }
371         }
372         return res;
373     }
374 
getCeDataInode(int userId)375     long getCeDataInode(int userId) {
376         return readUserState(userId).ceDataInode;
377     }
378 
setCeDataInode(long ceDataInode, int userId)379     void setCeDataInode(long ceDataInode, int userId) {
380         modifyUserState(userId).ceDataInode = ceDataInode;
381     }
382 
getStopped(int userId)383     boolean getStopped(int userId) {
384         return readUserState(userId).stopped;
385     }
386 
setStopped(boolean stop, int userId)387     void setStopped(boolean stop, int userId) {
388         modifyUserState(userId).stopped = stop;
389     }
390 
getNotLaunched(int userId)391     boolean getNotLaunched(int userId) {
392         return readUserState(userId).notLaunched;
393     }
394 
setNotLaunched(boolean stop, int userId)395     void setNotLaunched(boolean stop, int userId) {
396         modifyUserState(userId).notLaunched = stop;
397     }
398 
getHidden(int userId)399     boolean getHidden(int userId) {
400         return readUserState(userId).hidden;
401     }
402 
setHidden(boolean hidden, int userId)403     void setHidden(boolean hidden, int userId) {
404         modifyUserState(userId).hidden = hidden;
405     }
406 
getSuspended(int userId)407     boolean getSuspended(int userId) {
408         return readUserState(userId).suspended;
409     }
410 
setSuspended(boolean suspended, int userId)411     void setSuspended(boolean suspended, int userId) {
412         modifyUserState(userId).suspended = suspended;
413     }
414 
getInstantApp(int userId)415     boolean getInstantApp(int userId) {
416         return readUserState(userId).instantApp;
417     }
418 
setInstantApp(boolean instantApp, int userId)419     void setInstantApp(boolean instantApp, int userId) {
420         modifyUserState(userId).instantApp = instantApp;
421     }
422 
getVirtulalPreload(int userId)423     boolean getVirtulalPreload(int userId) {
424         return readUserState(userId).virtualPreload;
425     }
426 
setVirtualPreload(boolean virtualPreload, int userId)427     void setVirtualPreload(boolean virtualPreload, int userId) {
428         modifyUserState(userId).virtualPreload = virtualPreload;
429     }
430 
setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped, boolean notLaunched, boolean hidden, boolean suspended, boolean instantApp, boolean virtualPreload, String lastDisableAppCaller, ArraySet<String> enabledComponents, ArraySet<String> disabledComponents, int domainVerifState, int linkGeneration, int installReason)431     void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
432             boolean notLaunched, boolean hidden, boolean suspended, boolean instantApp,
433             boolean virtualPreload, String lastDisableAppCaller,
434             ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
435             int domainVerifState, int linkGeneration, int installReason) {
436         PackageUserState state = modifyUserState(userId);
437         state.ceDataInode = ceDataInode;
438         state.enabled = enabled;
439         state.installed = installed;
440         state.stopped = stopped;
441         state.notLaunched = notLaunched;
442         state.hidden = hidden;
443         state.suspended = suspended;
444         state.lastDisableAppCaller = lastDisableAppCaller;
445         state.enabledComponents = enabledComponents;
446         state.disabledComponents = disabledComponents;
447         state.domainVerificationStatus = domainVerifState;
448         state.appLinkGeneration = linkGeneration;
449         state.installReason = installReason;
450         state.instantApp = instantApp;
451         state.virtualPreload = virtualPreload;
452     }
453 
getEnabledComponents(int userId)454     ArraySet<String> getEnabledComponents(int userId) {
455         return readUserState(userId).enabledComponents;
456     }
457 
getDisabledComponents(int userId)458     ArraySet<String> getDisabledComponents(int userId) {
459         return readUserState(userId).disabledComponents;
460     }
461 
setEnabledComponents(ArraySet<String> components, int userId)462     void setEnabledComponents(ArraySet<String> components, int userId) {
463         modifyUserState(userId).enabledComponents = components;
464     }
465 
setDisabledComponents(ArraySet<String> components, int userId)466     void setDisabledComponents(ArraySet<String> components, int userId) {
467         modifyUserState(userId).disabledComponents = components;
468     }
469 
setEnabledComponentsCopy(ArraySet<String> components, int userId)470     void setEnabledComponentsCopy(ArraySet<String> components, int userId) {
471         modifyUserState(userId).enabledComponents = components != null
472                 ? new ArraySet<String>(components) : null;
473     }
474 
setDisabledComponentsCopy(ArraySet<String> components, int userId)475     void setDisabledComponentsCopy(ArraySet<String> components, int userId) {
476         modifyUserState(userId).disabledComponents = components != null
477                 ? new ArraySet<String>(components) : null;
478     }
479 
modifyUserStateComponents(int userId, boolean disabled, boolean enabled)480     PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) {
481         PackageUserState state = modifyUserState(userId);
482         if (disabled && state.disabledComponents == null) {
483             state.disabledComponents = new ArraySet<String>(1);
484         }
485         if (enabled && state.enabledComponents == null) {
486             state.enabledComponents = new ArraySet<String>(1);
487         }
488         return state;
489     }
490 
addDisabledComponent(String componentClassName, int userId)491     void addDisabledComponent(String componentClassName, int userId) {
492         modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName);
493     }
494 
addEnabledComponent(String componentClassName, int userId)495     void addEnabledComponent(String componentClassName, int userId) {
496         modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName);
497     }
498 
enableComponentLPw(String componentClassName, int userId)499     boolean enableComponentLPw(String componentClassName, int userId) {
500         PackageUserState state = modifyUserStateComponents(userId, false, true);
501         boolean changed = state.disabledComponents != null
502                 ? state.disabledComponents.remove(componentClassName) : false;
503         changed |= state.enabledComponents.add(componentClassName);
504         return changed;
505     }
506 
disableComponentLPw(String componentClassName, int userId)507     boolean disableComponentLPw(String componentClassName, int userId) {
508         PackageUserState state = modifyUserStateComponents(userId, true, false);
509         boolean changed = state.enabledComponents != null
510                 ? state.enabledComponents.remove(componentClassName) : false;
511         changed |= state.disabledComponents.add(componentClassName);
512         return changed;
513     }
514 
restoreComponentLPw(String componentClassName, int userId)515     boolean restoreComponentLPw(String componentClassName, int userId) {
516         PackageUserState state = modifyUserStateComponents(userId, true, true);
517         boolean changed = state.disabledComponents != null
518                 ? state.disabledComponents.remove(componentClassName) : false;
519         changed |= state.enabledComponents != null
520                 ? state.enabledComponents.remove(componentClassName) : false;
521         return changed;
522     }
523 
getCurrentEnabledStateLPr(String componentName, int userId)524     int getCurrentEnabledStateLPr(String componentName, int userId) {
525         PackageUserState state = readUserState(userId);
526         if (state.enabledComponents != null && state.enabledComponents.contains(componentName)) {
527             return COMPONENT_ENABLED_STATE_ENABLED;
528         } else if (state.disabledComponents != null
529                 && state.disabledComponents.contains(componentName)) {
530             return COMPONENT_ENABLED_STATE_DISABLED;
531         } else {
532             return COMPONENT_ENABLED_STATE_DEFAULT;
533         }
534     }
535 
removeUser(int userId)536     void removeUser(int userId) {
537         userState.delete(userId);
538     }
539 
getNotInstalledUserIds()540     public int[] getNotInstalledUserIds() {
541         int count = 0;
542         int userStateCount = userState.size();
543         for (int i = 0; i < userStateCount; i++) {
544             if (userState.valueAt(i).installed == false) {
545                 count++;
546             }
547         }
548         if (count == 0) return EMPTY_INT_ARRAY;
549         int[] excludedUserIds = new int[count];
550         int idx = 0;
551         for (int i = 0; i < userStateCount; i++) {
552             if (userState.valueAt(i).installed == false) {
553                 excludedUserIds[idx++] = userState.keyAt(i);
554             }
555         }
556         return excludedUserIds;
557     }
558 
getIntentFilterVerificationInfo()559     IntentFilterVerificationInfo getIntentFilterVerificationInfo() {
560         return verificationInfo;
561     }
562 
setIntentFilterVerificationInfo(IntentFilterVerificationInfo info)563     void setIntentFilterVerificationInfo(IntentFilterVerificationInfo info) {
564         verificationInfo = info;
565     }
566 
567     // Returns a packed value as a long:
568     //
569     // high 'int'-sized word: link status: undefined/ask/never/always.
570     // low 'int'-sized word: relative priority among 'always' results.
getDomainVerificationStatusForUser(int userId)571     long getDomainVerificationStatusForUser(int userId) {
572         PackageUserState state = readUserState(userId);
573         long result = (long) state.appLinkGeneration;
574         result |= ((long) state.domainVerificationStatus) << 32;
575         return result;
576     }
577 
setDomainVerificationStatusForUser(final int status, int generation, int userId)578     void setDomainVerificationStatusForUser(final int status, int generation, int userId) {
579         PackageUserState state = modifyUserState(userId);
580         state.domainVerificationStatus = status;
581         if (status == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
582             state.appLinkGeneration = generation;
583         }
584     }
585 
clearDomainVerificationStatusForUser(int userId)586     void clearDomainVerificationStatusForUser(int userId) {
587         modifyUserState(userId).domainVerificationStatus =
588                 PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
589     }
590 
writeUsersInfoToProto(ProtoOutputStream proto, long fieldId)591     protected void writeUsersInfoToProto(ProtoOutputStream proto, long fieldId) {
592         int count = userState.size();
593         for (int i = 0; i < count; i++) {
594             final long userToken = proto.start(fieldId);
595             final int userId = userState.keyAt(i);
596             final PackageUserState state = userState.valueAt(i);
597             proto.write(PackageProto.UserInfoProto.ID, userId);
598             final int installType;
599             if (state.instantApp) {
600                 installType = PackageProto.UserInfoProto.INSTANT_APP_INSTALL;
601             } else if (state.installed) {
602                 installType = PackageProto.UserInfoProto.FULL_APP_INSTALL;
603             } else {
604                 installType = PackageProto.UserInfoProto.NOT_INSTALLED_FOR_USER;
605             }
606             proto.write(PackageProto.UserInfoProto.INSTALL_TYPE, installType);
607             proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.hidden);
608             proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended);
609             proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.stopped);
610             proto.write(PackageProto.UserInfoProto.IS_LAUNCHED, !state.notLaunched);
611             proto.write(PackageProto.UserInfoProto.ENABLED_STATE, state.enabled);
612             proto.write(
613                     PackageProto.UserInfoProto.LAST_DISABLED_APP_CALLER,
614                     state.lastDisableAppCaller);
615             proto.end(userToken);
616         }
617     }
618 }
619