• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.managedprovisioning;
17 
18 import android.accounts.Account;
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.os.PersistableBundle;
23 import android.util.Xml;
24 
25 import com.android.internal.util.FastXmlSerializer;
26 
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.nio.charset.StandardCharsets;
32 import java.util.Set;
33 
34 import org.xmlpull.v1.XmlPullParser;
35 import org.xmlpull.v1.XmlPullParserException;
36 import org.xmlpull.v1.XmlSerializer;
37 
38 /**
39  * This class is used to store an intent to an xml file, and then restore it.
40  * Can only store:
41  * - the action
42  * - the component name
43  * - extras of type string, Integer, Long, Boolean, ComponentName, PersistableBundle, Account
44  */
45 public class IntentStore {
46 
47     private static final String TAG_INTENT_STORE = "intent-store";
48 
49     private static final String TAG_ACTION = "action";
50     private static final String TAG_COMPONENT_NAME = "component-name";
51 
52     private static final String TAG_EXTRAS = "extras";
53     private static final String TAG_STRING = "string";
54     private static final String TAG_INTEGER = "integer";
55     private static final String TAG_LONG = "long";
56     private static final String TAG_BOOLEAN = "boolean";
57     private static final String TAG_ACCOUNT = "account";
58     private static final String TAG_PERSISTABLE_BUNDLE = "persistable-bundle";
59 
60     private static final String ATTR_VALUE = "value";
61     private static final String ATTR_NAME = "name";
62     private static final String ATTR_ACCOUNT_NAME = "account-name";
63     private static final String ATTR_ACCOUNT_TYPE = "account-type";
64 
65     private final Context mContext;
66     private final String mName;
67 
68     private static final Object STATIC_LOCK = new Object();
69 
IntentStore(Context context, String name)70     public IntentStore(Context context, String name) {
71         mName = name;
72         mContext = context;
73     }
74 
save(Intent intent)75     public boolean save(Intent intent) {
76         synchronized(STATIC_LOCK) {
77             File file = getFile();
78             if (file.exists()) {
79                 ProvisionLogger.loge("Cannot save to the intent store because it already contains"
80                         + " an intent");
81                 return false;
82             }
83             try (FileOutputStream stream = new FileOutputStream(file)){
84                 XmlSerializer serializer = new FastXmlSerializer();
85                 serializer.setOutput(stream, StandardCharsets.UTF_8.name());
86                 serializer.startDocument(null, true);
87                 serializer.startTag(null, TAG_INTENT_STORE);
88                 writeIntent(intent, serializer);
89                 serializer.endTag(null, TAG_INTENT_STORE);
90                 serializer.endDocument();
91                 return true;
92             } catch (IOException | XmlPullParserException e) {
93                 ProvisionLogger.loge("Caught exception while trying to save an intent to the"
94                         + " intentStore", e);
95                 file.delete();
96                 return false;
97             }
98         }
99     }
100 
writeIntent(Intent intent, XmlSerializer serializer)101     private void writeIntent(Intent intent, XmlSerializer serializer)
102             throws IOException, XmlPullParserException {
103         if (intent.getAction() != null) {
104             writeTag(serializer, TAG_ACTION, intent.getAction());
105         }
106         if (intent.getComponent() != null) {
107             writeTag(serializer, TAG_COMPONENT_NAME,
108                     intent.getComponent().flattenToString());
109         }
110         if (intent.getExtras() != null) {
111             writeExtras(intent, serializer);
112         }
113     }
114 
writeExtras(Intent intent, XmlSerializer serializer)115     private void writeExtras(Intent intent, XmlSerializer serializer)
116             throws IOException, XmlPullParserException {
117         serializer.startTag(null, TAG_EXTRAS);
118         for (String key : intent.getExtras().keySet()) {
119             Object o = intent.getExtra(key);
120             if (o instanceof String) {
121                 writeTag(serializer, TAG_STRING, key, (String) o);
122             } else if (o instanceof Integer) {
123                 writeTag(serializer, TAG_INTEGER, key, o.toString());
124             } else if (o instanceof Long) {
125                 writeTag(serializer, TAG_LONG, key, o.toString());
126             } else if (o instanceof Boolean) {
127                 writeTag(serializer, TAG_BOOLEAN, key, o.toString());
128             } else if (o instanceof ComponentName) {
129                 writeTag(serializer, TAG_COMPONENT_NAME, key,
130                         ((ComponentName) o).flattenToString());
131             } else if (o instanceof Account) {
132                 Account account = (Account) o;
133                 serializer.startTag(null, TAG_ACCOUNT);
134                 serializer.attribute(null, ATTR_NAME, key);
135                 serializer.attribute(null, ATTR_ACCOUNT_NAME, account.name);
136                 serializer.attribute(null, ATTR_ACCOUNT_TYPE, account.type);
137                 serializer.endTag(null, TAG_ACCOUNT);
138             } else if (o instanceof PersistableBundle) {
139                 serializer.startTag(null, TAG_PERSISTABLE_BUNDLE);
140                 serializer.attribute(null, ATTR_NAME, key);
141                 ((PersistableBundle) o).saveToXml(serializer);
142                 serializer.endTag(null, TAG_PERSISTABLE_BUNDLE);
143             } else if (o != null) {
144                 ProvisionLogger.loge("extra for key " + key + " cannot be save in the intent"
145                         + " store: " + o, new RuntimeException());
146             }
147         }
148         serializer.endTag(null, TAG_EXTRAS);
149     }
150 
load()151     public Intent load() {
152         File file = getFile();
153         if (!file.exists()) {
154             return null;
155         }
156         synchronized(STATIC_LOCK) {
157             try (FileInputStream stream = new FileInputStream(file)) {
158                 XmlPullParser parser = Xml.newPullParser();
159                 parser.setInput(stream, null);
160                 Intent result = parseIntent(parser);
161                 return result;
162             } catch (IOException | XmlPullParserException e) {
163                 ProvisionLogger.loge("Caught exception while trying to load an intent from the"
164                         + " IntentStore", e);
165                 return null;
166             }
167         }
168     }
169 
parseIntent(XmlPullParser parser)170     private Intent parseIntent(XmlPullParser parser) throws XmlPullParserException, IOException {
171         Intent intent = new Intent();
172         int outerDepth = parser.getDepth();
173         int type;
174         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
175                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
176             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
177                 continue;
178             }
179             String tag = parser.getName();
180             if (tag.equals(TAG_ACTION)) {
181                 intent.setAction(parser.getAttributeValue(null, ATTR_VALUE));
182             } else if (tag.equals(TAG_COMPONENT_NAME)) {
183                 intent.setComponent(ComponentName.unflattenFromString(
184                         parser.getAttributeValue(null, ATTR_VALUE)));
185             } else if (tag.equals(TAG_EXTRAS)) {
186                 parseExtras(intent, parser);
187             }
188         }
189         return intent;
190     }
191 
parseExtras(Intent intent, XmlPullParser parser)192     private void parseExtras(Intent intent, XmlPullParser parser) throws XmlPullParserException,
193             IOException {
194         int outerDepth = parser.getDepth();
195         int type;
196         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
197                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
198             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
199                 continue;
200             }
201             String tag = parser.getName();
202             switch (tag) {
203                 case TAG_STRING:
204                     intent.putExtra(parser.getAttributeValue(null, ATTR_NAME),
205                             parser.getAttributeValue(null, ATTR_VALUE));
206                     break;
207                 case TAG_INTEGER:
208                     intent.putExtra(parser.getAttributeValue(null, ATTR_NAME),
209                             Integer.parseInt(parser.getAttributeValue(null, ATTR_VALUE)));
210                     break;
211                 case TAG_LONG:
212                     intent.putExtra(parser.getAttributeValue(null, ATTR_NAME),
213                             Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE)));
214                     break;
215                 case TAG_BOOLEAN:
216                     intent.putExtra(parser.getAttributeValue(null, ATTR_NAME),
217                             Boolean.parseBoolean(
218                             parser.getAttributeValue(null, ATTR_VALUE)));
219                     break;
220                 case TAG_COMPONENT_NAME:
221                     intent.putExtra(parser.getAttributeValue(null, ATTR_NAME),
222                             ComponentName.unflattenFromString(
223                             parser.getAttributeValue(null, ATTR_VALUE)));
224                     break;
225                 case TAG_ACCOUNT:
226                     Account a = new Account(
227                             parser.getAttributeValue(null, ATTR_ACCOUNT_NAME),
228                             parser.getAttributeValue(null, ATTR_ACCOUNT_TYPE));
229                     intent.putExtra(parser.getAttributeValue(null, ATTR_NAME), a);
230                     break;
231                 case TAG_PERSISTABLE_BUNDLE:
232                     intent.putExtra(parser.getAttributeValue(null, ATTR_NAME),
233                             PersistableBundle.restoreFromXml(parser));
234                     break;
235             }
236         }
237     }
238 
clear()239     public void clear() {
240         getFile().delete();
241     }
242 
writeTag(XmlSerializer serializer, String tag, String value)243     private void writeTag(XmlSerializer serializer, String tag, String value) throws IOException {
244         serializer.startTag(null, tag);
245         serializer.attribute(null, ATTR_VALUE, value);
246         serializer.endTag(null, tag);
247     }
248 
writeTag(XmlSerializer serializer, String tag, String name, String value)249     private void writeTag(XmlSerializer serializer, String tag, String name, String value)
250             throws IOException {
251         serializer.startTag(null, tag);
252         serializer.attribute(null, ATTR_NAME, name);
253         serializer.attribute(null, ATTR_VALUE, value);
254         serializer.endTag(null, tag);
255     }
256 
getFile()257     private File getFile() {
258         return new File(mContext.getFilesDir(), "intent_store_" + mName + ".xml");
259     }
260 }
261