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