summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alex Buynytskyy <alexbuy@google.com> 2023-06-05 16:40:27 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-06-05 16:40:27 +0000
commit6906686d7daf91a02811fd055c1be683c769b51a (patch)
treee4140f488d664253fc23a36e09942c0b4a791955
parent3198236b828283f557b382a488de304c29ac25ed (diff)
parentcf0b30b786bc2edfae5192a28feedba50ed13b1e (diff)
Merge "Add a backup and restore logic to ShortcutPackageItems"
-rw-r--r--services/core/java/com/android/server/pm/ShortcutLauncher.java68
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java68
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackageItem.java65
-rw-r--r--services/core/java/com/android/server/pm/ShortcutUser.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java11
5 files changed, 110 insertions, 112 deletions
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 00f7dc4025e6..bac300d4dd09 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -23,7 +23,6 @@ import android.content.pm.ShortcutInfo;
import android.content.pm.UserPackage;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.AtomicFile;
import android.util.Slog;
import android.util.Xml;
@@ -32,8 +31,6 @@ import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.ShortcutService.DumpFilter;
-import libcore.io.IoUtils;
-
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
@@ -41,7 +38,6 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -264,45 +260,41 @@ class ShortcutLauncher extends ShortcutPackageItem {
public static ShortcutLauncher loadFromFile(File path, ShortcutUser shortcutUser,
int ownerUserId, boolean fromBackup) {
+ try (ResilientAtomicFile file = getResilientFile(path)) {
+ FileInputStream in = null;
+ try {
+ in = file.openRead();
+ if (in == null) {
+ Slog.d(TAG, "Not found " + path);
+ return null;
+ }
- final AtomicFile file = new AtomicFile(path);
- final FileInputStream in;
- try {
- in = file.openRead();
- } catch (FileNotFoundException e) {
- if (ShortcutService.DEBUG) {
- Slog.d(TAG, "Not found " + path);
- }
- return null;
- }
-
- try {
- ShortcutLauncher ret = null;
- TypedXmlPullParser parser = Xml.resolvePullParser(in);
+ ShortcutLauncher ret = null;
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
- final int depth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ final int depth = parser.getDepth();
- final String tag = parser.getName();
- if (ShortcutService.DEBUG_LOAD) {
- Slog.d(TAG, String.format("depth=%d type=%d name=%s", depth, type, tag));
- }
- if ((depth == 1) && TAG_ROOT.equals(tag)) {
- ret = loadFromXml(parser, shortcutUser, ownerUserId, fromBackup);
- continue;
+ final String tag = parser.getName();
+ if (ShortcutService.DEBUG_LOAD) {
+ Slog.d(TAG, String.format("depth=%d type=%d name=%s", depth, type, tag));
+ }
+ if ((depth == 1) && TAG_ROOT.equals(tag)) {
+ ret = loadFromXml(parser, shortcutUser, ownerUserId, fromBackup);
+ continue;
+ }
+ ShortcutService.throwForInvalidTag(depth, tag);
}
- ShortcutService.throwForInvalidTag(depth, tag);
+ return ret;
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
+ file.failRead(in, e);
+ return loadFromFile(path, shortcutUser, ownerUserId, fromBackup);
}
- return ret;
- } catch (IOException | XmlPullParserException e) {
- Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
- return null;
- } finally {
- IoUtils.closeQuietly(in);
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 28cb7f0b03a6..0ea45c466ca7 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -50,7 +50,6 @@ import android.os.StrictMode;
import android.text.format.Formatter;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
import android.util.Xml;
@@ -69,8 +68,6 @@ import com.android.server.pm.ShortcutService.DumpFilter;
import com.android.server.pm.ShortcutService.ShortcutOperation;
import com.android.server.pm.ShortcutService.Stats;
-import libcore.io.IoUtils;
-
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
@@ -78,7 +75,6 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -1969,45 +1965,41 @@ class ShortcutPackage extends ShortcutPackageItem {
public static ShortcutPackage loadFromFile(ShortcutService s, ShortcutUser shortcutUser,
File path, boolean fromBackup) {
+ try (ResilientAtomicFile file = getResilientFile(path)) {
+ FileInputStream in = null;
+ try {
+ in = file.openRead();
+ if (in == null) {
+ Slog.d(TAG, "Not found " + path);
+ return null;
+ }
- final AtomicFile file = new AtomicFile(path);
- final FileInputStream in;
- try {
- in = file.openRead();
- } catch (FileNotFoundException e) {
- if (ShortcutService.DEBUG) {
- Slog.d(TAG, "Not found " + path);
- }
- return null;
- }
-
- try {
- ShortcutPackage ret = null;
- TypedXmlPullParser parser = Xml.resolvePullParser(in);
+ ShortcutPackage ret = null;
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
- final int depth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ final int depth = parser.getDepth();
- final String tag = parser.getName();
- if (ShortcutService.DEBUG_LOAD || ShortcutService.DEBUG_REBOOT) {
- Slog.d(TAG, String.format("depth=%d type=%d name=%s", depth, type, tag));
- }
- if ((depth == 1) && TAG_ROOT.equals(tag)) {
- ret = loadFromXml(s, shortcutUser, parser, fromBackup);
- continue;
+ final String tag = parser.getName();
+ if (ShortcutService.DEBUG_LOAD || ShortcutService.DEBUG_REBOOT) {
+ Slog.d(TAG, String.format("depth=%d type=%d name=%s", depth, type, tag));
+ }
+ if ((depth == 1) && TAG_ROOT.equals(tag)) {
+ ret = loadFromXml(s, shortcutUser, parser, fromBackup);
+ continue;
+ }
+ ShortcutService.throwForInvalidTag(depth, tag);
}
- ShortcutService.throwForInvalidTag(depth, tag);
+ return ret;
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
+ file.failRead(in, e);
+ return loadFromFile(s, shortcutUser, path, fromBackup);
}
- return ret;
- } catch (IOException | XmlPullParserException e) {
- Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
- return null;
- } finally {
- IoUtils.closeQuietly(in);
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 8b118da1cdbe..8667888fbb51 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -20,14 +20,13 @@ import android.annotation.Nullable;
import android.content.pm.PackageInfo;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
-import android.util.AtomicFile;
+import android.os.FileUtils;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.modules.utils.TypedXmlSerializer;
-import com.android.server.security.FileIntegrity;
import org.json.JSONException;
import org.json.JSONObject;
@@ -160,36 +159,31 @@ abstract class ShortcutPackageItem {
@GuardedBy("mLock")
public void saveToFileLocked(File path, boolean forBackup) {
- final AtomicFile file = new AtomicFile(path);
- FileOutputStream os = null;
- try {
- os = file.startWrite();
-
- // Write to XML
- final TypedXmlSerializer itemOut;
- if (forBackup) {
- itemOut = Xml.newFastSerializer();
- itemOut.setOutput(os, StandardCharsets.UTF_8.name());
- } else {
- itemOut = Xml.resolveSerializer(os);
- }
- itemOut.startDocument(null, true);
-
- saveToXml(itemOut, forBackup);
-
- itemOut.endDocument();
-
- os.flush();
- file.finishWrite(os);
-
+ try (ResilientAtomicFile file = getResilientFile(path)) {
+ FileOutputStream os = null;
try {
- FileIntegrity.setUpFsVerity(path);
- } catch (IOException e) {
- Slog.e(TAG, "Failed to verity-protect " + path, e);
+ os = file.startWrite();
+
+ // Write to XML
+ final TypedXmlSerializer itemOut;
+ if (forBackup) {
+ itemOut = Xml.newFastSerializer();
+ itemOut.setOutput(os, StandardCharsets.UTF_8.name());
+ } else {
+ itemOut = Xml.resolveSerializer(os);
+ }
+ itemOut.startDocument(null, true);
+
+ saveToXml(itemOut, forBackup);
+
+ itemOut.endDocument();
+
+ os.flush();
+ file.finishWrite(os);
+ } catch (XmlPullParserException | IOException e) {
+ Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
+ file.failWrite(os);
}
- } catch (XmlPullParserException | IOException e) {
- Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
- file.failWrite(os);
}
}
@@ -265,9 +259,18 @@ abstract class ShortcutPackageItem {
void removeShortcutPackageItem() {
synchronized (mLock) {
- getShortcutPackageItemFile().delete();
+ getResilientFile(getShortcutPackageItemFile()).delete();
}
}
protected abstract File getShortcutPackageItemFile();
+
+ protected static ResilientAtomicFile getResilientFile(File file) {
+ String path = file.getPath();
+ File temporaryBackup = new File(path + ".backup");
+ File reserveCopy = new File(path + ".reservecopy");
+ int fileMode = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH;
+ return new ResilientAtomicFile(file, temporaryBackup, reserveCopy, fileMode,
+ "shortcut package item", null);
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 94eb6bb25caa..d32eb22afb61 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -437,14 +437,14 @@ class ShortcutUser {
} else {
final File root = s.injectUserDataPath(userId);
- forAllFilesIn(new File(root, DIRECTORY_PACKAGES), (File f) -> {
+ forMainFilesIn(new File(root, DIRECTORY_PACKAGES), (File f) -> {
final ShortcutPackage sp = ShortcutPackage.loadFromFile(s, ret, f, fromBackup);
if (sp != null) {
ret.mPackages.put(sp.getPackageName(), sp);
}
});
- forAllFilesIn(new File(root, DIRECTORY_LUANCHERS), (File f) -> {
+ forMainFilesIn(new File(root, DIRECTORY_LUANCHERS), (File f) -> {
final ShortcutLauncher sl =
ShortcutLauncher.loadFromFile(f, ret, userId, fromBackup);
if (sl != null) {
@@ -456,13 +456,15 @@ class ShortcutUser {
return ret;
}
- private static void forAllFilesIn(File path, Consumer<File> callback) {
+ private static void forMainFilesIn(File path, Consumer<File> callback) {
if (!path.exists()) {
return;
}
File[] list = path.listFiles();
for (File f : list) {
- callback.accept(f);
+ if (!f.getName().endsWith(".reservecopy") && !f.getName().endsWith(".backup")) {
+ callback.accept(f);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 7c1845fcd54e..0f5fb91a140f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -125,6 +125,8 @@ import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -4014,8 +4016,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
ShortcutUser user = new ShortcutUser(mService, 0);
- File corruptedShortcutPackage = new File("/data/local/tmp/cts/content/",
+ File corruptedShortcutPackage = new File(getTestContext().getFilesDir(),
"broken_shortcut.xml");
+ Files.copy(new File("/data/local/tmp/cts/content/", "broken_shortcut.xml").toPath(),
+ corruptedShortcutPackage.toPath(), StandardCopyOption.REPLACE_EXISTING);
assertNull(ShortcutPackage.loadFromFile(mService, user, corruptedShortcutPackage, false));
}
@@ -4116,6 +4120,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
try (Writer os = new FileWriter(mService.getUserFile(USER_10).getBaseFile())) {
os.write("<?xml version='1.0' encoding='utf");
}
+ ShortcutPackage sp = mService.getUserShortcutsLocked(USER_0).getPackageShortcutsIfExists(
+ CALLING_PACKAGE_1);
+ try (Writer os = new FileWriter(sp.getShortcutPackageItemFile().getPath())) {
+ os.write("<?xml version='1.0' encoding='utf");
+ }
// Restore.
initService();