• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 package com.android.server.pm;
17 
18 import android.annotation.NonNull;
19 import android.content.pm.PackageInfo;
20 import android.content.pm.ShortcutInfo;
21 import android.util.AtomicFile;
22 import android.util.Slog;
23 
24 import com.android.internal.util.FastXmlSerializer;
25 import com.android.internal.util.Preconditions;
26 
27 import org.json.JSONException;
28 import org.json.JSONObject;
29 import org.xmlpull.v1.XmlPullParserException;
30 import org.xmlpull.v1.XmlSerializer;
31 
32 import java.io.BufferedOutputStream;
33 import java.io.File;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.nio.charset.StandardCharsets;
37 import java.util.Objects;
38 
39 /**
40  * All methods should be guarded by {@code #mShortcutUser.mService.mLock}.
41  */
42 abstract class ShortcutPackageItem {
43     private static final String TAG = ShortcutService.TAG;
44     private static final String KEY_NAME = "name";
45 
46     private final int mPackageUserId;
47     private final String mPackageName;
48 
49     private final ShortcutPackageInfo mPackageInfo;
50 
51     protected ShortcutUser mShortcutUser;
52 
ShortcutPackageItem(@onNull ShortcutUser shortcutUser, int packageUserId, @NonNull String packageName, @NonNull ShortcutPackageInfo packageInfo)53     protected ShortcutPackageItem(@NonNull ShortcutUser shortcutUser,
54             int packageUserId, @NonNull String packageName,
55             @NonNull ShortcutPackageInfo packageInfo) {
56         mShortcutUser = shortcutUser;
57         mPackageUserId = packageUserId;
58         mPackageName = Preconditions.checkStringNotEmpty(packageName);
59         mPackageInfo = Objects.requireNonNull(packageInfo);
60     }
61 
62     /**
63      * Change the parent {@link ShortcutUser}.  Need it in the restore code.
64      */
replaceUser(ShortcutUser user)65     public void replaceUser(ShortcutUser user) {
66         mShortcutUser = user;
67     }
68 
getUser()69     public ShortcutUser getUser() {
70         return mShortcutUser;
71     }
72 
73     /**
74      * ID of the user who actually has this package running on.  For {@link ShortcutPackage},
75      * this is the same thing as {@link #getOwnerUserId}, but if it's a {@link ShortcutLauncher} and
76      * {@link #getOwnerUserId} is of work profile, then this ID is of the primary user.
77      */
getPackageUserId()78     public int getPackageUserId() {
79         return mPackageUserId;
80     }
81 
82     /**
83      * ID of the user who sees the shortcuts from this instance.
84      */
getOwnerUserId()85     public abstract int getOwnerUserId();
86 
87     @NonNull
getPackageName()88     public String getPackageName() {
89         return mPackageName;
90     }
91 
getPackageInfo()92     public ShortcutPackageInfo getPackageInfo() {
93         return mPackageInfo;
94     }
95 
refreshPackageSignatureAndSave()96     public void refreshPackageSignatureAndSave() {
97         if (mPackageInfo.isShadow()) {
98             return; // Don't refresh for shadow user.
99         }
100         final ShortcutService s = mShortcutUser.mService;
101         mPackageInfo.refreshSignature(s, this);
102         s.scheduleSaveUser(getOwnerUserId());
103     }
104 
attemptToRestoreIfNeededAndSave()105     public void attemptToRestoreIfNeededAndSave() {
106         if (!mPackageInfo.isShadow()) {
107             return; // Already installed, nothing to do.
108         }
109         final ShortcutService s = mShortcutUser.mService;
110         if (!s.isPackageInstalled(mPackageName, mPackageUserId)) {
111             if (ShortcutService.DEBUG) {
112                 Slog.d(TAG, String.format("Package still not installed: %s/u%d",
113                         mPackageName, mPackageUserId));
114             }
115             return; // Not installed, no need to restore yet.
116         }
117         int restoreBlockReason;
118         long currentVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
119 
120         if (!mPackageInfo.hasSignatures()) {
121             s.wtf("Attempted to restore package " + mPackageName + "/u" + mPackageUserId
122                     + " but signatures not found in the restore data.");
123             restoreBlockReason = ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH;
124         } else {
125             final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
126             currentVersionCode = pi.getLongVersionCode();
127             restoreBlockReason = mPackageInfo.canRestoreTo(s, pi, canRestoreAnyVersion());
128         }
129 
130         if (ShortcutService.DEBUG) {
131             Slog.d(TAG, String.format("Restoring package: %s/u%d (version=%d) %s for u%d",
132                     mPackageName, mPackageUserId, currentVersionCode,
133                     ShortcutInfo.getDisabledReasonDebugString(restoreBlockReason),
134                     getOwnerUserId()));
135         }
136 
137         onRestored(restoreBlockReason);
138 
139         // Either way, it's no longer a shadow.
140         mPackageInfo.setShadow(false);
141 
142         s.scheduleSaveUser(mPackageUserId);
143     }
144 
canRestoreAnyVersion()145     protected abstract boolean canRestoreAnyVersion();
146 
onRestored(int restoreBlockReason)147     protected abstract void onRestored(int restoreBlockReason);
148 
saveToXml(@onNull XmlSerializer out, boolean forBackup)149     public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
150             throws IOException, XmlPullParserException;
151 
saveToFile(File path, boolean forBackup)152     public void saveToFile(File path, boolean forBackup) {
153         final AtomicFile file = new AtomicFile(path);
154         FileOutputStream os = null;
155         try {
156             os = file.startWrite();
157             final BufferedOutputStream bos = new BufferedOutputStream(os);
158 
159             // Write to XML
160             XmlSerializer itemOut = new FastXmlSerializer();
161             itemOut.setOutput(bos, StandardCharsets.UTF_8.name());
162             itemOut.startDocument(null, true);
163 
164             saveToXml(itemOut, forBackup);
165 
166             itemOut.endDocument();
167 
168             bos.flush();
169             os.flush();
170             file.finishWrite(os);
171         } catch (XmlPullParserException | IOException e) {
172             Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
173             file.failWrite(os);
174         }
175     }
176 
dumpCheckin(boolean clear)177     public JSONObject dumpCheckin(boolean clear) throws JSONException {
178         final JSONObject result = new JSONObject();
179         result.put(KEY_NAME, mPackageName);
180         return result;
181     }
182 
183     /**
184      * Verify various internal states.
185      */
verifyStates()186     public void verifyStates() {
187     }
188 }
189