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