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