B2G/gecko/toolkit/mozapps/extensions/XPIProvider.jsm
/**
     * Called to add the metadata for an add-on in one of the install locations
     * to the database. This can be called in three different cases. Either an
     * add-on has been dropped into the location from outside of Firefox, or
     * an add-on has been installed through the application, or the database
     * has been upgraded or become corrupt and add-on data has to be reloaded
     * into it.
     *
     * @param  aInstallLocation
     *         The install location containing the add-on
     * @param  aId
     *         The ID of the add-on
     * @param  aAddonState
     *         The new state of the add-on
     * @param  aMigrateData
     *         If during startup the database had to be upgraded this will
     *         contain data that used to be held about this add-on
     * @return a boolean indicating if flushing caches is required to complete
     *         changing this add-on
     */
Called to add the metadata for an add-on in one of the install locations
to the database. This can be called in three different cases. Either an
add-on has been dropped into the location from outside of Firefox, or
an add-on has been installed through the application, or the database
has been upgraded or become corrupt and add-on data has to be reloaded
into it.


Called to add the metadata for an add - on in one of the install locations to the database . This can be called in three different cases . Either an add - on has been dropped into the location from outside of Firefox or an add - on has been installed through the application or the database has been upgraded or become corrupt and add - on data has to be reloaded into it .
function addMetadata(aInstallLocation, aId, aAddonState, aMigrateData) {
      LOG("New add-on " + aId + " installed in " + aInstallLocation.name);
      let newAddon = null;
      let sameVersion = false;
      if (aInstallLocation.name in aManifests)
        newAddon = aManifests[aInstallLocation.name][aId];
      let isNewInstall = (!!newAddon) || (!XPIDatabase.activeBundles && !aMigrateData);
      let isDetectedInstall = isNewInstall && !newAddon;
      try {
        if (!newAddon) {
          let file = aInstallLocation.getLocationForID(aId);
          newAddon = loadManifestFromFile(file);
        }
        if (newAddon.id != aId)
          throw new Error("Incorrect id in install manifest");
      }
      catch (e) {
        WARN("Add-on is invalid", e);
        if (!aInstallLocation.locked)
          aInstallLocation.uninstallAddon(aId);
        else
          WARN("Could not uninstall invalid item from locked install location");
        return false;
      }
      newAddon._installLocation = aInstallLocation;
      newAddon.visible = !(newAddon.id in visibleAddons);
      newAddon.installDate = aAddonState.mtime;
      newAddon.updateDate = aAddonState.mtime;
      newAddon.foreignInstall = isDetectedInstall;
      if (aMigrateData) {
        LOG("Migrating data from old database");
        DB_MIGRATE_METADATA.forEach(function(aProp) {
          if (aProp == "userDisabled" && newAddon.type == "theme")
            return;
          if (aProp in aMigrateData)
            newAddon[aProp] = aMigrateData[aProp];
        });
        newAddon.foreignInstall |= aInstallLocation.name != KEY_APP_PROFILE;
        if (aMigrateData.version == newAddon.version) {
          LOG("Migrating compatibility info");
          sameVersion = true;
          if ("targetApplications" in aMigrateData)
            newAddon.applyCompatibilityUpdate(aMigrateData, true);
        }
        applyBlocklistChanges(newAddon, newAddon, aOldAppVersion,
                              aOldPlatformVersion);
      }
      if (newAddon.type == "theme" && newAddon.internalName == XPIProvider.defaultSkin)
        newAddon.foreignInstall = false;
      if (isDetectedInstall && newAddon.foreignInstall) {
        let disablingScopes = Prefs.getIntPref(PREF_EM_AUTO_DISABLED_SCOPES, 0);
        if (aInstallLocation.scope & disablingScopes)
          newAddon.userDisabled = true;
      }
      if (!isNewInstall && XPIDatabase.activeBundles) {
        if (newAddon.type == "theme")
          newAddon.active = newAddon.internalName == XPIProvider.currentSkin;
        else
          newAddon.active = XPIDatabase.activeBundles.indexOf(aAddonState.descriptor) != -1;
        if (!newAddon.active && newAddon.visible && !isAddonDisabled(newAddon)) {
          if (newAddon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED)
            newAddon.softDisabled = true;
          else
            newAddon.userDisabled = true;
        }
      }
      else {
        newAddon.active = (newAddon.visible && !isAddonDisabled(newAddon))
      }
      try {
        XPIDatabase.addAddonMetadata(newAddon, aAddonState.descriptor);
      }
      catch (e) {
        ERROR("Failed to add add-on " + aId + " in " + aInstallLocation.name +
              " to database", e);
        return false;
      }
      if (newAddon.visible) {
        if (isDetectedInstall) {
          if (AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_UNINSTALLED)
                          .indexOf(newAddon.id) != -1) {
            AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED,
                                                 newAddon.id);
          }
          else {
            AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_INSTALLED,
                                                 newAddon.id);
          }
        }
        if (newAddon._installLocation.name != KEY_APP_GLOBAL)
          XPIProvider.allAppGlobal = false;
        visibleAddons[newAddon.id] = newAddon;
        let installReason = BOOTSTRAP_REASONS.ADDON_INSTALL;
        if (newAddon.id in oldBootstrappedAddons) {
          let oldBootstrap = oldBootstrappedAddons[newAddon.id];
          XPIProvider.bootstrappedAddons[newAddon.id] = oldBootstrap;
          if (sameVersion || !isNewInstall)
            return false;
          installReason = Services.vc.compare(oldBootstrap.version, newAddon.version) < 0 ?
                          BOOTSTRAP_REASONS.ADDON_UPGRADE :
                          BOOTSTRAP_REASONS.ADDON_DOWNGRADE;
          let oldAddonFile = Cc["@mozilla.org/file/local;1"].
                             createInstance(Ci.nsIFile);
          oldAddonFile.persistentDescriptor = oldBootstrap.descriptor;
          XPIProvider.callBootstrapMethod(newAddon.id, oldBootstrap.version,
                                          oldBootstrap.type, oldAddonFile, "uninstall",
                                          installReason);
          XPIProvider.unloadBootstrapScope(newAddon.id);
          if (newAddon.bootstrap)
            flushStartupCache();
        }
        if (!newAddon.bootstrap)
          return true;
        let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
        file.persistentDescriptor = aAddonState.descriptor;
        XPIProvider.callBootstrapMethod(newAddon.id, newAddon.version, newAddon.type, file,
                                        "install", installReason);
        if (!newAddon.active)
          XPIProvider.unloadBootstrapScope(newAddon.id);
      }
      return false;
    }
function addMetadata ( aInstallLocation , aId , aAddonState , aMigrateData ) { LOG ( "New add-on " + aId + " installed in " + aInstallLocation . name ) ; let newAddon = null ; let sameVersion = false ; if ( aInstallLocation . name in aManifests ) newAddon = aManifests [ aInstallLocation . name ] [ aId ] ; let isNewInstall = ( ! ! newAddon ) || ( ! XPIDatabase . activeBundles && ! aMigrateData ) ; let isDetectedInstall = isNewInstall && ! newAddon ; try { if ( ! newAddon ) { let file = aInstallLocation . getLocationForID ( aId ) ; newAddon = loadManifestFromFile ( file ) ; } if ( newAddon . id != aId ) throw new Error ( "Incorrect id in install manifest" ) ; } catch ( e ) { WARN ( "Add-on is invalid" , e ) ; if ( ! aInstallLocation . locked ) aInstallLocation . uninstallAddon ( aId ) ; else WARN ( "Could not uninstall invalid item from locked install location" ) ; return false ; } newAddon . _installLocation = aInstallLocation ; newAddon . visible = ! ( newAddon . id in visibleAddons ) ; newAddon . installDate = aAddonState . mtime ; newAddon . updateDate = aAddonState . mtime ; newAddon . foreignInstall = isDetectedInstall ; if ( aMigrateData ) { LOG ( "Migrating data from old database" ) ; DB_MIGRATE_METADATA . forEach ( function ( aProp ) { if ( aProp == "userDisabled" && newAddon . type == "theme" ) return ; if ( aProp in aMigrateData ) newAddon [ aProp ] = aMigrateData [ aProp ] ; } ) ; newAddon . foreignInstall |= aInstallLocation . name != KEY_APP_PROFILE ; if ( aMigrateData . version == newAddon . version ) { LOG ( "Migrating compatibility info" ) ; sameVersion = true ; if ( "targetApplications" in aMigrateData ) newAddon . applyCompatibilityUpdate ( aMigrateData , true ) ; } applyBlocklistChanges ( newAddon , newAddon , aOldAppVersion , aOldPlatformVersion ) ; } if ( newAddon . type == "theme" && newAddon . internalName == XPIProvider . defaultSkin ) newAddon . foreignInstall = false ; if ( isDetectedInstall && newAddon . foreignInstall ) { let disablingScopes = Prefs . getIntPref ( PREF_EM_AUTO_DISABLED_SCOPES , 0 ) ; if ( aInstallLocation . scope & disablingScopes ) newAddon . userDisabled = true ; } if ( ! isNewInstall && XPIDatabase . activeBundles ) { if ( newAddon . type == "theme" ) newAddon . active = newAddon . internalName == XPIProvider . currentSkin ; else newAddon . active = XPIDatabase . activeBundles . indexOf ( aAddonState . descriptor ) != - 1 ; if ( ! newAddon . active && newAddon . visible && ! isAddonDisabled ( newAddon ) ) { if ( newAddon . blocklistState == Ci . nsIBlocklistService . STATE_SOFTBLOCKED ) newAddon . softDisabled = true ; else newAddon . userDisabled = true ; } } else { newAddon . active = ( newAddon . visible && ! isAddonDisabled ( newAddon ) ) } try { XPIDatabase . addAddonMetadata ( newAddon , aAddonState . descriptor ) ; } catch ( e ) { ERROR ( "Failed to add add-on " + aId + " in " + aInstallLocation . name + " to database" , e ) ; return false ; } if ( newAddon . visible ) { if ( isDetectedInstall ) { if ( AddonManager . getStartupChanges ( AddonManager . STARTUP_CHANGE_UNINSTALLED ) . indexOf ( newAddon . id ) != - 1 ) { AddonManagerPrivate . addStartupChange ( AddonManager . STARTUP_CHANGE_CHANGED , newAddon . id ) ; } else { AddonManagerPrivate . addStartupChange ( AddonManager . STARTUP_CHANGE_INSTALLED , newAddon . id ) ; } } if ( newAddon . _installLocation . name != KEY_APP_GLOBAL ) XPIProvider . allAppGlobal = false ; visibleAddons [ newAddon . id ] = newAddon ; let installReason = BOOTSTRAP_REASONS . ADDON_INSTALL ; if ( newAddon . id in oldBootstrappedAddons ) { let oldBootstrap = oldBootstrappedAddons [ newAddon . id ] ; XPIProvider . bootstrappedAddons [ newAddon . id ] = oldBootstrap ; if ( sameVersion || ! isNewInstall ) return false ; installReason = Services . vc . compare ( oldBootstrap . version , newAddon . version ) < 0 ? BOOTSTRAP_REASONS . ADDON_UPGRADE : BOOTSTRAP_REASONS . ADDON_DOWNGRADE ; let oldAddonFile = Cc [ "@mozilla.org/file/local;1" ] . createInstance ( Ci . nsIFile ) ; oldAddonFile . persistentDescriptor = oldBootstrap . descriptor ; XPIProvider . callBootstrapMethod ( newAddon . id , oldBootstrap . version , oldBootstrap . type , oldAddonFile , "uninstall" , installReason ) ; XPIProvider . unloadBootstrapScope ( newAddon . id ) ; if ( newAddon . bootstrap ) flushStartupCache ( ) ; } if ( ! newAddon . bootstrap ) return true ; let file = Cc [ "@mozilla.org/file/local;1" ] . createInstance ( Ci . nsIFile ) ; file . persistentDescriptor = aAddonState . descriptor ; XPIProvider . callBootstrapMethod ( newAddon . id , newAddon . version , newAddon . type , file , "install" , installReason ) ; if ( ! newAddon . active ) XPIProvider . unloadBootstrapScope ( newAddon . id ) ; } return false ; }
Called to add the metadata for an add-on in one of the install locations
 to the database.
Called to add the metadata for an add - on in one of the install locations to the database .
// Check the updated manifests lists for the install location, If there // is no manifest for the add-on ID then newAddon will be undefined // If we had staged data for this add-on or we aren't recovering from a // corrupt database and we don't have migration data for this add-on then // this must be a new install. // If it's a new install and we haven't yet loaded the manifest then it // must be something dropped directly into the install location // Load the manifest if necessary and sanity check the add-on ID // Load the manifest from the add-on. // The add-on in the manifest should match the add-on ID. // Remove the invalid add-on from the install location if the install // location isn't locked, no restart will be necessary // Update the AddonInternal properties. // If there is migration data then apply it. // A theme's disabled state is determined by the selected theme // preference which is read in loadManifestFromRDF // Force all non-profile add-ons to be foreignInstalls since they can't // have been installed through the API // Some properties should only be migrated if the add-on hasn't changed. // The version property isn't a perfect check for this but covers the // vast majority of cases. // Since the DB schema has changed make sure softDisabled is correct // The default theme is never a foreign install // If the add-on is a foreign install and is in a scope where add-ons // that were dropped in should default to disabled then disable it // If we have a list of what add-ons should be marked as active then use // it to guess at migration data. // For themes we know which is active by the current skin setting // If the add-on wasn't active and it isn't already disabled in some way // then it was probably either softDisabled or userDisabled // If the add-on is softblocked then assume it is softDisabled // Update the database. // Failing to write the add-on into the database is non-fatal, the // add-on will just be unavailable until we try again in a subsequent // startup // Remember add-ons that were first detected during startup. // If a copy from a higher priority location was removed then this // add-on has changed // Note if any visible add-on is not in the application install location // If we're hiding a bootstrapped add-on then call its uninstall method // If the old version is the same as the new version, or we're // recovering from a corrupt DB, don't call uninstall and install // methods. // If the new add-on is bootstrapped then we must flush the caches // before calling the new bootstrap script // Visible bootstrapped add-ons need to have their install method called