author | Michael Wu <mwu@mozilla.com> |
Tue, 21 Dec 2010 15:02:14 -0500 | |
changeset 59565 | cdddfc399df358ee40e65afb307e4483ae5cada6 |
parent 59564 | a57900b40a7bdcd2933ae994f6fc624db1e63252 |
child 59569 | e5ed12d16160b695c7388e4087c6596c8a007791 |
push id | 17668 |
push user | blassey@mozilla.com |
push date | Tue, 21 Dec 2010 20:03:08 +0000 |
treeherder | mozilla-central@cdddfc399df3 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | ted, blassy, stuart |
bugs | 620584 |
milestone | 2.0b9pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -700,16 +700,18 @@ MOZ_APP_EXTRA_LIBS = @MOZ_APP_EXTRA_LIBS ANDROID_NDK = @ANDROID_NDK@ ANDROID_TOOLCHAIN = @ANDROID_TOOLCHAIN@ ANDROID_PLATFORM = @ANDROID_PLATFORM@ ANDROID_SDK = @ANDROID_SDK@ ANDROID_PLATFORM_TOOLS = @ANDROID_PLATFORM_TOOLS@ ANDROID_VERSION = @ANDROID_VERSION@ +ANDROID_PACKAGE_NAME = @ANDROID_PACKAGE_NAME@ + JS_SHARED_LIBRARY = @JS_SHARED_LIBRARY@ # We only want to do the pymake sanity on Windows, other os's can cope ifeq (,$(filter-out WINNT WINCE,$(HOST_OS_ARCH))) # Ensure invariants between GNU Make and pymake # Checked here since we want the sane error in a file that # actually can be found regardless of path-style. ifeq (_:,$(.PYMAKE)_$(findstring :,$(srcdir)))
--- a/configure.in +++ b/configure.in @@ -321,30 +321,34 @@ if test "$target" = "arm-android-eabi" ; fi ANDROID_NDK="${android_ndk}" ANDROID_TOOLCHAIN="{android_toolchain}" ANDROID_PLATFORM="{android_platform}" ANDROID_SDK="${android_sdk}" ANDROID_PLATFORM_TOOLS="${android_platform_tools}" ANDROID_VERSION="${android_version}" + if test -z "$ANDROID_PACKAGE_NAME" ; then + ANDROID_PACKAGE_NAME='org.mozilla.$(MOZ_APP_NAME)' + fi AC_DEFINE(ANDROID) AC_DEFINE_UNQUOTED(ANDROID_VERSION, $android_version) AC_SUBST(ANDROID_VERSION) CROSS_COMPILE=1 MOZ_CHROME_FILE_FORMAT=omni ZLIB_DIR=yes fi AC_SUBST(ANDROID_NDK) AC_SUBST(ANDROID_TOOLCHAIN) AC_SUBST(ANDROID_PLATFORM) AC_SUBST(ANDROID_SDK) AC_SUBST(ANDROID_PLATFORM_TOOLS) +AC_SUBST(ANDROID_PACKAGE_NAME) dnl ======================================================== dnl Checks for compilers. dnl ======================================================== dnl Set CROSS_COMPILE in the environment when running configure dnl to use the cross-compile setup for now dnl ========================================================
--- a/embedding/android/AlertNotification.java +++ b/embedding/android/AlertNotification.java @@ -77,17 +77,17 @@ public class AlertNotification mNotificationManager.notify(mId, this); } public void updateProgress(String aAlertText, long aProgress, long aProgressMax) { if (!mProgressStyle) { // Custom view int layout = aAlertText.length() > 0 ? R.layout.notification_progress_text : R.layout.notification_progress; - RemoteViews view = new RemoteViews("org.mozilla." + GeckoApp.mAppContext.getAppName(), layout); + RemoteViews view = new RemoteViews(GeckoApp.mAppContext.getPackageName(), layout); view.setImageViewResource(R.id.notificationImage, mIcon); view.setTextViewText(R.id.notificationTitle, mTitle); contentView = view; flags |= FLAG_ONGOING_EVENT; mProgressStyle = true; }
--- a/embedding/android/AndroidManifest.xml.in +++ b/embedding/android/AndroidManifest.xml.in @@ -1,12 +1,12 @@ #filter substitution <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="org.mozilla.@MOZ_APP_NAME@" + package="@ANDROID_PACKAGE_NAME@" android:installLocation="auto" android:versionCode="1" android:versionName="@MOZ_APP_VERSION@" android:sharedUserId="org.mozilla.sharedID"> <uses-sdk android:minSdkVersion="5" android:targetSdkVersion="5"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> @@ -69,17 +69,17 @@ <action android:name="org.mozilla.gecko.ACTION_ALERT_CLICK" /> <action android:name="org.mozilla.gecko.ACTION_ALERT_CLEAR" /> </intent-filter> </receiver> <activity android:name="Restarter" android:theme="@android:style/Theme.Light.NoTitleBar"> <intent-filter> - <action android:name="org.mozilla.gecko.restart@MOZ_APP_NAME@" + <action android:name="org.mozilla.gecko.restart" android:process="@MOZ_APP_NAME@Restarter"/> </intent-filter> </activity> #if MOZ_CRASHREPORTER <activity android:name="CrashReporter" android:label="@MOZ_APP_DISPLAYNAME@ Crash Reporter" android:icon="@drawable/crash_reporter" > <intent-filter>
--- a/embedding/android/App.java.in +++ b/embedding/android/App.java.in @@ -31,21 +31,21 @@ * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #filter substitution -package org.mozilla.@MOZ_APP_NAME@; +package @ANDROID_PACKAGE_NAME@; import org.mozilla.gecko.GeckoApp; public class App extends GeckoApp { - public String getAppName() { - return "@MOZ_APP_NAME@"; + public String getPackageName() { + return "@ANDROID_PACKAGE_NAME@"; } public String getContentProcessName() { return "@MOZ_CHILD_PROCESS_NAME@"; } };
--- a/embedding/android/CrashReporter.java.in +++ b/embedding/android/CrashReporter.java.in @@ -31,17 +31,17 @@ * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #filter substitution -package org.mozilla.@MOZ_APP_NAME@; +package @ANDROID_PACKAGE_NAME@; import android.app.*; import android.content.*; import android.os.*; import android.util.*; import android.view.*; import android.view.View.*; @@ -103,17 +103,17 @@ public class CrashReporter extends Activ mProgressDialog = new ProgressDialog(CrashReporter.this); mProgressDialog.setMessage(getString(R.string.sending_crash_report)); final Button restartButton = (Button) findViewById(R.id.restart); final Button closeButton = (Button) findViewById(R.id.close); String passedMinidumpPath = getIntent().getStringExtra("minidumpPath"); File passedMinidumpFile = new File(passedMinidumpPath); File pendingDir = - new File("/data/data/org.mozilla.@MOZ_APP_NAME@/mozilla/Crash Reports/pending"); + new File("/data/data/@ANDROID_PACKAGE_NAME@/mozilla/Crash Reports/pending"); pendingDir.mkdirs(); mPendingMinidumpFile = new File(pendingDir, passedMinidumpFile.getName()); moveFile(passedMinidumpFile, mPendingMinidumpFile); File extrasFile = new File(passedMinidumpPath.replaceAll(".dmp", ".extra")); mPendingExtrasFile = new File(pendingDir, extrasFile.getName()); moveFile(extrasFile, mPendingExtrasFile); @@ -270,17 +270,17 @@ public class CrashReporter extends Activ os.close(); BufferedReader br = new BufferedReader( new InputStreamReader(conn.getInputStream())); HashMap<String, String> responseMap = new HashMap<String, String>(); readStringsFromReader(br, responseMap); if (conn.getResponseCode() == conn.HTTP_OK) { File submittedDir = new File( - "/data/data/org.mozilla.@MOZ_APP_NAME@/mozilla/Crash Reports/submitted"); + "/data/data/@ANDROID_PACKAGE_NAME@/mozilla/Crash Reports/submitted"); submittedDir.mkdirs(); minidumpFile.delete(); extrasFile.delete(); String crashid = responseMap.get("CrashID"); File file = new File(submittedDir, crashid + ".txt"); FileOutputStream fos = new FileOutputStream(file); fos.write("Crash ID: ".getBytes()); fos.write(crashid.getBytes()); @@ -293,18 +293,18 @@ public class CrashReporter extends Activ finish(); } void doRestart() { try { String action = "android.intent.action.MAIN"; Intent intent = new Intent(action); - intent.setClassName("org.mozilla.@MOZ_APP_NAME@", - "org.mozilla.@MOZ_APP_NAME@.App"); + intent.setClassName("@ANDROID_PACKAGE_NAME@", + "@ANDROID_PACKAGE_NAME@.App"); Log.i("GeckoCrashReporter", intent.toString()); startActivity(intent); } catch (Exception e) { Log.e("GeckoCrashReporter", "error while trying to restart", e); } } public String unescape(String string)
--- a/embedding/android/GeckoApp.java +++ b/embedding/android/GeckoApp.java @@ -319,26 +319,26 @@ abstract public class GeckoApp public void onLowMemory() { Log.i("GeckoApp", "low memory"); if (checkLaunchState(LaunchState.GeckoRunning)) GeckoAppShell.onLowMemory(); super.onLowMemory(); } - abstract public String getAppName(); + abstract public String getPackageName(); abstract public String getContentProcessName(); protected void unpackComponents() throws IOException, FileNotFoundException { ZipFile zip; InputStream listStream; - File componentsDir = new File("/data/data/org.mozilla." + getAppName() + + File componentsDir = new File("/data/data/" + getPackageName() + "/components"); componentsDir.mkdir(); zip = new ZipFile(getApplication().getPackageResourcePath()); byte[] buf = new byte[8192]; unpackFile(zip, buf, null, "application.ini"); unpackFile(zip, buf, null, getContentProcessName()); try { @@ -361,17 +361,17 @@ abstract public class GeckoApp throws IOException, FileNotFoundException { if (fileEntry == null) fileEntry = zip.getEntry(name); if (fileEntry == null) throw new FileNotFoundException("Can't find " + name + " in " + zip.getName()); - File outFile = new File("/data/data/org.mozilla." + getAppName() + + File outFile = new File("/data/data/" + getPackageName() + "/" + name); if (outFile.exists() && outFile.lastModified() == fileEntry.getTime() && outFile.length() == fileEntry.getSize()) return; File dir = outFile.getParentFile(); if (!outFile.exists()) @@ -403,20 +403,20 @@ abstract public class GeckoApp intent.putExtra("env" + c, entry.getKey() + "=" + entry.getValue()); c++; } } public void doRestart() { try { - String action = "org.mozilla.gecko.restart" + getAppName(); + String action = "org.mozilla.gecko.restart"; Intent intent = new Intent(action); - intent.setClassName("org.mozilla." + getAppName(), - "org.mozilla." + getAppName() + ".Restarter"); + intent.setClassName(getPackageName(), + getPackageName() + ".Restarter"); addEnvToIntent(intent); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); Log.i("GeckoAppJava", intent.toString()); startActivity(intent); } catch (Exception e) { Log.i("GeckoAppJava", e.toString()); } @@ -440,17 +440,17 @@ abstract public class GeckoApp return; if (!updateFile.exists()) return; Log.i("GeckoAppJava", "Update is available!"); // Launch APK - File updateFileToRun = new File(updateDir + getAppName() + "-update.apk"); + File updateFileToRun = new File(updateDir + getPackageName() + "-update.apk"); try { if (updateFile.renameTo(updateFileToRun)) { String amCmd = "/system/bin/am start -a android.intent.action.VIEW " + "-n com.android.packageinstaller/.PackageInstallerActivity -d file://" + updateFileToRun.getPath(); Log.i("GeckoAppJava", amCmd); Runtime.getRuntime().exec(amCmd); statusCode = 0; // OK @@ -522,18 +522,18 @@ abstract public class GeckoApp Uri uri = data.getData(); String mimeType = cr.getType(uri); String fileExt = "." + mimeType.substring(mimeType.lastIndexOf('/') + 1); File file = File.createTempFile("tmp_" + (int)Math.floor(1000 * Math.random()), fileExt, - new File("/data/data/org.mozilla." + - getAppName())); + new File("/data/data/" + + getPackageName())); FileOutputStream fos = new FileOutputStream(file); InputStream is = cr.openInputStream(uri); byte[] buf = new byte[4096]; int len = is.read(buf); while (len != -1) { fos.write(buf, 0, len); len = is.read(buf);
--- a/embedding/android/GeckoAppShell.java +++ b/embedding/android/GeckoAppShell.java @@ -104,18 +104,18 @@ class GeckoAppShell String env = i.getStringExtra("env0"); Log.i("GeckoApp", "env0: "+ env); for (int c = 1; env != null; c++) { GeckoAppShell.putenv(env); env = i.getStringExtra("env" + c); Log.i("GeckoApp", "env"+ c +": "+ env); } - File f = new File("/data/data/org.mozilla." + - GeckoApp.mAppContext.getAppName() +"/tmp"); + File f = new File("/data/data/" + + GeckoApp.mAppContext.getPackageName() + "/tmp"); if (!f.exists()) f.mkdirs(); GeckoAppShell.putenv("TMPDIR=" + f.getPath()); f = Environment.getDownloadCacheDirectory(); GeckoAppShell.putenv("EXTERNAL_STORAGE" + f.getPath()); @@ -361,17 +361,17 @@ class GeckoAppShell // "Installs" an application by creating a shortcut static void installWebApplication(String aURI, String aTitle, String aIconData) { Log.w("GeckoAppJava", "installWebApplication for " + aURI + " [" + aTitle + "]"); // the intent to be launched by the shortcut Intent shortcutIntent = new Intent("org.mozilla.fennec.WEBAPP"); shortcutIntent.setClassName(GeckoApp.mAppContext, - "org.mozilla." + GeckoApp.mAppContext.getAppName() + ".App"); + GeckoApp.mAppContext.getPackageName() + ".App"); shortcutIntent.putExtra("args", "--webapp=" + aURI); Intent intent = new Intent(); intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle); byte[] raw = Base64.decode(aIconData.substring(22), Base64.DEFAULT); Bitmap bitmap = BitmapFactory.decodeByteArray(raw, 0, raw.length); intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap); @@ -517,29 +517,29 @@ class GeckoAppShell removeNotification(notificationID); AlertNotification notification = new AlertNotification(GeckoApp.mAppContext, notificationID, icon, aAlertTitle, System.currentTimeMillis()); // The intent to launch when the user clicks the expanded notification Intent notificationIntent = new Intent(GeckoApp.ACTION_ALERT_CLICK); notificationIntent.setClassName(GeckoApp.mAppContext, - "org.mozilla." + GeckoApp.mAppContext.getAppName() + ".NotificationHandler"); + GeckoApp.mAppContext.getPackageName() + ".NotificationHandler"); // Put the strings into the intent as an URI "alert:<name>#<cookie>" Uri dataUri = Uri.fromParts("alert", aAlertName, aAlertCookie); notificationIntent.setData(dataUri); PendingIntent contentIntent = PendingIntent.getBroadcast(GeckoApp.mAppContext, 0, notificationIntent, 0); notification.setLatestEventInfo(GeckoApp.mAppContext, aAlertTitle, aAlertText, contentIntent); // The intent to execute when the status entry is deleted by the user with the "Clear All Notifications" button Intent clearNotificationIntent = new Intent(GeckoApp.ACTION_ALERT_CLEAR); clearNotificationIntent.setClassName(GeckoApp.mAppContext, - "org.mozilla." + GeckoApp.mAppContext.getAppName() + ".NotificationHandler"); + GeckoApp.mAppContext.getPackageName() + ".NotificationHandler"); clearNotificationIntent.setData(dataUri); notification.deleteIntent = PendingIntent.getBroadcast(GeckoApp.mAppContext, 0, clearNotificationIntent, 0); mAlertNotifications.put(notificationID, notification); notification.show(); Log.i("GeckoAppJava", "Created notification ID " + notificationID);
--- a/embedding/android/Makefile.in +++ b/embedding/android/Makefile.in @@ -61,16 +61,17 @@ PROCESSEDJAVAFILES = \ ifneq (,$(findstring -march=armv7,$(OS_CFLAGS))) MIN_CPU_VERSION=7 else MIN_CPU_VERSION=5 endif DEFINES += \ + -DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \ -DMOZ_APP_DISPLAYNAME=$(MOZ_APP_DISPLAYNAME) \ -DMOZ_APP_NAME=$(MOZ_APP_NAME) \ -DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \ -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME) \ -DMOZ_MIN_CPU_VERSION=$(MIN_CPU_VERSION) \ -DMOZ_CRASHREPORTER=$(MOZ_CRASHREPORTER) \ $(NULL)
--- a/embedding/android/NotificationHandler.java.in +++ b/embedding/android/NotificationHandler.java.in @@ -31,17 +31,17 @@ * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #filter substitution -package org.mozilla.@MOZ_APP_NAME@; +package @ANDROID_PACKAGE_NAME@; import android.app.NotificationManager; import android.content.Intent; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.Context; import android.os.Bundle; import android.util.Log;
--- a/other-licenses/android/APKOpen.cpp +++ b/other-licenses/android/APKOpen.cpp @@ -434,17 +434,17 @@ static void * mozload(const char * path, struct cdir_entry *entry = find_cdir_entry(cdir_start, cdir_entries, path); struct local_file_header *file = (struct local_file_header *)(zip + letoh32(entry->offset)); void * data = ((void *)&file->data) + letoh16(file->filename_size) + letoh16(file->extra_field_size); void * handle; if (extractLibs) { char fullpath[256]; - snprintf(fullpath, 256, "/data/data/org.mozilla.fennec/%s", path + 4); + snprintf(fullpath, 256, "/data/data/" ANDROID_PACKAGE_NAME "/%s", path + 4); __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "resolved %s to %s", path, fullpath); extractFile(fullpath, entry, data); handle = __wrap_dlopen(fullpath, RTLD_LAZY); if (!handle) __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't load %s because %s", fullpath, __wrap_dlerror()); #ifdef DEBUG gettimeofday(&t1, 0); __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "%s: spent %d", path, @@ -555,17 +555,17 @@ report_mapping(char *name, void *base, u info->file_id = strndup(entry + strlen(name) + 1, 32); } extern "C" void simple_linker_init(void); static void loadLibs(const char *apkName) { - chdir("/data/data/org.mozilla.fennec"); + chdir("/data/data/" ANDROID_PACKAGE_NAME); simple_linker_init(); struct stat status; if (!stat(apkName, &status)) apk_mtime = status.st_mtime; #ifdef DEBUG
--- a/other-licenses/android/Makefile.in +++ b/other-licenses/android/Makefile.in @@ -48,16 +48,17 @@ FORCE_SHARED_LIB = 1 DIST_INSTALL = 1 DEFINES += \ -DLINKER_DEBUG=0 \ -DANDROID_ARM_LINKER \ -DMOZ_LINKER \ -DLINKER_TEXT_BASE=0xB0001000 \ -DLINKER_AREA_SIZE=0x01000000 \ + -DANDROID_PACKAGE_NAME='"$(ANDROID_PACKAGE_NAME)"' \ $(NULL) CPPSRCS = \ nsGeckoUtils.cpp \ APKOpen.cpp \ $(NULL) CSRCS = \
--- a/toolkit/xre/Makefile.in +++ b/toolkit/xre/Makefile.in @@ -130,16 +130,17 @@ OS_CXXFLAGS += -fexceptions endif ifdef MOZ_X11 CPPSRCS += nsX11ErrorHandler.cpp endif ifeq ($(OS_TARGET),Android) CPPSRCS += nsAndroidStartup.cpp +DEFINES += -DANDROID_PACKAGE_NAME='"$(ANDROID_PACKAGE_NAME)"' endif SHARED_LIBRARY_LIBS += ../profile/src/$(LIB_PREFIX)profile_s.$(LIB_SUFFIX) ifdef MOZ_ENABLE_XREMOTE SHARED_LIBRARY_LIBS += $(DEPTH)/widget/src/xremoteclient/$(LIB_PREFIX)xremote_client_s.$(LIB_SUFFIX) LOCAL_INCLUDES += -I$(topsrcdir)/widget/src/xremoteclient endif
--- a/toolkit/xre/nsAndroidStartup.cpp +++ b/toolkit/xre/nsAndroidStartup.cpp @@ -89,33 +89,33 @@ GeckoStart(void *data) if (!data) { LOG("Failed to get arguments for GeckoStart\n"); return 0; } nsresult rv; nsCOMPtr<nsILocalFile> appini; - rv = NS_NewLocalFile(NS_LITERAL_STRING("/data/data/org.mozilla." MOZ_APP_NAME "/application.ini"), + rv = NS_NewLocalFile(NS_LITERAL_STRING("/data/data/" ANDROID_PACKAGE_NAME "/application.ini"), PR_FALSE, getter_AddRefs(appini)); if (NS_FAILED(rv)) { LOG("Failed to create nsILocalFile for appdata\n"); return 0; } nsXREAppData *appData; rv = XRE_CreateAppData(appini, &appData); if (NS_FAILED(rv)) { - LOG("Failed to load application.ini from /data/data/org.mozilla." MOZ_APP_NAME "/application.ini\n"); + LOG("Failed to load application.ini from /data/data/" ANDROID_PACKAGE_NAME "/application.ini\n"); return 0; } nsCOMPtr<nsILocalFile> xreDir; - rv = NS_NewLocalFile(NS_LITERAL_STRING("/data/data/org.mozilla." MOZ_APP_NAME), + rv = NS_NewLocalFile(NS_LITERAL_STRING("/data/data/" ANDROID_PACKAGE_NAME), PR_FALSE, getter_AddRefs(xreDir)); if (NS_FAILED(rv)) { LOG("Failed to create nsIFile for xreDirectory"); return 0; } appData->xreDirectory = xreDir.get();
--- a/toolkit/xre/nsXREDirProvider.cpp +++ b/toolkit/xre/nsXREDirProvider.cpp @@ -1099,17 +1099,17 @@ nsXREDirProvider::GetUserDataDirectoryHo appDir[len] = '/'; appDir[len+1] = '\0'; rv = NS_NewNativeLocalFile(nsDependentCString(appDir), PR_TRUE, getter_AddRefs(localDir)); #elif defined(ANDROID) // used for setting the patch to our profile // XXX: investigate putting the profile somewhere else - const char* homeDir = "/data/data/org.mozilla." MOZ_APP_NAME; + const char* homeDir = "/data/data/" ANDROID_PACKAGE_NAME; rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), PR_TRUE, getter_AddRefs(localDir)); #elif defined(XP_UNIX) const char* homeDir = getenv("HOME"); if (!homeDir || !*homeDir) return NS_ERROR_FAILURE;