Android-x86
Fork
Donation

  • R/O
  • HTTP
  • SSH
  • HTTPS

frameworks-base: Commit

frameworks/base


Commit MetaInfo

Revision908f7800e4f66bd952bcee69b20053e6083f2e2b (tree)
Time2020-05-20 20:54:56
AuthorChih-Wei Huang <cwhuang@linu...>
CommiterChih-Wei Huang

Log Message

Merge remote-tracking branch 'lineage/cm-14.1' into cm-14.1-x86

Change Summary

Incremental Difference

--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -128,6 +128,9 @@ public class DownloadManager {
128128 */
129129 public final static String COLUMN_STATUS = Downloads.Impl.COLUMN_STATUS;
130130
131+ /** {@hide} */
132+ public static final String COLUMN_FILE_NAME_HINT = Downloads.Impl.COLUMN_FILE_NAME_HINT;
133+
131134 /**
132135 * Provides more detail on the status of the download. Its meaning depends on the value of
133136 * {@link #COLUMN_STATUS}.
@@ -165,6 +168,9 @@ public class DownloadManager {
165168 */
166169 public static final String COLUMN_MEDIAPROVIDER_URI = Downloads.Impl.COLUMN_MEDIAPROVIDER_URI;
167170
171+ /** {@hide} */
172+ public static final String COLUMN_DESTINATION = Downloads.Impl.COLUMN_DESTINATION;
173+
168174 /**
169175 * @hide
170176 */
@@ -333,26 +339,22 @@ public class DownloadManager {
333339 * @hide
334340 */
335341 public static final String[] UNDERLYING_COLUMNS = new String[] {
336- Downloads.Impl._ID,
337- Downloads.Impl._DATA + " AS " + COLUMN_LOCAL_FILENAME,
338- Downloads.Impl.COLUMN_MEDIAPROVIDER_URI,
339- Downloads.Impl.COLUMN_DESTINATION,
340- Downloads.Impl.COLUMN_TITLE,
341- Downloads.Impl.COLUMN_DESCRIPTION,
342- Downloads.Impl.COLUMN_URI,
343- Downloads.Impl.COLUMN_STATUS,
344- Downloads.Impl.COLUMN_FILE_NAME_HINT,
345- Downloads.Impl.COLUMN_MIME_TYPE + " AS " + COLUMN_MEDIA_TYPE,
346- Downloads.Impl.COLUMN_TOTAL_BYTES + " AS " + COLUMN_TOTAL_SIZE_BYTES,
347- Downloads.Impl.COLUMN_LAST_MODIFICATION + " AS " + COLUMN_LAST_MODIFIED_TIMESTAMP,
348- Downloads.Impl.COLUMN_CURRENT_BYTES + " AS " + COLUMN_BYTES_DOWNLOADED_SO_FAR,
349- Downloads.Impl.COLUMN_ALLOW_WRITE,
350- /* add the following 'computed' columns to the cursor.
351- * they are not 'returned' by the database, but their inclusion
352- * eliminates need to have lot of methods in CursorTranslator
353- */
354- "'placeholder' AS " + COLUMN_LOCAL_URI,
355- "'placeholder' AS " + COLUMN_REASON
342+ DownloadManager.COLUMN_ID,
343+ DownloadManager.COLUMN_LOCAL_FILENAME,
344+ DownloadManager.COLUMN_MEDIAPROVIDER_URI,
345+ DownloadManager.COLUMN_DESTINATION,
346+ DownloadManager.COLUMN_TITLE,
347+ DownloadManager.COLUMN_DESCRIPTION,
348+ DownloadManager.COLUMN_URI,
349+ DownloadManager.COLUMN_STATUS,
350+ DownloadManager.COLUMN_FILE_NAME_HINT,
351+ DownloadManager.COLUMN_MEDIA_TYPE,
352+ DownloadManager.COLUMN_TOTAL_SIZE_BYTES,
353+ DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP,
354+ DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR,
355+ DownloadManager.COLUMN_ALLOW_WRITE,
356+ DownloadManager.COLUMN_LOCAL_URI,
357+ DownloadManager.COLUMN_REASON
356358 };
357359
358360 /**
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -65,24 +65,24 @@ public final class AssetManager implements AutoCloseable {
6565
6666 private static final String TAG = "AssetManager";
6767 private static final boolean localLOGV = false || false;
68-
68+
6969 private static final boolean DEBUG_REFS = false;
70-
70+
7171 private static final Object sSync = new Object();
7272 /*package*/ static AssetManager sSystem = null;
7373
7474 private final TypedValue mValue = new TypedValue();
7575 private final long[] mOffsets = new long[2];
76-
76+
7777 // For communication with native code.
7878 private long mObject;
7979
8080 private StringBlock mStringBlocks[] = null;
81-
81+
8282 private int mNumRefs = 1;
8383 private boolean mOpen = true;
8484 private HashMap<Long, RuntimeException> mRefStacks;
85-
85+
8686 /**
8787 * Create a new AssetManager containing only the basic system assets.
8888 * Applications will not generally use this method, instead retrieving the
@@ -111,7 +111,7 @@ public final class AssetManager implements AutoCloseable {
111111 }
112112 }
113113 }
114-
114+
115115 private AssetManager(boolean isSystem) {
116116 if (DEBUG_REFS) {
117117 synchronized (this) {
@@ -310,10 +310,10 @@ public final class AssetManager implements AutoCloseable {
310310 * Open an asset using ACCESS_STREAMING mode. This provides access to
311311 * files that have been bundled with an application as assets -- that is,
312312 * files placed in to the "assets" directory.
313- *
313+ *
314314 * @param fileName The name of the asset to open. This name can be
315315 * hierarchical.
316- *
316+ *
317317 * @see #open(String, int)
318318 * @see #list
319319 */
@@ -326,11 +326,11 @@ public final class AssetManager implements AutoCloseable {
326326 * read its contents. This provides access to files that have been bundled
327327 * with an application as assets -- that is, files placed in to the
328328 * "assets" directory.
329- *
329+ *
330330 * @param fileName The name of the asset to open. This name can be
331331 * hierarchical.
332332 * @param accessMode Desired access mode for retrieving the data.
333- *
333+ *
334334 * @see #ACCESS_UNKNOWN
335335 * @see #ACCESS_STREAMING
336336 * @see #ACCESS_RANDOM
@@ -370,14 +370,14 @@ public final class AssetManager implements AutoCloseable {
370370
371371 /**
372372 * Return a String array of all the assets at the given path.
373- *
373+ *
374374 * @param path A relative path within the assets, i.e., "docs/home.html".
375- *
375+ *
376376 * @return String[] Array of strings, one for each asset. These file
377377 * names are relative to 'path'. You can open the file by
378378 * concatenating 'path' and a name in the returned string (via
379379 * File) and passing that to open().
380- *
380+ *
381381 * @see #open
382382 */
383383 public native final String[] list(String path)
@@ -389,7 +389,7 @@ public final class AssetManager implements AutoCloseable {
389389 * provides direct access to all of the files included in an application
390390 * package (not only its assets). Applications should not normally use
391391 * this.
392- *
392+ *
393393 * @see #open(String)
394394 */
395395 public final InputStream openNonAsset(String fileName) throws IOException {
@@ -402,7 +402,7 @@ public final class AssetManager implements AutoCloseable {
402402 * provides direct access to all of the files included in an application
403403 * package (not only its assets). Applications should not normally use
404404 * this.
405- *
405+ *
406406 * @see #open(String, int)
407407 */
408408 public final InputStream openNonAsset(String fileName, int accessMode)
@@ -413,7 +413,7 @@ public final class AssetManager implements AutoCloseable {
413413 /**
414414 * {@hide}
415415 * Open a non-asset in a specified package. Not for use by applications.
416- *
416+ *
417417 * @param cookie Identifier of the package to be opened.
418418 * @param fileName Name of the asset to retrieve.
419419 */
@@ -425,7 +425,7 @@ public final class AssetManager implements AutoCloseable {
425425 /**
426426 * {@hide}
427427 * Open a non-asset in a specified package. Not for use by applications.
428- *
428+ *
429429 * @param cookie Identifier of the package to be opened.
430430 * @param fileName Name of the asset to retrieve.
431431 * @param accessMode Desired access mode for retrieving the data.
@@ -450,7 +450,7 @@ public final class AssetManager implements AutoCloseable {
450450 throws IOException {
451451 return openNonAssetFd(0, fileName);
452452 }
453-
453+
454454 public final AssetFileDescriptor openNonAssetFd(int cookie,
455455 String fileName) throws IOException {
456456 synchronized (this) {
@@ -465,20 +465,20 @@ public final class AssetManager implements AutoCloseable {
465465 }
466466 throw new FileNotFoundException("Asset absolute file: " + fileName);
467467 }
468-
468+
469469 /**
470470 * Retrieve a parser for a compiled XML file.
471- *
471+ *
472472 * @param fileName The name of the file to retrieve.
473473 */
474474 public final XmlResourceParser openXmlResourceParser(String fileName)
475475 throws IOException {
476476 return openXmlResourceParser(0, fileName);
477477 }
478-
478+
479479 /**
480480 * Retrieve a parser for a compiled XML file.
481- *
481+ *
482482 * @param cookie Identifier of the package to be opened.
483483 * @param fileName The name of the file to retrieve.
484484 */
@@ -494,7 +494,7 @@ public final class AssetManager implements AutoCloseable {
494494 * {@hide}
495495 * Retrieve a non-asset as a compiled XML file. Not for use by
496496 * applications.
497- *
497+ *
498498 * @param fileName The name of the file to retrieve.
499499 */
500500 /*package*/ final XmlBlock openXmlBlockAsset(String fileName)
@@ -506,7 +506,7 @@ public final class AssetManager implements AutoCloseable {
506506 * {@hide}
507507 * Retrieve a non-asset as a compiled XML file. Not for use by
508508 * applications.
509- *
509+ *
510510 * @param cookie Identifier of the package to be opened.
511511 * @param fileName Name of the asset to retrieve.
512512 */
@@ -561,12 +561,18 @@ public final class AssetManager implements AutoCloseable {
561561 }
562562 }
563563 }
564- destroy();
564+
565+ synchronized (this) {
566+ if (mObject != 0) {
567+ destroy();
568+ mObject = 0;
569+ }
570+ }
565571 } finally {
566572 super.finalize();
567573 }
568574 }
569-
575+
570576 public final class AssetInputStream extends InputStream {
571577 /**
572578 * @hide
@@ -769,7 +775,7 @@ public final class AssetManager implements AutoCloseable {
769775 /*package*/ native final String getResourcePackageName(int resid);
770776 /*package*/ native final String getResourceTypeName(int resid);
771777 /*package*/ native final String getResourceEntryName(int resid);
772-
778+
773779 private native final long openAsset(String fileName, int accessMode);
774780 private final native ParcelFileDescriptor openAssetFd(String fileName,
775781 long[] outOffsets) throws IOException;
@@ -829,17 +835,17 @@ public final class AssetManager implements AutoCloseable {
829835 * {@hide}
830836 */
831837 public native static final int getGlobalAssetCount();
832-
838+
833839 /**
834840 * {@hide}
835841 */
836842 public native static final String getAssetAllocations();
837-
843+
838844 /**
839845 * {@hide}
840846 */
841847 public native static final int getGlobalAssetManagerCount();
842-
848+
843849 private native final long newTheme();
844850 private native final void deleteTheme(long theme);
845851 /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
@@ -872,7 +878,7 @@ public final class AssetManager implements AutoCloseable {
872878 }
873879 mNumRefs++;
874880 }
875-
881+
876882 private final void decRefsLocked(long id) {
877883 if (DEBUG_REFS && mRefStacks != null) {
878884 mRefStacks.remove(id);
@@ -880,8 +886,9 @@ public final class AssetManager implements AutoCloseable {
880886 mNumRefs--;
881887 //System.out.println("Dec streams: mNumRefs=" + mNumRefs
882888 // + " mReleased=" + mReleased);
883- if (mNumRefs == 0) {
889+ if (mNumRefs == 0 && mObject != 0) {
884890 destroy();
891+ mObject = 0;
885892 }
886893 }
887894 }
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -28,14 +28,19 @@ import android.provider.BaseColumns;
2828 import android.text.TextUtils;
2929 import android.util.Log;
3030
31+import com.android.internal.util.ArrayUtils;
32+
3133 import libcore.util.EmptyArray;
3234
3335 import java.util.Arrays;
3436 import java.util.Iterator;
37+import java.util.List;
38+import java.util.Locale;
3539 import java.util.Map;
3640 import java.util.Map.Entry;
3741 import java.util.Objects;
3842 import java.util.Set;
43+import java.util.regex.Matcher;
3944 import java.util.regex.Pattern;
4045
4146 /**
@@ -45,15 +50,24 @@ import java.util.regex.Pattern;
4550 public class SQLiteQueryBuilder
4651 {
4752 private static final String TAG = "SQLiteQueryBuilder";
48- private static final Pattern sLimitPattern =
49- Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
5053
5154 private Map<String, String> mProjectionMap = null;
55+
56+ private static final Pattern sAggregationPattern = Pattern.compile(
57+ "(?i)(AVG|COUNT|MAX|MIN|SUM|TOTAL|GROUP_CONCAT)\\((.+)\\)");
58+
59+ private List<Pattern> mProjectionGreylist = null;
60+
5261 private String mTables = "";
5362 private StringBuilder mWhereClause = null; // lazily created
5463 private boolean mDistinct;
5564 private SQLiteDatabase.CursorFactory mFactory;
56- private boolean mStrict;
65+
66+ private static final int STRICT_PARENTHESES = 1 << 0;
67+ private static final int STRICT_COLUMNS = 1 << 1;
68+ private static final int STRICT_GRAMMAR = 1 << 2;
69+
70+ private int mStrictFlags;
5771
5872 public SQLiteQueryBuilder() {
5973 mDistinct = false;
@@ -139,6 +153,37 @@ public class SQLiteQueryBuilder
139153 }
140154
141155 /**
156+ * Gets the projection map for the query, as last configured by
157+ * {@link #setProjectionMap(Map)}.
158+ *
159+ * @hide
160+ */
161+ public @Nullable Map<String, String> getProjectionMap() {
162+ return mProjectionMap;
163+ }
164+
165+ /**
166+ * Sets a projection greylist of columns that will be allowed through, even
167+ * when {@link #setStrict(boolean)} is enabled. This provides a way for
168+ * abusive custom columns like {@code COUNT(*)} to continue working.
169+ *
170+ * @hide
171+ */
172+ public void setProjectionGreylist(@Nullable List<Pattern> projectionGreylist) {
173+ mProjectionGreylist = projectionGreylist;
174+ }
175+
176+ /**
177+ * Gets the projection greylist for the query, as last configured by
178+ * {@link #setProjectionGreylist(List)}.
179+ *
180+ * @hide
181+ */
182+ public @Nullable List<Pattern> getProjectionGreylist() {
183+ return mProjectionGreylist;
184+ }
185+
186+ /**
142187 * Sets the cursor factory to be used for the query. You can use
143188 * one factory for all queries on a database but it is normally
144189 * easier to specify the factory when doing this query.
@@ -170,8 +215,90 @@ public class SQLiteQueryBuilder
170215 * </ul>
171216 * By default, this value is false.
172217 */
173- public void setStrict(boolean flag) {
174- mStrict = flag;
218+ public void setStrict(boolean strict) {
219+ if (strict) {
220+ mStrictFlags |= STRICT_PARENTHESES;
221+ } else {
222+ mStrictFlags &= ~STRICT_PARENTHESES;
223+ }
224+ }
225+
226+ /**
227+ * Get if the query is marked as strict, as last configured by
228+ * {@link #setStrict(boolean)}.
229+ *
230+ * @hide
231+ */
232+ public boolean isStrict() {
233+ return (mStrictFlags & STRICT_PARENTHESES) != 0;
234+ }
235+
236+ /**
237+ * When enabled, verify that all projections and {@link ContentValues} only
238+ * contain valid columns as defined by {@link #setProjectionMap(Map)}.
239+ * <p>
240+ * This enforcement applies to {@link #insert}, {@link #query}, and
241+ * {@link #update} operations. Any enforcement failures will throw an
242+ * {@link IllegalArgumentException}.
243+ *
244+ * @hide
245+ */
246+ public void setStrictColumns(boolean strictColumns) {
247+ if (strictColumns) {
248+ mStrictFlags |= STRICT_COLUMNS;
249+ } else {
250+ mStrictFlags &= ~STRICT_COLUMNS;
251+ }
252+ }
253+
254+ /**
255+ * Get if the query is marked as strict, as last configured by
256+ * {@link #setStrictColumns(boolean)}.
257+ *
258+ * @hide
259+ */
260+ public boolean isStrictColumns() {
261+ return (mStrictFlags & STRICT_COLUMNS) != 0;
262+ }
263+
264+ /**
265+ * When enabled, verify that all untrusted SQL conforms to a restricted SQL
266+ * grammar. Here are the restrictions applied:
267+ * <ul>
268+ * <li>In {@code WHERE} and {@code HAVING} clauses: subqueries, raising, and
269+ * windowing terms are rejected.
270+ * <li>In {@code GROUP BY} clauses: only valid columns are allowed.
271+ * <li>In {@code ORDER BY} clauses: only valid columns, collation, and
272+ * ordering terms are allowed.
273+ * <li>In {@code LIMIT} clauses: only numerical values and offset terms are
274+ * allowed.
275+ * </ul>
276+ * All column references must be valid as defined by
277+ * {@link #setProjectionMap(Map)}.
278+ * <p>
279+ * This enforcement applies to {@link #query}, {@link #update} and
280+ * {@link #delete} operations. This enforcement does not apply to trusted
281+ * inputs, such as those provided by {@link #appendWhere}. Any enforcement
282+ * failures will throw an {@link IllegalArgumentException}.
283+ *
284+ * @hide
285+ */
286+ public void setStrictGrammar(boolean strictGrammar) {
287+ if (strictGrammar) {
288+ mStrictFlags |= STRICT_GRAMMAR;
289+ } else {
290+ mStrictFlags &= ~STRICT_GRAMMAR;
291+ }
292+ }
293+
294+ /**
295+ * Get if the query is marked as strict, as last configured by
296+ * {@link #setStrictGrammar(boolean)}.
297+ *
298+ * @hide
299+ */
300+ public boolean isStrictGrammar() {
301+ return (mStrictFlags & STRICT_GRAMMAR) != 0;
175302 }
176303
177304 /**
@@ -207,9 +334,6 @@ public class SQLiteQueryBuilder
207334 throw new IllegalArgumentException(
208335 "HAVING clauses are only permitted when using a groupBy clause");
209336 }
210- if (!TextUtils.isEmpty(limit) && !sLimitPattern.matcher(limit).matches()) {
211- throw new IllegalArgumentException("invalid LIMIT clauses:" + limit);
212- }
213337
214338 StringBuilder query = new StringBuilder(120);
215339
@@ -383,7 +507,13 @@ public class SQLiteQueryBuilder
383507 projectionIn, selection, groupBy, having,
384508 sortOrder, limit);
385509
386- if (mStrict && selection != null && selection.length() > 0) {
510+ if (isStrictColumns()) {
511+ enforceStrictColumns(projectionIn);
512+ }
513+ if (isStrictGrammar()) {
514+ enforceStrictGrammar(selection, groupBy, having, sortOrder, limit);
515+ }
516+ if (isStrict()) {
387517 // Validate the user-supplied selection to detect syntactic anomalies
388518 // in the selection string that could indicate a SQL injection attempt.
389519 // The idea is to ensure that the selection clause is a valid SQL expression
@@ -401,7 +531,7 @@ public class SQLiteQueryBuilder
401531
402532 // Execute wrapped query for extra protection
403533 final String wrappedSql = buildQuery(projectionIn, wrap(selection), groupBy,
404- having, sortOrder, limit);
534+ wrap(having), sortOrder, limit);
405535 sql = wrappedSql;
406536 } else {
407537 // Execute unwrapped query
@@ -446,7 +576,13 @@ public class SQLiteQueryBuilder
446576 final String sql;
447577 final String unwrappedSql = buildUpdate(values, selection);
448578
449- if (mStrict) {
579+ if (isStrictColumns()) {
580+ enforceStrictColumns(values);
581+ }
582+ if (isStrictGrammar()) {
583+ enforceStrictGrammar(selection, null, null, null, null);
584+ }
585+ if (isStrict()) {
450586 // Validate the user-supplied selection to detect syntactic anomalies
451587 // in the selection string that could indicate a SQL injection attempt.
452588 // The idea is to ensure that the selection clause is a valid SQL expression
@@ -516,7 +652,10 @@ public class SQLiteQueryBuilder
516652 final String sql;
517653 final String unwrappedSql = buildDelete(selection);
518654
519- if (mStrict) {
655+ if (isStrictGrammar()) {
656+ enforceStrictGrammar(selection, null, null, null, null);
657+ }
658+ if (isStrict()) {
520659 // Validate the user-supplied selection to detect syntactic anomalies
521660 // in the selection string that could indicate a SQL injection attempt.
522661 // The idea is to ensure that the selection clause is a valid SQL expression
@@ -551,6 +690,82 @@ public class SQLiteQueryBuilder
551690 return db.executeSql(sql, sqlArgs);
552691 }
553692
693+ private void enforceStrictColumns(@Nullable String[] projection) {
694+ Objects.requireNonNull(mProjectionMap, "No projection map defined");
695+
696+ computeProjection(projection);
697+ }
698+
699+ private void enforceStrictColumns(@NonNull ContentValues values) {
700+ Objects.requireNonNull(mProjectionMap, "No projection map defined");
701+
702+ final Set<String> rawValues = values.keySet();
703+ final Iterator<String> rawValuesIt = rawValues.iterator();
704+ while (rawValuesIt.hasNext()) {
705+ final String column = rawValuesIt.next();
706+ if (!mProjectionMap.containsKey(column)) {
707+ throw new IllegalArgumentException("Invalid column " + column);
708+ }
709+ }
710+ }
711+
712+ private void enforceStrictGrammar(@Nullable String selection, @Nullable String groupBy,
713+ @Nullable String having, @Nullable String sortOrder, @Nullable String limit) {
714+ SQLiteTokenizer.tokenize(selection, SQLiteTokenizer.OPTION_NONE,
715+ this::enforceStrictGrammarWhereHaving);
716+ SQLiteTokenizer.tokenize(groupBy, SQLiteTokenizer.OPTION_NONE,
717+ this::enforceStrictGrammarGroupBy);
718+ SQLiteTokenizer.tokenize(having, SQLiteTokenizer.OPTION_NONE,
719+ this::enforceStrictGrammarWhereHaving);
720+ SQLiteTokenizer.tokenize(sortOrder, SQLiteTokenizer.OPTION_NONE,
721+ this::enforceStrictGrammarOrderBy);
722+ SQLiteTokenizer.tokenize(limit, SQLiteTokenizer.OPTION_NONE,
723+ this::enforceStrictGrammarLimit);
724+ }
725+
726+ private void enforceStrictGrammarWhereHaving(@NonNull String token) {
727+ if (isTableOrColumn(token)) return;
728+ if (SQLiteTokenizer.isFunction(token)) return;
729+ if (SQLiteTokenizer.isType(token)) return;
730+
731+ // NOTE: we explicitly don't allow SELECT subqueries, since they could
732+ // leak data that should have been filtered by the trusted where clause
733+ switch (token.toUpperCase(Locale.US)) {
734+ case "AND": case "AS": case "BETWEEN": case "BINARY":
735+ case "CASE": case "CAST": case "COLLATE": case "DISTINCT":
736+ case "ELSE": case "END": case "ESCAPE": case "EXISTS":
737+ case "GLOB": case "IN": case "IS": case "ISNULL":
738+ case "LIKE": case "MATCH": case "NOCASE": case "NOT":
739+ case "NOTNULL": case "NULL": case "OR": case "REGEXP":
740+ case "RTRIM": case "THEN": case "WHEN":
741+ return;
742+ }
743+ throw new IllegalArgumentException("Invalid token " + token);
744+ }
745+
746+ private void enforceStrictGrammarGroupBy(@NonNull String token) {
747+ if (isTableOrColumn(token)) return;
748+ throw new IllegalArgumentException("Invalid token " + token);
749+ }
750+
751+ private void enforceStrictGrammarOrderBy(@NonNull String token) {
752+ if (isTableOrColumn(token)) return;
753+ switch (token.toUpperCase(Locale.US)) {
754+ case "COLLATE": case "ASC": case "DESC":
755+ case "BINARY": case "RTRIM": case "NOCASE":
756+ return;
757+ }
758+ throw new IllegalArgumentException("Invalid token " + token);
759+ }
760+
761+ private void enforceStrictGrammarLimit(@NonNull String token) {
762+ switch (token.toUpperCase(Locale.US)) {
763+ case "OFFSET":
764+ return;
765+ }
766+ throw new IllegalArgumentException("Invalid token " + token);
767+ }
768+
554769 /**
555770 * Construct a SELECT statement suitable for use in a group of
556771 * SELECT statements that will be joined through UNION operators
@@ -611,7 +826,7 @@ public class SQLiteQueryBuilder
611826
612827 StringBuilder sql = new StringBuilder(120);
613828 sql.append("UPDATE ");
614- sql.append(mTables);
829+ sql.append(SQLiteDatabase.findEditTable(mTables));
615830 sql.append(" SET ");
616831
617832 final String[] rawKeys = values.keySet().toArray(EmptyArray.STRING);
@@ -632,7 +847,7 @@ public class SQLiteQueryBuilder
632847 public String buildDelete(String selection) {
633848 StringBuilder sql = new StringBuilder(120);
634849 sql.append("DELETE FROM ");
635- sql.append(mTables);
850+ sql.append(SQLiteDatabase.findEditTable(mTables));
636851
637852 final String where = computeWhere(selection);
638853 appendClause(sql, " WHERE ", where);
@@ -763,35 +978,23 @@ public class SQLiteQueryBuilder
763978 return query.toString();
764979 }
765980
766- private String[] computeProjection(String[] projectionIn) {
767- if (projectionIn != null && projectionIn.length > 0) {
768- if (mProjectionMap != null) {
769- String[] projection = new String[projectionIn.length];
770- int length = projectionIn.length;
771-
772- for (int i = 0; i < length; i++) {
773- String userColumn = projectionIn[i];
774- String column = mProjectionMap.get(userColumn);
775-
776- if (column != null) {
777- projection[i] = column;
778- continue;
779- }
780-
781- if (!mStrict &&
782- ( userColumn.contains(" AS ") || userColumn.contains(" as "))) {
783- /* A column alias already exist */
784- projection[i] = userColumn;
785- continue;
786- }
981+ private static @NonNull String maybeWithOperator(@Nullable String operator,
982+ @NonNull String column) {
983+ if (operator != null) {
984+ return operator + "(" + column + ")";
985+ } else {
986+ return column;
987+ }
988+ }
787989
788- throw new IllegalArgumentException("Invalid column "
789- + projectionIn[i]);
790- }
791- return projection;
792- } else {
793- return projectionIn;
990+ /** {@hide} */
991+ public @Nullable String[] computeProjection(@Nullable String[] projectionIn) {
992+ if (!ArrayUtils.isEmpty(projectionIn)) {
993+ String[] projectionOut = new String[projectionIn.length];
994+ for (int i = 0; i < projectionIn.length; i++) {
995+ projectionOut[i] = computeSingleProjectionOrThrow(projectionIn[i]);
794996 }
997+ return projectionOut;
795998 } else if (mProjectionMap != null) {
796999 // Return all columns in projection map.
7971000 Set<Entry<String, String>> entrySet = mProjectionMap.entrySet();
@@ -813,7 +1016,71 @@ public class SQLiteQueryBuilder
8131016 return null;
8141017 }
8151018
816- private @Nullable String computeWhere(@Nullable String selection) {
1019+ private @NonNull String computeSingleProjectionOrThrow(@NonNull String userColumn) {
1020+ final String column = computeSingleProjection(userColumn);
1021+ if (column != null) {
1022+ return column;
1023+ } else {
1024+ throw new IllegalArgumentException("Invalid column " + userColumn);
1025+ }
1026+ }
1027+
1028+ private @Nullable String computeSingleProjection(@NonNull String userColumn) {
1029+ // When no mapping provided, anything goes
1030+ if (mProjectionMap == null) {
1031+ return userColumn;
1032+ }
1033+
1034+ String operator = null;
1035+ String column = mProjectionMap.get(userColumn);
1036+
1037+ // When no direct match found, look for aggregation
1038+ if (column == null) {
1039+ final Matcher matcher = sAggregationPattern.matcher(userColumn);
1040+ if (matcher.matches()) {
1041+ operator = matcher.group(1);
1042+ userColumn = matcher.group(2);
1043+ column = mProjectionMap.get(userColumn);
1044+ }
1045+ }
1046+
1047+ if (column != null) {
1048+ return maybeWithOperator(operator, column);
1049+ }
1050+
1051+ if (mStrictFlags == 0
1052+ && (userColumn.contains(" AS ") || userColumn.contains(" as "))) {
1053+ /* A column alias already exist */
1054+ return maybeWithOperator(operator, userColumn);
1055+ }
1056+
1057+ // If greylist is configured, we might be willing to let
1058+ // this custom column bypass our strict checks.
1059+ if (mProjectionGreylist != null) {
1060+ boolean match = false;
1061+ for (Pattern p : mProjectionGreylist) {
1062+ if (p.matcher(userColumn).matches()) {
1063+ match = true;
1064+ break;
1065+ }
1066+ }
1067+
1068+ if (match) {
1069+ Log.w(TAG, "Allowing abusive custom column: " + userColumn);
1070+ return maybeWithOperator(operator, userColumn);
1071+ }
1072+ }
1073+
1074+ return null;
1075+ }
1076+
1077+ private boolean isTableOrColumn(String token) {
1078+ if (mTables.equals(token)) return true;
1079+ return computeSingleProjection(token) != null;
1080+ }
1081+
1082+ /** {@hide} */
1083+ public @Nullable String computeWhere(@Nullable String selection) {
8171084 final boolean hasInternal = !TextUtils.isEmpty(mWhereClause);
8181085 final boolean hasExternal = !TextUtils.isEmpty(selection);
8191086
--- /dev/null
+++ b/core/java/android/database/sqlite/SQLiteTokenizer.java
@@ -0,0 +1,297 @@
1+/*
2+ * Copyright (C) 2019 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+
17+package android.database.sqlite;
18+
19+import android.annotation.NonNull;
20+import android.annotation.Nullable;
21+
22+import java.util.ArrayList;
23+import java.util.List;
24+import java.util.Locale;
25+import java.util.function.Consumer;
26+
27+/**
28+ * SQL Tokenizer specialized to extract tokens from SQL (snippets).
29+ * <p>
30+ * Based on sqlite3GetToken() in tokenzie.c in SQLite.
31+ * <p>
32+ * Source for v3.8.6 (which android uses): http://www.sqlite.org/src/artifact/ae45399d6252b4d7
33+ * (Latest source as of now: http://www.sqlite.org/src/artifact/78c8085bc7af1922)
34+ * <p>
35+ * Also draft spec: http://www.sqlite.org/draft/tokenreq.html
36+ *
37+ * @hide
38+ */
39+public class SQLiteTokenizer {
40+ private static boolean isAlpha(char ch) {
41+ return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || (ch == '_');
42+ }
43+
44+ private static boolean isNum(char ch) {
45+ return ('0' <= ch && ch <= '9');
46+ }
47+
48+ private static boolean isAlNum(char ch) {
49+ return isAlpha(ch) || isNum(ch);
50+ }
51+
52+ private static boolean isAnyOf(char ch, String set) {
53+ return set.indexOf(ch) >= 0;
54+ }
55+
56+ private static IllegalArgumentException genException(String message, String sql) {
57+ throw new IllegalArgumentException(message + " in '" + sql + "'");
58+ }
59+
60+ private static char peek(String s, int index) {
61+ return index < s.length() ? s.charAt(index) : '\0';
62+ }
63+
64+ public static final int OPTION_NONE = 0;
65+
66+ /**
67+ * Require that SQL contains only tokens; any comments or values will result
68+ * in an exception.
69+ */
70+ public static final int OPTION_TOKEN_ONLY = 1 << 0;
71+
72+ /**
73+ * Tokenize the given SQL, returning the list of each encountered token.
74+ *
75+ * @throws IllegalArgumentException if invalid SQL is encountered.
76+ */
77+ public static List<String> tokenize(@Nullable String sql, int options) {
78+ final ArrayList<String> res = new ArrayList<>();
79+ tokenize(sql, options, res::add);
80+ return res;
81+ }
82+
83+ /**
84+ * Tokenize the given SQL, sending each encountered token to the given
85+ * {@link Consumer}.
86+ *
87+ * @throws IllegalArgumentException if invalid SQL is encountered.
88+ */
89+ public static void tokenize(@Nullable String sql, int options, Consumer<String> checker) {
90+ if (sql == null) {
91+ return;
92+ }
93+ int pos = 0;
94+ final int len = sql.length();
95+ while (pos < len) {
96+ final char ch = peek(sql, pos);
97+
98+ // Regular token.
99+ if (isAlpha(ch)) {
100+ final int start = pos;
101+ pos++;
102+ while (isAlNum(peek(sql, pos))) {
103+ pos++;
104+ }
105+ final int end = pos;
106+
107+ final String token = sql.substring(start, end);
108+ checker.accept(token);
109+
110+ continue;
111+ }
112+
113+ // Handle quoted tokens
114+ if (isAnyOf(ch, "'\"`")) {
115+ final int quoteStart = pos;
116+ pos++;
117+
118+ for (;;) {
119+ pos = sql.indexOf(ch, pos);
120+ if (pos < 0) {
121+ throw genException("Unterminated quote", sql);
122+ }
123+ if (peek(sql, pos + 1) != ch) {
124+ break;
125+ }
126+ // Quoted quote char -- e.g. "abc""def" is a single string.
127+ pos += 2;
128+ }
129+ final int quoteEnd = pos;
130+ pos++;
131+
132+ if (ch != '\'') {
133+ // Extract the token
134+ final String tokenUnquoted = sql.substring(quoteStart + 1, quoteEnd);
135+
136+ final String token;
137+
138+ // Unquote if needed. i.e. "aa""bb" -> aa"bb
139+ if (tokenUnquoted.indexOf(ch) >= 0) {
140+ token = tokenUnquoted.replaceAll(
141+ String.valueOf(ch) + ch, String.valueOf(ch));
142+ } else {
143+ token = tokenUnquoted;
144+ }
145+ checker.accept(token);
146+ } else {
147+ if ((options &= OPTION_TOKEN_ONLY) != 0) {
148+ throw genException("Non-token detected", sql);
149+ }
150+ }
151+ continue;
152+ }
153+ // Handle tokens enclosed in [...]
154+ if (ch == '[') {
155+ final int quoteStart = pos;
156+ pos++;
157+
158+ pos = sql.indexOf(']', pos);
159+ if (pos < 0) {
160+ throw genException("Unterminated quote", sql);
161+ }
162+ final int quoteEnd = pos;
163+ pos++;
164+
165+ final String token = sql.substring(quoteStart + 1, quoteEnd);
166+
167+ checker.accept(token);
168+ continue;
169+ }
170+ if ((options &= OPTION_TOKEN_ONLY) != 0) {
171+ throw genException("Non-token detected", sql);
172+ }
173+
174+ // Detect comments.
175+ if (ch == '-' && peek(sql, pos + 1) == '-') {
176+ pos += 2;
177+ pos = sql.indexOf('\n', pos);
178+ if (pos < 0) {
179+ // We disallow strings ending in an inline comment.
180+ throw genException("Unterminated comment", sql);
181+ }
182+ pos++;
183+
184+ continue;
185+ }
186+ if (ch == '/' && peek(sql, pos + 1) == '*') {
187+ pos += 2;
188+ pos = sql.indexOf("*/", pos);
189+ if (pos < 0) {
190+ throw genException("Unterminated comment", sql);
191+ }
192+ pos += 2;
193+
194+ continue;
195+ }
196+
197+ // Semicolon is never allowed.
198+ if (ch == ';') {
199+ throw genException("Semicolon is not allowed", sql);
200+ }
201+
202+ // For this purpose, we can simply ignore other characters.
203+ // (Note it doesn't handle the X'' literal properly and reports this X as a token,
204+ // but that should be fine...)
205+ pos++;
206+ }
207+ }
208+
209+ /**
210+ * Test if given token is a
211+ * <a href="https://www.sqlite.org/lang_keywords.html">SQLite reserved
212+ * keyword</a>.
213+ */
214+ public static boolean isKeyword(@NonNull String token) {
215+ switch (token.toUpperCase(Locale.US)) {
216+ case "ABORT": case "ACTION": case "ADD": case "AFTER":
217+ case "ALL": case "ALTER": case "ANALYZE": case "AND":
218+ case "AS": case "ASC": case "ATTACH": case "AUTOINCREMENT":
219+ case "BEFORE": case "BEGIN": case "BETWEEN": case "BINARY":
220+ case "BY": case "CASCADE": case "CASE": case "CAST":
221+ case "CHECK": case "COLLATE": case "COLUMN": case "COMMIT":
222+ case "CONFLICT": case "CONSTRAINT": case "CREATE": case "CROSS":
223+ case "CURRENT": case "CURRENT_DATE": case "CURRENT_TIME": case "CURRENT_TIMESTAMP":
224+ case "DATABASE": case "DEFAULT": case "DEFERRABLE": case "DEFERRED":
225+ case "DELETE": case "DESC": case "DETACH": case "DISTINCT":
226+ case "DO": case "DROP": case "EACH": case "ELSE":
227+ case "END": case "ESCAPE": case "EXCEPT": case "EXCLUDE":
228+ case "EXCLUSIVE": case "EXISTS": case "EXPLAIN": case "FAIL":
229+ case "FILTER": case "FOLLOWING": case "FOR": case "FOREIGN":
230+ case "FROM": case "FULL": case "GLOB": case "GROUP":
231+ case "GROUPS": case "HAVING": case "IF": case "IGNORE":
232+ case "IMMEDIATE": case "IN": case "INDEX": case "INDEXED":
233+ case "INITIALLY": case "INNER": case "INSERT": case "INSTEAD":
234+ case "INTERSECT": case "INTO": case "IS": case "ISNULL":
235+ case "JOIN": case "KEY": case "LEFT": case "LIKE":
236+ case "LIMIT": case "MATCH": case "NATURAL": case "NO":
237+ case "NOCASE": case "NOT": case "NOTHING": case "NOTNULL":
238+ case "NULL": case "OF": case "OFFSET": case "ON":
239+ case "OR": case "ORDER": case "OTHERS": case "OUTER":
240+ case "OVER": case "PARTITION": case "PLAN": case "PRAGMA":
241+ case "PRECEDING": case "PRIMARY": case "QUERY": case "RAISE":
242+ case "RANGE": case "RECURSIVE": case "REFERENCES": case "REGEXP":
243+ case "REINDEX": case "RELEASE": case "RENAME": case "REPLACE":
244+ case "RESTRICT": case "RIGHT": case "ROLLBACK": case "ROW":
245+ case "ROWS": case "RTRIM": case "SAVEPOINT": case "SELECT":
246+ case "SET": case "TABLE": case "TEMP": case "TEMPORARY":
247+ case "THEN": case "TIES": case "TO": case "TRANSACTION":
248+ case "TRIGGER": case "UNBOUNDED": case "UNION": case "UNIQUE":
249+ case "UPDATE": case "USING": case "VACUUM": case "VALUES":
250+ case "VIEW": case "VIRTUAL": case "WHEN": case "WHERE":
251+ case "WINDOW": case "WITH": case "WITHOUT":
252+ return true;
253+ default:
254+ return false;
255+ }
256+ }
257+
258+ /**
259+ * Test if given token is a
260+ * <a href="https://www.sqlite.org/lang_corefunc.html">SQLite reserved
261+ * function</a>.
262+ */
263+ public static boolean isFunction(@NonNull String token) {
264+ switch (token.toLowerCase(Locale.US)) {
265+ case "abs": case "avg": case "char": case "coalesce":
266+ case "count": case "glob": case "group_concat": case "hex":
267+ case "ifnull": case "instr": case "length": case "like":
268+ case "likelihood": case "likely": case "lower": case "ltrim":
269+ case "max": case "min": case "nullif": case "random":
270+ case "randomblob": case "replace": case "round": case "rtrim":
271+ case "substr": case "sum": case "total": case "trim":
272+ case "typeof": case "unicode": case "unlikely": case "upper":
273+ case "zeroblob":
274+ return true;
275+ default:
276+ return false;
277+ }
278+ }
279+
280+ /**
281+ * Test if given token is a
282+ * <a href="https://www.sqlite.org/datatype3.html">SQLite reserved type</a>.
283+ */
284+ public static boolean isType(@NonNull String token) {
285+ switch (token.toUpperCase(Locale.US)) {
286+ case "INT": case "INTEGER": case "TINYINT": case "SMALLINT":
287+ case "MEDIUMINT": case "BIGINT": case "INT2": case "INT8":
288+ case "CHARACTER": case "VARCHAR": case "NCHAR": case "NVARCHAR":
289+ case "TEXT": case "CLOB": case "BLOB": case "REAL":
290+ case "DOUBLE": case "FLOAT": case "NUMERIC": case "DECIMAL":
291+ case "BOOLEAN": case "DATE": case "DATETIME":
292+ return true;
293+ default:
294+ return false;
295+ }
296+ }
297+}
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4883,6 +4883,18 @@ public final class Settings {
48834883 public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED;
48844884
48854885 /**
4886+ * Indicates whether a DPC has been downloaded during provisioning.
4887+ *
4888+ * <p>Type: int (0 for false, 1 for true)
4889+ *
4890+ * <p>If this is true, then any attempts to begin setup again should result in factory reset
4891+ *
4892+ * @hide
4893+ */
4894+ public static final String MANAGED_PROVISIONING_DPC_DOWNLOADED =
4895+ "managed_provisioning_dpc_downloaded";
4896+
4897+ /**
48864898 * Whether the current user has been set up via setup wizard (0 = false, 1 = true)
48874899 * @hide
48884900 */
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -208,6 +208,7 @@ class TextLine {
208208 int lastRunIndex = runs.length - 2;
209209 for (int i = 0; i < runs.length; i += 2) {
210210 int runStart = runs[i];
211+ if (runStart > mLen) break;
211212 int runLimit = runStart + (runs[i+1] & Layout.RUN_LENGTH_MASK);
212213 if (runLimit > mLen) {
213214 runLimit = mLen;
@@ -285,6 +286,7 @@ class TextLine {
285286 int[] runs = mDirections.mDirections;
286287 for (int i = 0; i < runs.length; i += 2) {
287288 int runStart = runs[i];
289+ if (runStart > mLen) break;
288290 int runLimit = runStart + (runs[i+1] & Layout.RUN_LENGTH_MASK);
289291 if (runLimit > mLen) {
290292 runLimit = mLen;
@@ -374,6 +376,7 @@ class TextLine {
374376 int[] runs = mDirections.mDirections;
375377 for (int i = 0; i < runs.length; i += 2) {
376378 int runStart = runs[i];
379+ if (runStart > mLen) break;
377380 int runLimit = runStart + (runs[i + 1] & Layout.RUN_LENGTH_MASK);
378381 if (runLimit > mLen) {
379382 runLimit = mLen;
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -16,6 +16,8 @@
1616
1717 package android.widget;
1818
19+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
20+
1921 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
2022
2123 import android.R;
@@ -24,11 +26,13 @@ import android.annotation.DrawableRes;
2426 import android.annotation.FloatRange;
2527 import android.annotation.NonNull;
2628 import android.annotation.Nullable;
29+import android.annotation.RequiresPermission;
2730 import android.annotation.Size;
2831 import android.annotation.StringRes;
2932 import android.annotation.StyleRes;
3033 import android.annotation.XmlRes;
3134 import android.app.Activity;
35+import android.app.ActivityManager;
3236 import android.app.assist.AssistStructure;
3337 import android.content.ClipData;
3438 import android.content.ClipboardManager;
@@ -620,6 +624,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
620624
621625 private InputFilter[] mFilters = NO_FILTERS;
622626
627+ /**
628+ * To keep the information to indicate if there is necessary to restrict the power of
629+ * INTERACT_ACROSS_USERS_FULL.
630+ * <p>
631+ * SystemUI always run as user 0 to process all of direct reply. SystemUI has the poer of
632+ * INTERACT_ACROSS_USERS_FULL. However, all of the notifications not only belong to user 0 but
633+ * also to the other users in multiple user environment.
634+ * </p>
635+ *
636+ * @see #setRestrictedAcrossUser(boolean)
637+ */
638+ private boolean mIsRestrictedAcrossUser;
639+
623640 private volatile Locale mCurrentSpellCheckerLocaleCache;
624641
625642 // It is possible to have a selection even when mEditor is null (programmatically set, like when
@@ -8827,6 +8844,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
88278844 }
88288845
88298846 /**
8847+ * To notify the TextView to restricted the power of the app granted INTERACT_ACROSS_USERS_FULL
8848+ * permission.
8849+ * <p>
8850+ * Most of applications should not granted the INTERACT_ACROSS_USERS_FULL permssion.
8851+ * SystemUI is the special one that run in user 0 process to handle multiple user notification.
8852+ * Unforunately, the power of INTERACT_ACROSS_USERS_FULL should be limited or restricted for
8853+ * preventing from information leak.</p>
8854+ * <p>This function call is called for SystemUI Keyguard and Notification.</p>
8855+ *
8856+ * @param isRestricted is true if the power of INTERACT_ACROSS_USERS_FULL should be limited.
8857+ * @hide
8858+ */
8859+ @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
8860+ public final void setRestrictedAcrossUser(boolean isRestricted) {
8861+ mIsRestrictedAcrossUser = isRestricted;
8862+ }
8863+
8864+ /**
88308865 * This is a temporary method. Future versions may support multi-locale text.
88318866 * Caveat: This method may not return the latest text services locale, but this should be
88328867 * acceptable and it's more important to make this method asynchronous.
@@ -9569,6 +9604,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
95699604 }
95709605
95719606 boolean canCut() {
9607+ if (mIsRestrictedAcrossUser
9608+ && UserHandle.myUserId() != ActivityManager.getCurrentUser()) {
9609+ // When it's restricted, and the curren user is not the process user. It can't cut
9610+ // because it may cut the text of the user 10 into the clipboard of user 0.
9611+ return false;
9612+ }
95729613 if (hasPasswordTransformationMethod()) {
95739614 return false;
95749615 }
@@ -9582,6 +9623,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
95829623 }
95839624
95849625 boolean canCopy() {
9626+ if (mIsRestrictedAcrossUser
9627+ && UserHandle.myUserId() != ActivityManager.getCurrentUser()) {
9628+ // When it's restricted, and the curren user is not the process user. It can't copy
9629+ // because it may copy the text of the user 10 to the clipboard of user 0.
9630+ return false;
9631+ }
95859632 if (hasPasswordTransformationMethod()) {
95869633 return false;
95879634 }
@@ -9611,6 +9658,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
96119658 }
96129659
96139660 boolean canPaste() {
9661+ if (mIsRestrictedAcrossUser
9662+ && UserHandle.myUserId() != ActivityManager.getCurrentUser()) {
9663+ // When it's restricted, and the curren user is not the process user. It can't paste
9664+ // because it may copy the text from the user 0 clipboard in current user is 10.
9665+ return false;
9666+ }
96149667 return (mText instanceof Editable &&
96159668 mEditor != null && mEditor.mKeyListener != null &&
96169669 getSelectionStart() >= 0 &&
--- /dev/null
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteTokenizerTest.java
@@ -0,0 +1,169 @@
1+/*
2+ * Copyright (C) 2019 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+
17+package android.database.sqlite;
18+
19+import static org.junit.Assert.assertEquals;
20+import static org.junit.Assert.assertTrue;
21+import static org.junit.Assert.fail;
22+
23+import org.junit.Test;
24+
25+import java.util.ArrayList;
26+import java.util.Arrays;
27+import java.util.List;
28+
29+public class SQLiteTokenizerTest {
30+ private List<String> getTokens(String sql) {
31+ return SQLiteTokenizer.tokenize(sql, SQLiteTokenizer.OPTION_NONE);
32+ }
33+
34+ private void checkTokens(String sql, String spaceSeparatedExpectedTokens) {
35+ final List<String> expected = spaceSeparatedExpectedTokens == null
36+ ? new ArrayList<>()
37+ : Arrays.asList(spaceSeparatedExpectedTokens.split(" +"));
38+
39+ assertEquals(expected, getTokens(sql));
40+ }
41+
42+ private void assertInvalidSql(String sql, String message) {
43+ try {
44+ getTokens(sql);
45+ fail("Didn't throw InvalidSqlException");
46+ } catch (IllegalArgumentException e) {
47+ assertTrue("Expected " + e.getMessage() + " to contain " + message,
48+ e.getMessage().contains(message));
49+ }
50+ }
51+
52+ @Test
53+ public void testWhitespaces() {
54+ checkTokens(" select \t\r\n a\n\n ", "select a");
55+ checkTokens("a b", "a b");
56+ }
57+
58+ @Test
59+ public void testComment() {
60+ checkTokens("--\n", null);
61+ checkTokens("a--\n", "a");
62+ checkTokens("a--abcdef\n", "a");
63+ checkTokens("a--abcdef\nx", "a x");
64+ checkTokens("a--\nx", "a x");
65+ assertInvalidSql("a--abcdef", "Unterminated comment");
66+ assertInvalidSql("a--abcdef\ndef--", "Unterminated comment");
67+
68+ checkTokens("/**/", null);
69+ assertInvalidSql("/*", "Unterminated comment");
70+ assertInvalidSql("/*/", "Unterminated comment");
71+ assertInvalidSql("/*\n* /*a", "Unterminated comment");
72+ checkTokens("a/**/", "a");
73+ checkTokens("/**/b", "b");
74+ checkTokens("a/**/b", "a b");
75+ checkTokens("a/* -- \n* /* **/b", "a b");
76+ }
77+
78+ @Test
79+ public void testStrings() {
80+ assertInvalidSql("'", "Unterminated quote");
81+ assertInvalidSql("a'", "Unterminated quote");
82+ assertInvalidSql("a'''", "Unterminated quote");
83+ assertInvalidSql("a''' ", "Unterminated quote");
84+ checkTokens("''", null);
85+ checkTokens("''''", null);
86+ checkTokens("a''''b", "a b");
87+ checkTokens("a' '' 'b", "a b");
88+ checkTokens("'abc'", null);
89+ checkTokens("'abc\ndef'", null);
90+ checkTokens("a'abc\ndef'", "a");
91+ checkTokens("'abc\ndef'b", "b");
92+ checkTokens("a'abc\ndef'b", "a b");
93+ checkTokens("a'''abc\nd''ef'''b", "a b");
94+ }
95+
96+ @Test
97+ public void testDoubleQuotes() {
98+ assertInvalidSql("\"", "Unterminated quote");
99+ assertInvalidSql("a\"", "Unterminated quote");
100+ assertInvalidSql("a\"\"\"", "Unterminated quote");
101+ assertInvalidSql("a\"\"\" ", "Unterminated quote");
102+ checkTokens("\"\"", "");
103+ checkTokens("\"\"\"\"", "\"");
104+ checkTokens("a\"\"\"\"b", "a \" b");
105+ checkTokens("a\"\t\"\"\t\"b", "a \t\"\t b");
106+ checkTokens("\"abc\"", "abc");
107+ checkTokens("\"abc\ndef\"", "abc\ndef");
108+ checkTokens("a\"abc\ndef\"", "a abc\ndef");
109+ checkTokens("\"abc\ndef\"b", "abc\ndef b");
110+ checkTokens("a\"abc\ndef\"b", "a abc\ndef b");
111+ checkTokens("a\"\"\"abc\nd\"\"ef\"\"\"b", "a \"abc\nd\"ef\" b");
112+ }
113+
114+ @Test
115+ public void testBackQuotes() {
116+ assertInvalidSql("`", "Unterminated quote");
117+ assertInvalidSql("a`", "Unterminated quote");
118+ assertInvalidSql("a```", "Unterminated quote");
119+ assertInvalidSql("a``` ", "Unterminated quote");
120+ checkTokens("``", "");
121+ checkTokens("````", "`");
122+ checkTokens("a````b", "a ` b");
123+ checkTokens("a`\t``\t`b", "a \t`\t b");
124+ checkTokens("`abc`", "abc");
125+ checkTokens("`abc\ndef`", "abc\ndef");
126+ checkTokens("a`abc\ndef`", "a abc\ndef");
127+ checkTokens("`abc\ndef`b", "abc\ndef b");
128+ checkTokens("a`abc\ndef`b", "a abc\ndef b");
129+ checkTokens("a```abc\nd``ef```b", "a `abc\nd`ef` b");
130+ }
131+
132+ @Test
133+ public void testBrackets() {
134+ assertInvalidSql("[", "Unterminated quote");
135+ assertInvalidSql("a[", "Unterminated quote");
136+ assertInvalidSql("a[ ", "Unterminated quote");
137+ assertInvalidSql("a[[ ", "Unterminated quote");
138+ checkTokens("[]", "");
139+ checkTokens("[[]", "[");
140+ checkTokens("a[[]b", "a [ b");
141+ checkTokens("a[\t[\t]b", "a \t[\t b");
142+ checkTokens("[abc]", "abc");
143+ checkTokens("[abc\ndef]", "abc\ndef");
144+ checkTokens("a[abc\ndef]", "a abc\ndef");
145+ checkTokens("[abc\ndef]b", "abc\ndef b");
146+ checkTokens("a[abc\ndef]b", "a abc\ndef b");
147+ checkTokens("a[[abc\nd[ef[]b", "a [abc\nd[ef[ b");
148+ }
149+
150+ @Test
151+ public void testSemicolons() {
152+ assertInvalidSql(";", "Semicolon is not allowed");
153+ assertInvalidSql(" ;", "Semicolon is not allowed");
154+ assertInvalidSql("; ", "Semicolon is not allowed");
155+ assertInvalidSql("-;-", "Semicolon is not allowed");
156+ checkTokens("--;\n", null);
157+ checkTokens("/*;*/", null);
158+ checkTokens("';'", null);
159+ checkTokens("[;]", ";");
160+ checkTokens("`;`", ";");
161+ }
162+
163+ @Test
164+ public void testTokens() {
165+ checkTokens("a,abc,a00b,_1,_123,abcdef", "a abc a00b _1 _123 abcdef");
166+ checkTokens("a--\nabc/**/a00b''_1'''ABC'''`_123`abc[d]\"e\"f",
167+ "a abc a00b _1 _123 abc d e f");
168+ }
169+}
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
@@ -79,6 +79,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
7979
8080 @Override
8181 protected void resetState() {
82+ mPasswordEntry.setRestrictedAcrossUser(true);
8283 mSecurityMessageDisplay.setMessage(getMessageWithCount(R.string.kg_password_instructions), false);
8384 final boolean wasDisabled = mPasswordEntry.isEnabled();
8485 setPasswordEntryEnabled(true);
@@ -175,6 +176,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
175176 Context.INPUT_METHOD_SERVICE);
176177
177178 mPasswordEntry = (TextView) findViewById(getPasswordTextViewId());
179+ mPasswordEntry.setRestrictedAcrossUser(true);
178180 mPasswordEntryDisabler = new TextViewInputDisabler(mPasswordEntry);
179181 mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
180182 mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -25,6 +25,7 @@ import android.content.SharedPreferences;
2525 import android.os.ParcelUuid;
2626 import android.os.SystemClock;
2727 import android.text.TextUtils;
28+import android.util.EventLog;
2829 import android.util.Log;
2930 import android.bluetooth.BluetoothAdapter;
3031
@@ -838,10 +839,9 @@ public final class CachedBluetoothDevice implements Comparable<CachedBluetoothDe
838839 == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE ||
839840 mDevice.getBluetoothClass().getDeviceClass()
840841 == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET) {
841- setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_ALLOWED);
842- } else {
843- setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_REJECTED);
842+ EventLog.writeEvent(0x534e4554, "138529441", -1, "");
844843 }
844+ setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_REJECTED);
845845 }
846846 }
847847 }
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.policy;
1818
1919 import android.animation.Animator;
2020 import android.animation.AnimatorListenerAdapter;
21+import android.app.ActivityManager;
2122 import android.app.Notification;
2223 import android.app.PendingIntent;
2324 import android.app.RemoteInput;
@@ -27,7 +28,9 @@ import android.content.pm.ShortcutManager;
2728 import android.graphics.Rect;
2829 import android.graphics.drawable.Drawable;
2930 import android.os.Bundle;
31+import android.os.UserHandle;
3032 import android.text.Editable;
33+import android.text.InputType;
3134 import android.text.TextWatcher;
3235 import android.util.AttributeSet;
3336 import android.util.Log;
@@ -174,6 +177,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
174177 LayoutInflater.from(context).inflate(R.layout.remote_input, root, false);
175178 v.mController = controller;
176179 v.mEntry = entry;
180+ v.mEditText.setRestrictedAcrossUser(true);
177181 v.setTag(VIEW_TAG);
178182
179183 return v;
@@ -268,6 +272,16 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
268272
269273 setVisibility(VISIBLE);
270274 mController.addRemoteInput(mEntry, mToken);
275+
276+ // Disable suggestions on non-owner (secondary) user.
277+ // SpellCheckerService of primary user runs on secondary as well which shows
278+ // "Add to dictionary" dialog on the primary user. (See b/123232892)
279+ // Note: this doesn't affect work-profile users on P or older versions.
280+ if (UserHandle.myUserId() != ActivityManager.getCurrentUser()) {
281+ mEditText.setInputType(
282+ mEditText.getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
283+ }
284+
271285 mEditText.setInnerFocusable(true);
272286 mEditText.mShowImeOnInputConnection = true;
273287 mEditText.setText(mEntry.remoteInputText);
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3635,7 +3635,8 @@ public final class ActivityManagerService extends ActivityManagerNative
36353635 final int procCount = procs.size();
36363636 for (int i = 0; i < procCount; i++) {
36373637 final int procUid = procs.keyAt(i);
3638- if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) {
3638+ if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)
3639+ || UserHandle.isIsolated(procUid)) {
36393640 // Don't use an app process or different user process for system component.
36403641 continue;
36413642 }
@@ -4914,9 +4915,9 @@ public final class ActivityManagerService extends ActivityManagerNative
49144915 userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
49154916
49164917 // TODO: Switch to user app stacks here.
4917- int ret = mActivityStarter.startActivityMayWait(null, uid, callingPackage, intent,
4918- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
4919- null, null, null, bOptions, false, userId, container, inTask);
4918+ int ret = mActivityStarter.startActivityMayWait(null, uid, ActivityStarter.PID_NULL, uid,
4919+ callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode,
4920+ startFlags, null, null, null, bOptions, false, userId, container, inTask);
49204921 return ret;
49214922 }
49224923
@@ -4936,12 +4937,19 @@ public final class ActivityManagerService extends ActivityManagerNative
49364937 final int startActivitiesInPackage(int uid, String callingPackage,
49374938 Intent[] intents, String[] resolvedTypes, IBinder resultTo,
49384939 Bundle bOptions, int userId) {
4940+ return startActivitiesInPackage(uid, ActivityStarter.PID_NULL, UserHandle.USER_NULL,
4941+ callingPackage, intents, resolvedTypes, resultTo, bOptions, userId);
4942+ }
4943+
4944+ final int startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid,
4945+ String callingPackage, Intent[] intents, String[] resolvedTypes,
4946+ IBinder resultTo, Bundle bOptions, int userId) {
49394947
49404948 userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
49414949 userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
49424950 // TODO: Switch to user app stacks here.
4943- int ret = mActivityStarter.startActivities(null, uid, callingPackage, intents, resolvedTypes,
4944- resultTo, bOptions, userId);
4951+ int ret = mActivityStarter.startActivities(null, uid, realCallingPid, realCallingUid,
4952+ callingPackage, intents, resolvedTypes, resultTo, bOptions, userId);
49454953 return ret;
49464954 }
49474955
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -129,6 +129,8 @@ import java.util.ArrayList;
129129 * an activity and associated task and stack.
130130 */
131131 class ActivityStarter {
132+ public static final int PID_NULL = 0;
133+
132134 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStarter" : TAG_AM;
133135 private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
134136 private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
@@ -737,12 +739,24 @@ class ActivityStarter {
737739 UserHandle.CURRENT);
738740 }
739741
742+ final int startActivityMayWait(IApplicationThread caller, int callingUid, String callingPackage,
743+ Intent intent, String resolvedType, IVoiceInteractionSession voiceSession,
744+ IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode,
745+ int startFlags, ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult,
746+ Configuration config, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
747+ IActivityContainer iContainer, TaskRecord inTask) {
748+ return startActivityMayWait(caller, callingUid, PID_NULL, UserHandle.USER_NULL,
749+ callingPackage, intent, resolvedType, voiceSession, voiceInteractor, resultTo,
750+ resultWho, requestCode, startFlags, profilerInfo, outResult, config, bOptions,
751+ ignoreTargetSecurity, userId, iContainer, inTask);
752+ }
753+
740754 final int startActivityMayWait(IApplicationThread caller, int callingUid,
741- String callingPackage, Intent intent, String resolvedType,
742- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
743- IBinder resultTo, String resultWho, int requestCode, int startFlags,
744- ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
745- Bundle bOptions, boolean ignoreTargetSecurity, int userId,
755+ int requestRealCallingPid, int requestRealCallingUid, String callingPackage,
756+ Intent intent, String resolvedType, IVoiceInteractionSession voiceSession,
757+ IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode,
758+ int startFlags, ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult,
759+ Configuration config, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
746760 IActivityContainer iContainer, TaskRecord inTask) {
747761 // Refuse possible leaked file descriptors
748762 if (intent != null && intent.hasFileDescriptors()) {
@@ -816,8 +830,13 @@ class ActivityStarter {
816830 e.printStackTrace();
817831 }
818832
819- final int realCallingPid = Binder.getCallingPid();
820- final int realCallingUid = Binder.getCallingUid();
833+ final int realCallingPid = requestRealCallingPid != PID_NULL
834+ ? requestRealCallingPid
835+ : Binder.getCallingPid();
836+ final int realCallingUid = requestRealCallingUid != UserHandle.USER_NULL
837+ ? requestRealCallingUid
838+ : Binder.getCallingUid();
839+
821840 int callingPid;
822841 if (callingUid >= 0) {
823842 callingPid = -1;
@@ -828,6 +847,7 @@ class ActivityStarter {
828847 callingPid = callingUid = -1;
829848 }
830849
850+
831851 final ActivityStack stack;
832852 if (container == null || container.mStack.isOnHomeDisplay()) {
833853 stack = mSupervisor.mFocusedStack;
@@ -969,8 +989,16 @@ class ActivityStarter {
969989 }
970990
971991 final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
972- Intent[] intents, String[] resolvedTypes, IBinder resultTo,
973- Bundle bOptions, int userId) {
992+ Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
993+ int userId) {
994+ return startActivities(caller, callingUid, PID_NULL, UserHandle.USER_NULL, callingPackage,
995+ intents, resolvedTypes, resultTo, bOptions, userId);
996+ }
997+
998+ final int startActivities(IApplicationThread caller, int callingUid,
999+ int incomingRealCallingPid, int incomingRealCallingUid, String callingPackage,
1000+ Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
1001+ int userId) {
9741002 if (intents == null) {
9751003 throw new NullPointerException("intents is null");
9761004 }
@@ -981,8 +1009,13 @@ class ActivityStarter {
9811009 throw new IllegalArgumentException("intents are length different than resolvedTypes");
9821010 }
9831011
984- final int realCallingPid = Binder.getCallingPid();
985- final int realCallingUid = Binder.getCallingUid();
1012+ final int realCallingPid = incomingRealCallingPid != PID_NULL
1013+ ? incomingRealCallingPid
1014+ : Binder.getCallingPid();
1015+
1016+ final int realCallingUid = incomingRealCallingUid != UserHandle.USER_NULL
1017+ ? incomingRealCallingUid
1018+ : Binder.getCallingUid();
9861019
9871020 int callingPid;
9881021 if (callingUid >= 0) {
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -21,6 +21,7 @@ import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
2121 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
2222 import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
2323 import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
24+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
2425 import static android.content.pm.PackageManager.GET_PERMISSIONS;
2526
2627 import android.content.BroadcastReceiver;
@@ -39,6 +40,8 @@ import android.os.UserManager;
3940 import android.text.TextUtils;
4041 import android.util.Log;
4142
43+import com.android.internal.util.ArrayUtils;
44+
4245 import java.util.ArrayList;
4346 import java.util.HashMap;
4447 import java.util.HashSet;
@@ -150,15 +153,13 @@ public class PermissionMonitor {
150153 update(mUsers, mApps, true);
151154 }
152155
153- private boolean hasPermission(PackageInfo app, String permission) {
154- if (app.requestedPermissions != null) {
155- for (String p : app.requestedPermissions) {
156- if (permission.equals(p)) {
157- return true;
158- }
159- }
156+ private boolean hasPermission(final PackageInfo app, final String permission) {
157+ if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
158+ return false;
160159 }
161- return false;
160+ final int index = ArrayUtils.indexOf(app.requestedPermissions, permission);
161+ if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
162+ return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
162163 }
163164
164165 private boolean hasNetworkPermission(PackageInfo app) {
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -591,6 +591,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
591591
592592 params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
593593 params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
594+ params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST;
594595 params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
595596 }
596597
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -15565,35 +15565,47 @@ public class PackageManagerService extends IPackageManager.Stub {
1556515565 int count = 0;
1556615566 final String packageName = pkg.packageName;
1556715567
15568+ boolean handlesWebUris = false;
15569+ final boolean alreadyVerified;
1556815570 synchronized (mPackages) {
1556915571 // If this is a new install and we see that we've already run verification for this
1557015572 // package, we have nothing to do: it means the state was restored from backup.
15571- if (!replacing) {
15572- IntentFilterVerificationInfo ivi =
15573- mSettings.getIntentFilterVerificationLPr(packageName);
15574- if (ivi != null) {
15575- if (DEBUG_DOMAIN_VERIFICATION) {
15576- Slog.i(TAG, "Package " + packageName+ " already verified: status="
15577- + ivi.getStatusString());
15578- }
15579- return;
15573+ final IntentFilterVerificationInfo ivi =
15574+ mSettings.getIntentFilterVerificationLPr(packageName);
15575+ alreadyVerified = (ivi != null);
15576+ if (!replacing && alreadyVerified) {
15577+ if (DEBUG_DOMAIN_VERIFICATION) {
15578+ Slog.i(TAG, "Package " + packageName + " already verified: status="
15579+ + ivi.getStatusString());
1558015580 }
15581+ return;
1558115582 }
1558215583
15583- // If any filters need to be verified, then all need to be.
15584+ // If any filters need to be verified, then all need to be. In addition, we need to
15585+ // know whether an updating app has any web navigation intent filters, to re-
15586+ // examine handling policy even if not re-verifying.
1558415587 boolean needToVerify = false;
1558515588 for (PackageParser.Activity a : pkg.activities) {
1558615589 for (ActivityIntentInfo filter : a.intents) {
15590+ if (filter.handlesWebUris(true)) {
15591+ handlesWebUris = true;
15592+ }
1558715593 if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
1558815594 if (DEBUG_DOMAIN_VERIFICATION) {
1558915595 Slog.d(TAG, "Intent filter needs verification, so processing all filters");
1559015596 }
1559115597 needToVerify = true;
15598+ // It's safe to break out here because filter.needsVerification()
15599+ // can only be true if filter.handlesWebUris(true) returns true, so
15600+ // we've already noted that.
1559215601 break;
1559315602 }
1559415603 }
1559515604 }
1559615605
15606+ // Note whether this app publishes any web navigation handling support at all,
15607+ // and whether there are any web-nav filters that fit the profile for running
15608+ // a verification pass now.
1559715609 if (needToVerify) {
1559815610 final int verificationId = mIntentFilterVerificationToken++;
1559915611 for (PackageParser.Activity a : pkg.activities) {
@@ -15611,13 +15623,23 @@ public class PackageManagerService extends IPackageManager.Stub {
1561115623 }
1561215624
1561315625 if (count > 0) {
15626+ // count > 0 means that we're running a full verification pass
1561415627 if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count
1561515628 + " IntentFilter verification" + (count > 1 ? "s" : "")
1561615629 + " for userId:" + userId);
1561715630 mIntentFilterVerifier.startVerifications(userId);
15631+ } else if (alreadyVerified && handlesWebUris) {
15632+ // App used autoVerify in the past, no longer does, but still handles web
15633+ // navigation starts.
15634+ if (DEBUG_DOMAIN_VERIFICATION) {
15635+ Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy");
15636+ }
15637+ synchronized (mPackages) {
15638+ clearIntentFilterVerificationsLPw(packageName, userId);
15639+ }
1561815640 } else {
1561915641 if (DEBUG_DOMAIN_VERIFICATION) {
15620- Slog.d(TAG, "No filters or not all autoVerify for " + packageName);
15642+ Slog.d(TAG, "No web filters or no prior verify policy for " + packageName);
1562115643 }
1562215644 }
1562315645 }
@@ -16215,7 +16237,8 @@ public class PackageManagerService extends IPackageManager.Stub {
1621516237 * Tries to delete system package.
1621616238 */
1621716239 private boolean deleteSystemPackageLIF(PackageParser.Package deletedPkg,
16218- PackageSetting deletedPs, int[] allUserHandles, int flags, PackageRemovedInfo outInfo,
16240+ PackageSetting deletedPs, int[] allUserHandles, int flags,
16241+ @Nullable PackageRemovedInfo outInfo,
1621916242 boolean writeSettings) {
1622016243 if (deletedPs.parentPackageName != null) {
1622116244 Slog.w(TAG, "Attempt to delete child system package " + deletedPkg.packageName);
@@ -16223,7 +16246,7 @@ public class PackageManagerService extends IPackageManager.Stub {
1622316246 }
1622416247
1622516248 final boolean applyUserRestrictions
16226- = (allUserHandles != null) && (outInfo.origUsers != null);
16249+ = (allUserHandles != null) && outInfo != null && (outInfo.origUsers != null);
1622716250 final PackageSetting disabledPs;
1622816251 // Confirm if the system package has been updated
1622916252 // An updated system app can be deleted. This will also have to restore
@@ -16253,19 +16276,21 @@ public class PackageManagerService extends IPackageManager.Stub {
1625316276 }
1625416277 }
1625516278
16256- // Delete the updated package
16257- outInfo.isRemovedPackageSystemUpdate = true;
16258- if (outInfo.removedChildPackages != null) {
16259- final int childCount = (deletedPs.childPackageNames != null)
16260- ? deletedPs.childPackageNames.size() : 0;
16261- for (int i = 0; i < childCount; i++) {
16262- String childPackageName = deletedPs.childPackageNames.get(i);
16263- if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
16264- .contains(childPackageName)) {
16265- PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
16266- childPackageName);
16267- if (childInfo != null) {
16268- childInfo.isRemovedPackageSystemUpdate = true;
16279+ if (outInfo != null) {
16280+ // Delete the updated package
16281+ outInfo.isRemovedPackageSystemUpdate = true;
16282+ if (outInfo.removedChildPackages != null) {
16283+ final int childCount = (deletedPs.childPackageNames != null)
16284+ ? deletedPs.childPackageNames.size() : 0;
16285+ for (int i = 0; i < childCount; i++) {
16286+ String childPackageName = deletedPs.childPackageNames.get(i);
16287+ if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
16288+ .contains(childPackageName)) {
16289+ PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
16290+ childPackageName);
16291+ if (childInfo != null) {
16292+ childInfo.isRemovedPackageSystemUpdate = true;
16293+ }
1626916294 }
1627016295 }
1627116296 }
@@ -20168,9 +20193,9 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
2016820193 mSettings.writeKernelMappingLPr(ps);
2016920194 }
2017020195
20171- final UserManager um = mContext.getSystemService(UserManager.class);
20196+ final UserManagerService um = sUserManager;
2017220197 UserManagerInternal umInternal = getUserManagerInternal();
20173- for (UserInfo user : um.getUsers()) {
20198+ for (UserInfo user : um.getUsers(false /* excludeDying */)) {
2017420199 final int flags;
2017520200 if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
2017620201 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1331,6 +1331,7 @@ final class Settings {
13311331 return false;
13321332 }
13331333 ps.clearDomainVerificationStatusForUser(userId);
1334+ ps.setIntentFilterVerificationInfo(null);
13341335 return true;
13351336 }
13361337
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2863,6 +2863,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
28632863 attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
28642864 }
28652865 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
2866+ // Toasts can't be clickable
2867+ attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
28662868 break;
28672869 }
28682870
--- /dev/null
+++ b/services/core/java/com/android/server/wallpaper/GLHelper.java
@@ -0,0 +1,148 @@
1+/*
2+ * Copyright (C) 2019 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+
17+package com.android.server.wallpaper;
18+
19+import static android.opengl.EGL14.EGL_ALPHA_SIZE;
20+import static android.opengl.EGL14.EGL_BLUE_SIZE;
21+import static android.opengl.EGL14.EGL_CONFIG_CAVEAT;
22+import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
23+import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY;
24+import static android.opengl.EGL14.EGL_DEPTH_SIZE;
25+import static android.opengl.EGL14.EGL_GREEN_SIZE;
26+import static android.opengl.EGL14.EGL_HEIGHT;
27+import static android.opengl.EGL14.EGL_NONE;
28+import static android.opengl.EGL14.EGL_NO_CONTEXT;
29+import static android.opengl.EGL14.EGL_NO_DISPLAY;
30+import static android.opengl.EGL14.EGL_NO_SURFACE;
31+import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT;
32+import static android.opengl.EGL14.EGL_RED_SIZE;
33+import static android.opengl.EGL14.EGL_RENDERABLE_TYPE;
34+import static android.opengl.EGL14.EGL_STENCIL_SIZE;
35+import static android.opengl.EGL14.EGL_WIDTH;
36+import static android.opengl.EGL14.eglChooseConfig;
37+import static android.opengl.EGL14.eglCreateContext;
38+import static android.opengl.EGL14.eglCreatePbufferSurface;
39+import static android.opengl.EGL14.eglDestroyContext;
40+import static android.opengl.EGL14.eglDestroySurface;
41+import static android.opengl.EGL14.eglGetDisplay;
42+import static android.opengl.EGL14.eglGetError;
43+import static android.opengl.EGL14.eglInitialize;
44+import static android.opengl.EGL14.eglMakeCurrent;
45+import static android.opengl.EGL14.eglTerminate;
46+import static android.opengl.GLES20.GL_MAX_TEXTURE_SIZE;
47+import static android.opengl.GLES20.glGetIntegerv;
48+
49+import android.opengl.EGLConfig;
50+import android.opengl.EGLContext;
51+import android.opengl.EGLDisplay;
52+import android.opengl.EGLSurface;
53+import android.opengl.GLUtils;
54+import android.os.SystemProperties;
55+import android.util.Log;
56+
57+class GLHelper {
58+ private static final String TAG = GLHelper.class.getSimpleName();
59+ private static final int sMaxTextureSize;
60+
61+ static {
62+ int maxTextureSize = SystemProperties.getInt("sys.max_texture_size", 0);
63+ sMaxTextureSize = maxTextureSize > 0 ? maxTextureSize : retrieveTextureSizeFromGL();
64+ }
65+
66+ private static int retrieveTextureSizeFromGL() {
67+ try {
68+ String err;
69+
70+ // Before we can retrieve info from GL,
71+ // we have to create EGLContext, EGLConfig and EGLDisplay first.
72+ // We will fail at querying info from GL once one of above failed.
73+ // When this happens, we will use defValue instead.
74+ EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
75+ if (eglDisplay == null || eglDisplay == EGL_NO_DISPLAY) {
76+ err = "eglGetDisplay failed: " + GLUtils.getEGLErrorString(eglGetError());
77+ throw new RuntimeException(err);
78+ }
79+
80+ if (!eglInitialize(eglDisplay, null, 0 /* majorOffset */, null, 1 /* minorOffset */)) {
81+ err = "eglInitialize failed: " + GLUtils.getEGLErrorString(eglGetError());
82+ throw new RuntimeException(err);
83+ }
84+
85+ EGLConfig eglConfig = null;
86+ int[] configsCount = new int[1];
87+ EGLConfig[] configs = new EGLConfig[1];
88+ int[] configSpec = new int[] {
89+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
90+ EGL_RED_SIZE, 8,
91+ EGL_GREEN_SIZE, 8,
92+ EGL_BLUE_SIZE, 8,
93+ EGL_ALPHA_SIZE, 0,
94+ EGL_DEPTH_SIZE, 0,
95+ EGL_STENCIL_SIZE, 0,
96+ EGL_CONFIG_CAVEAT, EGL_NONE,
97+ EGL_NONE
98+ };
99+
100+ if (!eglChooseConfig(eglDisplay, configSpec, 0 /* attrib_listOffset */,
101+ configs, 0 /* configOffset */, 1 /* config_size */,
102+ configsCount, 0 /* num_configOffset */)) {
103+ err = "eglChooseConfig failed: " + GLUtils.getEGLErrorString(eglGetError());
104+ throw new RuntimeException(err);
105+ } else if (configsCount[0] > 0) {
106+ eglConfig = configs[0];
107+ }
108+
109+ if (eglConfig == null) {
110+ throw new RuntimeException("eglConfig not initialized!");
111+ }
112+
113+ int[] attr_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
114+ EGLContext eglContext = eglCreateContext(
115+ eglDisplay, eglConfig, EGL_NO_CONTEXT, attr_list, 0 /* offset */);
116+
117+ if (eglContext == null || eglContext == EGL_NO_CONTEXT) {
118+ err = "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError());
119+ throw new RuntimeException(err);
120+ }
121+
122+ // We create a push buffer temporarily for querying info from GL.
123+ int[] attrs = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
124+ EGLSurface eglSurface =
125+ eglCreatePbufferSurface(eglDisplay, eglConfig, attrs, 0 /* offset */);
126+ eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
127+
128+ // Now, we are ready to query the info from GL.
129+ int[] maxSize = new int[1];
130+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0 /* offset */);
131+
132+ // We have got the info we want, release all egl resources.
133+ eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
134+ eglDestroySurface(eglDisplay, eglSurface);
135+ eglDestroyContext(eglDisplay, eglContext);
136+ eglTerminate(eglDisplay);
137+ return maxSize[0];
138+ } catch (RuntimeException e) {
139+ Log.w(TAG, "Retrieve from GL failed", e);
140+ return Integer.MAX_VALUE;
141+ }
142+ }
143+
144+ static int getMaxTextureSize() {
145+ return sMaxTextureSize;
146+ }
147+}
148+
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -115,6 +115,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
115115 static final String TAG = "WallpaperManagerService";
116116 static final boolean DEBUG = false;
117117
118+ // This 100MB limitation is defined in DisplayListCanvas.
119+ private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024;
120+
118121 public static class Lifecycle extends SystemService {
119122 private WallpaperManagerService mService;
120123
@@ -368,7 +371,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
368371 }
369372
370373 // scale if the crop height winds up not matching the recommended metrics
371- needScale = (wallpaper.height != cropHint.height());
374+ // also take care of invalid dimensions.
375+ needScale = wallpaper.height != cropHint.height()
376+ || cropHint.height() > GLHelper.getMaxTextureSize()
377+ || cropHint.width() > GLHelper.getMaxTextureSize();
372378
373379 if (DEBUG) {
374380 Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
@@ -380,14 +386,29 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
380386 if (!needCrop && !needScale) {
381387 // Simple case: the nominal crop fits what we want, so we take
382388 // the whole thing and just copy the image file directly.
383- if (DEBUG) {
384- Slog.v(TAG, "Null crop of new wallpaper; copying");
389+
390+ // TODO: It is not accurate to estimate bitmap size without decoding it,
391+ // may be we can try to remove this optimized way in the future,
392+ // that means, we will always go into the 'else' block.
393+
394+ // This is just a quick estimation, may be smaller than it is.
395+ long estimateSize = options.outWidth * options.outHeight * 4;
396+
397+ // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail.
398+ // Please see: DisplayListCanvas#throwIfCannotDraw.
399+ if (estimateSize < MAX_BITMAP_SIZE) {
400+ success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
385401 }
386- success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
402+
387403 if (!success) {
388404 wallpaper.cropFile.delete();
389405 // TODO: fall back to default wallpaper in this case
390406 }
407+
408+ if (DEBUG) {
409+ Slog.v(TAG, "Null crop of new wallpaper, estimate size=" + estimateSize
410+ + ", success=" + success);
411+ }
391412 } else {
392413 // Fancy case: crop and scale. First, we decode and scale down if appropriate.
393414 FileOutputStream f = null;
@@ -401,48 +422,78 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
401422 // We calculate the largest power-of-two under the actual ratio rather than
402423 // just let the decode take care of it because we also want to remap where the
403424 // cropHint rectangle lies in the decoded [super]rect.
404- final BitmapFactory.Options scaler;
405425 final int actualScale = cropHint.height() / wallpaper.height;
406426 int scale = 1;
407- while (2*scale < actualScale) {
427+ while (2*scale <= actualScale) {
408428 scale *= 2;
409429 }
410- if (scale > 1) {
411- scaler = new BitmapFactory.Options();
412- scaler.inSampleSize = scale;
430+ options.inSampleSize = scale;
431+ options.inJustDecodeBounds = false;
432+
433+ final Rect estimateCrop = new Rect(cropHint);
434+ estimateCrop.scale(1f / options.inSampleSize);
435+ final float hRatio = (float) wallpaper.height / estimateCrop.height();
436+ final int destHeight = (int) (estimateCrop.height() * hRatio);
437+ final int destWidth = (int) (estimateCrop.width() * hRatio);
438+
439+ // We estimated an invalid crop, try to adjust the cropHint to get a valid one.
440+ if (destWidth > GLHelper.getMaxTextureSize()) {
441+ int newHeight = (int) (wallpaper.height / hRatio);
442+ int newWidth = (int) (wallpaper.width / hRatio);
443+
413444 if (DEBUG) {
414- Slog.v(TAG, "Downsampling cropped rect with scale " + scale);
445+ Slog.v(TAG, "Invalid crop dimensions, trying to adjust.");
415446 }
416- } else {
417- scaler = null;
447+
448+ estimateCrop.set(cropHint);
449+ estimateCrop.left += (cropHint.width() - newWidth) / 2;
450+ estimateCrop.top += (cropHint.height() - newHeight) / 2;
451+ estimateCrop.right = estimateCrop.left + newWidth;
452+ estimateCrop.bottom = estimateCrop.top + newHeight;
453+ cropHint.set(estimateCrop);
454+ estimateCrop.scale(1f / options.inSampleSize);
455+ }
456+
457+ // We've got the safe cropHint; now we want to scale it properly to
458+ // the desired rectangle.
459+ // That's a height-biased operation: make it fit the hinted height.
460+ final int safeHeight = (int) (estimateCrop.height() * hRatio);
461+ final int safeWidth = (int) (estimateCrop.width() * hRatio);
462+
463+ if (DEBUG) {
464+ Slog.v(TAG, "Decode parameters:");
465+ Slog.v(TAG, " cropHint=" + cropHint + ", estimateCrop=" + estimateCrop);
466+ Slog.v(TAG, " down sampling=" + options.inSampleSize
467+ + ", hRatio=" + hRatio);
468+ Slog.v(TAG, " dest=" + destWidth + "x" + destHeight);
469+ Slog.v(TAG, " safe=" + safeWidth + "x" + safeHeight);
470+ Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize());
418471 }
419- Bitmap cropped = decoder.decodeRegion(cropHint, scaler);
472+
473+ Bitmap cropped = decoder.decodeRegion(cropHint, options);
420474 decoder.recycle();
421475
422476 if (cropped == null) {
423477 Slog.e(TAG, "Could not decode new wallpaper");
424478 } else {
425- // We've got the extracted crop; now we want to scale it properly to
426- // the desired rectangle. That's a height-biased operation: make it
427- // fit the hinted height, and accept whatever width we end up with.
428- cropHint.offsetTo(0, 0);
429- cropHint.right /= scale; // adjust by downsampling factor
430- cropHint.bottom /= scale;
431- final float heightR = ((float)wallpaper.height) / ((float)cropHint.height());
432- if (DEBUG) {
433- Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint);
434- }
435- final int destWidth = (int)(cropHint.width() * heightR);
479+ // We are safe to create final crop with safe dimensions now.
436480 final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped,
437- destWidth, wallpaper.height, true);
481+ safeWidth, safeHeight, true);
438482 if (DEBUG) {
439483 Slog.v(TAG, "Final extract:");
440484 Slog.v(TAG, " dims: w=" + wallpaper.width
441485 + " h=" + wallpaper.height);
442- Slog.v(TAG, " out: w=" + finalCrop.getWidth()
486+ Slog.v(TAG, " out: w=" + finalCrop.getWidth()
443487 + " h=" + finalCrop.getHeight());
444488 }
445489
490+ // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail.
491+ // Please see: DisplayListCanvas#throwIfCannotDraw.
492+ if (finalCrop.getByteCount() > MAX_BITMAP_SIZE) {
493+ throw new RuntimeException(
494+ "Too large bitmap, limit=" + MAX_BITMAP_SIZE);
495+ }
496+
446497 f = new FileOutputStream(wallpaper.cropFile);
447498 bos = new BufferedOutputStream(f, 32*1024);
448499 finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos);
@@ -1234,6 +1285,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
12341285 if (!isWallpaperSupported(callingPackage)) {
12351286 return;
12361287 }
1288+
1289+ // Make sure both width and height are not larger than max texture size.
1290+ width = Math.min(width, GLHelper.getMaxTextureSize());
1291+ height = Math.min(height, GLHelper.getMaxTextureSize());
1292+
12371293 synchronized (mLock) {
12381294 int userId = UserHandle.getCallingUserId();
12391295 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Show on old repository browser