Home | History | Annotate | Download | only in packageinstaller
      1 /*
      2 **
      3 ** Copyright 2007, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 package com.android.packageinstaller;
     18 
     19 import android.app.Activity;
     20 import android.app.ActivityManagerNative;
     21 import android.app.AlertDialog;
     22 import android.app.Dialog;
     23 import android.content.Context;
     24 import android.content.DialogInterface;
     25 import android.content.DialogInterface.OnCancelListener;
     26 import android.content.Intent;
     27 import android.content.SharedPreferences;
     28 import android.content.pm.ApplicationInfo;
     29 import android.content.pm.ManifestDigest;
     30 import android.content.pm.PackageInfo;
     31 import android.content.pm.PackageInstaller;
     32 import android.content.pm.PackageManager;
     33 import android.content.pm.PackageManager.NameNotFoundException;
     34 import android.content.pm.PackageParser;
     35 import android.content.pm.PackageUserState;
     36 import android.content.pm.ResolveInfo;
     37 import android.content.pm.VerificationParams;
     38 import android.net.Uri;
     39 import android.os.Bundle;
     40 import android.os.SystemClock;
     41 import android.os.UserManager;
     42 import android.provider.Settings;
     43 import android.support.v4.view.ViewPager;
     44 import android.util.Log;
     45 import android.view.LayoutInflater;
     46 import android.view.View;
     47 import android.view.View.OnClickListener;
     48 import android.view.ViewGroup;
     49 import android.widget.AppSecurityPermissions;
     50 import android.widget.Button;
     51 import android.widget.TabHost;
     52 import android.widget.TextView;
     53 
     54 import java.io.File;
     55 import java.util.List;
     56 
     57 /*
     58  * This activity is launched when a new application is installed via side loading
     59  * The package is first parsed and the user is notified of parse errors via a dialog.
     60  * If the package is successfully parsed, the user is notified to turn on the install unknown
     61  * applications setting. A memory check is made at this point and the user is notified of out
     62  * of memory conditions if any. If the package is already existing on the device,
     63  * a confirmation dialog (to replace the existing package) is presented to the user.
     64  * Based on the user response the package is then installed by launching InstallAppConfirm
     65  * sub activity. All state transitions are handled in this activity
     66  */
     67 public class PackageInstallerActivity extends Activity implements OnCancelListener, OnClickListener {
     68     private static final String TAG = "PackageInstaller";
     69 
     70     private int mSessionId = -1;
     71     private Uri mPackageURI;
     72     private Uri mOriginatingURI;
     73     private Uri mReferrerURI;
     74     private int mOriginatingUid = VerificationParams.NO_UID;
     75     private ManifestDigest mPkgDigest;
     76 
     77     private boolean localLOGV = false;
     78     PackageManager mPm;
     79     UserManager mUserManager;
     80     PackageInstaller mInstaller;
     81     PackageInfo mPkgInfo;
     82     ApplicationInfo mSourceInfo;
     83 
     84     // ApplicationInfo object primarily used for already existing applications
     85     private ApplicationInfo mAppInfo = null;
     86 
     87     private InstallFlowAnalytics mInstallFlowAnalytics;
     88 
     89     // View for install progress
     90     View mInstallConfirm;
     91     // Buttons to indicate user acceptance
     92     private Button mOk;
     93     private Button mCancel;
     94     CaffeinatedScrollView mScrollView = null;
     95     private boolean mOkCanInstall = false;
     96 
     97     static final String PREFS_ALLOWED_SOURCES = "allowed_sources";
     98 
     99     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
    100 
    101     private static final String TAB_ID_ALL = "all";
    102     private static final String TAB_ID_NEW = "new";
    103 
    104     // Dialog identifiers used in showDialog
    105     private static final int DLG_BASE = 0;
    106     private static final int DLG_UNKNOWN_SOURCES = DLG_BASE + 1;
    107     private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2;
    108     private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3;
    109     private static final int DLG_INSTALL_ERROR = DLG_BASE + 4;
    110     private static final int DLG_ALLOW_SOURCE = DLG_BASE + 5;
    111     private static final int DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES = DLG_BASE + 6;
    112 
    113     private void startInstallConfirm() {
    114         TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
    115         tabHost.setup();
    116         ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
    117         TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager);
    118         adapter.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
    119             @Override
    120             public void onTabChanged(String tabId) {
    121                 if (TAB_ID_ALL.equals(tabId)) {
    122                     mInstallFlowAnalytics.setAllPermissionsDisplayed(true);
    123                 } else if (TAB_ID_NEW.equals(tabId)) {
    124                     mInstallFlowAnalytics.setNewPermissionsDisplayed(true);
    125                 }
    126             }
    127         });
    128 
    129         boolean permVisible = false;
    130         mScrollView = null;
    131         mOkCanInstall = false;
    132         int msg = 0;
    133         if (mPkgInfo != null) {
    134             AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);
    135             final int NP = perms.getPermissionCount(AppSecurityPermissions.WHICH_PERSONAL);
    136             final int ND = perms.getPermissionCount(AppSecurityPermissions.WHICH_DEVICE);
    137             if (mAppInfo != null) {
    138                 msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
    139                         ? R.string.install_confirm_question_update_system
    140                         : R.string.install_confirm_question_update;
    141                 mScrollView = new CaffeinatedScrollView(this);
    142                 mScrollView.setFillViewport(true);
    143                 boolean newPermissionsFound =
    144                         (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0);
    145                 mInstallFlowAnalytics.setNewPermissionsFound(newPermissionsFound);
    146                 if (newPermissionsFound) {
    147                     permVisible = true;
    148                     mScrollView.addView(perms.getPermissionsView(
    149                             AppSecurityPermissions.WHICH_NEW));
    150                 } else {
    151                     LayoutInflater inflater = (LayoutInflater)getSystemService(
    152                             Context.LAYOUT_INFLATER_SERVICE);
    153                     TextView label = (TextView)inflater.inflate(R.layout.label, null);
    154                     label.setText(R.string.no_new_perms);
    155                     mScrollView.addView(label);
    156                 }
    157                 adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator(
    158                         getText(R.string.newPerms)), mScrollView);
    159             } else  {
    160                 findViewById(R.id.tabscontainer).setVisibility(View.GONE);
    161                 findViewById(R.id.divider).setVisibility(View.VISIBLE);
    162             }
    163             if (NP > 0 || ND > 0) {
    164                 permVisible = true;
    165                 LayoutInflater inflater = (LayoutInflater)getSystemService(
    166                         Context.LAYOUT_INFLATER_SERVICE);
    167                 View root = inflater.inflate(R.layout.permissions_list, null);
    168                 if (mScrollView == null) {
    169                     mScrollView = (CaffeinatedScrollView)root.findViewById(R.id.scrollview);
    170                 }
    171                 if (NP > 0) {
    172                     ((ViewGroup)root.findViewById(R.id.privacylist)).addView(
    173                             perms.getPermissionsView(AppSecurityPermissions.WHICH_PERSONAL));
    174                 } else {
    175                     root.findViewById(R.id.privacylist).setVisibility(View.GONE);
    176                 }
    177                 if (ND > 0) {
    178                     ((ViewGroup)root.findViewById(R.id.devicelist)).addView(
    179                             perms.getPermissionsView(AppSecurityPermissions.WHICH_DEVICE));
    180                 } else {
    181                     root.findViewById(R.id.devicelist).setVisibility(View.GONE);
    182                 }
    183                 adapter.addTab(tabHost.newTabSpec(TAB_ID_ALL).setIndicator(
    184                         getText(R.string.allPerms)), root);
    185             }
    186         }
    187         mInstallFlowAnalytics.setPermissionsDisplayed(permVisible);
    188         if (!permVisible) {
    189             if (mAppInfo != null) {
    190                 // This is an update to an application, but there are no
    191                 // permissions at all.
    192                 msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
    193                         ? R.string.install_confirm_question_update_system_no_perms
    194                         : R.string.install_confirm_question_update_no_perms;
    195             } else {
    196                 // This is a new application with no permissions.
    197                 msg = R.string.install_confirm_question_no_perms;
    198             }
    199             tabHost.setVisibility(View.GONE);
    200             mInstallFlowAnalytics.setAllPermissionsDisplayed(false);
    201             mInstallFlowAnalytics.setNewPermissionsDisplayed(false);
    202             findViewById(R.id.filler).setVisibility(View.VISIBLE);
    203             findViewById(R.id.divider).setVisibility(View.GONE);
    204             mScrollView = null;
    205         }
    206         if (msg != 0) {
    207             ((TextView)findViewById(R.id.install_confirm_question)).setText(msg);
    208         }
    209         mInstallConfirm.setVisibility(View.VISIBLE);
    210         mOk = (Button)findViewById(R.id.ok_button);
    211         mCancel = (Button)findViewById(R.id.cancel_button);
    212         mOk.setOnClickListener(this);
    213         mCancel.setOnClickListener(this);
    214         if (mScrollView == null) {
    215             // There is nothing to scroll view, so the ok button is immediately
    216             // set to install.
    217             mOk.setText(R.string.install);
    218             mOkCanInstall = true;
    219         } else {
    220             mScrollView.setFullScrollAction(new Runnable() {
    221                 @Override
    222                 public void run() {
    223                     mOk.setText(R.string.install);
    224                     mOkCanInstall = true;
    225                 }
    226             });
    227         }
    228     }
    229 
    230     private void showDialogInner(int id) {
    231         // TODO better fix for this? Remove dialog so that it gets created again
    232         removeDialog(id);
    233         showDialog(id);
    234     }
    235 
    236     @Override
    237     public Dialog onCreateDialog(int id, Bundle bundle) {
    238         switch (id) {
    239         case DLG_UNKNOWN_SOURCES:
    240             return new AlertDialog.Builder(this)
    241                     .setTitle(R.string.unknown_apps_dlg_title)
    242                     .setMessage(R.string.unknown_apps_dlg_text)
    243                     .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    244                         public void onClick(DialogInterface dialog, int which) {
    245                             Log.i(TAG, "Finishing off activity so that user can navigate to settings manually");
    246                             finish();
    247                         }})
    248                     .setPositiveButton(R.string.settings, new DialogInterface.OnClickListener() {
    249                         public void onClick(DialogInterface dialog, int which) {
    250                             Log.i(TAG, "Launching settings");
    251                             launchSettingsAppAndFinish();
    252                         }
    253                     })
    254                     .setOnCancelListener(this)
    255                     .create();
    256         case DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES:
    257             return new AlertDialog.Builder(this)
    258                     .setTitle(R.string.unknown_apps_dlg_title)
    259                     .setMessage(R.string.unknown_apps_admin_dlg_text)
    260                     .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
    261                         public void onClick(DialogInterface dialog, int which) {
    262                             finish();
    263                         }
    264                     })
    265                     .setOnCancelListener(this)
    266                     .create();
    267         case DLG_PACKAGE_ERROR :
    268             return new AlertDialog.Builder(this)
    269                     .setTitle(R.string.Parse_error_dlg_title)
    270                     .setMessage(R.string.Parse_error_dlg_text)
    271                     .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
    272                         public void onClick(DialogInterface dialog, int which) {
    273                             finish();
    274                         }
    275                     })
    276                     .setOnCancelListener(this)
    277                     .create();
    278         case DLG_OUT_OF_SPACE:
    279             // Guaranteed not to be null. will default to package name if not set by app
    280             CharSequence appTitle = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
    281             String dlgText = getString(R.string.out_of_space_dlg_text,
    282                     appTitle.toString());
    283             return new AlertDialog.Builder(this)
    284                     .setTitle(R.string.out_of_space_dlg_title)
    285                     .setMessage(dlgText)
    286                     .setPositiveButton(R.string.manage_applications, new DialogInterface.OnClickListener() {
    287                         public void onClick(DialogInterface dialog, int which) {
    288                             //launch manage applications
    289                             Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE");
    290                             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    291                             startActivity(intent);
    292                             finish();
    293                         }
    294                     })
    295                     .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    296                         public void onClick(DialogInterface dialog, int which) {
    297                             Log.i(TAG, "Canceling installation");
    298                             finish();
    299                         }
    300                   })
    301                   .setOnCancelListener(this)
    302                   .create();
    303         case DLG_INSTALL_ERROR :
    304             // Guaranteed not to be null. will default to package name if not set by app
    305             CharSequence appTitle1 = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
    306             String dlgText1 = getString(R.string.install_failed_msg,
    307                     appTitle1.toString());
    308             return new AlertDialog.Builder(this)
    309                     .setTitle(R.string.install_failed)
    310                     .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
    311                         public void onClick(DialogInterface dialog, int which) {
    312                             finish();
    313                         }
    314                     })
    315                     .setMessage(dlgText1)
    316                     .setOnCancelListener(this)
    317                     .create();
    318         case DLG_ALLOW_SOURCE:
    319             CharSequence appTitle2 = mPm.getApplicationLabel(mSourceInfo);
    320             String dlgText2 = getString(R.string.allow_source_dlg_text,
    321                     appTitle2.toString());
    322             return new AlertDialog.Builder(this)
    323                     .setTitle(R.string.allow_source_dlg_title)
    324                     .setMessage(dlgText2)
    325                     .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    326                         public void onClick(DialogInterface dialog, int which) {
    327                             setResult(RESULT_CANCELED);
    328                             finish();
    329                         }})
    330                     .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
    331                         public void onClick(DialogInterface dialog, int which) {
    332                             SharedPreferences prefs = getSharedPreferences(PREFS_ALLOWED_SOURCES,
    333                                     Context.MODE_PRIVATE);
    334                             prefs.edit().putBoolean(mSourceInfo.packageName, true).apply();
    335                             startInstallConfirm();
    336                         }
    337                     })
    338                     .setOnCancelListener(this)
    339                     .create();
    340        }
    341        return null;
    342    }
    343 
    344     private void launchSettingsAppAndFinish() {
    345         // Create an intent to launch SettingsTwo activity
    346         Intent launchSettingsIntent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
    347         launchSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    348         startActivity(launchSettingsIntent);
    349         finish();
    350     }
    351 
    352     private boolean isInstallRequestFromUnknownSource(Intent intent) {
    353         String callerPackage = getCallingPackage();
    354         if (callerPackage != null && intent.getBooleanExtra(
    355                 Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) {
    356             try {
    357                 mSourceInfo = mPm.getApplicationInfo(callerPackage, 0);
    358                 if (mSourceInfo != null) {
    359                     if ((mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
    360                         // Privileged apps are not considered an unknown source.
    361                         return false;
    362                     }
    363                 }
    364             } catch (NameNotFoundException e) {
    365             }
    366         }
    367 
    368         return true;
    369     }
    370 
    371     private boolean isVerifyAppsEnabled() {
    372         if (mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS)) {
    373             return true;
    374         }
    375         return Settings.Global.getInt(getContentResolver(),
    376                 Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) > 0;
    377     }
    378 
    379     private boolean isAppVerifierInstalled() {
    380         final PackageManager pm = getPackageManager();
    381         final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
    382         verification.setType(PACKAGE_MIME_TYPE);
    383         verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    384         final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(verification, 0);
    385         return (receivers.size() > 0) ? true : false;
    386     }
    387 
    388     /**
    389      * @return whether unknown sources is enabled by user in Settings
    390      */
    391     private boolean isUnknownSourcesEnabled() {
    392         return Settings.Secure.getInt(getContentResolver(),
    393                 Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0;
    394     }
    395 
    396     /**
    397      * @return whether the device admin restricts installation from unknown sources
    398      */
    399     private boolean isUnknownSourcesAllowedByAdmin() {
    400         return !mUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
    401     }
    402 
    403     private void initiateInstall() {
    404         String pkgName = mPkgInfo.packageName;
    405         // Check if there is already a package on the device with this name
    406         // but it has been renamed to something else.
    407         String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
    408         if (oldName != null && oldName.length > 0 && oldName[0] != null) {
    409             pkgName = oldName[0];
    410             mPkgInfo.packageName = pkgName;
    411             mPkgInfo.applicationInfo.packageName = pkgName;
    412         }
    413         // Check if package is already installed. display confirmation dialog if replacing pkg
    414         try {
    415             // This is a little convoluted because we want to get all uninstalled
    416             // apps, but this may include apps with just data, and if it is just
    417             // data we still want to count it as "installed".
    418             mAppInfo = mPm.getApplicationInfo(pkgName,
    419                     PackageManager.GET_UNINSTALLED_PACKAGES);
    420             if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
    421                 mAppInfo = null;
    422             }
    423         } catch (NameNotFoundException e) {
    424             mAppInfo = null;
    425         }
    426 
    427         mInstallFlowAnalytics.setReplace(mAppInfo != null);
    428         mInstallFlowAnalytics.setSystemApp(
    429                 (mAppInfo != null) && ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0));
    430 
    431         startInstallConfirm();
    432     }
    433 
    434     void setPmResult(int pmResult) {
    435         Intent result = new Intent();
    436         result.putExtra(Intent.EXTRA_INSTALL_RESULT, pmResult);
    437         setResult(pmResult == PackageManager.INSTALL_SUCCEEDED
    438                 ? RESULT_OK : RESULT_FIRST_USER, result);
    439     }
    440 
    441     @Override
    442     protected void onCreate(Bundle icicle) {
    443         super.onCreate(icicle);
    444 
    445         mPm = getPackageManager();
    446         mInstaller = mPm.getPackageInstaller();
    447         mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
    448 
    449         final Intent intent = getIntent();
    450         if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
    451             final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
    452             final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
    453             if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {
    454                 Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
    455                 finish();
    456                 return;
    457             }
    458 
    459             mSessionId = sessionId;
    460             mPackageURI = Uri.fromFile(new File(info.resolvedBaseCodePath));
    461             mOriginatingURI = null;
    462             mReferrerURI = null;
    463         } else {
    464             mSessionId = -1;
    465             mPackageURI = intent.getData();
    466             mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
    467             mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
    468         }
    469 
    470         final boolean unknownSourcesAllowedByAdmin = isUnknownSourcesAllowedByAdmin();
    471         final boolean unknownSourcesAllowedByUser = isUnknownSourcesEnabled();
    472 
    473         boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
    474         mInstallFlowAnalytics = new InstallFlowAnalytics();
    475         mInstallFlowAnalytics.setContext(this);
    476         mInstallFlowAnalytics.setStartTimestampMillis(SystemClock.elapsedRealtime());
    477         mInstallFlowAnalytics.setInstallsFromUnknownSourcesPermitted(unknownSourcesAllowedByAdmin
    478                 && unknownSourcesAllowedByUser);
    479         mInstallFlowAnalytics.setInstallRequestFromUnknownSource(requestFromUnknownSource);
    480         mInstallFlowAnalytics.setVerifyAppsEnabled(isVerifyAppsEnabled());
    481         mInstallFlowAnalytics.setAppVerifierInstalled(isAppVerifierInstalled());
    482         mInstallFlowAnalytics.setPackageUri(mPackageURI.toString());
    483 
    484         final String scheme = mPackageURI.getScheme();
    485         if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {
    486             Log.w(TAG, "Unsupported scheme " + scheme);
    487             setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
    488             mInstallFlowAnalytics.setFlowFinished(
    489                     InstallFlowAnalytics.RESULT_FAILED_UNSUPPORTED_SCHEME);
    490             finish();
    491             return;
    492         }
    493 
    494         final PackageUtil.AppSnippet as;
    495         if ("package".equals(mPackageURI.getScheme())) {
    496             mInstallFlowAnalytics.setFileUri(false);
    497             try {
    498                 mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(),
    499                         PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES);
    500             } catch (NameNotFoundException e) {
    501             }
    502             if (mPkgInfo == null) {
    503                 Log.w(TAG, "Requested package " + mPackageURI.getScheme()
    504                         + " not available. Discontinuing installation");
    505                 showDialogInner(DLG_PACKAGE_ERROR);
    506                 setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
    507                 mInstallFlowAnalytics.setPackageInfoObtained();
    508                 mInstallFlowAnalytics.setFlowFinished(
    509                         InstallFlowAnalytics.RESULT_FAILED_PACKAGE_MISSING);
    510                 return;
    511             }
    512             as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo),
    513                     mPm.getApplicationIcon(mPkgInfo.applicationInfo));
    514         } else {
    515             mInstallFlowAnalytics.setFileUri(true);
    516             final File sourceFile = new File(mPackageURI.getPath());
    517             PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);
    518 
    519             // Check for parse errors
    520             if (parsed == null) {
    521                 Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
    522                 showDialogInner(DLG_PACKAGE_ERROR);
    523                 setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
    524                 mInstallFlowAnalytics.setPackageInfoObtained();
    525                 mInstallFlowAnalytics.setFlowFinished(
    526                         InstallFlowAnalytics.RESULT_FAILED_TO_GET_PACKAGE_INFO);
    527                 return;
    528             }
    529             mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
    530                     PackageManager.GET_PERMISSIONS, 0, 0, null,
    531                     new PackageUserState());
    532             mPkgDigest = parsed.manifestDigest;
    533             as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
    534         }
    535         mInstallFlowAnalytics.setPackageInfoObtained();
    536 
    537         //set view
    538         setContentView(R.layout.install_start);
    539         mInstallConfirm = findViewById(R.id.install_confirm_panel);
    540         mInstallConfirm.setVisibility(View.INVISIBLE);
    541         PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
    542 
    543         mOriginatingUid = getOriginatingUid(intent);
    544 
    545         // Block the install attempt on the Unknown Sources setting if necessary.
    546         if (!requestFromUnknownSource) {
    547             initiateInstall();
    548             return;
    549         }
    550 
    551         // If the admin prohibits it, or we're running in a managed profile, just show error
    552         // and exit. Otherwise show an option to take the user to Settings to change the setting.
    553         final boolean isManagedProfile = mUserManager.isManagedProfile();
    554         if (!unknownSourcesAllowedByAdmin
    555                 || (!unknownSourcesAllowedByUser && isManagedProfile)) {
    556             showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES);
    557             mInstallFlowAnalytics.setFlowFinished(
    558                     InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
    559         } else if (!unknownSourcesAllowedByUser) {
    560             // Ask user to enable setting first
    561             showDialogInner(DLG_UNKNOWN_SOURCES);
    562             mInstallFlowAnalytics.setFlowFinished(
    563                     InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
    564         } else {
    565             initiateInstall();
    566         }
    567     }
    568 
    569     /** Get the ApplicationInfo for the calling package, if available */
    570     private ApplicationInfo getSourceInfo() {
    571         String callingPackage = getCallingPackage();
    572         if (callingPackage != null) {
    573             try {
    574                 return mPm.getApplicationInfo(callingPackage, 0);
    575             } catch (NameNotFoundException ex) {
    576                 // ignore
    577             }
    578         }
    579         return null;
    580     }
    581 
    582 
    583     /** Get the originating uid if possible, or VerificationParams.NO_UID if not available */
    584     private int getOriginatingUid(Intent intent) {
    585         // The originating uid from the intent. We only trust/use this if it comes from a
    586         // system application
    587         int uidFromIntent = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,
    588                 VerificationParams.NO_UID);
    589 
    590         // Get the source info from the calling package, if available. This will be the
    591         // definitive calling package, but it only works if the intent was started using
    592         // startActivityForResult,
    593         ApplicationInfo sourceInfo = getSourceInfo();
    594         if (sourceInfo != null) {
    595             if (uidFromIntent != VerificationParams.NO_UID &&
    596                     (mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
    597                 return uidFromIntent;
    598 
    599             }
    600             // We either didn't get a uid in the intent, or we don't trust it. Use the
    601             // uid of the calling package instead.
    602             return sourceInfo.uid;
    603         }
    604 
    605         // We couldn't get the specific calling package. Let's get the uid instead
    606         int callingUid;
    607         try {
    608             callingUid = ActivityManagerNative.getDefault()
    609                     .getLaunchedFromUid(getActivityToken());
    610         } catch (android.os.RemoteException ex) {
    611             Log.w(TAG, "Could not determine the launching uid.");
    612             // nothing else we can do
    613             return VerificationParams.NO_UID;
    614         }
    615 
    616         // If we got a uid from the intent, we need to verify that the caller is a
    617         // privileged system package before we use it
    618         if (uidFromIntent != VerificationParams.NO_UID) {
    619             String[] callingPackages = mPm.getPackagesForUid(callingUid);
    620             if (callingPackages != null) {
    621                 for (String packageName: callingPackages) {
    622                     try {
    623                         ApplicationInfo applicationInfo =
    624                                 mPm.getApplicationInfo(packageName, 0);
    625 
    626                         if ((applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
    627                             return uidFromIntent;
    628                         }
    629                     } catch (NameNotFoundException ex) {
    630                         // ignore it, and try the next package
    631                     }
    632                 }
    633             }
    634         }
    635         // We either didn't get a uid from the intent, or we don't trust it. Use the
    636         // calling uid instead.
    637         return callingUid;
    638     }
    639 
    640     @Override
    641     public void onBackPressed() {
    642         if (mSessionId != -1) {
    643             mInstaller.setPermissionsResult(mSessionId, false);
    644         }
    645         mInstallFlowAnalytics.setFlowFinished(
    646                 InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);
    647         super.onBackPressed();
    648     }
    649 
    650     // Generic handling when pressing back key
    651     public void onCancel(DialogInterface dialog) {
    652         finish();
    653     }
    654 
    655     public void onClick(View v) {
    656         if (v == mOk) {
    657             if (mOkCanInstall || mScrollView == null) {
    658                 mInstallFlowAnalytics.setInstallButtonClicked();
    659                 if (mSessionId != -1) {
    660                     mInstaller.setPermissionsResult(mSessionId, true);
    661 
    662                     // We're only confirming permissions, so we don't really know how the
    663                     // story ends; assume success.
    664                     mInstallFlowAnalytics.setFlowFinishedWithPackageManagerResult(
    665                             PackageManager.INSTALL_SUCCEEDED);
    666                 } else {
    667                     // Start subactivity to actually install the application
    668                     Intent newIntent = new Intent();
    669                     newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
    670                             mPkgInfo.applicationInfo);
    671                     newIntent.setData(mPackageURI);
    672                     newIntent.setClass(this, InstallAppProgress.class);
    673                     newIntent.putExtra(InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest);
    674                     newIntent.putExtra(
    675                             InstallAppProgress.EXTRA_INSTALL_FLOW_ANALYTICS, mInstallFlowAnalytics);
    676                     String installerPackageName = getIntent().getStringExtra(
    677                             Intent.EXTRA_INSTALLER_PACKAGE_NAME);
    678                     if (mOriginatingURI != null) {
    679                         newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
    680                     }
    681                     if (mReferrerURI != null) {
    682                         newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
    683                     }
    684                     if (mOriginatingUid != VerificationParams.NO_UID) {
    685                         newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
    686                     }
    687                     if (installerPackageName != null) {
    688                         newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
    689                                 installerPackageName);
    690                     }
    691                     if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
    692                         newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
    693                         newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
    694                     }
    695                     if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
    696                     startActivity(newIntent);
    697                 }
    698                 finish();
    699             } else {
    700                 mScrollView.pageScroll(View.FOCUS_DOWN);
    701             }
    702         } else if(v == mCancel) {
    703             // Cancel and finish
    704             setResult(RESULT_CANCELED);
    705             if (mSessionId != -1) {
    706                 mInstaller.setPermissionsResult(mSessionId, false);
    707             }
    708             mInstallFlowAnalytics.setFlowFinished(
    709                     InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);
    710             finish();
    711         }
    712     }
    713 }
    714