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.util.Slog;
21 
22 import com.android.internal.util.Preconditions;
23 
24 import org.json.JSONException;
25 import org.json.JSONObject;
26 import org.xmlpull.v1.XmlPullParserException;
27 import org.xmlpull.v1.XmlSerializer;
28 
29 import java.io.IOException;
30 
31 /**
32  * All methods should be guarded by {@code #mShortcutUser.mService.mLock}.
33  */
34 abstract class ShortcutPackageItem {
35     private static final String TAG = ShortcutService.TAG;
36     private static final String KEY_NAME = "name";
37 
38     private final int mPackageUserId;
39     private final String mPackageName;
40 
41     private final ShortcutPackageInfo mPackageInfo;
42 
43     protected ShortcutUser mShortcutUser;
44 
ShortcutPackageItem(@onNull ShortcutUser shortcutUser, int packageUserId, @NonNull String packageName, @NonNull ShortcutPackageInfo packageInfo)45     protected ShortcutPackageItem(@NonNull ShortcutUser shortcutUser,
46             int packageUserId, @NonNull String packageName,
47             @NonNull ShortcutPackageInfo packageInfo) {
48         mShortcutUser = shortcutUser;
49         mPackageUserId = packageUserId;
50         mPackageName = Preconditions.checkStringNotEmpty(packageName);
51         mPackageInfo = Preconditions.checkNotNull(packageInfo);
52     }
53 
54     /**
55      * Change the parent {@link ShortcutUser}.  Need it in the restore code.
56      */
replaceUser(ShortcutUser user)57     public void replaceUser(ShortcutUser user) {
58         mShortcutUser = user;
59     }
60 
getUser()61     public ShortcutUser getUser() {
62         return mShortcutUser;
63     }
64 
65     /**
66      * ID of the user who actually has this package running on.  For {@link ShortcutPackage},
67      * this is the same thing as {@link #getOwnerUserId}, but if it's a {@link ShortcutLauncher} and
68      * {@link #getOwnerUserId} is of work profile, then this ID is of the primary user.
69      */
getPackageUserId()70     public int getPackageUserId() {
71         return mPackageUserId;
72     }
73 
74     /**
75      * ID of the user who sees the shortcuts from this instance.
76      */
getOwnerUserId()77     public abstract int getOwnerUserId();
78 
79     @NonNull
getPackageName()80     public String getPackageName() {
81         return mPackageName;
82     }
83 
getPackageInfo()84     public ShortcutPackageInfo getPackageInfo() {
85         return mPackageInfo;
86     }
87 
refreshPackageSignatureAndSave()88     public void refreshPackageSignatureAndSave() {
89         if (mPackageInfo.isShadow()) {
90             return; // Don't refresh for shadow user.
91         }
92         final ShortcutService s = mShortcutUser.mService;
93         mPackageInfo.refreshSignature(s, this);
94         s.scheduleSaveUser(getOwnerUserId());
95     }
96 
attemptToRestoreIfNeededAndSave()97     public void attemptToRestoreIfNeededAndSave() {
98         if (!mPackageInfo.isShadow()) {
99             return; // Already installed, nothing to do.
100         }
101         final ShortcutService s = mShortcutUser.mService;
102         if (!s.isPackageInstalled(mPackageName, mPackageUserId)) {
103             if (ShortcutService.DEBUG) {
104                 Slog.d(TAG, String.format("Package still not installed: %s user=%d",
105                         mPackageName, mPackageUserId));
106             }
107             return; // Not installed, no need to restore yet.
108         }
109         boolean blockRestore = false;
110         if (!mPackageInfo.hasSignatures()) {
111             s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId
112                     + " but signatures not found in the restore data.");
113             blockRestore = true;
114         }
115         if (!blockRestore) {
116             final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
117             if (!mPackageInfo.canRestoreTo(s, pi)) {
118                 // Package is now installed, but can't restore.  Let the subclass do the cleanup.
119                 blockRestore = true;
120             }
121         }
122         if (blockRestore) {
123             onRestoreBlocked();
124         } else {
125             if (ShortcutService.DEBUG) {
126                 Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName,
127                         mPackageUserId, getOwnerUserId()));
128             }
129 
130             onRestored();
131         }
132 
133         // Either way, it's no longer a shadow.
134         mPackageInfo.setShadow(false);
135 
136         s.scheduleSaveUser(mPackageUserId);
137     }
138 
139     /**
140      * Called when the new package can't be restored because it has a lower version number
141      * or different signatures.
142      */
onRestoreBlocked()143     protected abstract void onRestoreBlocked();
144 
145     /**
146      * Called when the new package is successfully restored.
147      */
onRestored()148     protected abstract void onRestored();
149 
saveToXml(@onNull XmlSerializer out, boolean forBackup)150     public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
151             throws IOException, XmlPullParserException;
152 
dumpCheckin(boolean clear)153     public JSONObject dumpCheckin(boolean clear) throws JSONException {
154         final JSONObject result = new JSONObject();
155         result.put(KEY_NAME, mPackageName);
156         return result;
157     }
158 
159     /**
160      * Verify various internal states.
161      */
verifyStates()162     public void verifyStates() {
163     }
164 }
165