• 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 
17 package com.android.packageinstaller;
18 
19 import android.Manifest;
20 import android.app.Activity;
21 import android.app.ActivityManager;
22 import android.app.AppGlobals;
23 import android.app.IActivityManager;
24 import android.content.Intent;
25 import android.content.pm.ApplicationInfo;
26 import android.content.pm.IPackageManager;
27 import android.content.pm.PackageInstaller;
28 import android.content.pm.PackageManager;
29 import android.net.Uri;
30 import android.os.Build;
31 import android.os.Bundle;
32 import android.os.RemoteException;
33 import android.support.annotation.Nullable;
34 import android.util.Log;
35 
36 import com.android.internal.annotations.VisibleForTesting;
37 
38 /**
39  * Select which activity is the first visible activity of the installation and forward the intent to
40  * it.
41  */
42 public class InstallStart extends Activity {
43     private static final String LOG_TAG = InstallStart.class.getSimpleName();
44 
45     private static final String SCHEME_CONTENT = "content";
46     private static final String DOWNLOADS_AUTHORITY = "downloads";
47     private IActivityManager mIActivityManager;
48     private IPackageManager mIPackageManager;
49     private boolean mAbortInstall = false;
50 
51     @Override
onCreate(@ullable Bundle savedInstanceState)52     protected void onCreate(@Nullable Bundle savedInstanceState) {
53         super.onCreate(savedInstanceState);
54         mIPackageManager = AppGlobals.getPackageManager();
55         Intent intent = getIntent();
56         String callingPackage = getCallingPackage();
57 
58         // If the activity was started via a PackageInstaller session, we retrieve the calling
59         // package from that session
60         int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
61         if (callingPackage == null && sessionId != -1) {
62             PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
63             PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
64             callingPackage = (sessionInfo != null) ? sessionInfo.getInstallerPackageName() : null;
65         }
66 
67         final ApplicationInfo sourceInfo = getSourceInfo(callingPackage);
68         final int originatingUid = getOriginatingUid(sourceInfo);
69         boolean isTrustedSource = false;
70         if (sourceInfo != null
71                 && (sourceInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
72             isTrustedSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false);
73         }
74 
75         if (!isTrustedSource && originatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
76             final int targetSdkVersion = getMaxTargetSdkVersionForUid(originatingUid);
77             if (targetSdkVersion < 0) {
78                 Log.w(LOG_TAG, "Cannot get target sdk version for uid " + originatingUid);
79                 // Invalid originating uid supplied. Abort install.
80                 mAbortInstall = true;
81             } else if (targetSdkVersion >= Build.VERSION_CODES.O && !declaresAppOpPermission(
82                     originatingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES)) {
83                 Log.e(LOG_TAG, "Requesting uid " + originatingUid + " needs to declare permission "
84                         + Manifest.permission.REQUEST_INSTALL_PACKAGES);
85                 mAbortInstall = true;
86             }
87         }
88         if (mAbortInstall) {
89             setResult(RESULT_CANCELED);
90             finish();
91             return;
92         }
93 
94         Intent nextActivity = new Intent(intent);
95         nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
96 
97         // The the installation source as the nextActivity thinks this activity is the source, hence
98         // set the originating UID and sourceInfo explicitly
99         nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_PACKAGE, callingPackage);
100         nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINAL_SOURCE_INFO, sourceInfo);
101         nextActivity.putExtra(Intent.EXTRA_ORIGINATING_UID, originatingUid);
102 
103         if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
104             nextActivity.setClass(this, PackageInstallerActivity.class);
105         } else {
106             Uri packageUri = intent.getData();
107 
108             if (packageUri == null) {
109                 // if there's nothing to do, quietly slip into the ether
110                 Intent result = new Intent();
111                 result.putExtra(Intent.EXTRA_INSTALL_RESULT,
112                         PackageManager.INSTALL_FAILED_INVALID_URI);
113                 setResult(RESULT_FIRST_USER, result);
114 
115                 nextActivity = null;
116             } else {
117                 if (packageUri.getScheme().equals(SCHEME_CONTENT)) {
118                     nextActivity.setClass(this, InstallStaging.class);
119                 } else {
120                     nextActivity.setClass(this, PackageInstallerActivity.class);
121                 }
122             }
123         }
124 
125         if (nextActivity != null) {
126             startActivity(nextActivity);
127         }
128         finish();
129     }
130 
declaresAppOpPermission(int uid, String permission)131     private boolean declaresAppOpPermission(int uid, String permission) {
132         try {
133             final String[] packages = mIPackageManager.getAppOpPermissionPackages(permission);
134             for (String packageName : packages) {
135                 try {
136                     if (uid == getPackageManager().getPackageUid(packageName, 0)) {
137                         return true;
138                     }
139                 } catch (PackageManager.NameNotFoundException e) {
140                     // Ignore and try the next package
141                 }
142             }
143         } catch (RemoteException rexc) {
144             // If remote package manager cannot be reached, install will likely fail anyway.
145         }
146         return false;
147     }
148 
getMaxTargetSdkVersionForUid(int uid)149     private int getMaxTargetSdkVersionForUid(int uid) {
150         final String[] packages = getPackageManager().getPackagesForUid(uid);
151         int targetSdkVersion = -1;
152         if (packages != null) {
153             for (String packageName : packages) {
154                 try {
155                     ApplicationInfo info = getPackageManager().getApplicationInfo(packageName, 0);
156                     targetSdkVersion = Math.max(targetSdkVersion, info.targetSdkVersion);
157                 } catch (PackageManager.NameNotFoundException e) {
158                     // Ignore and try the next package
159                 }
160             }
161         }
162         return targetSdkVersion;
163     }
164 
165     /**
166      * @return the ApplicationInfo for the installation source (the calling package), if available
167      */
getSourceInfo(@ullable String callingPackage)168     private ApplicationInfo getSourceInfo(@Nullable String callingPackage) {
169         if (callingPackage != null) {
170             try {
171                 return getPackageManager().getApplicationInfo(callingPackage, 0);
172             } catch (PackageManager.NameNotFoundException ex) {
173                 // ignore
174             }
175         }
176         return null;
177     }
178 
179     /**
180      * Get the originating uid if possible, or
181      * {@link android.content.pm.PackageInstaller.SessionParams#UID_UNKNOWN} if not available
182      *
183      * @param sourceInfo The source of this installation
184      * @return The UID of the installation source or UID_UNKNOWN
185      */
getOriginatingUid(@ullable ApplicationInfo sourceInfo)186     private int getOriginatingUid(@Nullable ApplicationInfo sourceInfo) {
187         // The originating uid from the intent. We only trust/use this if it comes from either
188         // the document manager app or the downloads provider
189         final int uidFromIntent = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
190                 PackageInstaller.SessionParams.UID_UNKNOWN);
191 
192         final int callingUid;
193         if (sourceInfo != null) {
194             callingUid = sourceInfo.uid;
195         } else {
196             try {
197                 callingUid = getIActivityManager()
198                         .getLaunchedFromUid(getActivityToken());
199             } catch (RemoteException ex) {
200                 // Cannot reach ActivityManager. Aborting install.
201                 Log.e(LOG_TAG, "Could not determine the launching uid.");
202                 mAbortInstall = true;
203                 return PackageInstaller.SessionParams.UID_UNKNOWN;
204             }
205         }
206         try {
207             if (mIPackageManager.checkUidPermission(Manifest.permission.MANAGE_DOCUMENTS,
208                     callingUid) == PackageManager.PERMISSION_GRANTED) {
209                 return uidFromIntent;
210             }
211         } catch (RemoteException rexc) {
212             // Ignore. Should not happen.
213         }
214         if (isSystemDownloadsProvider(callingUid)) {
215             return uidFromIntent;
216         }
217         // We don't trust uid from the intent. Use the calling uid instead.
218         return callingUid;
219     }
220 
isSystemDownloadsProvider(int uid)221     private boolean isSystemDownloadsProvider(int uid) {
222         final String downloadProviderPackage = getPackageManager().resolveContentProvider(
223                 DOWNLOADS_AUTHORITY, 0).getComponentName().getPackageName();
224         if (downloadProviderPackage == null) {
225             return false;
226         }
227         try {
228             ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(
229                     downloadProviderPackage, 0);
230             return (applicationInfo.isSystemApp() && uid == applicationInfo.uid);
231         } catch (PackageManager.NameNotFoundException ex) {
232             return false;
233         }
234     }
235 
getIActivityManager()236     private IActivityManager getIActivityManager() {
237         if (mIActivityManager == null) {
238             return ActivityManager.getService();
239         }
240         return mIActivityManager;
241     }
242 
243     @VisibleForTesting
injectIActivityManager(IActivityManager iActivityManager)244     void injectIActivityManager(IActivityManager iActivityManager) {
245         mIActivityManager = iActivityManager;
246     }
247 }
248