private GeckoProfile(Context context, String profileName) throws NoMozillaDirectoryException { if (TextUtils.isEmpty(profileName)) { throw new IllegalArgumentException("Unable to create GeckoProfile for empty profile name."); } mApplicationContext = context.getApplicationContext(); mName = profileName; mIsWebAppProfile = profileName.startsWith("webapp"); mMozillaDir = GeckoProfileDirectories.getMozillaDirectory(context); }
/** * Discover the default profile name by examining profiles.ini. * * <p>Package-scoped because {@link GeckoProfile} needs access to it. * * @return null if there is no "Default" entry in profiles.ini, or the profile name if there is. * @throws NoMozillaDirectoryException if the Mozilla directory did not exist and could not be * created. */ static String findDefaultProfileName(final Context context) throws NoMozillaDirectoryException { final INIParser parser = GeckoProfileDirectories.getProfilesINI(getMozillaDirectory(context)); for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements(); ) { final INISection section = e.nextElement(); if (section.getIntProperty("Default") == 1) { return section.getStringProperty("Name"); } } return null; }
public static File findProfileDir(final File mozillaDir, final String profileName) throws NoSuchProfileException { // Open profiles.ini to find the correct path. final INIParser parser = GeckoProfileDirectories.getProfilesINI(mozillaDir); for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements(); ) { final INISection section = e.nextElement(); final String name = section.getStringProperty("Name"); if (name != null && name.equals(profileName)) { if (section.getIntProperty("IsRelative") == 1) { return new File(mozillaDir, section.getStringProperty("Path")); } return new File(section.getStringProperty("Path")); } } throw new NoSuchProfileException("No profile " + profileName); }
/** * @return the default profile name for this application, or {@link GeckoProfile#DEFAULT_PROFILE} * if none could be found. * @throws NoMozillaDirectoryException if the Mozilla directory did not exist and could not be * created. */ public static String getDefaultProfileName(final Context context) throws NoMozillaDirectoryException { // Have we read the default profile from the INI already? // Changing the default profile requires a restart, so we don't // need to worry about runtime changes. if (sDefaultProfileName != null) { return sDefaultProfileName; } final String profileName = GeckoProfileDirectories.findDefaultProfileName(context); if (profileName == null) { // Note that we don't persist this back to profiles.ini. sDefaultProfileName = DEFAULT_PROFILE; return DEFAULT_PROFILE; } sDefaultProfileName = profileName; return sDefaultProfileName; }
/** * Return a mapping from the names of all matching profiles (that is, profiles appearing in * profiles.ini that match the supplied predicate) to their absolute paths on disk. * * @param mozillaDir a directory containing profiles.ini. * @param predicate a predicate to use when evaluating whether to include a particular INI * section. * @param stopOnSuccess if true, this method will return with the first result that matches the * predicate; if false, all matching results are included. * @return a {@link Map} from name to path. */ public static Map<String, String> getMatchingProfiles( final File mozillaDir, INISectionPredicate predicate, boolean stopOnSuccess) { final HashMap<String, String> result = new HashMap<String, String>(); final INIParser parser = GeckoProfileDirectories.getProfilesINI(mozillaDir); for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements(); ) { final INISection section = e.nextElement(); if (predicate == null || predicate.matches(section)) { final String name = section.getStringProperty("Name"); final String pathString = section.getStringProperty("Path"); final boolean isRelative = section.getIntProperty("IsRelative") == 1; final File path = isRelative ? new File(mozillaDir, pathString) : new File(pathString); result.put(name, path.getAbsolutePath()); if (stopOnSuccess) { return result; } } } return result; }
private File createProfileDir() throws IOException { INIParser parser = GeckoProfileDirectories.getProfilesINI(mMozillaDir); // Salt the name of our requested profile String saltedName = GeckoProfileDirectories.saltProfileName(mName); File profileDir = new File(mMozillaDir, saltedName); while (profileDir.exists()) { saltedName = GeckoProfileDirectories.saltProfileName(mName); profileDir = new File(mMozillaDir, saltedName); } // Attempt to create the salted profile dir if (!profileDir.mkdirs()) { throw new IOException("Unable to create profile."); } Log.d(LOGTAG, "Created new profile dir."); // Now update profiles.ini // If this is the first time its created, we also add a General section // look for the first profile number that isn't taken yet int profileNum = 0; boolean isDefaultSet = false; INISection profileSection; while ((profileSection = parser.getSection("Profile" + profileNum)) != null) { profileNum++; if (profileSection.getProperty("Default") != null) { isDefaultSet = true; } } profileSection = new INISection("Profile" + profileNum); profileSection.setProperty("Name", mName); profileSection.setProperty("IsRelative", 1); profileSection.setProperty("Path", saltedName); if (parser.getSection("General") == null) { INISection generalSection = new INISection("General"); generalSection.setProperty("StartWithLastProfile", 1); parser.addSection(generalSection); } if (!isDefaultSet && !mIsWebAppProfile) { // only set as default if this is the first non-webapp // profile we're creating profileSection.setProperty("Default", 1); // We have no intention of stopping this session. The FIRSTRUN session // ends when the browsing session/activity has ended. All events // during firstrun will be tagged as FIRSTRUN. Telemetry.startUISession(TelemetryContract.Session.FIRSTRUN); } parser.addSection(profileSection); parser.write(); // Trigger init for non-webapp profiles. if (!mIsWebAppProfile) { enqueueInitialization(); } // Write out profile creation time, mirroring the logic in nsToolkitProfileService. try { FileOutputStream stream = new FileOutputStream(profileDir.getAbsolutePath() + File.separator + "times.json"); OutputStreamWriter writer = new OutputStreamWriter(stream, Charset.forName("UTF-8")); try { writer.append("{\"created\": " + System.currentTimeMillis() + "}\n"); } finally { writer.close(); } } catch (Exception e) { // Best-effort. Log.w(LOGTAG, "Couldn't write times.json.", e); } // Initialize pref flag for displaying the start pane for a new non-webapp profile. if (!mIsWebAppProfile) { final SharedPreferences prefs = GeckoSharedPrefs.forProfile(mApplicationContext); prefs.edit().putBoolean(BrowserApp.PREF_STARTPANE_ENABLED, true).apply(); } return profileDir; }
private File findProfileDir() throws NoSuchProfileException { return GeckoProfileDirectories.findProfileDir(mMozillaDir, mName); }
private boolean remove() { try { synchronized (this) { final File dir = getDir(); if (dir.exists()) { delete(dir); } try { mProfileDir = findProfileDir(); } catch (NoSuchProfileException noSuchProfile) { // If the profile doesn't exist, there's nothing left for us to do. return false; } } final INIParser parser = GeckoProfileDirectories.getProfilesINI(mMozillaDir); final Hashtable<String, INISection> sections = parser.getSections(); for (Enumeration<INISection> e = sections.elements(); e.hasMoreElements(); ) { final INISection section = e.nextElement(); String name = section.getStringProperty("Name"); if (name == null || !name.equals(mName)) { continue; } if (section.getName().startsWith("Profile")) { // ok, we have stupid Profile#-named things. Rename backwards. try { int sectionNumber = Integer.parseInt(section.getName().substring("Profile".length())); String curSection = "Profile" + sectionNumber; String nextSection = "Profile" + (sectionNumber + 1); sections.remove(curSection); while (sections.containsKey(nextSection)) { parser.renameSection(nextSection, curSection); sectionNumber++; curSection = nextSection; nextSection = "Profile" + (sectionNumber + 1); } } catch (NumberFormatException nex) { // uhm, malformed Profile thing; we can't do much. Log.e(LOGTAG, "Malformed section name in profiles.ini: " + section.getName()); return false; } } else { // this really shouldn't be the case, but handle it anyway parser.removeSection(mName); } break; } parser.write(); return true; } catch (IOException ex) { Log.w(LOGTAG, "Failed to remove profile.", ex); return false; } }