Loading core/java/com/android/internal/util/NamedLock.java 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.util; import java.util.Objects; /** * A lock with a name! * * <p>This class should be used as a synchronization lock (i.e., instead of * {@code mLock = new Object()}, so stack traces show exactly what the lock's for (other than just * it's internal address). In other words, it solves the "A Lock has no Name!" issue). * * @hide */ public final class NamedLock { private final String mName; private NamedLock(String name) { mName = Objects.requireNonNull(name, "name cannot be null"); String stripped = name.strip(); Preconditions.checkArgument(name.equals(stripped), "name (%s) cannot start or end with blank characters", name); Preconditions.checkArgument(!name.isEmpty(), "name cannot be empty"); } /** * Creates a lock with the given name. * * @throws IllegalArgumentException if the name is empty, starts with a blank character, or ends * with a blank character. */ public static Object create(String name) { return new NamedLock(name); } @Override public String toString() { return mName; } } core/tests/coretests/src/com/android/internal/util/NamedLockTest.java 0 → 100644 +93 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.util; import static com.android.internal.util.NamedLock.create; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertThrows; import org.junit.Test; public final class NamedLockTest { @Test public void testFactoryMethod_null() { assertThrows(NullPointerException.class, () -> create(null)); } @Test public void testFactoryMethod_empty() { assertThrows(IllegalArgumentException.class, () -> create("")); assertThrows(IllegalArgumentException.class, () -> create(" ")); assertThrows(IllegalArgumentException.class, () -> create("\t")); } @Test public void testFactoryMethod_startsWithSpace() { assertThrows(IllegalArgumentException.class, () -> create(" NAME, Y U START WITH SPACE?")); } @Test public void testFactoryMethod_startsWithTab() { assertThrows(IllegalArgumentException.class, () -> create("\tNAME, Y U START WITH TAB?")); } @Test public void testFactoryMethod_endsWithSpace() { assertThrows(IllegalArgumentException.class, () -> create("NAME, Y U END WITH SPACE? ")); } @Test public void testFactoryMethod_endsWithTab() { assertThrows(IllegalArgumentException.class, () -> create("NAME, Y U END WITH TAB?\t")); } @Test public void testOneInstance() { var namedLock = create("Bond, James Bond"); assertWithMessage("create()").that(namedLock).isNotNull(); assertWithMessage("toString()").that(namedLock.toString()).isEqualTo("Bond, James Bond"); } @Test public void testMultipleInstances_sameName() { String commonName = "Bond, James Bond"; var namedLock1 = create(commonName); var namedLock2 = create(commonName); assertWithMessage("namedLock1").that(namedLock1).isNotSameInstanceAs(namedLock2); assertWithMessage("namedLock1").that(namedLock1).isNotEqualTo(namedLock2); assertWithMessage("namedLock2").that(namedLock2).isNotEqualTo(namedLock1); } @Test public void testMultipleInstances_differentNames() { var namedLock1 = create("Bond, James Bond"); var namedLock2 = create("A Lock has a Name"); assertWithMessage("namedLock1").that(namedLock1).isNotSameInstanceAs(namedLock2); assertWithMessage("namedLock1").that(namedLock1).isNotEqualTo(namedLock2); assertWithMessage("namedLock2").that(namedLock2).isNotEqualTo(namedLock1); } } Loading
core/java/com/android/internal/util/NamedLock.java 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.util; import java.util.Objects; /** * A lock with a name! * * <p>This class should be used as a synchronization lock (i.e., instead of * {@code mLock = new Object()}, so stack traces show exactly what the lock's for (other than just * it's internal address). In other words, it solves the "A Lock has no Name!" issue). * * @hide */ public final class NamedLock { private final String mName; private NamedLock(String name) { mName = Objects.requireNonNull(name, "name cannot be null"); String stripped = name.strip(); Preconditions.checkArgument(name.equals(stripped), "name (%s) cannot start or end with blank characters", name); Preconditions.checkArgument(!name.isEmpty(), "name cannot be empty"); } /** * Creates a lock with the given name. * * @throws IllegalArgumentException if the name is empty, starts with a blank character, or ends * with a blank character. */ public static Object create(String name) { return new NamedLock(name); } @Override public String toString() { return mName; } }
core/tests/coretests/src/com/android/internal/util/NamedLockTest.java 0 → 100644 +93 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.util; import static com.android.internal.util.NamedLock.create; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertThrows; import org.junit.Test; public final class NamedLockTest { @Test public void testFactoryMethod_null() { assertThrows(NullPointerException.class, () -> create(null)); } @Test public void testFactoryMethod_empty() { assertThrows(IllegalArgumentException.class, () -> create("")); assertThrows(IllegalArgumentException.class, () -> create(" ")); assertThrows(IllegalArgumentException.class, () -> create("\t")); } @Test public void testFactoryMethod_startsWithSpace() { assertThrows(IllegalArgumentException.class, () -> create(" NAME, Y U START WITH SPACE?")); } @Test public void testFactoryMethod_startsWithTab() { assertThrows(IllegalArgumentException.class, () -> create("\tNAME, Y U START WITH TAB?")); } @Test public void testFactoryMethod_endsWithSpace() { assertThrows(IllegalArgumentException.class, () -> create("NAME, Y U END WITH SPACE? ")); } @Test public void testFactoryMethod_endsWithTab() { assertThrows(IllegalArgumentException.class, () -> create("NAME, Y U END WITH TAB?\t")); } @Test public void testOneInstance() { var namedLock = create("Bond, James Bond"); assertWithMessage("create()").that(namedLock).isNotNull(); assertWithMessage("toString()").that(namedLock.toString()).isEqualTo("Bond, James Bond"); } @Test public void testMultipleInstances_sameName() { String commonName = "Bond, James Bond"; var namedLock1 = create(commonName); var namedLock2 = create(commonName); assertWithMessage("namedLock1").that(namedLock1).isNotSameInstanceAs(namedLock2); assertWithMessage("namedLock1").that(namedLock1).isNotEqualTo(namedLock2); assertWithMessage("namedLock2").that(namedLock2).isNotEqualTo(namedLock1); } @Test public void testMultipleInstances_differentNames() { var namedLock1 = create("Bond, James Bond"); var namedLock2 = create("A Lock has a Name"); assertWithMessage("namedLock1").that(namedLock1).isNotSameInstanceAs(namedLock2); assertWithMessage("namedLock1").that(namedLock1).isNotEqualTo(namedLock2); assertWithMessage("namedLock2").that(namedLock2).isNotEqualTo(namedLock1); } }