6464import java .io .IOException ;
6565import java .io .PrintWriter ;
6666import java .nio .charset .StandardCharsets ;
67+ import java .nio .file .Files ;
68+ import java .nio .file .Path ;
6769import java .util .ArrayList ;
6870import java .util .List ;
6971import java .util .Objects ;
@@ -716,6 +718,23 @@ private void doWriteState() {
716718 }
717719 } catch (Throwable t ) {
718720 Slog .wtf (LOG_TAG , "Failed to write settings, restoring backup" , t );
721+ if (t instanceof IOException ) {
722+ // we failed to create a directory, so log the permissions and existence
723+ // state for the settings file and directory
724+ logSettingsDirectoryInformation (destination .getBaseFile ());
725+ if (t .getMessage ().contains ("Couldn't create directory" )) {
726+ // attempt to create the directory with Files.createDirectories, which
727+ // throws more informative errors than File.mkdirs.
728+ Path parentPath = destination .getBaseFile ().getParentFile ().toPath ();
729+ try {
730+ Files .createDirectories (parentPath );
731+ Slog .i (LOG_TAG , "Successfully created " + parentPath );
732+ } catch (Throwable t2 ) {
733+ Slog .e (LOG_TAG , "Failed to write " + parentPath
734+ + " with Files.writeDirectories" , t2 );
735+ }
736+ }
737+ }
719738 destination .failWrite (out );
720739 } finally {
721740 IoUtils .closeQuietly (out );
@@ -729,6 +748,33 @@ private void doWriteState() {
729748 }
730749 }
731750
751+ private static void logSettingsDirectoryInformation (File settingsFile ) {
752+ File parent = settingsFile .getParentFile ();
753+ Slog .i (LOG_TAG , "directory info for directory/file " + settingsFile
754+ + " with stacktrace " , new Exception ());
755+ File ancestorDir = parent ;
756+ while (ancestorDir != null ) {
757+ if (!ancestorDir .exists ()) {
758+ Slog .i (LOG_TAG , "ancestor directory " + ancestorDir
759+ + " does not exist" );
760+ ancestorDir = ancestorDir .getParentFile ();
761+ } else {
762+ Slog .i (LOG_TAG , "ancestor directory " + ancestorDir
763+ + " exists" );
764+ Slog .i (LOG_TAG , "ancestor directory " + ancestorDir
765+ + " permissions: r: " + ancestorDir .canRead () + " w: "
766+ + ancestorDir .canWrite () + " x: " + ancestorDir .canExecute ());
767+ File ancestorParent = ancestorDir .getParentFile ();
768+ if (ancestorParent != null ) {
769+ Slog .i (LOG_TAG , "ancestor's parent directory " + ancestorParent
770+ + " permissions: r: " + ancestorParent .canRead () + " w: "
771+ + ancestorParent .canWrite () + " x: " + ancestorParent .canExecute ());
772+ }
773+ break ;
774+ }
775+ }
776+ }
777+
732778 static void writeSingleSetting (int version , XmlSerializer serializer , String id ,
733779 String name , String value , String defaultValue , String packageName ,
734780 String tag , boolean defaultSysSet ) throws IOException {
@@ -803,6 +849,7 @@ private void readStateSyncLocked() {
803849 in = new AtomicFile (mStatePersistFile ).openRead ();
804850 } catch (FileNotFoundException fnfe ) {
805851 Slog .i (LOG_TAG , "No settings state " + mStatePersistFile );
852+ logSettingsDirectoryInformation (mStatePersistFile );
806853 addHistoricalOperationLocked (HISTORICAL_OPERATION_INITIALIZE , null );
807854 return ;
808855 }
0 commit comments