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